summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authoracolwell@chromium.org <acolwell@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-12-12 18:04:58 +0000
committeracolwell@chromium.org <acolwell@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-12-12 18:04:58 +0000
commitfa51035c240ed1096c97dd7aaa505bd61857d672 (patch)
tree35f2ad644f67026ed8e4e6bf8943e0a99a2136b8 /media
parent1e75b26d2526d7a5ec2d9cc4ef1250fa3ea26e81 (diff)
downloadchromium_src-fa51035c240ed1096c97dd7aaa505bd61857d672.zip
chromium_src-fa51035c240ed1096c97dd7aaa505bd61857d672.tar.gz
chromium_src-fa51035c240ed1096c97dd7aaa505bd61857d672.tar.bz2
Revert 114030 - Adding support for incremental cluster parsing.
BUG=104160 TEST=Covered by ChunkDemuxer unittests. Review URL: http://codereview.chromium.org/8775035 TBR=acolwell@chromium.org Review URL: http://codereview.chromium.org/8921010 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@114033 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r--media/filters/chunk_demuxer.cc52
-rw-r--r--media/filters/chunk_demuxer.h11
-rw-r--r--media/media.gyp1
-rw-r--r--media/webm/webm_cluster_parser.cc36
-rw-r--r--media/webm/webm_cluster_parser.h2
-rw-r--r--media/webm/webm_constants.h2
-rw-r--r--media/webm/webm_info_parser.cc18
-rw-r--r--media/webm/webm_parser.cc519
-rw-r--r--media/webm/webm_parser.h113
-rw-r--r--media/webm/webm_parser_unittest.cc264
-rw-r--r--media/webm/webm_tracks_parser.cc38
11 files changed, 263 insertions, 793 deletions
diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc
index f81b80f..d437d91 100644
--- a/media/filters/chunk_demuxer.cc
+++ b/media/filters/chunk_demuxer.cc
@@ -130,7 +130,7 @@ void ChunkDemuxerStream::Flush() {
bool ChunkDemuxerStream::CanAddBuffers(const BufferQueue& buffers) const {
base::AutoLock auto_lock(lock_);
- // If we haven't seen any buffers yet, then anything can be added.
+ // If we haven't seen any buffers yet than anything can be added.
if (last_buffer_timestamp_ == kNoTimestamp)
return true;
@@ -434,7 +434,7 @@ bool ChunkDemuxer::AppendData(const uint8* data, size_t length) {
int cur_size = 0;
int bytes_parsed = 0;
int result = -1;
- bool can_complete_seek = false;
+ bool parsed_a_cluster = false;
byte_queue_.Peek(&cur, &cur_size);
@@ -449,19 +449,16 @@ bool ChunkDemuxer::AppendData(const uint8* data, size_t length) {
}
break;
- case INITIALIZED: {
- bool buffers_added = false;
- result = ParseCluster_Locked(cur, cur_size, &buffers_added);
+ case INITIALIZED:
+ result = ParseCluster_Locked(cur, cur_size);
if (result < 0) {
VLOG(1) << "AppendData(): parsing data failed";
ReportError_Locked(PIPELINE_ERROR_DECODE);
return true;
}
- // We can complete the seek if we have successfully parsed
- // some data and buffers were added to one of the DemuxerStreams.
- can_complete_seek |= (result > 0 && buffers_added);
- } break;
+ parsed_a_cluster = (result > 0);
+ break;
case WAITING_FOR_INIT:
case ENDED:
@@ -480,7 +477,7 @@ bool ChunkDemuxer::AppendData(const uint8* data, size_t length) {
byte_queue_.Pop(bytes_parsed);
- if (can_complete_seek && seek_waits_for_data_) {
+ if (parsed_a_cluster && seek_waits_for_data_) {
seek_waits_for_data_ = false;
if (!seek_cb_.is_null())
@@ -733,8 +730,7 @@ bool ChunkDemuxer::SetupStreams() {
return !no_supported_streams;
}
-int ChunkDemuxer::ParseCluster_Locked(const uint8* data, int size,
- bool* buffers_added) {
+int ChunkDemuxer::ParseCluster_Locked(const uint8* data, int size) {
lock_.AssertAcquired();
if (!cluster_parser_.get())
return -1;
@@ -753,6 +749,9 @@ int ChunkDemuxer::ParseCluster_Locked(const uint8* data, int size,
}
// Skip the element.
return result + element_size;
+ } else if (id != kWebMIdCluster) {
+ VLOG(1) << "Unexpected ID 0x" << std::hex << id;
+ return -1;
}
int bytes_parsed = cluster_parser_->Parse(data, size);
@@ -760,25 +759,20 @@ int ChunkDemuxer::ParseCluster_Locked(const uint8* data, int size,
if (bytes_parsed <= 0)
return bytes_parsed;
- if (!cluster_parser_->audio_buffers().empty() ||
- !cluster_parser_->video_buffers().empty()) {
- // Make sure we can add the buffers to both streams before we actually
- // add them. This allows us to accept all of the data or none of it.
- if ((audio_.get() &&
- !audio_->CanAddBuffers(cluster_parser_->audio_buffers())) ||
- (video_.get() &&
- !video_->CanAddBuffers(cluster_parser_->video_buffers()))) {
- return -1;
- }
-
- if (audio_.get())
- audio_->AddBuffers(cluster_parser_->audio_buffers());
+ // Make sure we can add the buffers to both streams before we actutally
+ // add them. This allows us to accept all of the data or none of it.
+ if ((audio_.get() &&
+ !audio_->CanAddBuffers(cluster_parser_->audio_buffers())) ||
+ (video_.get() &&
+ !video_->CanAddBuffers(cluster_parser_->video_buffers()))) {
+ return -1;
+ }
- if (video_.get())
- video_->AddBuffers(cluster_parser_->video_buffers());
+ if (audio_.get())
+ audio_->AddBuffers(cluster_parser_->audio_buffers());
- *buffers_added = true;
- }
+ if (video_.get())
+ video_->AddBuffers(cluster_parser_->video_buffers());
// TODO(acolwell) : make this more representative of what is actually
// buffered.
diff --git a/media/filters/chunk_demuxer.h b/media/filters/chunk_demuxer.h
index 42f1097..b0f0d02 100644
--- a/media/filters/chunk_demuxer.h
+++ b/media/filters/chunk_demuxer.h
@@ -81,18 +81,13 @@ class MEDIA_EXPORT ChunkDemuxer : public Demuxer {
// found.
bool SetupStreams();
- // Parse a cluster and add the buffers to the appropriate DemuxerStream. This
- // method also skips over CUES elements if it happens to encounter them.
- //
- // |data| is expected to point to the beginning of an element.
- //
- // |buffers_added| - Indicates whether Buffers were added to DemuxerStreams
- // during the call. This is only valid if the return value > 0.
+ // Parse a cluster add add the buffers to the appropriate DemxuerStream.
+ // |data| is expected to point to the beginning of a cluster element.
//
// Returns -1 if the parse fails.
// Returns 0 if more data is needed.
// Returns the number of bytes parsed on success.
- int ParseCluster_Locked(const uint8* data, int size, bool* buffers_added);
+ int ParseCluster_Locked(const uint8* data, int size);
// Reports an error and puts the demuxer in a state where it won't accept more
// data.
diff --git a/media/media.gyp b/media/media.gyp
index abe8310..a52d4a5 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -621,7 +621,6 @@
'video/capture/video_capture_device_unittest.cc',
'webm/cluster_builder.cc',
'webm/cluster_builder.h',
- 'webm/webm_parser_unittest.cc',
],
'conditions': [
['os_posix==1 and OS!="mac"', {
diff --git a/media/webm/webm_cluster_parser.cc b/media/webm/webm_cluster_parser.cc
index fd716b2..8eb045c 100644
--- a/media/webm/webm_cluster_parser.cc
+++ b/media/webm/webm_cluster_parser.cc
@@ -26,7 +26,6 @@ WebMClusterParser::WebMClusterParser(int64 timecode_scale,
audio_default_duration_(audio_default_duration),
video_track_num_(video_track_num),
video_default_duration_(video_default_duration),
- parser_(kWebMIdCluster),
last_block_timecode_(-1),
cluster_timecode_(-1) {
}
@@ -34,25 +33,12 @@ WebMClusterParser::WebMClusterParser(int64 timecode_scale,
WebMClusterParser::~WebMClusterParser() {}
int WebMClusterParser::Parse(const uint8* buf, int size) {
+ last_block_timecode_ = -1;
+ cluster_timecode_ = -1;
audio_buffers_.clear();
video_buffers_.clear();
- int result = parser_.Parse(buf, size, this);
-
- if (result <= 0)
- return result;
-
- if (parser_.IsParsingComplete()) {
- // Reset the parser if we're done parsing so that
- // it is ready to accept another cluster on the next
- // call.
- parser_.Reset();
-
- last_block_timecode_ = -1;
- cluster_timecode_ = -1;
- }
-
- return result;
+ return WebMParseListElement(buf, size, kWebMIdCluster, 1, this);
}
bool WebMClusterParser::OnListStart(int id) {
@@ -81,17 +67,17 @@ bool WebMClusterParser::OnUInt(int id, int64 val) {
}
bool WebMClusterParser::OnFloat(int id, double val) {
- DVLOG(1) << "Unexpected float element with ID " << std::hex << id;
+ VLOG(1) << "Unexpected float element with ID " << std::hex << id;
return false;
}
bool WebMClusterParser::OnBinary(int id, const uint8* data, int size) {
- DVLOG(1) << "Unexpected binary element with ID " << std::hex << id;
+ VLOG(1) << "Unexpected binary element with ID " << std::hex << id;
return false;
}
bool WebMClusterParser::OnString(int id, const std::string& str) {
- DVLOG(1) << "Unexpected string element with ID " << std::hex << id;
+ VLOG(1) << "Unexpected string element with ID " << std::hex << id;
return false;
}
@@ -99,17 +85,17 @@ bool WebMClusterParser::OnSimpleBlock(int track_num, int timecode,
int flags,
const uint8* data, int size) {
if (cluster_timecode_ == -1) {
- DVLOG(1) << "Got SimpleBlock before cluster timecode.";
+ VLOG(1) << "Got SimpleBlock before cluster timecode.";
return false;
}
if (timecode < 0) {
- DVLOG(1) << "Got SimpleBlock with negative timecode offset " << timecode;
+ VLOG(1) << "Got SimpleBlock with negative timecode offset " << timecode;
return false;
}
if (last_block_timecode_ != -1 && timecode < last_block_timecode_) {
- DVLOG(1) << "Got SimpleBlock with a timecode before the previous block.";
+ VLOG(1) << "Got SimpleBlock with a timecode before the previous block.";
return false;
}
@@ -129,13 +115,13 @@ bool WebMClusterParser::OnSimpleBlock(int track_num, int timecode,
buffer->SetDuration(video_default_duration_);
queue = &video_buffers_;
} else {
- DVLOG(1) << "Unexpected track number " << track_num;
+ VLOG(1) << "Unexpected track number " << track_num;
return false;
}
if (!queue->empty() &&
buffer->GetTimestamp() == queue->back()->GetTimestamp()) {
- DVLOG(1) << "Got SimpleBlock timecode is not strictly monotonically "
+ VLOG(1) << "Got SimpleBlock timecode is not strictly monotonically "
<< "increasing for track " << track_num;
return false;
}
diff --git a/media/webm/webm_cluster_parser.h b/media/webm/webm_cluster_parser.h
index 7fb1b94..5a367b0 100644
--- a/media/webm/webm_cluster_parser.h
+++ b/media/webm/webm_cluster_parser.h
@@ -53,8 +53,6 @@ class WebMClusterParser : public WebMParserClient {
int video_track_num_;
base::TimeDelta video_default_duration_;
- WebMListParser parser_;
-
int64 last_block_timecode_;
int64 cluster_timecode_;
diff --git a/media/webm/webm_constants.h b/media/webm/webm_constants.h
index 96e7c01..471115b 100644
--- a/media/webm/webm_constants.h
+++ b/media/webm/webm_constants.h
@@ -64,8 +64,6 @@ const int kWebMIdVideo = 0xE0;
const int kWebMIdVoid = 0xEC;
const int kWebMIdWritingApp = 0x5741;
-const int64 kWebMUnknownSize = GG_LONGLONG(0x00FFFFFFFFFFFFFF);
-
// Default timecode scale if the TimecodeScale element is
// not specified in the INFO element.
const int kWebMDefaultTimecodeScale = 1000000;
diff --git a/media/webm/webm_info_parser.cc b/media/webm/webm_info_parser.cc
index 5807d7e..41e1a25 100644
--- a/media/webm/webm_info_parser.cc
+++ b/media/webm/webm_info_parser.cc
@@ -17,17 +17,7 @@ WebMInfoParser::WebMInfoParser()
WebMInfoParser::~WebMInfoParser() {}
int WebMInfoParser::Parse(const uint8* buf, int size) {
- timecode_scale_ = -1;
- duration_ = -1;
-
- WebMListParser parser(kWebMIdInfo);
- int result = parser.Parse(buf, size, this);
-
- if (result <= 0)
- return result;
-
- // For now we do all or nothing parsing.
- return parser.IsParsingComplete() ? result : 0;
+ return WebMParseListElement(buf, size, kWebMIdInfo, 1, this);
}
bool WebMInfoParser::OnListStart(int id) { return true; }
@@ -46,7 +36,7 @@ bool WebMInfoParser::OnUInt(int id, int64 val) {
return true;
if (timecode_scale_ != -1) {
- DVLOG(1) << "Multiple values for id " << std::hex << id << " specified";
+ VLOG(1) << "Multiple values for id " << std::hex << id << " specified";
return false;
}
@@ -56,12 +46,12 @@ bool WebMInfoParser::OnUInt(int id, int64 val) {
bool WebMInfoParser::OnFloat(int id, double val) {
if (id != kWebMIdDuration) {
- DVLOG(1) << "Unexpected float for id" << std::hex << id;
+ VLOG(1) << "Unexpected float for id" << std::hex << id;
return false;
}
if (duration_ != -1) {
- DVLOG(1) << "Multiple values for duration.";
+ VLOG(1) << "Multiple values for duration.";
return false;
}
diff --git a/media/webm/webm_parser.cc b/media/webm/webm_parser.cc
index 1422308..1e42815 100644
--- a/media/webm/webm_parser.cc
+++ b/media/webm/webm_parser.cc
@@ -20,7 +20,6 @@ namespace media {
static const int kMaxLevelDepth = 6;
enum ElementType {
- UNKNOWN,
LIST,
UINT,
FLOAT,
@@ -31,13 +30,13 @@ enum ElementType {
};
struct ElementIdInfo {
+ int level_;
ElementType type_;
int id_;
};
struct ListElementInfo {
int id_;
- int level_;
const ElementIdInfo* id_info_;
int id_info_size_;
};
@@ -48,83 +47,84 @@ struct ListElementInfo {
// marked as SKIP because they are valid, but we don't care about them
// right now.
static const ElementIdInfo kClusterIds[] = {
- {UINT, kWebMIdTimecode},
- {SBLOCK, kWebMIdSimpleBlock},
- {LIST, kWebMIdBlockGroup},
-};
-
-static const ElementIdInfo kSegmentIds[] = {
- {SKIP, kWebMIdSeekHead}, // TODO(acolwell): add SeekHead info
- {LIST, kWebMIdInfo},
- {LIST, kWebMIdCluster},
- {LIST, kWebMIdTracks},
- {SKIP, kWebMIdCues}, // TODO(acolwell): add CUES info
+ {2, UINT, kWebMIdTimecode},
+ {2, SBLOCK, kWebMIdSimpleBlock},
+ {2, LIST, kWebMIdBlockGroup},
};
static const ElementIdInfo kInfoIds[] = {
- {SKIP, kWebMIdSegmentUID},
- {UINT, kWebMIdTimecodeScale},
- {FLOAT, kWebMIdDuration},
- {SKIP, kWebMIdDateUTC},
- {SKIP, kWebMIdTitle},
- {SKIP, kWebMIdMuxingApp},
- {SKIP, kWebMIdWritingApp},
+ {2, SKIP, kWebMIdSegmentUID},
+ {2, UINT, kWebMIdTimecodeScale},
+ {2, FLOAT, kWebMIdDuration},
+ {2, SKIP, kWebMIdDateUTC},
+ {2, SKIP, kWebMIdTitle},
+ {2, SKIP, kWebMIdMuxingApp},
+ {2, SKIP, kWebMIdWritingApp},
};
static const ElementIdInfo kTracksIds[] = {
- {LIST, kWebMIdTrackEntry},
+ {2, LIST, kWebMIdTrackEntry},
};
static const ElementIdInfo kTrackEntryIds[] = {
- {UINT, kWebMIdTrackNumber},
- {SKIP, kWebMIdTrackUID},
- {UINT, kWebMIdTrackType},
- {SKIP, kWebMIdFlagEnabled},
- {SKIP, kWebMIdFlagDefault},
- {SKIP, kWebMIdFlagForced},
- {UINT, kWebMIdFlagLacing},
- {UINT, kWebMIdDefaultDuration},
- {SKIP, kWebMIdName},
- {SKIP, kWebMIdLanguage},
- {STRING, kWebMIdCodecID},
- {BINARY, kWebMIdCodecPrivate},
- {SKIP, kWebMIdCodecName},
- {LIST, kWebMIdVideo},
- {LIST, kWebMIdAudio},
+ {3, UINT, kWebMIdTrackNumber},
+ {3, SKIP, kWebMIdTrackUID},
+ {3, UINT, kWebMIdTrackType},
+ {3, SKIP, kWebMIdFlagEnabled},
+ {3, SKIP, kWebMIdFlagDefault},
+ {3, SKIP, kWebMIdFlagForced},
+ {3, UINT, kWebMIdFlagLacing},
+ {3, UINT, kWebMIdDefaultDuration},
+ {3, SKIP, kWebMIdName},
+ {3, SKIP, kWebMIdLanguage},
+ {3, STRING, kWebMIdCodecID},
+ {3, BINARY, kWebMIdCodecPrivate},
+ {3, SKIP, kWebMIdCodecName},
+ {3, LIST, kWebMIdVideo},
+ {3, LIST, kWebMIdAudio},
};
static const ElementIdInfo kVideoIds[] = {
- {SKIP, kWebMIdFlagInterlaced},
- {SKIP, kWebMIdStereoMode},
- {UINT, kWebMIdPixelWidth},
- {UINT, kWebMIdPixelHeight},
- {SKIP, kWebMIdPixelCropBottom},
- {SKIP, kWebMIdPixelCropTop},
- {SKIP, kWebMIdPixelCropLeft},
- {SKIP, kWebMIdPixelCropRight},
- {SKIP, kWebMIdDisplayWidth},
- {SKIP, kWebMIdDisplayHeight},
- {SKIP, kWebMIdDisplayUnit},
- {SKIP, kWebMIdAspectRatioType},
+ {4, SKIP, kWebMIdFlagInterlaced},
+ {4, SKIP, kWebMIdStereoMode},
+ {4, UINT, kWebMIdPixelWidth},
+ {4, UINT, kWebMIdPixelHeight},
+ {4, SKIP, kWebMIdPixelCropBottom},
+ {4, SKIP, kWebMIdPixelCropTop},
+ {4, SKIP, kWebMIdPixelCropLeft},
+ {4, SKIP, kWebMIdPixelCropRight},
+ {4, SKIP, kWebMIdDisplayWidth},
+ {4, SKIP, kWebMIdDisplayHeight},
+ {4, SKIP, kWebMIdDisplayUnit},
+ {4, SKIP, kWebMIdAspectRatioType},
};
static const ElementIdInfo kAudioIds[] = {
- {SKIP, kWebMIdSamplingFrequency},
- {SKIP, kWebMIdOutputSamplingFrequency},
- {UINT, kWebMIdChannels},
- {SKIP, kWebMIdBitDepth},
+ {4, SKIP, kWebMIdSamplingFrequency},
+ {4, SKIP, kWebMIdOutputSamplingFrequency},
+ {4, UINT, kWebMIdChannels},
+ {4, SKIP, kWebMIdBitDepth},
+};
+
+static const ElementIdInfo kClustersOnly[] = {
+ {1, LIST, kWebMIdCluster},
};
static const ListElementInfo kListElementInfo[] = {
- { kWebMIdCluster, 1, kClusterIds, sizeof(kClusterIds) },
- { kWebMIdSegment, 0, kSegmentIds, sizeof(kSegmentIds) },
- { kWebMIdInfo, 1, kInfoIds, sizeof(kInfoIds) },
- { kWebMIdTracks, 1, kTracksIds, sizeof(kTracksIds) },
- { kWebMIdTrackEntry, 2, kTrackEntryIds, sizeof(kTrackEntryIds) },
- { kWebMIdVideo, 3, kVideoIds, sizeof(kVideoIds) },
- { kWebMIdAudio, 3, kAudioIds, sizeof(kAudioIds) },
+ { kWebMIdCluster, kClusterIds, sizeof(kClusterIds) },
+ { kWebMIdInfo, kInfoIds, sizeof(kInfoIds) },
+ { kWebMIdTracks, kTracksIds, sizeof(kTracksIds) },
+ { kWebMIdTrackEntry, kTrackEntryIds, sizeof(kTrackEntryIds) },
+ { kWebMIdVideo, kVideoIds, sizeof(kVideoIds) },
+ { kWebMIdAudio, kAudioIds, sizeof(kAudioIds) },
};
+// Number of elements in kListElementInfo.
+const int kListElementInfoCount =
+ sizeof(kListElementInfo) / sizeof(ListElementInfo);
+
+WebMParserClient::~WebMParserClient() {}
+
// Parses an element header id or size field. These fields are variable length
// encoded. The first byte indicates how many bytes the field occupies.
// |buf| - The buffer to parse.
@@ -206,27 +206,22 @@ int WebMParseElementHeader(const uint8* buf, int size,
return num_id_bytes + num_size_bytes;
}
-// Finds ElementType for a specific ID.
-static ElementType FindIdType(int id,
- const ElementIdInfo* id_info,
- int id_info_size) {
-
- // Check for global element IDs that can be anywhere.
- if (id == kWebMIdVoid || id == kWebMIdCRC32)
- return SKIP;
-
+// Finds ElementIdInfo for a specific ID.
+static const ElementIdInfo* FindIdInfo(int id,
+ const ElementIdInfo* id_info,
+ int id_info_size) {
int count = id_info_size / sizeof(*id_info);
for (int i = 0; i < count; ++i) {
if (id == id_info[i].id_)
- return id_info[i].type_;
+ return &id_info[i];
}
- return UNKNOWN;
+ return NULL;
}
// Finds ListElementInfo for a specific ID.
static const ListElementInfo* FindListInfo(int id) {
- for (size_t i = 0; i < arraysize(kListElementInfo); ++i) {
+ for (int i = 0; i < kListElementInfoCount; ++i) {
if (id == kListElementInfo[i].id_)
return &kListElementInfo[i];
}
@@ -242,7 +237,7 @@ static int ParseSimpleBlock(const uint8* buf, int size,
// Return an error if the trackNum > 127. We just aren't
// going to support large track numbers right now.
if ((buf[0] & 0x80) != 0x80) {
- DVLOG(1) << "TrackNumber over 127 not supported";
+ VLOG(1) << "TrackNumber over 127 not supported";
return -1;
}
@@ -252,7 +247,7 @@ static int ParseSimpleBlock(const uint8* buf, int size,
int lacing = (flags >> 1) & 0x3;
if (lacing != 0) {
- DVLOG(1) << "Lacing " << lacing << " not supported yet.";
+ VLOG(1) << "Lacing " << lacing << " not supported yet.";
return -1;
}
@@ -270,6 +265,39 @@ static int ParseSimpleBlock(const uint8* buf, int size,
return size;
}
+static int ParseElements(const ElementIdInfo* id_info,
+ int id_info_size,
+ const uint8* buf, int size, int level,
+ WebMParserClient* client);
+
+static int ParseElementList(const uint8* buf, int size,
+ int id, int level,
+ WebMParserClient* client) {
+ const ListElementInfo* list_info = FindListInfo(id);
+
+ if (!list_info) {
+ VLOG(1) << "Failed to find list info for ID " << std::hex << id;
+ return -1;
+ }
+
+ if (!client->OnListStart(id))
+ return -1;
+
+ int result = ParseElements(list_info->id_info_,
+ list_info->id_info_size_,
+ buf, size,
+ level + 1,
+ client);
+
+ if (result <= 0)
+ return result;
+
+ if (!client->OnListEnd(id))
+ return -1;
+
+ DCHECK_EQ(result, size);
+ return result;
+}
static int ParseUInt(const uint8* buf, int size, int id,
WebMParserClient* client) {
@@ -326,285 +354,142 @@ static int ParseFloat(const uint8* buf, int size, int id,
return size;
}
-static int ParseNonListElement(ElementType type, int id, int64 element_size,
- const uint8* buf, int size,
- WebMParserClient* client) {
- DCHECK_GE(size, element_size);
-
- int result = -1;
- switch(type) {
- case SBLOCK:
- result = ParseSimpleBlock(buf, element_size, client);
- break;
- case LIST:
- NOTIMPLEMENTED();
- result = -1;
- break;
- case UINT:
- result = ParseUInt(buf, element_size, id, client);
- break;
- case FLOAT:
- result = ParseFloat(buf, element_size, id, client);
- break;
- case BINARY:
- if (client->OnBinary(id, buf, element_size)) {
- result = element_size;
- } else {
- result = -1;
- }
- break;
- case STRING:
- if (client->OnString(id,
- std::string(reinterpret_cast<const char*>(buf),
- element_size))) {
- result = element_size;
- } else {
- result = -1;
- }
- break;
- case SKIP:
- result = element_size;
- break;
- default:
- DVLOG(1) << "Unhandled ID type " << type;
- return -1;
- };
-
- DCHECK_LE(result, size);
- return result;
-}
-
-WebMParserClient::WebMParserClient() {}
-WebMParserClient::~WebMParserClient() {}
-
-WebMListParser::WebMListParser(int id)
- : state_(NEED_LIST_HEADER),
- root_id_(id) {
- const ListElementInfo* list_info = FindListInfo(id);
-
- DCHECK(list_info);
+static int ParseElements(const ElementIdInfo* id_info,
+ int id_info_size,
+ const uint8* buf, int size, int level,
+ WebMParserClient* client) {
+ DCHECK_GE(id_info_size, 0);
+ DCHECK_GE(size, 0);
+ DCHECK_GE(level, 0);
- root_level_ = list_info->level_;
-}
+ const uint8* cur = buf;
+ int cur_size = size;
+ int used = 0;
-WebMListParser::~WebMListParser() {}
+ if (level > kMaxLevelDepth)
+ return -1;
-void WebMListParser::Reset() {
- ChangeState(NEED_LIST_HEADER);
- list_state_stack_.clear();
-}
+ while (cur_size > 0) {
+ int id = 0;
+ int64 element_size = 0;
+ int result = WebMParseElementHeader(cur, cur_size, &id, &element_size);
-int WebMListParser::Parse(const uint8* buf, int size,
- WebMParserClient* client) {
- DCHECK(buf);
- DCHECK(client);
+ if (result <= 0)
+ return result;
- if (size < 0 || state_ == PARSE_ERROR || state_ == DONE_PARSING_LIST)
- return -1;
+ cur += result;
+ cur_size -= result;
+ used += result;
- if (size == 0)
- return 0;
+ // Check to see if the element is larger than the remaining data.
+ if (element_size > cur_size)
+ return 0;
- const uint8* cur = buf;
- int cur_size = size;
- int bytes_parsed = 0;
+ const ElementIdInfo* info = FindIdInfo(id, id_info, id_info_size);
- while (cur_size > 0 && state_ != PARSE_ERROR && state_ != DONE_PARSING_LIST) {
- int element_id = 0;
- int64 element_size = 0;
- int result = WebMParseElementHeader(cur, cur_size, &element_id,
- &element_size);
+ if (info == NULL) {
+ VLOG(1) << "No info for ID " << std::hex << id;
- if (result < 0)
- return result;
+ // TODO(acolwell): Change this to return -1 after the API has solidified.
+ // We don't want to allow elements we don't recognize.
+ cur += element_size;
+ cur_size -= element_size;
+ used += element_size;
+ continue;
+ }
- if (result == 0)
- return bytes_parsed;
+ if (info->level_ != level) {
+ VLOG(1) << "ID " << std::hex << id << std::dec << " at level "
+ << level << " instead of " << info->level_;
+ return -1;
+ }
- switch(state_) {
- case NEED_LIST_HEADER: {
- if (element_id != root_id_) {
- ChangeState(PARSE_ERROR);
+ switch(info->type_) {
+ case SBLOCK:
+ if (ParseSimpleBlock(cur, element_size, client) <= 0)
return -1;
- }
-
- // TODO(acolwell): Add support for lists of unknown size.
- if (element_size == kWebMUnknownSize) {
- ChangeState(PARSE_ERROR);
+ break;
+ case LIST:
+ if (ParseElementList(cur, element_size, id, level, client) < 0)
return -1;
- }
-
- ChangeState(INSIDE_LIST);
- if (!OnListStart(root_id_, element_size, client))
+ break;
+ case UINT:
+ if (ParseUInt(cur, element_size, id, client) <= 0)
return -1;
-
break;
- }
-
- case INSIDE_LIST: {
- int header_size = result;
- const uint8* element_data = cur + header_size;
- int element_data_size = cur_size - header_size;
-
- if (element_size < element_data_size)
- element_data_size = element_size;
-
- result = ParseListElement(header_size, element_id, element_size,
- element_data, element_data_size, client);
-
- DCHECK_LE(result, header_size + element_data_size);
- if (result < 0) {
- ChangeState(PARSE_ERROR);
+ case FLOAT:
+ if (ParseFloat(cur, element_size, id, client) <= 0)
return -1;
- }
-
- if (result == 0)
- return bytes_parsed;
-
break;
- }
- case DONE_PARSING_LIST:
- case PARSE_ERROR:
- // Shouldn't be able to get here.
- NOTIMPLEMENTED();
+ case BINARY:
+ if (!client->OnBinary(id, cur, element_size))
+ return -1;
break;
- }
-
- cur += result;
- cur_size -= result;
- bytes_parsed += result;
+ case STRING:
+ if (!client->OnString(id,
+ std::string(reinterpret_cast<const char*>(cur),
+ element_size)))
+ return -1;
+ break;
+ case SKIP:
+ // Do nothing.
+ break;
+ default:
+ VLOG(1) << "Unhandled id type " << info->type_;
+ return -1;
+ };
+
+ cur += element_size;
+ cur_size -= element_size;
+ used += element_size;
}
- return (state_ == PARSE_ERROR) ? -1 : bytes_parsed;
+ return used;
}
-bool WebMListParser::IsParsingComplete() const {
- return state_ == DONE_PARSING_LIST;
-}
-
-void WebMListParser::ChangeState(State new_state) {
- state_ = new_state;
-}
-
-int WebMListParser::ParseListElement(int header_size,
- int id, int64 element_size,
- const uint8* data, int size,
- WebMParserClient* client) {
- DCHECK_GT(list_state_stack_.size(), 0u);
-
- ListState& list_state = list_state_stack_.back();
- DCHECK(list_state.element_info_);
-
- const ListElementInfo* element_info = list_state.element_info_;
- ElementType id_type =
- FindIdType(id, element_info->id_info_, element_info->id_info_size_);
-
- // Unexpected ID.
- if (id_type == UNKNOWN) {
- DVLOG(1) << "No ElementType info for ID 0x" << std::hex << id;
- return -1;
- }
-
- // Make sure the whole element can fit inside the current list.
- int64 total_element_size = header_size + element_size;
- if (list_state.size_ != kWebMUnknownSize &&
- list_state.size_ < list_state.bytes_parsed_ + total_element_size) {
+// Parses a single list element that matches |id|. This method fails if the
+// buffer points to an element that does not match |id|.
+int WebMParseListElement(const uint8* buf, int size, int id,
+ int level, WebMParserClient* client) {
+ if (size < 0)
return -1;
- }
-
- if (id_type == LIST) {
- list_state.bytes_parsed_ += header_size;
-
- if (!OnListStart(id, element_size, client))
- return -1;
- return header_size;
- }
- // Make sure we have the entire element before trying to parse a non-list
- // element.
- if (size < element_size)
+ if (size == 0)
return 0;
- int bytes_parsed = ParseNonListElement(id_type, id, element_size,
- data, size, client);
- DCHECK_LE(bytes_parsed, size);
-
- // Return if an error occurred or we need more data.
- // Note: bytes_parsed is 0 for a successful parse of a size 0 element. We
- // need to check the element_size to disambiguate the "need more data" case
- // from a successful parse.
- if (bytes_parsed < 0 || (bytes_parsed == 0 && element_size != 0))
- return bytes_parsed;
-
- int result = header_size + bytes_parsed;
- list_state.bytes_parsed_ += result;
-
- // See if we have reached the end of the current list.
- if (list_state.bytes_parsed_ == list_state.size_) {
- if (!OnListEnd(client))
- return -1;
- }
-
- return result;
-}
-
-bool WebMListParser::OnListStart(int id, int64 size, WebMParserClient* client) {
- ListState list_state = { id, size, 0, FindListInfo(id)};
-
- if (!list_state.element_info_)
- return false;
-
- int current_level = root_level_ + list_state_stack_.size() - 1;
- if (current_level + 1 != list_state.element_info_->level_)
- return false;
-
- if (!list_state_stack_.empty()) {
-
- // Make sure the new list doesn't go past the end of the current list.
- ListState current_list = list_state_stack_.back();
- if (current_list.size_ != kWebMUnknownSize &&
- current_list.size_ < current_list.bytes_parsed_ + size)
- return false;
- }
-
- if (!client->OnListStart(id))
- return false;
+ const uint8* cur = buf;
+ int cur_size = size;
+ int bytes_parsed = 0;
+ int element_id = 0;
+ int64 element_size = 0;
+ int result = WebMParseElementHeader(cur, cur_size, &element_id,
+ &element_size);
- list_state_stack_.push_back(list_state);
+ if (result <= 0)
+ return result;
- if (size == 0) {
- return OnListEnd(client);
- }
+ cur += result;
+ cur_size -= result;
+ bytes_parsed += result;
- return true;
-}
-
-bool WebMListParser::OnListEnd(WebMParserClient* client) {
- int lists_ended = 0;
- for (; !list_state_stack_.empty(); ++lists_ended) {
- const ListState& list_state = list_state_stack_.back();
+ if (element_id != id)
+ return -1;
- if (list_state.bytes_parsed_ != list_state.size_)
- break;
+ if (element_size > cur_size)
+ return 0;
- if (!client->OnListEnd(list_state.id_))
- return false;
+ if (element_size > 0) {
+ result = ParseElementList(cur, element_size, element_id, level, client);
- int64 bytes_parsed = list_state.bytes_parsed_;
- list_state_stack_.pop_back();
+ if (result <= 0)
+ return result;
- if (!list_state_stack_.empty()) {
- // Update the bytes_parsed_ for the parent element.
- list_state_stack_.back().bytes_parsed_ += bytes_parsed;
- }
+ cur += result;
+ cur_size -= result;
+ bytes_parsed += result;
}
- DCHECK_GE(lists_ended, 1);
-
- if (list_state_stack_.empty())
- ChangeState(DONE_PARSING_LIST);
-
- return true;
+ return bytes_parsed;
}
} // namespace media
diff --git a/media/webm/webm_parser.h b/media/webm/webm_parser.h
index bc3e09f..7d15f9b 100644
--- a/media/webm/webm_parser.h
+++ b/media/webm/webm_parser.h
@@ -6,10 +6,8 @@
#define MEDIA_WEBM_WEBM_PARSER_H_
#include <string>
-#include <vector>
#include "base/basictypes.h"
-#include "media/base/media_export.h"
namespace media {
@@ -23,7 +21,7 @@ namespace media {
// indicates whether the parsed data is valid. If false is returned
// then the parse is immediately terminated and an error is reported by the
// parser.
-class MEDIA_EXPORT WebMParserClient {
+class WebMParserClient {
public:
virtual ~WebMParserClient();
@@ -36,106 +34,6 @@ class MEDIA_EXPORT WebMParserClient {
virtual bool OnSimpleBlock(int track_num, int timecode,
int flags,
const uint8* data, int size) = 0;
- protected:
- WebMParserClient();
-
- DISALLOW_COPY_AND_ASSIGN(WebMParserClient);
-};
-
-struct ListElementInfo;
-
-// Parses a WebM list element and all of its children. This
-// class supports incremental parsing of the list so Parse()
-// can be called multiple times with pieces of the list.
-// IsParsingComplete() will return true once the entire list has
-// been parsed.
-class MEDIA_EXPORT WebMListParser {
- public:
- // |id| - Element ID of the list we intend to parse.
- explicit WebMListParser(int id);
- ~WebMListParser();
-
- // Resets the state of the parser so it can start parsing a new list.
- void Reset();
-
- // Parses list data contained in |buf|.
- // |client| Called as different elements in the list are parsed.
- //
- // Returns < 0 if the parse fails.
- // Returns 0 if more data is needed.
- // Returning > 0 indicates success & the number of bytes parsed.
- int Parse(const uint8* buf, int size, WebMParserClient* client);
-
- // Returns true if the entire list has been parsed.
- bool IsParsingComplete() const;
-
- private:
- enum State {
- NEED_LIST_HEADER,
- INSIDE_LIST,
- DONE_PARSING_LIST,
- PARSE_ERROR,
- };
-
- struct ListState {
- int id_;
- int size_;
- int bytes_parsed_;
- const ListElementInfo* element_info_;
- };
-
- void ChangeState(State new_state);
-
- // Parses a single element in the current list.
- //
- // |header_size| - The size of the element header
- // |id| - The ID of the element being parsed.
- // |element_size| - The size of the element body.
- // |data| - Pointer to the element contents.
- // |size| - Number of bytes in |data|
- // |client| - Client to pass the parsed data to.
- //
- // Returns < 0 if the parse fails.
- // Returns 0 if more data is needed.
- // Returning > 0 indicates success & the number of bytes parsed.
- int ParseListElement(int header_size,
- int id, int64 element_size,
- const uint8* data, int size,
- WebMParserClient* client);
-
- // Called when starting to parse a new list.
- //
- // |id| - The ID of the new list.
- // |size| - The size of the new list.
- // |client| - The client object to notify that a new list is being parsed.
- //
- // Returns true if this list can be started in the current context. False
- // if starting this list causes some sort of parse error.
- bool OnListStart(int id, int64 size, WebMParserClient* client);
-
- // Called when the end of the current list has been reached. This may also
- // signal the end of the current list's ancestors if the current list happens
- // to be at the end of its parent.
- //
- // |client| - The client to notify about lists ending.
- //
- // Returns true if no errors occurred while ending this list(s).
- bool OnListEnd(WebMParserClient* client);
-
- State state_;
-
- // Element ID passed to the constructor.
- int root_id_;
-
- // Element level for |root_id_|. Used to verify that elements appear at
- // the correct level.
- int root_level_;
-
- // Stack of state for all the lists currently being parsed. Lists are
- // added and removed from this stack as they are parsed.
- std::vector<ListState> list_state_stack_;
-
- DISALLOW_COPY_AND_ASSIGN(WebMListParser);
};
// Parses an element header & returns the ID and element size.
@@ -149,6 +47,15 @@ class MEDIA_EXPORT WebMListParser {
int WebMParseElementHeader(const uint8* buf, int size,
int* id, int64* element_size);
+// Parses a single list element that matches |id|. This method fails if the
+// buffer points to an element that does not match |id|.
+//
+// Returns -1 if the parse fails.
+// Returns 0 if more data is needed.
+// Returns the number of bytes parsed on success.
+int WebMParseListElement(const uint8* buf, int size, int id,
+ int level, WebMParserClient* client);
+
} // namespace media
#endif // MEDIA_WEBM_WEBM_PARSER_H_
diff --git a/media/webm/webm_parser_unittest.cc b/media/webm/webm_parser_unittest.cc
deleted file mode 100644
index e377fda..0000000
--- a/media/webm/webm_parser_unittest.cc
+++ /dev/null
@@ -1,264 +0,0 @@
-// Copyright (c) 2011 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.
-
-#include "media/webm/cluster_builder.h"
-#include "media/webm/webm_constants.h"
-#include "media/webm/webm_parser.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using ::testing::InSequence;
-using ::testing::Return;
-using ::testing::StrictMock;
-using ::testing::_;
-
-namespace media {
-
-class MockWebMParserClient : public WebMParserClient {
- public:
- virtual ~MockWebMParserClient() {}
-
- // WebMParserClient methods.
- MOCK_METHOD1(OnListStart, bool(int));
- MOCK_METHOD1(OnListEnd, bool(int));
- MOCK_METHOD2(OnUInt, bool(int, int64));
- MOCK_METHOD2(OnFloat, bool(int, double));
- MOCK_METHOD3(OnBinary, bool(int, const uint8*, int));
- MOCK_METHOD2(OnString, bool(int, const std::string&));
- MOCK_METHOD5(OnSimpleBlock, bool(int, int, int, const uint8*, int));
-};
-
-class WebMParserTest : public testing::Test {
- protected:
- StrictMock<MockWebMParserClient> client_;
-};
-
-struct SimpleBlockInfo {
- int track_num;
- int timestamp;
-};
-
-static void AddSimpleBlock(ClusterBuilder* cb, int track_num,
- int64 timecode) {
- uint8 data[] = { 0x00 };
- cb->AddSimpleBlock(track_num, timecode, 0, data, sizeof(data));
-}
-
-static Cluster* CreateCluster(int timecode,
- const SimpleBlockInfo* block_info,
- int block_count) {
- ClusterBuilder cb;
- cb.SetClusterTimecode(0);
-
- for (int i = 0; i < block_count; i++)
- AddSimpleBlock(&cb, block_info[i].track_num, block_info[i].timestamp);
-
- return cb.Finish();
-}
-
-static void CreateClusterExpectations(int timecode,
- const SimpleBlockInfo* block_info,
- int block_count,
- MockWebMParserClient* client) {
-
- InSequence s;
- EXPECT_CALL(*client, OnListStart(kWebMIdCluster)).WillOnce(Return(true));
- EXPECT_CALL(*client, OnUInt(kWebMIdTimecode, 0)).WillOnce(Return(true));
-
- for (int i = 0; i < block_count; i++) {
- EXPECT_CALL(*client, OnSimpleBlock(block_info[i].track_num,
- block_info[i].timestamp,
- _, _, _))
- .WillOnce(Return(true));
- }
-
- EXPECT_CALL(*client, OnListEnd(kWebMIdCluster)).WillOnce(Return(true));
-}
-
-TEST_F(WebMParserTest, EmptyCluster) {
- const uint8 kEmptyCluster[] = {
- 0x1F, 0x43, 0xB6, 0x75, 0x80 // CLUSTER (size = 0)
- };
- int size = sizeof(kEmptyCluster);
-
- InSequence s;
- EXPECT_CALL(client_, OnListStart(kWebMIdCluster)).WillOnce(Return(true));
- EXPECT_CALL(client_, OnListEnd(kWebMIdCluster)).WillOnce(Return(true));
-
- WebMListParser parser(kWebMIdCluster);
- int result = parser.Parse(kEmptyCluster, size, &client_);
- EXPECT_EQ(size, result);
- EXPECT_TRUE(parser.IsParsingComplete());
-}
-
-TEST_F(WebMParserTest, EmptyClusterInSegment) {
- const uint8 kBuffer[] = {
- 0x18, 0x53, 0x80, 0x67, 0x85, // SEGMENT (size = 5)
- 0x1F, 0x43, 0xB6, 0x75, 0x80, // CLUSTER (size = 0)
- };
- int size = sizeof(kBuffer);
-
- InSequence s;
- EXPECT_CALL(client_, OnListStart(kWebMIdSegment)).WillOnce(Return(true));
- EXPECT_CALL(client_, OnListStart(kWebMIdCluster)).WillOnce(Return(true));
- EXPECT_CALL(client_, OnListEnd(kWebMIdCluster)).WillOnce(Return(true));
- EXPECT_CALL(client_, OnListEnd(kWebMIdSegment)).WillOnce(Return(true));
-
- WebMListParser parser(kWebMIdSegment);
- int result = parser.Parse(kBuffer, size, &client_);
- EXPECT_EQ(size, result);
- EXPECT_TRUE(parser.IsParsingComplete());
-}
-
-// Test the case where a non-list child element has a size
-// that is beyond the end of the parent.
-TEST_F(WebMParserTest, ChildNonListLargerThanParent) {
- const uint8 kBuffer[] = {
- 0x1F, 0x43, 0xB6, 0x75, 0x81, // CLUSTER (size = 1)
- 0xE7, 0x81, 0x01, // Timecode (size=1, value=1)
- };
- int size = sizeof(kBuffer);
-
- InSequence s;
- EXPECT_CALL(client_, OnListStart(kWebMIdCluster)).WillOnce(Return(true));
-
- WebMListParser parser(kWebMIdCluster);
- int result = parser.Parse(kBuffer, size, &client_);
- EXPECT_EQ(-1, result);
- EXPECT_FALSE(parser.IsParsingComplete());
-}
-
-// Test the case where a list child element has a size
-// that is beyond the end of the parent.
-TEST_F(WebMParserTest, ChildListLargerThanParent) {
- const uint8 kBuffer[] = {
- 0x18, 0x53, 0x80, 0x67, 0x85, // SEGMENT (size = 5)
- 0x1F, 0x43, 0xB6, 0x75, 0x81, 0x11 // CLUSTER (size = 1)
- };
- int size = sizeof(kBuffer);
-
- InSequence s;
- EXPECT_CALL(client_, OnListStart(kWebMIdSegment)).WillOnce(Return(true));
-
- WebMListParser parser(kWebMIdSegment);
- int result = parser.Parse(kBuffer, size, &client_);
- EXPECT_EQ(-1, result);
- EXPECT_FALSE(parser.IsParsingComplete());
-}
-
-// Expecting to parse a Cluster, but get a Segment.
-TEST_F(WebMParserTest, ListIdDoesNotMatch) {
- const uint8 kBuffer[] = {
- 0x18, 0x53, 0x80, 0x67, 0x80, // SEGMENT (size = 0)
- };
- int size = sizeof(kBuffer);
-
- WebMListParser parser(kWebMIdCluster);
- int result = parser.Parse(kBuffer, size, &client_);
- EXPECT_EQ(-1, result);
- EXPECT_FALSE(parser.IsParsingComplete());
-}
-
-TEST_F(WebMParserTest, InvalidElementInList) {
- const uint8 kBuffer[] = {
- 0x18, 0x53, 0x80, 0x67, 0x82, // SEGMENT (size = 2)
- 0xAE, 0x80, // TrackEntry (size = 0)
- };
- int size = sizeof(kBuffer);
-
- InSequence s;
- EXPECT_CALL(client_, OnListStart(kWebMIdSegment)).WillOnce(Return(true));
-
- WebMListParser parser(kWebMIdSegment);
- int result = parser.Parse(kBuffer, size, &client_);
- EXPECT_EQ(-1, result);
- EXPECT_FALSE(parser.IsParsingComplete());
-}
-
-TEST_F(WebMParserTest, VoidAndCRC32InList) {
- const uint8 kBuffer[] = {
- 0x18, 0x53, 0x80, 0x67, 0x99, // SEGMENT (size = 25)
- 0xEC, 0x83, 0x00, 0x00, 0x00, // Void (size = 3)
- 0xBF, 0x83, 0x00, 0x00, 0x00, // CRC32 (size = 3)
- 0x1F, 0x43, 0xB6, 0x75, 0x8A, // CLUSTER (size = 10)
- 0xEC, 0x83, 0x00, 0x00, 0x00, // Void (size = 3)
- 0xBF, 0x83, 0x00, 0x00, 0x00, // CRC32 (size = 3)
- };
- int size = sizeof(kBuffer);
-
- InSequence s;
- EXPECT_CALL(client_, OnListStart(kWebMIdSegment)).WillOnce(Return(true));
- EXPECT_CALL(client_, OnListStart(kWebMIdCluster)).WillOnce(Return(true));
- EXPECT_CALL(client_, OnListEnd(kWebMIdCluster)).WillOnce(Return(true));
- EXPECT_CALL(client_, OnListEnd(kWebMIdSegment)).WillOnce(Return(true));
-
- WebMListParser parser(kWebMIdSegment);
- int result = parser.Parse(kBuffer, size, &client_);
- EXPECT_EQ(size, result);
- EXPECT_TRUE(parser.IsParsingComplete());
-}
-
-
-TEST_F(WebMParserTest, ParseListElementWithSingleCall) {
- const SimpleBlockInfo kBlockInfo[] = {
- { 0, 1 },
- { 1, 2 },
- { 0, 3 },
- { 0, 4 },
- { 1, 4 },
- };
- int block_count = arraysize(kBlockInfo);
-
- scoped_ptr<Cluster> cluster(CreateCluster(0, kBlockInfo, block_count));
- CreateClusterExpectations(0, kBlockInfo, block_count, &client_);
-
- WebMListParser parser(kWebMIdCluster);
- int result = parser.Parse(cluster->data(), cluster->size(), &client_);
- EXPECT_EQ(cluster->size(), result);
- EXPECT_TRUE(parser.IsParsingComplete());
-}
-
-TEST_F(WebMParserTest, ParseListElementWithMultipleCalls) {
- const SimpleBlockInfo kBlockInfo[] = {
- { 0, 1 },
- { 1, 2 },
- { 0, 3 },
- { 0, 4 },
- { 1, 4 },
- };
- int block_count = arraysize(kBlockInfo);
-
- scoped_ptr<Cluster> cluster(CreateCluster(0, kBlockInfo, block_count));
- CreateClusterExpectations(0, kBlockInfo, block_count, &client_);
-
- const uint8* data = cluster->data();
- int size = cluster->size();
- int default_parse_size = 3;
- WebMListParser parser(kWebMIdCluster);
- int parse_size = std::min(default_parse_size, size);
-
- while (size > 0) {
- int result = parser.Parse(data, parse_size, &client_);
- EXPECT_GE(result, 0);
- EXPECT_LE(result, parse_size);
-
- if (result == 0) {
- // The parser needs more data so increase the parse_size a little.
- EXPECT_FALSE(parser.IsParsingComplete());
- parse_size += default_parse_size;
- parse_size = std::min(parse_size, size);
- continue;
- }
-
- parse_size = default_parse_size;
-
- data += result;
- size -= result;
-
- EXPECT_EQ((size == 0), parser.IsParsingComplete());
- }
- EXPECT_TRUE(parser.IsParsingComplete());
-}
-
-} // namespace media
diff --git a/media/webm/webm_tracks_parser.cc b/media/webm/webm_tracks_parser.cc
index 7cd9569..29b4f33 100644
--- a/media/webm/webm_tracks_parser.cc
+++ b/media/webm/webm_tracks_parser.cc
@@ -9,39 +9,21 @@
namespace media {
-static const base::TimeDelta kNoDuration =
- base::TimeDelta::FromMicroseconds(-1);
-
WebMTracksParser::WebMTracksParser(int64 timecode_scale)
: timecode_scale_(timecode_scale),
track_type_(-1),
track_num_(-1),
track_default_duration_(-1),
audio_track_num_(-1),
- audio_default_duration_(kNoDuration),
+ audio_default_duration_(base::TimeDelta::FromMicroseconds(-1)),
video_track_num_(-1),
- video_default_duration_(kNoDuration) {
+ video_default_duration_(base::TimeDelta::FromMicroseconds(-1)) {
}
WebMTracksParser::~WebMTracksParser() {}
int WebMTracksParser::Parse(const uint8* buf, int size) {
- track_type_ =-1;
- track_num_ = -1;
- track_default_duration_ = -1;
- audio_track_num_ = -1;
- audio_default_duration_ = kNoDuration;
- video_track_num_ = -1;
- video_default_duration_ = kNoDuration;
-
- WebMListParser parser(kWebMIdTracks);
- int result = parser.Parse(buf, size, this);
-
- if (result <= 0)
- return result;
-
- // For now we do all or nothing parsing.
- return parser.IsParsingComplete() ? result : 0;
+ return WebMParseListElement(buf, size, kWebMIdTracks, 1, this);
}
@@ -58,9 +40,9 @@ bool WebMTracksParser::OnListStart(int id) {
bool WebMTracksParser::OnListEnd(int id) {
if (id == kWebMIdTrackEntry) {
if (track_type_ == -1 || track_num_ == -1) {
- DVLOG(1) << "Missing TrackEntry data"
- << " TrackType " << track_type_
- << " TrackNum " << track_num_;
+ VLOG(1) << "Missing TrackEntry data"
+ << " TrackType " << track_type_
+ << " TrackNum " << track_num_;
return false;
}
@@ -75,7 +57,7 @@ bool WebMTracksParser::OnListEnd(int id) {
audio_track_num_ = track_num_;
audio_default_duration_ = default_duration;
} else {
- DVLOG(1) << "Unexpected TrackType " << track_type_;
+ VLOG(1) << "Unexpected TrackType " << track_type_;
return false;
}
@@ -104,7 +86,7 @@ bool WebMTracksParser::OnUInt(int id, int64 val) {
}
if (*dst != -1) {
- DVLOG(1) << "Multiple values for id " << std::hex << id << " specified";
+ VLOG(1) << "Multiple values for id " << std::hex << id << " specified";
return false;
}
@@ -113,7 +95,7 @@ bool WebMTracksParser::OnUInt(int id, int64 val) {
}
bool WebMTracksParser::OnFloat(int id, double val) {
- DVLOG(1) << "Unexpected float for id" << std::hex << id;
+ VLOG(1) << "Unexpected float for id" << std::hex << id;
return false;
}
@@ -126,7 +108,7 @@ bool WebMTracksParser::OnString(int id, const std::string& str) {
return false;
if (str != "A_VORBIS" && str != "V_VP8") {
- DVLOG(1) << "Unexpected CodecID " << str;
+ VLOG(1) << "Unexpected CodecID " << str;
return false;
}