summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--media/filters/chunk_demuxer_unittest.cc32
-rw-r--r--media/formats/webm/cluster_builder.cc11
-rw-r--r--media/formats/webm/cluster_builder.h1
-rw-r--r--media/formats/webm/webm_stream_parser.cc100
4 files changed, 96 insertions, 48 deletions
diff --git a/media/filters/chunk_demuxer_unittest.cc b/media/filters/chunk_demuxer_unittest.cc
index 294d769..74f2a01 100644
--- a/media/filters/chunk_demuxer_unittest.cc
+++ b/media/filters/chunk_demuxer_unittest.cc
@@ -673,6 +673,13 @@ class ChunkDemuxerTest : public ::testing::TestWithParam<bool> {
scoped_ptr<Cluster> GenerateCluster(int first_audio_timecode,
int first_video_timecode,
int block_count) {
+ return GenerateCluster(first_audio_timecode, first_video_timecode,
+ block_count, false);
+ }
+ scoped_ptr<Cluster> GenerateCluster(int first_audio_timecode,
+ int first_video_timecode,
+ int block_count,
+ bool unknown_size) {
CHECK_GT(block_count, 0);
int size = 10;
@@ -722,7 +729,7 @@ class ChunkDemuxerTest : public ::testing::TestWithParam<bool> {
kWebMFlagKeyframe, data.get(), size);
}
- return cb.Finish();
+ return unknown_size ? cb.FinishWithUnknownSize() : cb.Finish();
}
scoped_ptr<Cluster> GenerateSingleStreamCluster(int timecode,
@@ -2893,11 +2900,14 @@ TEST_P(ChunkDemuxerTest, EmitBuffersDuringAbort) {
#endif
TEST_P(ChunkDemuxerTest, WebMIsParsingMediaSegmentDetection) {
- // TODO(wolenetz): Also test 'unknown' sized clusters.
- // See http://crbug.com/335676.
const uint8 kBuffer[] = {
0x1F, 0x43, 0xB6, 0x75, 0x83, // CLUSTER (size = 3)
0xE7, 0x81, 0x01, // Cluster TIMECODE (value = 1)
+
+ 0x1F, 0x43, 0xB6, 0x75, 0xFF, // CLUSTER (size = unknown; really 3 due to:)
+ 0xE7, 0x81, 0x02, // Cluster TIMECODE (value = 2)
+ /* e.g. put some blocks here... */
+ 0x1A, 0x45, 0xDF, 0xA3, 0x8A, // EBMLHEADER (size = 10, not fully appended)
};
// This array indicates expected return value of IsParsingMediaSegment()
@@ -2905,6 +2915,11 @@ TEST_P(ChunkDemuxerTest, WebMIsParsingMediaSegmentDetection) {
const bool kExpectedReturnValues[] = {
false, false, false, false, true,
true, true, false,
+
+ false, false, false, false, true,
+ true, true, true,
+
+ true, true, true, true, false,
};
COMPILE_ASSERT(arraysize(kBuffer) == arraysize(kExpectedReturnValues),
@@ -3454,6 +3469,17 @@ TEST_P(ChunkDemuxerTest, SeekCompletesWithoutTextCues) {
CheckExpectedBuffers(video_stream, "180 210");
}
+TEST_P(ChunkDemuxerTest, ClusterWithUnknownSize) {
+ ASSERT_TRUE(InitDemuxer(HAS_AUDIO | HAS_VIDEO));
+
+ AppendCluster(GenerateCluster(0, 0, 4, true));
+ CheckExpectedRanges(kSourceId, "{ [0,46) }");
+
+ // A new cluster indicates end of the previous cluster with unknown size.
+ AppendCluster(GenerateCluster(46, 66, 5, true));
+ CheckExpectedRanges(kSourceId, "{ [0,115) }");
+}
+
// Generate two sets of tests: one using FrameProcessor, and one using
// LegacyFrameProcessor.
INSTANTIATE_TEST_CASE_P(NewFrameProcessor, ChunkDemuxerTest, Values(false));
diff --git a/media/formats/webm/cluster_builder.cc b/media/formats/webm/cluster_builder.cc
index bada9e2..1a3b358 100644
--- a/media/formats/webm/cluster_builder.cc
+++ b/media/formats/webm/cluster_builder.cc
@@ -6,6 +6,7 @@
#include "base/logging.h"
#include "media/base/data_buffer.h"
+#include "media/formats/webm/webm_constants.h"
namespace media {
@@ -180,6 +181,16 @@ scoped_ptr<Cluster> ClusterBuilder::Finish() {
return ret.Pass();
}
+scoped_ptr<Cluster> ClusterBuilder::FinishWithUnknownSize() {
+ DCHECK_NE(cluster_timecode_, -1);
+
+ UpdateUInt64(kClusterSizeOffset, kWebMUnknownSize);
+
+ scoped_ptr<Cluster> ret(new Cluster(buffer_.Pass(), bytes_used_));
+ Reset();
+ return ret.Pass();
+}
+
void ClusterBuilder::Reset() {
buffer_size_ = kInitialBufferSize;
buffer_.reset(new uint8[buffer_size_]);
diff --git a/media/formats/webm/cluster_builder.h b/media/formats/webm/cluster_builder.h
index ac5464a..ab5797c 100644
--- a/media/formats/webm/cluster_builder.h
+++ b/media/formats/webm/cluster_builder.h
@@ -40,6 +40,7 @@ class ClusterBuilder {
int flags, const uint8* data, int size);
scoped_ptr<Cluster> Finish();
+ scoped_ptr<Cluster> FinishWithUnknownSize();
private:
void AddBlockGroupInternal(int track_num, int64 timecode,
diff --git a/media/formats/webm/webm_stream_parser.cc b/media/formats/webm/webm_stream_parser.cc
index a90a623..3f370da 100644
--- a/media/formats/webm/webm_stream_parser.cc
+++ b/media/formats/webm/webm_stream_parser.cc
@@ -143,6 +143,7 @@ int WebMStreamParser::ParseInfoAndTracks(const uint8* data, int size) {
case kWebMIdCRC32:
case kWebMIdCues:
case kWebMIdChapters:
+ // TODO(matthewjheaney): Implement support for chapters.
if (cur_size < (result + element_size)) {
// We don't have the whole element yet. Signal we need more data.
return 0;
@@ -242,61 +243,70 @@ int WebMStreamParser::ParseCluster(const uint8* data, int size) {
if (!cluster_parser_)
return -1;
- int id;
- int64 element_size;
- int result = WebMParseElementHeader(data, size, &id, &element_size);
-
- if (result <= 0)
- return result;
-
- // TODO(matthewjheaney): implement support for chapters
- if (id == kWebMIdCues || id == kWebMIdChapters) {
- // TODO(wolenetz): Handle unknown-sized cluster parse completion correctly.
- // See http://crbug.com/335676.
- if (size < (result + element_size)) {
- // We don't have the whole element yet. Signal we need more data.
- return 0;
+ int result = 0;
+ int bytes_parsed;
+ bool cluster_ended;
+ do {
+ cluster_ended = false;
+
+ // If we are not parsing a cluster then handle the case when the next
+ // element is not a cluster.
+ if (!parsing_cluster_) {
+ int id;
+ int64 element_size;
+ bytes_parsed = WebMParseElementHeader(data, size, &id, &element_size);
+
+ if (bytes_parsed < 0)
+ return bytes_parsed;
+
+ if (bytes_parsed == 0)
+ return result;
+
+ if (id != kWebMIdCluster) {
+ ChangeState(kParsingHeaders);
+ return result;
+ }
}
- // Skip the element.
- return result + element_size;
- }
- if (id == kWebMIdEBMLHeader) {
- // TODO(wolenetz): Handle unknown-sized cluster parse completion correctly.
- // See http://crbug.com/335676.
- ChangeState(kParsingHeaders);
- return 0;
- }
+ bytes_parsed = cluster_parser_->Parse(data, size);
- int bytes_parsed = cluster_parser_->Parse(data, size);
+ if (bytes_parsed < 0)
+ return bytes_parsed;
- if (bytes_parsed <= 0)
- return bytes_parsed;
+ // If cluster detected, immediately notify new segment if we have not
+ // already done this.
+ if (!parsing_cluster_ && bytes_parsed > 0) {
+ parsing_cluster_ = true;
+ new_segment_cb_.Run();
+ }
- // If cluster detected, immediately notify new segment if we have not already
- // done this.
- if (id == kWebMIdCluster && !parsing_cluster_) {
- parsing_cluster_ = true;
- new_segment_cb_.Run();
- }
+ const BufferQueue& audio_buffers = cluster_parser_->GetAudioBuffers();
+ const BufferQueue& video_buffers = cluster_parser_->GetVideoBuffers();
+ const TextBufferQueueMap& text_map = cluster_parser_->GetTextBuffers();
- const BufferQueue& audio_buffers = cluster_parser_->GetAudioBuffers();
- const BufferQueue& video_buffers = cluster_parser_->GetVideoBuffers();
- const TextBufferQueueMap& text_map = cluster_parser_->GetTextBuffers();
+ cluster_ended = cluster_parser_->cluster_ended();
- bool cluster_ended = cluster_parser_->cluster_ended();
+ if ((!audio_buffers.empty() || !video_buffers.empty() ||
+ !text_map.empty()) &&
+ !new_buffers_cb_.Run(audio_buffers, video_buffers, text_map)) {
+ return -1;
+ }
- if ((!audio_buffers.empty() || !video_buffers.empty() || !text_map.empty()) &&
- !new_buffers_cb_.Run(audio_buffers, video_buffers, text_map)) {
- return -1;
- }
+ if (cluster_ended) {
+ parsing_cluster_ = false;
+ end_of_segment_cb_.Run();
+ }
- if (cluster_ended) {
- parsing_cluster_ = false;
- end_of_segment_cb_.Run();
- }
+ result += bytes_parsed;
+ data += bytes_parsed;
+ size -= bytes_parsed;
- return bytes_parsed;
+ // WebMClusterParser returns 0 and |cluster_ended| is true if previously
+ // parsing an unknown-size cluster and |data| does not continue that
+ // cluster. Try parsing again in that case.
+ } while (size > 0 && (bytes_parsed > 0 || cluster_ended));
+
+ return result;
}
void WebMStreamParser::FireNeedKey(const std::string& key_id) {