summaryrefslogtreecommitdiffstats
path: root/media/webm
diff options
context:
space:
mode:
authoracolwell@chromium.org <acolwell@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-06 19:16:53 +0000
committeracolwell@chromium.org <acolwell@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-06 19:16:53 +0000
commit07b405307121188af8edc4c65c46c134f419a662 (patch)
tree3fd0febf03149bd1519791b9989334c754990ba6 /media/webm
parentcea8417218ddd2f3012aaf221dd46dc80c7c2c2f (diff)
downloadchromium_src-07b405307121188af8edc4c65c46c134f419a662.zip
chromium_src-07b405307121188af8edc4c65c46c134f419a662.tar.gz
chromium_src-07b405307121188af8edc4c65c46c134f419a662.tar.bz2
WebM parser bug fixes for live streams.
- Update ChunkDemuxer so kInfiniteDuration streams are not seekable. - Add support for Segment & Cluster elements of unknown size to WebMListParser. - Update WebMStreamParser to treat content without a Duration header as having kInfiniteDuration. BUG=116824 TEST=ChunkDemuxerTest.TestWebMFile_LiveAudioAndVideo, WebMParserTest.ReservedIds, WebMParserTest.ReservedSizes Review URL: http://codereview.chromium.org/9600028 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@125197 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/webm')
-rw-r--r--media/webm/webm_constants.h3
-rw-r--r--media/webm/webm_parser.cc68
-rw-r--r--media/webm/webm_parser.h13
-rw-r--r--media/webm/webm_parser_unittest.cc57
-rw-r--r--media/webm/webm_stream_parser.cc10
5 files changed, 133 insertions, 18 deletions
diff --git a/media/webm/webm_constants.h b/media/webm/webm_constants.h
index ecd01df..f6afef4 100644
--- a/media/webm/webm_constants.h
+++ b/media/webm/webm_constants.h
@@ -21,7 +21,7 @@ const int kWebMIdBitDepth = 0x6264;
const int kWebMIdBlock = 0xA1;
const int kWebMIdBlockAddID = 0xEE;
const int kWebMIdBlockAdditions = 0x75A1;
-const int kWebMIdBlockAdditional = 0xA4;
+const int kWebMIdBlockAdditional = 0xA5;
const int kWebMIdBlockDuration = 0x9B;
const int kWebMIdBlockGroup = 0xA0;
const int kWebMIdBlockMore = 0xA6;
@@ -192,6 +192,7 @@ const int kWebMIdVideo = 0xE0;
const int kWebMIdVoid = 0xEC;
const int kWebMIdWritingApp = 0x5741;
+const int64 kWebMReservedId = 0x1FFFFFFF;
const int64 kWebMUnknownSize = GG_LONGLONG(0x00FFFFFFFFFFFFFF);
} // namespace media
diff --git a/media/webm/webm_parser.cc b/media/webm/webm_parser.cc
index 777ec91..ea7eea9 100644
--- a/media/webm/webm_parser.cc
+++ b/media/webm/webm_parser.cc
@@ -424,13 +424,16 @@ static int ParseWebMElementHeaderField(const uint8* buf, int size,
int mask = 0x80;
uint8 ch = buf[0];
int extra_bytes = -1;
+ bool all_ones = false;
for (int i = 0; i < max_bytes; ++i) {
- if ((ch & mask) == mask) {
- *num = mask_first_byte ? ch & ~mask : ch;
+ if ((ch & mask) != 0) {
+ mask = ~mask & 0xff;
+ *num = mask_first_byte ? ch & mask : ch;
+ all_ones = (ch & mask) == mask;
extra_bytes = i;
break;
}
- mask >>= 1;
+ mask = 0x80 | mask >> 1;
}
if (extra_bytes == -1)
@@ -442,8 +445,14 @@ static int ParseWebMElementHeaderField(const uint8* buf, int size,
int bytes_used = 1;
- for (int i = 0; i < extra_bytes; ++i)
- *num = (*num << 8) | (0xff & buf[bytes_used++]);
+ for (int i = 0; i < extra_bytes; ++i) {
+ ch = buf[bytes_used++];
+ all_ones &= (ch == 0xff);
+ *num = (*num << 8) | ch;
+ }
+
+ if (all_ones)
+ *num = kint64max;
return bytes_used;
}
@@ -464,6 +473,9 @@ int WebMParseElementHeader(const uint8* buf, int size,
if (num_id_bytes <= 0)
return num_id_bytes;
+ if (tmp == kint64max)
+ tmp = kWebMReservedId;
+
*id = static_cast<int>(tmp);
int num_size_bytes = ParseWebMElementHeaderField(buf + num_id_bytes,
@@ -473,7 +485,12 @@ int WebMParseElementHeader(const uint8* buf, int size,
if (num_size_bytes <= 0)
return num_size_bytes;
+ if (tmp == kint64max)
+ tmp = kWebMUnknownSize;
+
*element_size = tmp;
+ DVLOG(3) << "WebMParseElementHeader() : id " << std::hex << *id << std::dec
+ << " size " << *element_size;
return num_id_bytes + num_size_bytes;
}
@@ -740,8 +757,10 @@ int WebMListParser::Parse(const uint8* buf, int size) {
return -1;
}
- // TODO(acolwell): Add support for lists of unknown size.
- if (element_size == kWebMUnknownSize) {
+ // Only allow Segment & Cluster to have an unknown size.
+ if (element_size == kWebMUnknownSize &&
+ (element_id != kWebMIdSegment) &&
+ (element_id != kWebMIdCluster)) {
ChangeState(PARSE_ERROR);
return -1;
}
@@ -812,8 +831,24 @@ int WebMListParser::ParseListElement(int header_size,
// Unexpected ID.
if (id_type == UNKNOWN) {
- DVLOG(1) << "No ElementType info for ID 0x" << std::hex << id;
- return -1;
+ if (list_state.size_ != kWebMUnknownSize ||
+ !IsSiblingOrAncestor(list_state.id_, id)) {
+ DVLOG(1) << "No ElementType info for ID 0x" << std::hex << id;
+ return -1;
+ }
+
+ // We've reached the end of a list of unknown size. Update the size now that
+ // we know it and dispatch the end of list calls.
+ list_state.size_ = list_state.bytes_parsed_;
+
+ if (!OnListEnd())
+ return -1;
+
+ // Check to see if all open lists have ended.
+ if (list_state_stack_.size() == 0)
+ return 0;
+
+ list_state = list_state_stack_.back();
}
// Make sure the whole element can fit inside the current list.
@@ -925,4 +960,19 @@ bool WebMListParser::OnListEnd() {
return true;
}
+bool WebMListParser::IsSiblingOrAncestor(int id_a, int id_b) const {
+ DCHECK((id_a == kWebMIdSegment) || (id_a == kWebMIdCluster));
+
+ if (id_a == kWebMIdCluster) {
+ // kWebMIdCluster siblings.
+ for (size_t i = 0; i < arraysize(kSegmentIds); i++) {
+ if (kSegmentIds[i].id_ == id_b)
+ return true;
+ }
+ }
+
+ // kWebMIdSegment siblings.
+ return ((id_b == kWebMIdSegment) || (id_b == kWebMIdEBMLHeader));
+}
+
} // namespace media
diff --git a/media/webm/webm_parser.h b/media/webm/webm_parser.h
index 4575286..2c6d459 100644
--- a/media/webm/webm_parser.h
+++ b/media/webm/webm_parser.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -82,8 +82,8 @@ class MEDIA_EXPORT WebMListParser {
struct ListState {
int id_;
- int size_;
- int bytes_parsed_;
+ int64 size_;
+ int64 bytes_parsed_;
const ListElementInfo* element_info_;
WebMParserClient* client_;
};
@@ -123,6 +123,9 @@ class MEDIA_EXPORT WebMListParser {
// Returns true if no errors occurred while ending this list(s).
bool OnListEnd();
+ // Checks to see if |id_b| is a sibling or ancestor of |id_a|.
+ bool IsSiblingOrAncestor(int id_a, int id_b) const;
+
State state_;
// Element ID passed to the constructor.
@@ -150,8 +153,8 @@ class MEDIA_EXPORT WebMListParser {
// |*id| contains the element ID on success and is undefined otherwise.
// |*element_size| contains the element size on success and is undefined
// otherwise.
-int WebMParseElementHeader(const uint8* buf, int size,
- int* id, int64* element_size);
+int MEDIA_EXPORT WebMParseElementHeader(const uint8* buf, int size,
+ int* id, int64* element_size);
} // namespace media
diff --git a/media/webm/webm_parser_unittest.cc b/media/webm/webm_parser_unittest.cc
index c7b30f7..e518386 100644
--- a/media/webm/webm_parser_unittest.cc
+++ b/media/webm/webm_parser_unittest.cc
@@ -352,4 +352,61 @@ TEST_F(WebMParserTest, InvalidClient) {
EXPECT_FALSE(parser.IsParsingComplete());
}
+TEST_F(WebMParserTest, ReservedIds) {
+ const uint8 k1ByteReservedId[] = { 0xFF, 0x81 };
+ const uint8 k2ByteReservedId[] = { 0x7F, 0xFF, 0x81 };
+ const uint8 k3ByteReservedId[] = { 0x3F, 0xFF, 0xFF, 0x81 };
+ const uint8 k4ByteReservedId[] = { 0x1F, 0xFF, 0xFF, 0xFF, 0x81 };
+ const uint8* kBuffers[] = {
+ k1ByteReservedId,
+ k2ByteReservedId,
+ k3ByteReservedId,
+ k4ByteReservedId
+ };
+
+ for (size_t i = 0; i < arraysize(kBuffers); i++) {
+ int id;
+ int64 element_size;
+ int buffer_size = 2 + i;
+ EXPECT_EQ(buffer_size, WebMParseElementHeader(kBuffers[i], buffer_size,
+ &id, &element_size));
+ EXPECT_EQ(id, kWebMReservedId);
+ EXPECT_EQ(element_size, 1);
+ }
+}
+
+TEST_F(WebMParserTest, ReservedSizes) {
+ const uint8 k1ByteReservedSize[] = { 0xA3, 0xFF };
+ const uint8 k2ByteReservedSize[] = { 0xA3, 0x7F, 0xFF };
+ const uint8 k3ByteReservedSize[] = { 0xA3, 0x3F, 0xFF, 0xFF };
+ const uint8 k4ByteReservedSize[] = { 0xA3, 0x1F, 0xFF, 0xFF, 0xFF };
+ const uint8 k5ByteReservedSize[] = { 0xA3, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF };
+ const uint8 k6ByteReservedSize[] = { 0xA3, 0x07, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF };
+ const uint8 k7ByteReservedSize[] = { 0xA3, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF };
+ const uint8 k8ByteReservedSize[] = { 0xA3, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF };
+ const uint8* kBuffers[] = {
+ k1ByteReservedSize,
+ k2ByteReservedSize,
+ k3ByteReservedSize,
+ k4ByteReservedSize,
+ k5ByteReservedSize,
+ k6ByteReservedSize,
+ k7ByteReservedSize,
+ k8ByteReservedSize
+ };
+
+ for (size_t i = 0; i < arraysize(kBuffers); i++) {
+ int id;
+ int64 element_size;
+ int buffer_size = 2 + i;
+ EXPECT_EQ(buffer_size, WebMParseElementHeader(kBuffers[i], buffer_size,
+ &id, &element_size));
+ EXPECT_EQ(id, 0xA3);
+ EXPECT_EQ(element_size, kWebMUnknownSize);
+ }
+}
+
} // namespace media
diff --git a/media/webm/webm_stream_parser.cc b/media/webm/webm_stream_parser.cc
index d49ed7c..036f7e7b0 100644
--- a/media/webm/webm_stream_parser.cc
+++ b/media/webm/webm_stream_parser.cc
@@ -281,9 +281,13 @@ int WebMStreamParser::ParseInfoAndTracks(const uint8* data, int size) {
bytes_parsed += result;
- double mult = info_parser.timecode_scale() / 1000.0;
- base::TimeDelta duration =
- base::TimeDelta::FromMicroseconds(info_parser.duration() * mult);
+ base::TimeDelta duration = kInfiniteDuration();
+
+ if (info_parser.duration() > 0) {
+ double mult = info_parser.timecode_scale() / 1000.0;
+ int64 duration_in_us = info_parser.duration() * mult;
+ duration = base::TimeDelta::FromMicroseconds(duration_in_us);
+ }
FFmpegConfigHelper config_helper;