diff options
-rw-r--r-- | media/filters/audio_file_reader.cc | 34 | ||||
-rw-r--r-- | media/filters/audio_file_reader.h | 9 | ||||
-rw-r--r-- | media/filters/audio_file_reader_unittest.cc | 18 | ||||
-rw-r--r-- | media/filters/chunk_demuxer.cc | 2 | ||||
-rw-r--r-- | media/filters/ffmpeg_audio_decoder.cc | 21 | ||||
-rw-r--r-- | media/filters/ffmpeg_audio_decoder.h | 4 | ||||
-rw-r--r-- | media/filters/pipeline_integration_test.cc | 9 | ||||
-rw-r--r-- | webkit/media/crypto/ppapi/ffmpeg_cdm_audio_decoder.cc | 20 | ||||
-rw-r--r-- | webkit/media/crypto/ppapi/ffmpeg_cdm_audio_decoder.h | 4 |
9 files changed, 98 insertions, 23 deletions
diff --git a/media/filters/audio_file_reader.cc b/media/filters/audio_file_reader.cc index 58c4501..32627b0 100644 --- a/media/filters/audio_file_reader.cc +++ b/media/filters/audio_file_reader.cc @@ -15,21 +15,16 @@ namespace media { AudioFileReader::AudioFileReader(FFmpegURLProtocol* protocol) : codec_context_(NULL), stream_index_(0), - protocol_(protocol) { + protocol_(protocol), + channels_(0), + sample_rate_(0), + av_sample_format_(0) { } AudioFileReader::~AudioFileReader() { Close(); } -int AudioFileReader::channels() const { - return codec_context_->channels; -} - -int AudioFileReader::sample_rate() const { - return codec_context_->sample_rate; -} - base::TimeDelta AudioFileReader::duration() const { const AVRational av_time_base = {1, AV_TIME_BASE}; @@ -110,6 +105,11 @@ bool AudioFileReader::Open() { return false; } + // Store initial values to guard against midstream configuration changes. + channels_ = codec_context_->channels; + sample_rate_ = codec_context_->sample_rate; + av_sample_format_ = codec_context_->sample_fmt; + return true; } @@ -179,6 +179,22 @@ int AudioFileReader::Read(AudioBus* audio_bus) { break; } + if (av_frame->sample_rate != sample_rate_ || + av_frame->channels != channels_ || + av_frame->format != av_sample_format_) { + DLOG(ERROR) << "Unsupported midstream configuration change!" + << " Sample Rate: " << av_frame->sample_rate << " vs " + << sample_rate_ + << ", Channels: " << av_frame->channels << " vs " + << channels_ + << ", Sample Format: " << av_frame->format << " vs " + << av_sample_format_; + + // This is an unrecoverable error, so bail out. + continue_decoding = false; + break; + } + // Truncate, if necessary, if the destination isn't big enough. if (current_frame + frames_read > audio_bus->frames()) frames_read = audio_bus->frames() - current_frame; diff --git a/media/filters/audio_file_reader.h b/media/filters/audio_file_reader.h index c9996f39..e345dc0 100644 --- a/media/filters/audio_file_reader.h +++ b/media/filters/audio_file_reader.h @@ -43,8 +43,8 @@ class MEDIA_EXPORT AudioFileReader { int Read(AudioBus* audio_bus); // These methods can be called once Open() has been called. - int channels() const; - int sample_rate() const; + int channels() const { return channels_; } + int sample_rate() const { return sample_rate_; } // Please note that duration() and number_of_frames() attempt to be accurate, // but are only estimates. For some encoded formats, the actual duration @@ -58,6 +58,11 @@ class MEDIA_EXPORT AudioFileReader { AVCodecContext* codec_context_; int stream_index_; FFmpegURLProtocol* protocol_; + int channels_; + int sample_rate_; + + // AVSampleFormat initially requested; not Chrome's SampleFormat. + int av_sample_format_; DISALLOW_COPY_AND_ASSIGN(AudioFileReader); }; diff --git a/media/filters/audio_file_reader_unittest.cc b/media/filters/audio_file_reader_unittest.cc index 72c2603..64c58e0 100644 --- a/media/filters/audio_file_reader_unittest.cc +++ b/media/filters/audio_file_reader_unittest.cc @@ -73,11 +73,19 @@ class AudioFileReaderTest : public testing::Test { ReadAndVerify(hash, trimmed_frames); } - void RunFailingTest(const char* fn) { + void RunTestFailingDemux(const char* fn) { Initialize(fn); EXPECT_FALSE(reader_->Open()); } + void RunTestFailingDecode(const char* fn) { + Initialize(fn); + EXPECT_TRUE(reader_->Open()); + scoped_ptr<AudioBus> decoded_audio_data = AudioBus::Create( + reader_->channels(), reader_->number_of_frames()); + EXPECT_EQ(reader_->Read(decoded_audio_data.get()), 0); + } + protected: scoped_refptr<DecoderBuffer> data_; scoped_ptr<InMemoryUrlProtocol> protocol_; @@ -91,7 +99,7 @@ TEST_F(AudioFileReaderTest, WithoutOpen) { } TEST_F(AudioFileReaderTest, InvalidFile) { - RunFailingTest("ten_byte_file"); + RunTestFailingDemux("ten_byte_file"); } TEST_F(AudioFileReaderTest, WithVideo) { @@ -134,10 +142,14 @@ TEST_F(AudioFileReaderTest, AAC) { RunTest("sfx.m4a", NULL, 1, 44100, base::TimeDelta::FromMicroseconds(312001), 13759, 13312); } + +TEST_F(AudioFileReaderTest, MidStreamConfigChangesFail) { + RunTestFailingDecode("midstream_config_change.mp3"); +} #endif TEST_F(AudioFileReaderTest, VorbisInvalidChannelLayout) { - RunFailingTest("9ch.ogg"); + RunTestFailingDemux("9ch.ogg"); } TEST_F(AudioFileReaderTest, WaveValidFourChannelLayout) { diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc index 1f091c3..8162bbf 100644 --- a/media/filters/chunk_demuxer.cc +++ b/media/filters/chunk_demuxer.cc @@ -218,7 +218,7 @@ class ChunkDemuxerStream : public DemuxerStream { // Append() belong to a media segment that starts at |start_timestamp|. void OnNewMediaSegment(TimeDelta start_timestamp); - // Called when mid-stream config updates occur. + // Called when midstream config updates occur. // Returns true if the new config is accepted. // Returns false if the new config should trigger an error. bool UpdateAudioConfig(const AudioDecoderConfig& config); diff --git a/media/filters/ffmpeg_audio_decoder.cc b/media/filters/ffmpeg_audio_decoder.cc index be142d5..6180063 100644 --- a/media/filters/ffmpeg_audio_decoder.cc +++ b/media/filters/ffmpeg_audio_decoder.cc @@ -43,7 +43,9 @@ FFmpegAudioDecoder::FFmpegAudioDecoder( codec_context_(NULL), bits_per_channel_(0), channel_layout_(CHANNEL_LAYOUT_NONE), + channels_(0), samples_per_second_(0), + av_sample_format_(0), bytes_per_frame_(0), last_input_timestamp_(kNoTimestamp()), output_bytes_to_drop_(0), @@ -303,6 +305,11 @@ bool FFmpegAudioDecoder::ConfigureDecoder() { output_timestamp_helper_.reset(new AudioTimestampHelper( config.bytes_per_frame(), config.samples_per_second())); bytes_per_frame_ = config.bytes_per_frame(); + + // Store initial values to guard against midstream configuration changes. + channels_ = codec_context_->channels; + av_sample_format_ = codec_context_->sample_fmt; + return true; } @@ -387,10 +394,16 @@ void FFmpegAudioDecoder::RunDecodeLoop( int decoded_audio_size = 0; if (frame_decoded) { - int output_sample_rate = av_frame_->sample_rate; - if (output_sample_rate != samples_per_second_) { - DLOG(ERROR) << "Output sample rate (" << output_sample_rate - << ") doesn't match expected rate " << samples_per_second_; + if (av_frame_->sample_rate != samples_per_second_ || + av_frame_->channels != channels_ || + av_frame_->format != av_sample_format_) { + DLOG(ERROR) << "Unsupported midstream configuration change!" + << " Sample Rate: " << av_frame_->sample_rate << " vs " + << samples_per_second_ + << ", Channels: " << av_frame_->channels << " vs " + << channels_ + << ", Sample Format: " << av_frame_->format << " vs " + << av_sample_format_; // This is an unrecoverable error, so bail out. QueuedAudioBuffer queue_entry = { kDecodeError, NULL }; diff --git a/media/filters/ffmpeg_audio_decoder.h b/media/filters/ffmpeg_audio_decoder.h index d2ba8c5..99fef1b 100644 --- a/media/filters/ffmpeg_audio_decoder.h +++ b/media/filters/ffmpeg_audio_decoder.h @@ -65,8 +65,12 @@ class MEDIA_EXPORT FFmpegAudioDecoder : public AudioDecoder { // Decoded audio format. int bits_per_channel_; ChannelLayout channel_layout_; + int channels_; int samples_per_second_; + // AVSampleFormat initially requested; not Chrome's SampleFormat. + int av_sample_format_; + // Used for computing output timestamps. scoped_ptr<AudioTimestampHelper> output_timestamp_helper_; int bytes_per_frame_; diff --git a/media/filters/pipeline_integration_test.cc b/media/filters/pipeline_integration_test.cc index 3e2eb19..e96da57 100644 --- a/media/filters/pipeline_integration_test.cc +++ b/media/filters/pipeline_integration_test.cc @@ -660,6 +660,15 @@ TEST_F(PipelineIntegrationTest, EXPECT_EQ(PIPELINE_ERROR_DECODE, WaitUntilEndedOrError()); source.Abort(); } + +// Verify files which change configuration midstream fail gracefully. +TEST_F(PipelineIntegrationTest, MidStreamConfigChangesFail) { + ASSERT_TRUE(Start( + GetTestDataFilePath("midstream_config_change.mp3"), PIPELINE_OK)); + Play(); + ASSERT_EQ(WaitUntilEndedOrError(), PIPELINE_ERROR_DECODE); +} + #endif TEST_F(PipelineIntegrationTest, BasicPlayback_16x9AspectRatio) { diff --git a/webkit/media/crypto/ppapi/ffmpeg_cdm_audio_decoder.cc b/webkit/media/crypto/ppapi/ffmpeg_cdm_audio_decoder.cc index 8edbb01..d7f3f27 100644 --- a/webkit/media/crypto/ppapi/ffmpeg_cdm_audio_decoder.cc +++ b/webkit/media/crypto/ppapi/ffmpeg_cdm_audio_decoder.cc @@ -87,6 +87,8 @@ FFmpegCdmAudioDecoder::FFmpegCdmAudioDecoder(cdm::Host* host) av_frame_(NULL), bits_per_channel_(0), samples_per_second_(0), + channels_(0), + av_sample_format_(0), bytes_per_frame_(0), last_input_timestamp_(media::kNoTimestamp()), output_bytes_to_drop_(0) { @@ -154,6 +156,10 @@ bool FFmpegCdmAudioDecoder::Initialize(const cdm::AudioDecoderConfig& config) { serialized_audio_frames_.reserve(bytes_per_frame_ * samples_per_second_); is_initialized_ = true; + // Store initial values to guard against midstream configuration changes. + channels_ = codec_context_->channels; + av_sample_format_ = codec_context_->sample_fmt; + return true; } @@ -269,10 +275,16 @@ cdm::Status FFmpegCdmAudioDecoder::DecodeBuffer( int decoded_audio_size = 0; if (frame_decoded) { - int output_sample_rate = av_frame_->sample_rate; - if (output_sample_rate != samples_per_second_) { - DLOG(ERROR) << "Output sample rate (" << output_sample_rate - << ") doesn't match expected rate " << samples_per_second_; + if (av_frame_->sample_rate != samples_per_second_ || + av_frame_->channels != channels_ || + av_frame_->format != av_sample_format_) { + DLOG(ERROR) << "Unsupported midstream configuration change!" + << " Sample Rate: " << av_frame_->sample_rate << " vs " + << samples_per_second_ + << ", Channels: " << av_frame_->channels << " vs " + << channels_ + << ", Sample Format: " << av_frame_->format << " vs " + << av_sample_format_; return cdm::kDecodeError; } diff --git a/webkit/media/crypto/ppapi/ffmpeg_cdm_audio_decoder.h b/webkit/media/crypto/ppapi/ffmpeg_cdm_audio_decoder.h index 266b4ad..1c2c819 100644 --- a/webkit/media/crypto/ppapi/ffmpeg_cdm_audio_decoder.h +++ b/webkit/media/crypto/ppapi/ffmpeg_cdm_audio_decoder.h @@ -69,6 +69,10 @@ class FFmpegCdmAudioDecoder { // Audio format. int bits_per_channel_; int samples_per_second_; + int channels_; + + // AVSampleFormat initially requested; not Chrome's SampleFormat. + int av_sample_format_; // Used for computing output timestamps. scoped_ptr<media::AudioTimestampHelper> output_timestamp_helper_; |