diff --git a/packager/app/test/packager_test.py b/packager/app/test/packager_test.py index 6bed8b64c0..1e82f9f451 100755 --- a/packager/app/test/packager_test.py +++ b/packager/app/test/packager_test.py @@ -143,6 +143,14 @@ class PackagerAppTest(unittest.TestCase): self._DiffGold(self.output[1], 'bear-320x240-vp9-golden.webm') self._DiffGold(self.mpd_output, 'bear-320x240-vp9-opus-webm-golden.mpd') + def testPackageVp9WebmWithBlockgroup(self): + self.packager.Package( + self._GetStreams(['video'], + output_format='webm', + test_files=['bear-vp9-blockgroup.webm']), + self._GetFlags()) + self._DiffGold(self.output[0], 'bear-vp9-blockgroup-golden.webm') + def testPackageVorbisWebm(self): self.packager.Package( self._GetStreams(['audio'], diff --git a/packager/app/test/testdata/bear-vp9-blockgroup-golden.webm b/packager/app/test/testdata/bear-vp9-blockgroup-golden.webm new file mode 100644 index 0000000000..9ab11de170 Binary files /dev/null and b/packager/app/test/testdata/bear-vp9-blockgroup-golden.webm differ diff --git a/packager/media/formats/webm/cluster_builder.cc b/packager/media/formats/webm/cluster_builder.cc index 9921724170..17a7ae6af6 100644 --- a/packager/media/formats/webm/cluster_builder.cc +++ b/packager/media/formats/webm/cluster_builder.cc @@ -40,6 +40,11 @@ static const uint8_t kBlockGroupHeaderWithoutBlockDuration[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Block(size = 0) }; +static const uint8_t kBlockGroupReferenceBlock[] = { + 0xFB, // ReferenceBlock ID + 0x81, 0x00, // ReferenceBlock (size=1, value=0) +}; + enum { kClusterSizeOffset = 4, kClusterTimecodeOffset = 14, @@ -99,17 +104,21 @@ void ClusterBuilder::AddBlockGroup(int track_num, int64_t timecode, int duration, int flags, + bool is_key_frame, const uint8_t* data, int size) { - AddBlockGroupInternal(track_num, timecode, true, duration, flags, data, size); + AddBlockGroupInternal(track_num, timecode, true, duration, flags, + is_key_frame, data, size); } void ClusterBuilder::AddBlockGroupWithoutBlockDuration(int track_num, int64_t timecode, int flags, + bool is_key_frame, const uint8_t* data, int size) { - AddBlockGroupInternal(track_num, timecode, false, 0, flags, data, size); + AddBlockGroupInternal(track_num, timecode, false, 0, flags, is_key_frame, + data, size); } void ClusterBuilder::AddBlockGroupInternal(int track_num, @@ -117,6 +126,7 @@ void ClusterBuilder::AddBlockGroupInternal(int track_num, bool include_block_duration, int duration, int flags, + bool is_key_frame, const uint8_t* data, int size) { int block_size = size + 4; @@ -126,6 +136,9 @@ void ClusterBuilder::AddBlockGroupInternal(int track_num, } else { bytes_needed += sizeof(kBlockGroupHeaderWithoutBlockDuration); } + if (!is_key_frame) { + bytes_needed += sizeof(kBlockGroupReferenceBlock); + } int block_group_size = bytes_needed - 9; @@ -155,7 +168,10 @@ void ClusterBuilder::AddBlockGroupInternal(int track_num, flags &= 0x0f; WriteBlock(buf, track_num, timecode, flags, data, size); + buf += size + 4; + if (!is_key_frame) + memcpy(buf, kBlockGroupReferenceBlock, sizeof(kBlockGroupReferenceBlock)); bytes_used_ += bytes_needed; } diff --git a/packager/media/formats/webm/cluster_builder.h b/packager/media/formats/webm/cluster_builder.h index 7cd3bbbcdc..f21ce6ce21 100644 --- a/packager/media/formats/webm/cluster_builder.h +++ b/packager/media/formats/webm/cluster_builder.h @@ -41,11 +41,13 @@ class ClusterBuilder { int64_t timecode, int duration, int flags, + bool is_key_frame, const uint8_t* data, int size); void AddBlockGroupWithoutBlockDuration(int track_num, int64_t timecode, int flags, + bool is_key_frame, const uint8_t* data, int size); @@ -58,6 +60,7 @@ class ClusterBuilder { bool include_block_duration, int duration, int flags, + bool is_key_frame, const uint8_t* data, int size); void Reset(); diff --git a/packager/media/formats/webm/webm_cluster_parser.cc b/packager/media/formats/webm/webm_cluster_parser.cc index c2268e378f..3907db0289 100644 --- a/packager/media/formats/webm/webm_cluster_parser.cc +++ b/packager/media/formats/webm/webm_cluster_parser.cc @@ -23,27 +23,6 @@ namespace { const int64_t kMicrosecondsPerMillisecond = 1000; -// Helper function used to inspect block data to determine if the -// block is a keyframe. -// |data| contains the bytes in the block. -// |size| indicates the number of bytes in |data|. -bool IsKeyframe(bool is_video, Codec codec, const uint8_t* data, int size) { - // For now, assume that all blocks are keyframes for datatypes other than - // video. This is a valid assumption for Vorbis, WebVTT, & Opus. - if (!is_video) - return true; - - switch (codec) { - case kCodecVP8: - return VP8Parser::IsKeyframe(data, size); - case kCodecVP9: - return VP9Parser::IsKeyframe(data, size); - default: - NOTIMPLEMENTED() << "Unsupported codec " << codec; - return false; - } -} - } // namespace WebMClusterParser::WebMClusterParser( @@ -151,6 +130,7 @@ WebMParserClient* WebMClusterParser::OnListStart(int id) { block_duration_ = -1; discard_padding_ = -1; discard_padding_set_ = false; + reference_block_set_ = false; } else if (id == kWebMIdBlockAdditions) { block_add_id_ = -1; block_additional_data_.reset(); @@ -170,10 +150,10 @@ bool WebMClusterParser::OnListEnd(int id) { return false; } - bool result = ParseBlock(false, block_data_.get(), block_data_size_, - block_additional_data_.get(), - block_additional_data_size_, block_duration_, - discard_padding_set_ ? discard_padding_ : 0); + bool result = ParseBlock( + false, block_data_.get(), block_data_size_, block_additional_data_.get(), + block_additional_data_size_, block_duration_, + discard_padding_set_ ? discard_padding_ : 0, reference_block_set_); block_data_.reset(); block_data_size_ = -1; block_duration_ = -1; @@ -182,6 +162,7 @@ bool WebMClusterParser::OnListEnd(int id) { block_additional_data_size_ = 0; discard_padding_ = -1; discard_padding_set_ = false; + reference_block_set_ = false; return result; } @@ -212,7 +193,8 @@ bool WebMClusterParser::ParseBlock(bool is_simple_block, const uint8_t* additional, int additional_size, int duration, - int64_t discard_padding) { + int64_t discard_padding, + bool reference_block_set) { if (size < 4) return false; @@ -237,17 +219,24 @@ bool WebMClusterParser::ParseBlock(bool is_simple_block, if (timecode & 0x8000) timecode |= ~0xffff; + // The first bit of the flags is set when a SimpleBlock contains only + // keyframes. If this is a Block, then keyframe is inferred by the absence of + // the ReferenceBlock Element. + // http://www.matroska.org/technical/specs/index.html + bool is_key_frame = + is_simple_block ? (flags & 0x80) != 0 : !reference_block_set; + const uint8_t* frame_data = buf + 4; int frame_size = size - (frame_data - buf); - return OnBlock(is_simple_block, track_num, timecode, duration, flags, - frame_data, frame_size, additional, additional_size, - discard_padding); + return OnBlock(is_simple_block, track_num, timecode, duration, frame_data, + frame_size, additional, additional_size, discard_padding, + is_key_frame); } bool WebMClusterParser::OnBinary(int id, const uint8_t* data, int size) { switch (id) { case kWebMIdSimpleBlock: - return ParseBlock(true, data, size, NULL, 0, -1, 0); + return ParseBlock(true, data, size, NULL, 0, -1, 0, false); case kWebMIdBlock: if (block_data_) { @@ -293,6 +282,12 @@ bool WebMClusterParser::OnBinary(int id, const uint8_t* data, int size) { return true; } + case kWebMIdReferenceBlock: + // We use ReferenceBlock to determine whether the current Block contains a + // keyframe or not. Other than that, we don't care about the value of the + // ReferenceBlock element itself. + reference_block_set_ = true; + return true; default: return true; } @@ -302,12 +297,12 @@ bool WebMClusterParser::OnBlock(bool is_simple_block, int track_num, int timecode, int block_duration, - int flags, const uint8_t* data, int size, const uint8_t* additional, int additional_size, - int64_t discard_padding) { + int64_t discard_padding, + bool is_key_frame) { DCHECK_GE(size, 0); if (cluster_timecode_ == -1) { LOG(ERROR) << "Got a block before cluster timecode."; @@ -358,18 +353,6 @@ bool WebMClusterParser::OnBlock(bool is_simple_block, scoped_refptr buffer; if (stream_type != kStreamText) { - // The first bit of the flags is set when a SimpleBlock contains only - // keyframes. If this is a Block, then inspection of the payload is - // necessary to determine whether it contains a keyframe or not. - // http://www.matroska.org/technical/specs/index.html - bool is_keyframe = - is_simple_block - ? (flags & 0x80) != 0 - : IsKeyframe(stream_type == kStreamVideo, - video_stream_info_ ? video_stream_info_->codec() - : kUnknownCodec, - data, size); - // Every encrypted Block has a signal byte and IV prepended to it. Current // encrypted WebM request for comments specification is here // http://wiki.webmproject.org/encryption/webm-encryption-rfc @@ -385,7 +368,7 @@ bool WebMClusterParser::OnBlock(bool is_simple_block, } buffer = MediaSample::CopyFrom(data + data_offset, size - data_offset, - additional, additional_size, is_keyframe); + additional, additional_size, is_key_frame); if (decrypt_config) { if (!decryptor_source_) { diff --git a/packager/media/formats/webm/webm_cluster_parser.h b/packager/media/formats/webm/webm_cluster_parser.h index 78ad269690..5e21139176 100644 --- a/packager/media/formats/webm/webm_cluster_parser.h +++ b/packager/media/formats/webm/webm_cluster_parser.h @@ -163,17 +163,18 @@ class WebMClusterParser : public WebMParserClient { const uint8_t* additional, int additional_size, int duration, - int64_t discard_padding); + int64_t discard_padding, + bool reference_block_set); bool OnBlock(bool is_simple_block, int track_num, int timecode, int duration, - int flags, const uint8_t* data, int size, const uint8_t* additional, int additional_size, - int64_t discard_padding); + int64_t discard_padding, + bool is_key_frame); // Resets the Track objects associated with each text track. void ResetTextTracks(); @@ -215,6 +216,8 @@ class WebMClusterParser : public WebMParserClient { int64_t discard_padding_ = -1; bool discard_padding_set_ = false; + bool reference_block_set_ = false; + int64_t cluster_timecode_ = -1; int64_t cluster_start_time_; bool cluster_ended_ = false; diff --git a/packager/media/formats/webm/webm_cluster_parser_unittest.cc b/packager/media/formats/webm/webm_cluster_parser_unittest.cc index e1a2af2c1d..8235094fb8 100644 --- a/packager/media/formats/webm/webm_cluster_parser_unittest.cc +++ b/packager/media/formats/webm/webm_cluster_parser_unittest.cc @@ -121,17 +121,19 @@ struct BlockInfo { // Default data will be used if no data given. const uint8_t* data; int data_length; + + bool is_key_frame; }; const BlockInfo kDefaultBlockInfo[] = { - {kAudioTrackNum, 0, 23, true, NULL, 0}, - {kAudioTrackNum, 23, 23, true, NULL, 0}, + {kAudioTrackNum, 0, 23, true, NULL, 0, true}, + {kAudioTrackNum, 23, 23, true, NULL, 0, true}, // Assumes not using DefaultDuration - {kVideoTrackNum, 33, 34, true, NULL, 0}, - {kAudioTrackNum, 46, 23, true, NULL, 0}, - {kVideoTrackNum, 67, 33, false, NULL, 0}, - {kAudioTrackNum, 69, 23, false, NULL, 0}, - {kVideoTrackNum, 100, 33, false, NULL, 0}, + {kVideoTrackNum, 33, 34, true, NULL, 0, true}, + {kAudioTrackNum, 46, 23, true, NULL, 0, false}, + {kVideoTrackNum, 67, 33, false, NULL, 0, true}, + {kAudioTrackNum, 69, 23, false, NULL, 0, false}, + {kVideoTrackNum, 100, 33, false, NULL, 0, false}, }; const uint8_t kEncryptedFrame[] = { @@ -203,20 +205,22 @@ scoped_ptr CreateCluster(int timecode, if (block_info[i].use_simple_block) { CHECK_GE(block_info[i].duration, 0); - cb.AddSimpleBlock(block_info[i].track_num, block_info[i].timestamp, 0, - data, data_length); + cb.AddSimpleBlock(block_info[i].track_num, block_info[i].timestamp, + block_info[i].is_key_frame ? 0x80 : 0x00, data, + data_length); continue; } if (block_info[i].duration < 0) { - cb.AddBlockGroupWithoutBlockDuration(block_info[i].track_num, - block_info[i].timestamp, 0, data, - data_length); + cb.AddBlockGroupWithoutBlockDuration( + block_info[i].track_num, block_info[i].timestamp, 0, + block_info[i].is_key_frame, data, data_length); continue; } cb.AddBlockGroup(block_info[i].track_num, block_info[i].timestamp, - block_info[i].duration, 0, data, data_length); + block_info[i].duration, 0, block_info[i].is_key_frame, + data, data_length); } return cb.Finish(); @@ -277,6 +281,7 @@ bool VerifyBuffersHelper(const BufferQueue& audio_buffers, buffer->pts()); EXPECT_EQ(std::abs(block_info[i].duration) * kMicrosecondsPerMillisecond, buffer->duration()); + EXPECT_EQ(block_info[i].is_key_frame, buffer->is_key_frame()); } return true; @@ -476,29 +481,30 @@ TEST_F(WebMClusterParserTest, TracksWithSampleMissingDuration) { const BlockInfo kBlockInfo[] = { // Note that for simple blocks, duration is not encoded. - {kVideoTrackNum, 0, 0, true, NULL, 0}, - {kAudioTrackNum, 0, 23, false, NULL, 0}, - {kTextTrackNum, 10, 42, false, NULL, 0}, - {kAudioTrackNum, 23, 0, true, NULL, 0}, - {kVideoTrackNum, 33, 0, true, NULL, 0}, - {kAudioTrackNum, 36, 0, true, NULL, 0}, - {kVideoTrackNum, 66, 0, true, NULL, 0}, - {kAudioTrackNum, 70, 0, true, NULL, 0}, - {kAudioTrackNum, 83, 0, true, NULL, 0}, + {kVideoTrackNum, 0, 0, true, NULL, 0, false}, + {kAudioTrackNum, 0, 23, false, NULL, 0, false}, + {kTextTrackNum, 10, 42, false, NULL, 0, true}, + {kAudioTrackNum, 23, 0, true, NULL, 0, false}, + {kVideoTrackNum, 33, 0, true, NULL, 0, false}, + {kAudioTrackNum, 36, 0, true, NULL, 0, false}, + {kVideoTrackNum, 66, 0, true, NULL, 0, false}, + {kAudioTrackNum, 70, 0, true, NULL, 0, false}, + {kAudioTrackNum, 83, 0, true, NULL, 0, false}, }; // Samples are not emitted in the same order as |kBlockInfo| due to missing of // duration in some samples. const BlockInfo kExpectedBlockInfo[] = { - {kAudioTrackNum, 0, 23, false, NULL, 0}, - {kTextTrackNum, 10, 42, false, NULL, 0}, - {kVideoTrackNum, 0, 33, true, NULL, 0}, - {kAudioTrackNum, 23, 13, true, NULL, 0}, - {kVideoTrackNum, 33, 33, true, NULL, 0}, - {kAudioTrackNum, 36, 34, true, NULL, 0}, - {kAudioTrackNum, 70, 13, true, NULL, 0}, - {kAudioTrackNum, 83, kTestAudioFrameDefaultDurationInMs, true, NULL, 0}, - {kVideoTrackNum, 66, kExpectedVideoEstimationInMs, true, NULL, 0}, + {kAudioTrackNum, 0, 23, false, NULL, 0, false}, + {kTextTrackNum, 10, 42, false, NULL, 0, true}, + {kVideoTrackNum, 0, 33, true, NULL, 0, false}, + {kAudioTrackNum, 23, 13, true, NULL, 0, false}, + {kVideoTrackNum, 33, 33, true, NULL, 0, false}, + {kAudioTrackNum, 36, 34, true, NULL, 0, false}, + {kAudioTrackNum, 70, 13, true, NULL, 0, false}, + {kAudioTrackNum, 83, kTestAudioFrameDefaultDurationInMs, true, NULL, 0, + false}, + {kVideoTrackNum, 66, kExpectedVideoEstimationInMs, true, NULL, 0, false}, }; const int kExpectedBuffersOnPartialCluster[] = { 0, // Video simple block without duration should be held back @@ -609,8 +615,8 @@ TEST_F(WebMClusterParserTest, ParseClusterWithMultipleCalls) { // one of these scenarios. TEST_F(WebMClusterParserTest, ParseBlockGroup) { const BlockInfo kBlockInfo[] = { - {kAudioTrackNum, 0, 23, false, NULL, 0}, - {kVideoTrackNum, 33, 34, false, NULL, 0}, + {kAudioTrackNum, 0, 23, false, NULL, 0, true}, + {kVideoTrackNum, 33, 34, false, NULL, 0, true}, }; int block_count = arraysize(kBlockInfo); @@ -635,11 +641,11 @@ TEST_F(WebMClusterParserTest, ParseBlockGroup) { TEST_F(WebMClusterParserTest, ParseSimpleBlockAndBlockGroupMixture) { const BlockInfo kBlockInfo[] = { - {kAudioTrackNum, 0, 23, true, NULL, 0}, - {kAudioTrackNum, 23, 23, false, NULL, 0}, - {kVideoTrackNum, 33, 34, true, NULL, 0}, - {kAudioTrackNum, 46, 23, false, NULL, 0}, - {kVideoTrackNum, 67, 33, false, NULL, 0}, + {kAudioTrackNum, 0, 23, true, NULL, 0, false}, + {kAudioTrackNum, 23, 23, false, NULL, 0, false}, + {kVideoTrackNum, 33, 34, true, NULL, 0, false}, + {kAudioTrackNum, 46, 23, false, NULL, 0, false}, + {kVideoTrackNum, 67, 33, false, NULL, 0, false}, }; int block_count = arraysize(kBlockInfo); scoped_ptr cluster(CreateCluster(0, kBlockInfo, block_count)); @@ -656,21 +662,21 @@ TEST_F(WebMClusterParserTest, IgnoredTracks) { parser_.reset(CreateParserWithIgnoredTracks(ignored_tracks)); const BlockInfo kInputBlockInfo[] = { - {kAudioTrackNum, 0, 23, true, NULL, 0}, - {kAudioTrackNum, 23, 23, true, NULL, 0}, - {kVideoTrackNum, 33, 34, true, NULL, 0}, - {kTextTrackNum, 33, 99, true, NULL, 0}, - {kAudioTrackNum, 46, 23, true, NULL, 0}, - {kVideoTrackNum, 67, 34, true, NULL, 0}, + {kAudioTrackNum, 0, 23, true, NULL, 0, false}, + {kAudioTrackNum, 23, 23, true, NULL, 0, false}, + {kVideoTrackNum, 33, 34, true, NULL, 0, false}, + {kTextTrackNum, 33, 99, true, NULL, 0, false}, + {kAudioTrackNum, 46, 23, true, NULL, 0, false}, + {kVideoTrackNum, 67, 34, true, NULL, 0, false}, }; int input_block_count = arraysize(kInputBlockInfo); const BlockInfo kOutputBlockInfo[] = { - {kAudioTrackNum, 0, 23, true, NULL, 0}, - {kAudioTrackNum, 23, 23, true, NULL, 0}, - {kVideoTrackNum, 33, 34, true, NULL, 0}, - {kAudioTrackNum, 46, 23, true, NULL, 0}, - {kVideoTrackNum, 67, 34, true, NULL, 0}, + {kAudioTrackNum, 0, 23, true, NULL, 0, false}, + {kAudioTrackNum, 23, 23, true, NULL, 0, false}, + {kVideoTrackNum, 33, 34, true, NULL, 0, false}, + {kAudioTrackNum, 46, 23, true, NULL, 0, false}, + {kVideoTrackNum, 67, 34, true, NULL, 0, false}, }; int output_block_count = arraysize(kOutputBlockInfo); @@ -694,13 +700,13 @@ TEST_F(WebMClusterParserTest, ParseTextTracks) { kNoTimestamp, kNoTimestamp, text_tracks)); const BlockInfo kInputBlockInfo[] = { - {kAudioTrackNum, 0, 23, true, NULL, 0}, - {kAudioTrackNum, 23, 23, true, NULL, 0}, - {kVideoTrackNum, 33, 34, true, NULL, 0}, - {kTextTrackNum, 33, 42, false, NULL, 0}, - {kAudioTrackNum, 46, 23, true, NULL, 0}, - {kTextTrackNum, 55, 44, false, NULL, 0}, - {kVideoTrackNum, 67, 34, true, NULL, 0}, + {kAudioTrackNum, 0, 23, true, NULL, 0, false}, + {kAudioTrackNum, 23, 23, true, NULL, 0, false}, + {kVideoTrackNum, 33, 34, true, NULL, 0, false}, + {kTextTrackNum, 33, 42, false, NULL, 0, true}, + {kAudioTrackNum, 46, 23, true, NULL, 0, false}, + {kTextTrackNum, 55, 44, false, NULL, 0, true}, + {kVideoTrackNum, 67, 34, true, NULL, 0, false}, }; int input_block_count = arraysize(kInputBlockInfo); @@ -724,7 +730,7 @@ TEST_F(WebMClusterParserTest, TextTracksSimpleBlock) { kNoTimestamp, kNoTimestamp, text_tracks)); const BlockInfo kInputBlockInfo[] = { - { kTextTrackNum, 33, 42, true }, + {kTextTrackNum, 33, 42, true, NULL, 0, false}, }; int input_block_count = arraysize(kInputBlockInfo); @@ -753,14 +759,14 @@ TEST_F(WebMClusterParserTest, ParseMultipleTextTracks) { kNoTimestamp, kNoTimestamp, text_tracks)); const BlockInfo kInputBlockInfo[] = { - {kAudioTrackNum, 0, 23, true, NULL, 0}, - {kAudioTrackNum, 23, 23, true, NULL, 0}, - {kVideoTrackNum, 33, 34, true, NULL, 0}, - {kSubtitleTextTrackNum, 33, 42, false, NULL, 0}, - {kAudioTrackNum, 46, 23, true, NULL, 0}, - {kCaptionTextTrackNum, 55, 44, false, NULL, 0}, - {kVideoTrackNum, 67, 34, true, NULL, 0}, - {kSubtitleTextTrackNum, 67, 33, false, NULL, 0}, + {kAudioTrackNum, 0, 23, true, NULL, 0, false}, + {kAudioTrackNum, 23, 23, true, NULL, 0, false}, + {kVideoTrackNum, 33, 34, true, NULL, 0, false}, + {kSubtitleTextTrackNum, 33, 42, false, NULL, 0, false}, + {kAudioTrackNum, 46, 23, true, NULL, 0, false}, + {kCaptionTextTrackNum, 55, 44, false, NULL, 0, false}, + {kVideoTrackNum, 67, 34, true, NULL, 0, false}, + {kSubtitleTextTrackNum, 67, 33, false, NULL, 0, false}, }; int input_block_count = arraysize(kInputBlockInfo); @@ -907,7 +913,7 @@ TEST_F(WebMClusterParserTest, ParseInvalidTextBlockGroupWithoutDuration) { kNoTimestamp, kNoTimestamp, text_tracks)); const BlockInfo kBlockInfo[] = { - { kTextTrackNum, 33, -42, false }, + {kTextTrackNum, 33, -42, false, NULL, 0, false}, }; int block_count = arraysize(kBlockInfo); scoped_ptr cluster(CreateCluster(0, kBlockInfo, block_count)); @@ -924,13 +930,15 @@ TEST_F(WebMClusterParserTest, ParseWithDefaultDurationsSimpleBlocks) { const BlockInfo kBlockInfo[] = { // Note that for simple blocks, duration is not encoded. - {kAudioTrackNum, 0, 23, true, NULL, 0}, - {kAudioTrackNum, 23, 23, true, NULL, 0}, - {kVideoTrackNum, 33, 34, true, NULL, 0}, - {kAudioTrackNum, 46, 23, true, NULL, 0}, - {kVideoTrackNum, 67, 33, true, NULL, 0}, - {kAudioTrackNum, 69, kTestAudioFrameDefaultDurationInMs, true, NULL, 0}, - {kVideoTrackNum, 100, kTestVideoFrameDefaultDurationInMs, true, NULL, 0}, + {kAudioTrackNum, 0, 23, true, NULL, 0, false}, + {kAudioTrackNum, 23, 23, true, NULL, 0, false}, + {kVideoTrackNum, 33, 34, true, NULL, 0, false}, + {kAudioTrackNum, 46, 23, true, NULL, 0, false}, + {kVideoTrackNum, 67, 33, true, NULL, 0, false}, + {kAudioTrackNum, 69, kTestAudioFrameDefaultDurationInMs, true, NULL, 0, + false}, + {kVideoTrackNum, 100, kTestVideoFrameDefaultDurationInMs, true, NULL, 0, + false}, }; int block_count = arraysize(kBlockInfo); @@ -958,13 +966,13 @@ TEST_F(WebMClusterParserTest, ParseWithoutAnyDurationsSimpleBlocks) { // Flush() is called. We use the maximum seen so far for estimation. const BlockInfo kBlockInfo1[] = { - {kAudioTrackNum, 0, 23, true, NULL, 0}, - {kAudioTrackNum, 23, 22, true, NULL, 0}, - {kVideoTrackNum, 33, 33, true, NULL, 0}, - {kAudioTrackNum, 45, 23, true, NULL, 0}, - {kVideoTrackNum, 66, 34, true, NULL, 0}, - {kAudioTrackNum, 68, 24, true, NULL, 0}, - {kVideoTrackNum, 100, 35, true, NULL, 0}, + {kAudioTrackNum, 0, 23, true, NULL, 0, false}, + {kAudioTrackNum, 23, 22, true, NULL, 0, false}, + {kVideoTrackNum, 33, 33, true, NULL, 0, false}, + {kAudioTrackNum, 45, 23, true, NULL, 0, false}, + {kVideoTrackNum, 66, 34, true, NULL, 0, false}, + {kAudioTrackNum, 68, 24, true, NULL, 0, false}, + {kVideoTrackNum, 100, 35, true, NULL, 0, false}, }; int block_count1 = arraysize(kBlockInfo1); @@ -984,8 +992,8 @@ TEST_F(WebMClusterParserTest, ParseWithoutAnyDurationsSimpleBlocks) { const int kExpectedAudioEstimationInMs = 24; const int kExpectedVideoEstimationInMs = 35; const BlockInfo kBlockInfo2[] = { - {kAudioTrackNum, 92, kExpectedAudioEstimationInMs, true, NULL, 0}, - {kVideoTrackNum, 135, kExpectedVideoEstimationInMs, true, NULL, 0}, + {kAudioTrackNum, 92, kExpectedAudioEstimationInMs, true, NULL, 0, false}, + {kVideoTrackNum, 135, kExpectedVideoEstimationInMs, true, NULL, 0, false}, }; int block_count2 = arraysize(kBlockInfo2); @@ -1010,13 +1018,13 @@ TEST_F(WebMClusterParserTest, ParseWithoutAnyDurationsBlockGroups) { // for each track when Flush() is called. We use the maximum seen so far. const BlockInfo kBlockInfo1[] = { - {kAudioTrackNum, 0, -23, false, NULL, 0}, - {kAudioTrackNum, 23, -22, false, NULL, 0}, - {kVideoTrackNum, 33, -33, false, NULL, 0}, - {kAudioTrackNum, 45, -23, false, NULL, 0}, - {kVideoTrackNum, 66, -34, false, NULL, 0}, - {kAudioTrackNum, 68, -24, false, NULL, 0}, - {kVideoTrackNum, 100, -35, false, NULL, 0}, + {kAudioTrackNum, 0, -23, false, NULL, 0, false}, + {kAudioTrackNum, 23, -22, false, NULL, 0, false}, + {kVideoTrackNum, 33, -33, false, NULL, 0, false}, + {kAudioTrackNum, 45, -23, false, NULL, 0, false}, + {kVideoTrackNum, 66, -34, false, NULL, 0, false}, + {kAudioTrackNum, 68, -24, false, NULL, 0, false}, + {kVideoTrackNum, 100, -35, false, NULL, 0, false}, }; int block_count1 = arraysize(kBlockInfo1); @@ -1036,8 +1044,10 @@ TEST_F(WebMClusterParserTest, ParseWithoutAnyDurationsBlockGroups) { const int kExpectedAudioEstimationInMs = 24; const int kExpectedVideoEstimationInMs = 35; const BlockInfo kBlockInfo2[] = { - {kAudioTrackNum, 92, -kExpectedAudioEstimationInMs, false, NULL, 0}, - {kVideoTrackNum, 135, -kExpectedVideoEstimationInMs, false, NULL, 0}, + {kAudioTrackNum, 92, -kExpectedAudioEstimationInMs, false, NULL, 0, + false}, + {kVideoTrackNum, 135, -kExpectedVideoEstimationInMs, false, NULL, 0, + false}, }; int block_count2 = arraysize(kBlockInfo2); @@ -1056,17 +1066,10 @@ TEST_F(WebMClusterParserTest, ParseWithoutAnyDurationsBlockGroups) { TEST_F(WebMClusterParserTest, ParseDegenerateClusterYieldsHardcodedEstimatedDurations) { const BlockInfo kBlockInfo[] = { - { - kAudioTrackNum, - 0, - WebMClusterParser::kDefaultAudioBufferDurationInMs, - true - }, { - kVideoTrackNum, - 0, - WebMClusterParser::kDefaultVideoBufferDurationInMs, - true - }, + {kAudioTrackNum, 0, WebMClusterParser::kDefaultAudioBufferDurationInMs, + true, NULL, 0, false}, + {kVideoTrackNum, 0, WebMClusterParser::kDefaultVideoBufferDurationInMs, + true, NULL, 0, false}, }; int block_count = arraysize(kBlockInfo); @@ -1082,8 +1085,10 @@ TEST_F(WebMClusterParserTest, ResetParserToHaveDefaultDurations(); const BlockInfo kBlockInfo[] = { - { kAudioTrackNum, 0, kTestAudioFrameDefaultDurationInMs, true }, - { kVideoTrackNum, 0, kTestVideoFrameDefaultDurationInMs, true }, + {kAudioTrackNum, 0, kTestAudioFrameDefaultDurationInMs, true, NULL, 0, + false}, + {kVideoTrackNum, 0, kTestVideoFrameDefaultDurationInMs, true, NULL, 0, + false}, }; int block_count = arraysize(kBlockInfo); diff --git a/packager/media/test/data/bear-vp9-blockgroup.webm b/packager/media/test/data/bear-vp9-blockgroup.webm new file mode 100644 index 0000000000..ecffa7d76e Binary files /dev/null and b/packager/media/test/data/bear-vp9-blockgroup.webm differ