summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authoracolwell@chromium.org <acolwell@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-04 23:26:03 +0000
committeracolwell@chromium.org <acolwell@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-04 23:26:03 +0000
commit42b933fe8d7733d3a5c9f2afa65b186db7c51533 (patch)
treef66dd5d673d0e446085724c1ced0543279baba07 /media
parentfc0d94c64292dc6702e2b4c28e446dbcd14f0ad2 (diff)
downloadchromium_src-42b933fe8d7733d3a5c9f2afa65b186db7c51533.zip
chromium_src-42b933fe8d7733d3a5c9f2afa65b186db7c51533.tar.gz
chromium_src-42b933fe8d7733d3a5c9f2afa65b186db7c51533.tar.bz2
Add basic parsing functionality to ChunkDemuxer for skipping WebM file headers.
BUG=86536 TEST=ChunkDemuxerTest::TestWebMFile Review URL: http://codereview.chromium.org/8443004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@108740 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r--media/filters/chunk_demuxer.cc55
-rw-r--r--media/filters/chunk_demuxer_unittest.cc104
-rw-r--r--media/webm/webm_constants.h7
-rw-r--r--media/webm/webm_parser.cc13
-rw-r--r--media/webm/webm_parser.h11
5 files changed, 156 insertions, 34 deletions
diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc
index 8762003..0df22a5 100644
--- a/media/filters/chunk_demuxer.cc
+++ b/media/filters/chunk_demuxer.cc
@@ -324,6 +324,7 @@ void ChunkDemuxer::Init(const PipelineStatusCB& cb) {
}
void ChunkDemuxer::set_host(FilterHost* filter_host) {
+ DCHECK_EQ(state_, INITIALIZED);
Demuxer::set_host(filter_host);
filter_host->SetDuration(duration_);
filter_host->SetCurrentReadPosition(0);
@@ -577,8 +578,41 @@ int ChunkDemuxer::ParseInfoAndTracks_Locked(const uint8* data, int size) {
const uint8* cur = data;
int cur_size = size;
int bytes_parsed = 0;
+
+ int id;
+ int64 element_size;
+ int result = WebMParseElementHeader(cur, cur_size, &id, &element_size);
+
+ if (result <= 0)
+ return result;
+
+ switch (id) {
+ case kWebMIdEBML :
+ case kWebMIdSeekHead :
+ case kWebMIdVoid :
+ case kWebMIdCRC32 :
+ case kWebMIdCues :
+ if (cur_size < (result + element_size)) {
+ // We don't have the whole element yet. Signal we need more data.
+ return 0;
+ }
+ // Skip the element.
+ return result + element_size;
+ break;
+ case kWebMIdSegment :
+ // Just consume the segment header.
+ return result;
+ break;
+ case kWebMIdInfo :
+ // We've found the element we are looking for.
+ break;
+ default:
+ VLOG(1) << "Unexpected ID 0x" << std::hex << id;
+ return -1;
+ }
+
WebMInfoParser info_parser;
- int result = info_parser.Parse(cur, cur_size);
+ result = info_parser.Parse(cur, cur_size);
if (result <= 0)
return result;
@@ -686,6 +720,25 @@ int ChunkDemuxer::ParseCluster_Locked(const uint8* data, int size) {
if (!cluster_parser_.get())
return -1;
+ int id;
+ int64 element_size;
+ int result = WebMParseElementHeader(data, size, &id, &element_size);
+
+ if (result <= 0)
+ return result;
+
+ if (id == kWebMIdCues) {
+ if (size < (result + element_size)) {
+ // We don't have the whole element yet. Signal we need more data.
+ return 0;
+ }
+ // 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);
if (bytes_parsed <= 0)
diff --git a/media/filters/chunk_demuxer_unittest.cc b/media/filters/chunk_demuxer_unittest.cc
index dc99422..bffb8ad 100644
--- a/media/filters/chunk_demuxer_unittest.cc
+++ b/media/filters/chunk_demuxer_unittest.cc
@@ -44,7 +44,7 @@ class MockChunkDemuxerClient : public ChunkDemuxerClient {
DISALLOW_COPY_AND_ASSIGN(MockChunkDemuxerClient);
};
-class ChunkDemuxerTest : public testing::Test{
+class ChunkDemuxerTest : public testing::Test {
protected:
enum CodecsIndex {
AUDIO,
@@ -121,11 +121,14 @@ class ChunkDemuxerTest : public testing::Test{
}
void AppendDataInPieces(const uint8* data, size_t length) {
+ AppendDataInPieces(data, length, 7);
+ }
+
+ void AppendDataInPieces(const uint8* data, size_t length, size_t piece_size) {
const uint8* start = data;
const uint8* end = data + length;
- size_t default_size = 7;
while (start < end) {
- size_t append_size = std::min(default_size,
+ size_t append_size = std::min(piece_size,
static_cast<size_t>(end - start));
AppendData(start, append_size);
start += append_size;
@@ -139,30 +142,35 @@ class ChunkDemuxerTest : public testing::Test{
AppendData(info_tracks.get(), info_tracks_size);
}
- static void InitDoneCalled(bool* was_called, PipelineStatus expectedStatus,
- PipelineStatus status) {
- EXPECT_EQ(status, expectedStatus);
- *was_called = true;
+ void InitDoneCalled(const base::TimeDelta& expected_duration,
+ PipelineStatus expected_status,
+ PipelineStatus status) {
+ EXPECT_EQ(status, expected_status);
+
+ if (status == PIPELINE_OK) {
+ EXPECT_CALL(mock_filter_host_, SetDuration(expected_duration));
+ EXPECT_CALL(mock_filter_host_, SetCurrentReadPosition(_));
+
+ demuxer_->set_host(&mock_filter_host_);
+ }
+ }
+
+ PipelineStatusCB CreateInitDoneCB(int duration,
+ PipelineStatus expected_status) {
+ return base::Bind(&ChunkDemuxerTest::InitDoneCalled,
+ base::Unretained(this),
+ base::TimeDelta::FromMilliseconds(duration),
+ expected_status);
}
void InitDemuxer(bool has_audio, bool has_video) {
- bool init_done_called = false;
- PipelineStatus expectedStatus =
+ PipelineStatus expected_status =
(has_audio || has_video) ? PIPELINE_OK : DEMUXER_ERROR_COULD_NOT_OPEN;
EXPECT_CALL(*client_, DemuxerOpened(_));
- demuxer_->Init(base::Bind(&ChunkDemuxerTest::InitDoneCalled,
- &init_done_called,
- expectedStatus));
-
- EXPECT_FALSE(init_done_called);
+ demuxer_->Init(CreateInitDoneCB(201224, expected_status));
AppendInfoTracks(has_audio, has_video);
-
- EXPECT_TRUE(init_done_called);
- EXPECT_CALL(mock_filter_host_, SetDuration(_));
- EXPECT_CALL(mock_filter_host_, SetCurrentReadPosition(_));
- demuxer_->set_host(&mock_filter_host_);
}
void ShutdownDemuxer() {
@@ -651,11 +659,7 @@ TEST_F(ChunkDemuxerTest, TestReadsAfterEndOfStream) {
TEST_F(ChunkDemuxerTest, TestAppendingInPieces) {
EXPECT_CALL(*client_, DemuxerOpened(_));
- demuxer_->Init(NewExpectedStatusCB(PIPELINE_OK));
-
- EXPECT_CALL(mock_filter_host_, SetDuration(_));
- EXPECT_CALL(mock_filter_host_, SetCurrentReadPosition(_));
- demuxer_->set_host(&mock_filter_host_);
+ demuxer_->Init(CreateInitDoneCB(201224, PIPELINE_OK));
scoped_array<uint8> info_tracks;
int info_tracks_size = 0;
@@ -721,4 +725,56 @@ TEST_F(ChunkDemuxerTest, TestAppendingInPieces) {
EXPECT_TRUE(video_read_done);
}
+struct BufferTimestamps {
+ int video_time;
+ int audio_time;
+};
+
+TEST_F(ChunkDemuxerTest, TestWebMFile) {
+ scoped_array<uint8> buffer;
+ int buffer_size = 0;
+
+ EXPECT_CALL(*client_, DemuxerOpened(_));
+ demuxer_->Init(CreateInitDoneCB(2744, PIPELINE_OK));
+
+ // Read a WebM file into memory and send the data to the demuxer.
+ ReadTestDataFile("bear-320x240.webm", &buffer, &buffer_size);
+ AppendDataInPieces(buffer.get(), buffer_size, 512);
+
+ scoped_refptr<DemuxerStream> audio =
+ demuxer_->GetStream(DemuxerStream::AUDIO);
+ scoped_refptr<DemuxerStream> video =
+ demuxer_->GetStream(DemuxerStream::VIDEO);
+
+ ASSERT_TRUE(audio);
+ ASSERT_TRUE(video);
+
+ struct BufferTimestamps buffer_timestamps[] = {
+ {0, 0},
+ {33, 3},
+ {67, 6},
+ {100, 9},
+ {133, 12},
+ };
+
+ // Verify that the timestamps on the first few packets match what we
+ // expect.
+ for (size_t i = 0; i < arraysize(buffer_timestamps); i++) {
+ bool audio_read_done = false;
+ bool video_read_done = false;
+ audio->Read(base::Bind(&OnReadDone,
+ base::TimeDelta::FromMilliseconds(
+ buffer_timestamps[i].audio_time),
+ &audio_read_done));
+
+ video->Read(base::Bind(&OnReadDone,
+ base::TimeDelta::FromMilliseconds(
+ buffer_timestamps[i].video_time),
+ &video_read_done));
+
+ EXPECT_TRUE(audio_read_done);
+ EXPECT_TRUE(video_read_done);
+ }
+}
+
} // namespace media
diff --git a/media/webm/webm_constants.h b/media/webm/webm_constants.h
index aa6dda0..471115b 100644
--- a/media/webm/webm_constants.h
+++ b/media/webm/webm_constants.h
@@ -20,12 +20,15 @@ const int kWebMIdCluster = 0x1f43b675;
const int kWebMIdCodecID = 0x86;
const int kWebMIdCodecName = 0x258688;
const int kWebMIdCodecPrivate = 0x63A2;
+const int kWebMIdCRC32 = 0xBF;
+const int kWebMIdCues = 0x1C53BB6B;
const int kWebMIdDateUTC = 0x4461;
const int kWebMIdDefaultDuration = 0x23E383;
const int kWebMIdDisplayHeight = 0x54BA;
const int kWebMIdDisplayUnit = 0x54B2;
const int kWebMIdDisplayWidth = 0x54B0;
const int kWebMIdDuration = 0x4489;
+const int kWebMIdEBML = 0x1A45DFA3;
const int kWebMIdFlagDefault = 0x88;
const int kWebMIdFlagEnabled = 0xB9;
const int kWebMIdFlagForced = 0x55AA;
@@ -42,7 +45,10 @@ const int kWebMIdPixelCropRight = 0x54DD;
const int kWebMIdPixelCropTop = 0x54BB;
const int kWebMIdPixelHeight = 0xBA;
const int kWebMIdPixelWidth = 0xB0;
+const int kWebMIdPrevSize = 0xAB;
const int kWebMIdSamplingFrequency = 0xB5;
+const int kWebMIdSeekHead = 0x114D9B74;
+const int kWebMIdSegment = 0x18538067;
const int kWebMIdSegmentUID = 0x73A4;
const int kWebMIdSimpleBlock = 0xA3;
const int kWebMIdStereoMode = 0x53B8;
@@ -55,6 +61,7 @@ const int kWebMIdTrackType = 0x83;
const int kWebMIdTrackUID = 0x73C5;
const int kWebMIdTracks = 0x1654AE6B;
const int kWebMIdVideo = 0xE0;
+const int kWebMIdVoid = 0xEC;
const int kWebMIdWritingApp = 0x5741;
// Default timecode scale if the TimecodeScale element is
diff --git a/media/webm/webm_parser.cc b/media/webm/webm_parser.cc
index 43dd509..1e42815 100644
--- a/media/webm/webm_parser.cc
+++ b/media/webm/webm_parser.cc
@@ -177,13 +177,8 @@ static int ParseWebMElementHeaderField(const uint8* buf, int size,
return bytes_used;
}
-// Parses an element header & returns the ID and element size.
-//
-// Returns: The number of bytes parsed on success. -1 on error.
-// |*id| contains the element ID on success & undefined on error.
-// |*element_size| contains the element size on success & undefined on error.
-static int ParseWebMElementHeader(const uint8* buf, int size,
- int* id, int64* element_size) {
+int WebMParseElementHeader(const uint8* buf, int size,
+ int* id, int64* element_size) {
DCHECK(buf);
DCHECK_GE(size, 0);
DCHECK(id);
@@ -377,7 +372,7 @@ static int ParseElements(const ElementIdInfo* id_info,
while (cur_size > 0) {
int id = 0;
int64 element_size = 0;
- int result = ParseWebMElementHeader(cur, cur_size, &id, &element_size);
+ int result = WebMParseElementHeader(cur, cur_size, &id, &element_size);
if (result <= 0)
return result;
@@ -467,7 +462,7 @@ int WebMParseListElement(const uint8* buf, int size, int id,
int bytes_parsed = 0;
int element_id = 0;
int64 element_size = 0;
- int result = ParseWebMElementHeader(cur, cur_size, &element_id,
+ int result = WebMParseElementHeader(cur, cur_size, &element_id,
&element_size);
if (result <= 0)
diff --git a/media/webm/webm_parser.h b/media/webm/webm_parser.h
index 92dd679..7d15f9b 100644
--- a/media/webm/webm_parser.h
+++ b/media/webm/webm_parser.h
@@ -36,6 +36,17 @@ class WebMParserClient {
const uint8* data, int size) = 0;
};
+// Parses an element header & returns the ID and element size.
+//
+// Returns < 0 if the parse fails.
+// Returns 0 if more data is needed.
+// Returning > 0 indicates success & the number of bytes parsed.
+// |*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);
+
// Parses a single list element that matches |id|. This method fails if the
// buffer points to an element that does not match |id|.
//