diff options
24 files changed, 202 insertions, 49 deletions
diff --git a/media/base/audio_decoder_config.cc b/media/base/audio_decoder_config.cc index 38db05d..dfaf94a 100644 --- a/media/base/audio_decoder_config.cc +++ b/media/base/audio_decoder_config.cc @@ -6,6 +6,7 @@ #include "base/logging.h" #include "base/metrics/histogram.h" +#include "base/time/time.h" #include "media/audio/sample_rates.h" #include "media/base/limits.h" #include "media/base/sample_format.h" @@ -30,7 +31,8 @@ AudioDecoderConfig::AudioDecoderConfig(AudioCodec codec, size_t extra_data_size, bool is_encrypted) { Initialize(codec, sample_format, channel_layout, samples_per_second, - extra_data, extra_data_size, is_encrypted, true); + extra_data, extra_data_size, is_encrypted, true, + base::TimeDelta(), base::TimeDelta()); } void AudioDecoderConfig::Initialize(AudioCodec codec, @@ -40,7 +42,9 @@ void AudioDecoderConfig::Initialize(AudioCodec codec, const uint8* extra_data, size_t extra_data_size, bool is_encrypted, - bool record_stats) { + bool record_stats, + base::TimeDelta seek_preroll, + base::TimeDelta codec_delay) { CHECK((extra_data_size != 0) == (extra_data != NULL)); if (record_stats) { @@ -66,6 +70,8 @@ void AudioDecoderConfig::Initialize(AudioCodec codec, bytes_per_channel_ = SampleFormatToBytesPerChannel(sample_format); extra_data_.assign(extra_data, extra_data + extra_data_size); is_encrypted_ = is_encrypted; + seek_preroll_ = seek_preroll; + codec_delay_ = codec_delay; int channels = ChannelLayoutToChannelCount(channel_layout_); bytes_per_frame_ = channels * bytes_per_channel_; @@ -80,7 +86,9 @@ bool AudioDecoderConfig::IsValidConfig() const { bytes_per_channel_ <= limits::kMaxBytesPerSample && samples_per_second_ > 0 && samples_per_second_ <= limits::kMaxSampleRate && - sample_format_ != kUnknownSampleFormat; + sample_format_ != kUnknownSampleFormat && + seek_preroll_ >= base::TimeDelta() && + codec_delay_ >= base::TimeDelta(); } bool AudioDecoderConfig::Matches(const AudioDecoderConfig& config) const { @@ -92,7 +100,9 @@ bool AudioDecoderConfig::Matches(const AudioDecoderConfig& config) const { (!extra_data() || !memcmp(extra_data(), config.extra_data(), extra_data_size())) && (is_encrypted() == config.is_encrypted()) && - (sample_format() == config.sample_format())); + (sample_format() == config.sample_format()) && + (seek_preroll() == config.seek_preroll()) && + (codec_delay() == config.codec_delay())); } } // namespace media diff --git a/media/base/audio_decoder_config.h b/media/base/audio_decoder_config.h index 1c61e70..a17d221 100644 --- a/media/base/audio_decoder_config.h +++ b/media/base/audio_decoder_config.h @@ -8,6 +8,7 @@ #include <vector> #include "base/basictypes.h" +#include "base/time/time.h" #include "media/base/channel_layout.h" #include "media/base/media_export.h" #include "media/base/sample_format.h" @@ -63,7 +64,9 @@ class MEDIA_EXPORT AudioDecoderConfig { void Initialize(AudioCodec codec, SampleFormat sample_format, ChannelLayout channel_layout, int samples_per_second, const uint8* extra_data, size_t extra_data_size, - bool is_encrypted, bool record_stats); + bool is_encrypted, bool record_stats, + base::TimeDelta seek_preroll, + base::TimeDelta codec_delay); // Returns true if this object has appropriate configuration values, false // otherwise. @@ -80,6 +83,8 @@ class MEDIA_EXPORT AudioDecoderConfig { int samples_per_second() const { return samples_per_second_; } SampleFormat sample_format() const { return sample_format_; } int bytes_per_frame() const { return bytes_per_frame_; } + base::TimeDelta seek_preroll() const { return seek_preroll_; } + base::TimeDelta codec_delay() const { return codec_delay_; } // Optional byte data required to initialize audio decoders such as Vorbis // codebooks. @@ -103,6 +108,15 @@ class MEDIA_EXPORT AudioDecoderConfig { std::vector<uint8> extra_data_; bool is_encrypted_; + // |seek_preroll_| is the duration of the data that the decoder must decode + // before the decoded data is valid. + base::TimeDelta seek_preroll_; + + // |codec_delay_| is the overall delay overhead added by the codec while + // encoding. This value should be subtracted from each block's timestamp to + // get the actual timestamp. + base::TimeDelta codec_delay_; + // Not using DISALLOW_COPY_AND_ASSIGN here intentionally to allow the compiler // generated copy constructor and assignment operator. Since the extra data is // typically small, the performance impact is minimal. diff --git a/media/base/decoder_buffer.cc b/media/base/decoder_buffer.cc index 9eaa128..d4e7541 100644 --- a/media/base/decoder_buffer.cc +++ b/media/base/decoder_buffer.cc @@ -80,7 +80,8 @@ std::string DecoderBuffer::AsHumanReadableString() { << " duration: " << duration_.InMicroseconds() << " size: " << size_ << " side_data_size: " << side_data_size_ - << " encrypted: " << (decrypt_config_ != NULL); + << " encrypted: " << (decrypt_config_ != NULL) + << " discard_padding (ms): " << discard_padding_.InMilliseconds(); return s.str(); } diff --git a/media/base/decoder_buffer.h b/media/base/decoder_buffer.h index 6cf519f..393e586 100644 --- a/media/base/decoder_buffer.h +++ b/media/base/decoder_buffer.h @@ -105,6 +105,16 @@ class MEDIA_EXPORT DecoderBuffer return side_data_size_; } + base::TimeDelta discard_padding() const { + DCHECK(!end_of_stream()); + return discard_padding_; + } + + void set_discard_padding(const base::TimeDelta discard_padding) { + DCHECK(!end_of_stream()); + discard_padding_ = discard_padding; + } + const DecryptConfig* decrypt_config() const { DCHECK(!end_of_stream()); return decrypt_config_.get(); @@ -142,6 +152,7 @@ class MEDIA_EXPORT DecoderBuffer int side_data_size_; scoped_ptr<uint8, base::ScopedPtrAlignedFree> side_data_; scoped_ptr<DecryptConfig> decrypt_config_; + base::TimeDelta discard_padding_; // Constructor helper method for memory allocations. void Initialize(); diff --git a/media/base/run_all_unittests.cc b/media/base/run_all_unittests.cc index c63f1dc..1c4da93 100644 --- a/media/base/run_all_unittests.cc +++ b/media/base/run_all_unittests.cc @@ -41,6 +41,10 @@ void TestSuiteNoAtExit::Initialize() { media::InitializeMediaLibraryForTesting(); CommandLine* cmd_line = CommandLine::ForCurrentProcess(); cmd_line->AppendSwitch(switches::kEnableMP3StreamParser); + + // Enable Opus support for all media tests. + // TODO(vigneshv): Remove this once the Opus flag is removed or negated. + cmd_line->AppendSwitch(switches::kEnableOpusPlayback); } int main(int argc, char** argv) { diff --git a/media/ffmpeg/ffmpeg_common.cc b/media/ffmpeg/ffmpeg_common.cc index 9693bbb..72b3125 100644 --- a/media/ffmpeg/ffmpeg_common.cc +++ b/media/ffmpeg/ffmpeg_common.cc @@ -291,7 +291,9 @@ static void AVCodecContextToAudioDecoderConfig( codec_context->extradata, codec_context->extradata_size, is_encrypted, - record_stats); + record_stats, + base::TimeDelta(), + base::TimeDelta()); if (codec != kCodecOpus) { DCHECK_EQ(av_get_bytes_per_sample(codec_context->sample_fmt) * 8, config->bits_per_channel()); diff --git a/media/filters/decrypting_audio_decoder.cc b/media/filters/decrypting_audio_decoder.cc index f516674..2c144b4 100644 --- a/media/filters/decrypting_audio_decoder.cc +++ b/media/filters/decrypting_audio_decoder.cc @@ -191,7 +191,9 @@ void DecryptingAudioDecoder::SetDecryptor(Decryptor* decryptor) { input_config.extra_data(), input_config.extra_data_size(), input_config.is_encrypted(), - false); + false, + base::TimeDelta(), + base::TimeDelta()); state_ = kPendingDecoderInit; decryptor_->InitializeAudioDecoder( @@ -282,7 +284,9 @@ void DecryptingAudioDecoder::DecryptAndDecodeBuffer( input_config.extra_data(), input_config.extra_data_size(), input_config.is_encrypted(), - false); + false, + base::TimeDelta(), + base::TimeDelta()); state_ = kPendingConfigChange; decryptor_->DeinitializeDecoder(Decryptor::kAudio); diff --git a/media/filters/decrypting_audio_decoder_unittest.cc b/media/filters/decrypting_audio_decoder_unittest.cc index fb97b91..2f07e23 100644 --- a/media/filters/decrypting_audio_decoder_unittest.cc +++ b/media/filters/decrypting_audio_decoder_unittest.cc @@ -113,7 +113,8 @@ class DecryptingAudioDecoderTest : public testing::Test { .WillOnce(SaveArg<1>(&key_added_cb_)); config_.Initialize(kCodecVorbis, kSampleFormatPlanarF32, - CHANNEL_LAYOUT_STEREO, 44100, NULL, 0, true, true); + CHANNEL_LAYOUT_STEREO, 44100, NULL, 0, true, true, + base::TimeDelta(), base::TimeDelta()); InitializeAndExpectStatus(config_, PIPELINE_OK); EXPECT_EQ(DecryptingAudioDecoder::kSupportedBitsPerChannel, diff --git a/media/filters/decrypting_demuxer_stream.cc b/media/filters/decrypting_demuxer_stream.cc index 1f183ce..39386e0 100644 --- a/media/filters/decrypting_demuxer_stream.cc +++ b/media/filters/decrypting_demuxer_stream.cc @@ -302,7 +302,9 @@ void DecryptingDemuxerStream::InitializeDecoderConfig() { input_audio_config.extra_data(), input_audio_config.extra_data_size(), false, // Output audio is not encrypted. - false); + false, + base::TimeDelta(), + base::TimeDelta()); break; } diff --git a/media/filters/opus_audio_decoder.cc b/media/filters/opus_audio_decoder.cc index 115799a..b3e903b 100644 --- a/media/filters/opus_audio_decoder.cc +++ b/media/filters/opus_audio_decoder.cc @@ -4,6 +4,8 @@ #include "media/filters/opus_audio_decoder.h" +#include <cmath> + #include "base/bind.h" #include "base/callback_helpers.h" #include "base/location.h" @@ -250,7 +252,6 @@ OpusAudioDecoder::OpusAudioDecoder( channel_layout_(CHANNEL_LAYOUT_NONE), samples_per_second_(0), last_input_timestamp_(kNoTimestamp()), - output_bytes_to_drop_(0), skip_samples_(0) { } @@ -457,10 +458,24 @@ bool OpusAudioDecoder::ConfigureDecoder() { config, &opus_header); - skip_samples_ = opus_header.skip_samples; - - if (skip_samples_ > 0) - output_bytes_to_drop_ = skip_samples_ * config.bytes_per_frame(); + if (!config.codec_delay().InMicroseconds()) { + // TODO(vigneshv): Replace this with return false once ffmpeg demuxer code + // starts populating the config correctly. + skip_samples_ = opus_header.skip_samples; + } else { + // Convert from seconds to samples. + skip_samples_ = std::ceil(config.codec_delay().InMicroseconds() * + config.samples_per_second() / 1000000.0); + if (skip_samples_ < 0) { + DVLOG(1) << "Invalid file. Incorrect value for codec delay."; + return false; + } + if (skip_samples_ != opus_header.skip_samples) { + DVLOG(1) << "Invalid file. Codec Delay in container does not match the " + << "value in Opus header."; + return false; + } + } uint8 channel_mapping[kMaxVorbisChannels]; memcpy(&channel_mapping, @@ -487,9 +502,6 @@ bool OpusAudioDecoder::ConfigureDecoder() { return false; } - // TODO(tomfinegan): Handle audio delay once the matroska spec is updated - // to represent the value. - bits_per_channel_ = config.bits_per_channel(); channel_layout_ = config.channel_layout(); samples_per_second_ = config.samples_per_second(); @@ -508,7 +520,7 @@ void OpusAudioDecoder::CloseDecoder() { void OpusAudioDecoder::ResetTimestampState() { output_timestamp_helper_->SetBaseTimestamp(kNoTimestamp()); last_input_timestamp_ = kNoTimestamp(); - output_bytes_to_drop_ = 0; + skip_samples_ = 0; } bool OpusAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& input, @@ -539,16 +551,6 @@ bool OpusAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& input, output_timestamp_helper_->SetBaseTimestamp(input->timestamp()); } - if (decoded_audio_size > 0 && output_bytes_to_drop_ > 0) { - int dropped_size = std::min(decoded_audio_size, output_bytes_to_drop_); - DCHECK_EQ(dropped_size % kBytesPerChannel, 0); - decoded_audio_data += dropped_size; - decoded_audio_size -= dropped_size; - output_bytes_to_drop_ -= dropped_size; - samples_decoded = decoded_audio_size / - demuxer_stream_->audio_decoder_config().bytes_per_frame(); - } - if (decoded_audio_size > 0) { // Copy the audio samples into an output buffer. uint8* data[] = { decoded_audio_data }; @@ -560,8 +562,28 @@ bool OpusAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& input, output_timestamp_helper_->GetTimestamp(), output_timestamp_helper_->GetFrameDuration(samples_decoded)); output_timestamp_helper_->AddFrames(samples_decoded); + if (skip_samples_ > 0) { + int dropped_size = std::min(samples_decoded, skip_samples_); + output_buffer->get()->TrimStart(dropped_size); + skip_samples_ -= dropped_size; + samples_decoded -= dropped_size; + } + if (input->discard_padding().InMicroseconds() > 0) { + int discard_padding = std::ceil( + input->discard_padding().InMicroseconds() * + samples_per_second_ / 1000000.0); + if (discard_padding < 0 || discard_padding > samples_decoded) { + DVLOG(1) << "Invalid file. Incorrect discard padding value."; + return false; + } + output_buffer->get()->TrimEnd(std::min(samples_decoded, discard_padding)); + samples_decoded -= discard_padding; + } } + decoded_audio_size = + samples_decoded * + demuxer_stream_->audio_decoder_config().bytes_per_frame(); // Decoding finished successfully, update statistics. PipelineStatistics statistics; statistics.audio_bytes_decoded = decoded_audio_size; diff --git a/media/filters/opus_audio_decoder.h b/media/filters/opus_audio_decoder.h index a808ff3..77e8434 100644 --- a/media/filters/opus_audio_decoder.h +++ b/media/filters/opus_audio_decoder.h @@ -70,10 +70,6 @@ class MEDIA_EXPORT OpusAudioDecoder : public AudioDecoder { scoped_ptr<AudioTimestampHelper> output_timestamp_helper_; base::TimeDelta last_input_timestamp_; - // Number of output sample bytes to drop before generating - // output buffers. - int output_bytes_to_drop_; - ReadCB read_cb_; int skip_samples_; diff --git a/media/filters/pipeline_integration_test.cc b/media/filters/pipeline_integration_test.cc index a767b7f..0ce2fd1 100644 --- a/media/filters/pipeline_integration_test.cc +++ b/media/filters/pipeline_integration_test.cc @@ -28,6 +28,7 @@ static const uint8 kInitData[] = { 0x69, 0x6e, 0x69, 0x74 }; static const char kWebM[] = "video/webm; codecs=\"vp8,vorbis\""; static const char kWebMVP9[] = "video/webm; codecs=\"vp9\""; static const char kAudioOnlyWebM[] = "video/webm; codecs=\"vorbis\""; +static const char kOpusAudioOnlyWebM[] = "video/webm; codecs=\"opus\""; static const char kVideoOnlyWebM[] = "video/webm; codecs=\"vp8\""; static const char kMP4[] = "video/mp4; codecs=\"avc1.4D4041,mp4a.40.2\""; static const char kMP4Video[] = "video/mp4; codecs=\"avc1.4D4041\""; @@ -58,6 +59,8 @@ static const int k640WebMFileDurationMs = 2763; static const int k640IsoFileDurationMs = 2737; static const int k640IsoCencFileDurationMs = 2736; static const int k1280IsoFileDurationMs = 2736; +static const int kOpusEndTrimmingWebMFileDurationMs = 2771; +static const uint32 kOpusEndTrimmingWebMFileAudioBytes = 528676; static const int kVP9WebMFileDurationMs = 2735; static const int kVP8AWebMFileDurationMs = 2700; @@ -534,6 +537,26 @@ TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource_VP8A_WebM) { Stop(); } +TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource_Opus_WebM) { + EXPECT_CALL(*this, OnSetOpaque(false)).Times(AnyNumber()); + MockMediaSource source("bear-opus-end-trimming.webm", kOpusAudioOnlyWebM, + kAppendWholeFile); + StartPipelineWithMediaSource(&source); + source.EndOfStream(); + + EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size()); + EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds()); + EXPECT_EQ(kOpusEndTrimmingWebMFileDurationMs, + pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds()); + Play(); + + ASSERT_TRUE(WaitUntilOnEnded()); + EXPECT_EQ(kOpusEndTrimmingWebMFileAudioBytes, + pipeline_->GetStatistics().audio_bytes_decoded); + source.Abort(); + Stop(); +} + TEST_F(PipelineIntegrationTest, MediaSource_ConfigChange_WebM) { MockMediaSource source("bear-320x240-16x9-aspect.webm", kWebM, kAppendWholeFile); diff --git a/media/filters/stream_parser_factory.cc b/media/filters/stream_parser_factory.cc index 2b2ec9cb..4d2e524 100644 --- a/media/filters/stream_parser_factory.cc +++ b/media/filters/stream_parser_factory.cc @@ -41,6 +41,7 @@ struct CodecInfo { HISTOGRAM_MPEG4AAC, HISTOGRAM_EAC3, HISTOGRAM_MP3, + HISTOGRAM_OPUS, HISTOGRAM_MAX // Must be the last entry. }; @@ -66,6 +67,8 @@ static const CodecInfo kVP9CodecInfo = { "vp9", CodecInfo::VIDEO, NULL, CodecInfo::HISTOGRAM_VP9 }; static const CodecInfo kVorbisCodecInfo = { "vorbis", CodecInfo::AUDIO, NULL, CodecInfo::HISTOGRAM_VORBIS }; +static const CodecInfo kOpusCodecInfo = { "opus", CodecInfo::AUDIO, NULL, + CodecInfo::HISTOGRAM_OPUS }; static const CodecInfo* kVideoWebMCodecs[] = { &kVP8CodecInfo, @@ -75,11 +78,13 @@ static const CodecInfo* kVideoWebMCodecs[] = { &kVP9CodecInfo, #endif &kVorbisCodecInfo, + &kOpusCodecInfo, NULL }; static const CodecInfo* kAudioWebMCodecs[] = { &kVorbisCodecInfo, + &kOpusCodecInfo, NULL }; @@ -233,7 +238,11 @@ static bool VerifyCodec( return false; } #endif - + if (codec_info->tag == CodecInfo::HISTOGRAM_OPUS) { + const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); + if (!cmd_line->HasSwitch(switches::kEnableOpusPlayback)) + return false; + } if (audio_codecs) audio_codecs->push_back(codec_info->tag); return true; diff --git a/media/mp3/mp3_stream_parser.cc b/media/mp3/mp3_stream_parser.cc index 86348ff..319c868 100644 --- a/media/mp3/mp3_stream_parser.cc +++ b/media/mp3/mp3_stream_parser.cc @@ -378,7 +378,8 @@ int MP3StreamParser::ParseMP3Frame(const uint8* data, int size) { if (!config_.IsValidConfig()) { config_.Initialize(kCodecMP3, kSampleFormatF32, channel_layout, - sample_rate, NULL, 0, false, false); + sample_rate, NULL, 0, false, false, + base::TimeDelta(), base::TimeDelta()); base::TimeDelta base_timestamp; if (timestamp_helper_) diff --git a/media/mp4/mp4_stream_parser.cc b/media/mp4/mp4_stream_parser.cc index 51ed756..26cee44 100644 --- a/media/mp4/mp4_stream_parser.cc +++ b/media/mp4/mp4_stream_parser.cc @@ -257,7 +257,8 @@ bool MP4StreamParser::ParseMoov(BoxReader* reader) { audio_config.Initialize( codec, sample_format, channel_layout, sample_per_second, extra_data.size() ? &extra_data[0] : NULL, extra_data.size(), - is_audio_track_encrypted_, false); + is_audio_track_encrypted_, false, base::TimeDelta(), + base::TimeDelta()); has_audio_ = true; audio_track_id_ = track->header.track_id; } diff --git a/media/webm/webm_audio_client.cc b/media/webm/webm_audio_client.cc index e52f44b..1ef640c 100644 --- a/media/webm/webm_audio_client.cc +++ b/media/webm/webm_audio_client.cc @@ -26,12 +26,15 @@ void WebMAudioClient::Reset() { bool WebMAudioClient::InitializeConfig( const std::string& codec_id, const std::vector<uint8>& codec_private, - bool is_encrypted, AudioDecoderConfig* config) { + int64 seek_preroll, int64 codec_delay, bool is_encrypted, + AudioDecoderConfig* config) { DCHECK(config); AudioCodec audio_codec = kUnknownAudioCodec; if (codec_id == "A_VORBIS") { audio_codec = kCodecVorbis; + } else if (codec_id == "A_OPUS") { + audio_codec = kCodecOpus; } else { MEDIA_LOG(log_cb_) << "Unsupported audio codec_id " << codec_id; return false; @@ -63,8 +66,14 @@ bool WebMAudioClient::InitializeConfig( } config->Initialize( - audio_codec, kSampleFormatPlanarF32, channel_layout, - samples_per_second, extra_data, extra_data_size, is_encrypted, true); + audio_codec, + (audio_codec == kCodecOpus) ? kSampleFormatS16 : kSampleFormatPlanarF32, + channel_layout, + samples_per_second, extra_data, extra_data_size, is_encrypted, true, + base::TimeDelta::FromMicroseconds( + (seek_preroll != -1 ? seek_preroll : 0) / 1000), + base::TimeDelta::FromMicroseconds( + (codec_delay != -1 ? codec_delay : 0) / 1000)); return config->IsValidConfig(); } diff --git a/media/webm/webm_audio_client.h b/media/webm/webm_audio_client.h index 1338f5c..7874cec 100644 --- a/media/webm/webm_audio_client.h +++ b/media/webm/webm_audio_client.h @@ -31,6 +31,8 @@ class WebMAudioClient : public WebMParserClient { // audio track element fields. bool InitializeConfig(const std::string& codec_id, const std::vector<uint8>& codec_private, + const int64 seek_preroll, + const int64 codec_delay, bool is_encrypted, AudioDecoderConfig* config); diff --git a/media/webm/webm_cluster_parser.cc b/media/webm/webm_cluster_parser.cc index 9991d6b..87cccae 100644 --- a/media/webm/webm_cluster_parser.cc +++ b/media/webm/webm_cluster_parser.cc @@ -64,6 +64,7 @@ WebMClusterParser::WebMClusterParser( block_duration_(-1), block_add_id_(-1), block_additional_data_size_(-1), + discard_padding_(-1), cluster_timecode_(-1), cluster_start_time_(kNoTimestamp()), cluster_ended_(false), @@ -137,6 +138,8 @@ WebMParserClient* WebMClusterParser::OnListStart(int id) { block_data_.reset(); block_data_size_ = -1; block_duration_ = -1; + discard_padding_ = -1; + discard_padding_set_ = false; } else if (id == kWebMIdBlockAdditions) { block_add_id_ = -1; block_additional_data_.reset(); @@ -158,13 +161,16 @@ bool WebMClusterParser::OnListEnd(int id) { bool result = ParseBlock(false, block_data_.get(), block_data_size_, block_additional_data_.get(), - block_additional_data_size_, block_duration_); + block_additional_data_size_, block_duration_, + discard_padding_set_ ? discard_padding_ : 0); block_data_.reset(); block_data_size_ = -1; block_duration_ = -1; block_add_id_ = -1; block_additional_data_.reset(); block_additional_data_size_ = -1; + discard_padding_ = -1; + discard_padding_set_ = false; return result; } @@ -180,6 +186,12 @@ bool WebMClusterParser::OnUInt(int id, int64 val) { case kWebMIdBlockAddID: dst = &block_add_id_; break; + case kWebMIdDiscardPadding: + if (discard_padding_set_) + return false; + discard_padding_set_ = true; + discard_padding_ = val; + return true; default: return true; } @@ -191,7 +203,8 @@ bool WebMClusterParser::OnUInt(int id, int64 val) { bool WebMClusterParser::ParseBlock(bool is_simple_block, const uint8* buf, int size, const uint8* additional, - int additional_size, int duration) { + int additional_size, int duration, + int64 discard_padding) { if (size < 4) return false; @@ -219,13 +232,14 @@ bool WebMClusterParser::ParseBlock(bool is_simple_block, const uint8* buf, const uint8* 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); + frame_data, frame_size, additional, additional_size, + discard_padding); } bool WebMClusterParser::OnBinary(int id, const uint8* data, int size) { switch (id) { case kWebMIdSimpleBlock: - return ParseBlock(true, data, size, NULL, -1, -1); + return ParseBlock(true, data, size, NULL, -1, -1, 0); case kWebMIdBlock: if (block_data_) { @@ -270,7 +284,8 @@ bool WebMClusterParser::OnBlock(bool is_simple_block, int track_num, int block_duration, int flags, const uint8* data, int size, - const uint8* additional, int additional_size) { + const uint8* additional, int additional_size, + int64 discard_padding) { DCHECK_GE(size, 0); if (cluster_timecode_ == -1) { MEDIA_LOG(log_cb_) << "Got a block before cluster timecode."; @@ -350,6 +365,11 @@ bool WebMClusterParser::OnBlock(bool is_simple_block, int track_num, block_duration * timecode_multiplier_)); } + if (discard_padding != 0) { + buffer->set_discard_padding(base::TimeDelta::FromMicroseconds( + discard_padding / 1000)); + } + return track->AddBuffer(buffer); } diff --git a/media/webm/webm_cluster_parser.h b/media/webm/webm_cluster_parser.h index e156d47..5aa957c 100644 --- a/media/webm/webm_cluster_parser.h +++ b/media/webm/webm_cluster_parser.h @@ -110,10 +110,12 @@ class MEDIA_EXPORT WebMClusterParser : public WebMParserClient { virtual bool OnBinary(int id, const uint8* data, int size) OVERRIDE; bool ParseBlock(bool is_simple_block, const uint8* buf, int size, - const uint8* additional, int additional_size, int duration); + const uint8* additional, int additional_size, int duration, + int64 discard_padding); bool OnBlock(bool is_simple_block, int track_num, int timecode, int duration, int flags, const uint8* data, int size, - const uint8* additional, int additional_size); + const uint8* additional, int additional_size, + int64 discard_padding); // Resets the Track objects associated with each text track. void ResetTextTracks(); @@ -137,6 +139,8 @@ class MEDIA_EXPORT WebMClusterParser : public WebMParserClient { int64 block_add_id_; scoped_ptr<uint8[]> block_additional_data_; int block_additional_data_size_; + int64 discard_padding_; + bool discard_padding_set_; int64 cluster_timecode_; base::TimeDelta cluster_start_time_; diff --git a/media/webm/webm_constants.h b/media/webm/webm_constants.h index cda45e0..8764eeb 100644 --- a/media/webm/webm_constants.h +++ b/media/webm/webm_constants.h @@ -57,6 +57,7 @@ const int kWebMIdChapterTranslateID = 0x69A5; const int kWebMIdChapterUID = 0x73C4; const int kWebMIdCluster = 0x1F43B675; const int kWebMIdCodecDecodeAll = 0xAA; +const int kWebMIdCodecDelay = 0x56AA; const int kWebMIdCodecID = 0x86; const int kWebMIdCodecName = 0x258688; const int kWebMIdCodecPrivate = 0x63A2; @@ -91,6 +92,7 @@ const int kWebMIdCueTrack = 0xF7; const int kWebMIdCueTrackPositions = 0xB7; const int kWebMIdDateUTC = 0x4461; const int kWebMIdDefaultDuration = 0x23E383; +const int kWebMIdDiscardPadding = 0x75A2; const int kWebMIdDisplayHeight = 0x54BA; const int kWebMIdDisplayUnit = 0x54B2; const int kWebMIdDisplayWidth = 0x54B0; @@ -147,6 +149,7 @@ const int kWebMIdSeek = 0x4DBB; const int kWebMIdSeekHead = 0x114D9B74; const int kWebMIdSeekID = 0x53AB; const int kWebMIdSeekPosition = 0x53AC; +const int kWebMIdSeekPreRoll = 0x56BB; const int kWebMIdSegment = 0x18538067; const int kWebMIdSegmentFamily = 0x4444; const int kWebMIdSegmentFilename = 0x7384; diff --git a/media/webm/webm_parser.cc b/media/webm/webm_parser.cc index 30e5c1b5..ab41e2a 100644 --- a/media/webm/webm_parser.cc +++ b/media/webm/webm_parser.cc @@ -118,6 +118,7 @@ static const ElementIdInfo kBlockGroupIds[] = { {UINT, kWebMIdReferencePriority}, {BINARY, kWebMIdReferenceBlock}, {BINARY, kWebMIdCodecState}, + {UINT, kWebMIdDiscardPadding}, {LIST, kWebMIdSlices}, }; @@ -163,6 +164,8 @@ static const ElementIdInfo kTrackEntryIds[] = { {UINT, kWebMIdAttachmentLink}, {UINT, kWebMIdCodecDecodeAll}, {UINT, kWebMIdTrackOverlay}, + {UINT, kWebMIdCodecDelay}, + {UINT, kWebMIdSeekPreRoll}, {LIST, kWebMIdTrackTranslate}, {LIST, kWebMIdVideo}, {LIST, kWebMIdAudio}, diff --git a/media/webm/webm_tracks_parser.cc b/media/webm/webm_tracks_parser.cc index 67bac04..aa28d6f 100644 --- a/media/webm/webm_tracks_parser.cc +++ b/media/webm/webm_tracks_parser.cc @@ -31,6 +31,8 @@ static TextKind CodecIdToTextKind(const std::string& codec_id) { WebMTracksParser::WebMTracksParser(const LogCB& log_cb, bool ignore_text_tracks) : track_type_(-1), track_num_(-1), + seek_preroll_(-1), + codec_delay_(-1), audio_track_num_(-1), video_track_num_(-1), ignore_text_tracks_(ignore_text_tracks), @@ -161,8 +163,8 @@ bool WebMTracksParser::OnListEnd(int id) { DCHECK(!audio_decoder_config_.IsValidConfig()); if (!audio_client_.InitializeConfig( - codec_id_, codec_private_, !audio_encryption_key_id_.empty(), - &audio_decoder_config_)) { + codec_id_, codec_private_, seek_preroll_, codec_delay_, + !audio_encryption_key_id_.empty(), &audio_decoder_config_)) { return false; } } else { @@ -226,6 +228,12 @@ bool WebMTracksParser::OnUInt(int id, int64 val) { case kWebMIdTrackType: dst = &track_type_; break; + case kWebMIdSeekPreRoll: + dst = &seek_preroll_; + break; + case kWebMIdCodecDelay: + dst = &codec_delay_; + break; default: return true; } diff --git a/media/webm/webm_tracks_parser.h b/media/webm/webm_tracks_parser.h index 81588e4..d399320 100644 --- a/media/webm/webm_tracks_parser.h +++ b/media/webm/webm_tracks_parser.h @@ -83,6 +83,8 @@ class MEDIA_EXPORT WebMTracksParser : public WebMParserClient { std::string track_language_; std::string codec_id_; std::vector<uint8> codec_private_; + int64 seek_preroll_; + int64 codec_delay_; scoped_ptr<WebMContentEncodingsClient> track_content_encodings_client_; int64 audio_track_num_; diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index cb4ef31..ce1beed 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml @@ -22618,6 +22618,7 @@ other types of suffix sets. <int value="6" label="MPEG4 AAC"/> <int value="7" label="EAC3"/> <int value="8" label="MP3"/> + <int value="9" label="OPUS"/> </enum> <enum name="NavigationScheme" type="int"> |