summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--media/base/audio_decoder_config.cc18
-rw-r--r--media/base/audio_decoder_config.h16
-rw-r--r--media/base/decoder_buffer.cc3
-rw-r--r--media/base/decoder_buffer.h11
-rw-r--r--media/base/run_all_unittests.cc4
-rw-r--r--media/ffmpeg/ffmpeg_common.cc4
-rw-r--r--media/filters/decrypting_audio_decoder.cc8
-rw-r--r--media/filters/decrypting_audio_decoder_unittest.cc3
-rw-r--r--media/filters/decrypting_demuxer_stream.cc4
-rw-r--r--media/filters/opus_audio_decoder.cc60
-rw-r--r--media/filters/opus_audio_decoder.h4
-rw-r--r--media/filters/pipeline_integration_test.cc23
-rw-r--r--media/filters/stream_parser_factory.cc11
-rw-r--r--media/mp3/mp3_stream_parser.cc3
-rw-r--r--media/mp4/mp4_stream_parser.cc3
-rw-r--r--media/webm/webm_audio_client.cc15
-rw-r--r--media/webm/webm_audio_client.h2
-rw-r--r--media/webm/webm_cluster_parser.cc30
-rw-r--r--media/webm/webm_cluster_parser.h8
-rw-r--r--media/webm/webm_constants.h3
-rw-r--r--media/webm/webm_parser.cc3
-rw-r--r--media/webm/webm_tracks_parser.cc12
-rw-r--r--media/webm/webm_tracks_parser.h2
-rw-r--r--tools/metrics/histograms/histograms.xml1
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">