diff options
author | acolwell@chromium.org <acolwell@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-08-21 20:54:26 +0000 |
---|---|---|
committer | acolwell@chromium.org <acolwell@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-08-21 20:54:26 +0000 |
commit | 50464198dea18732a8baeacd4fb01f9c93d41a85 (patch) | |
tree | 5cf56b0cf940eeed23f36d80fac17973a82b505a /media | |
parent | 91fdfe2fe39c1fb55708f2d65203caecdbdbfa34 (diff) | |
download | chromium_src-50464198dea18732a8baeacd4fb01f9c93d41a85.zip chromium_src-50464198dea18732a8baeacd4fb01f9c93d41a85.tar.gz chromium_src-50464198dea18732a8baeacd4fb01f9c93d41a85.tar.bz2 |
Revert 152622 - Add support for config changes during playback to FFmpegVideoDecoder.
Also fixed a minor config change related bug in SourceBufferStream.
BUG=122913
TEST=PipelineIntegrationTest.MediaSource_MP4ConfigChange, SourceBufferStreamTest.ConfigChange_Basic, PipelineIntegrationTest.MediaSource_Seek
Review URL: https://chromiumcodereview.appspot.com/10836304
TBR=acolwell@chromium.org
Review URL: https://chromiumcodereview.appspot.com/10866002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@152629 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r-- | media/filters/chunk_demuxer_unittest.cc | 14 | ||||
-rw-r--r-- | media/filters/ffmpeg_video_decoder.cc | 85 | ||||
-rw-r--r-- | media/filters/ffmpeg_video_decoder.h | 4 | ||||
-rw-r--r-- | media/filters/pipeline_integration_test.cc | 113 | ||||
-rw-r--r-- | media/filters/source_buffer_stream.cc | 39 | ||||
-rw-r--r-- | media/filters/source_buffer_stream.h | 8 | ||||
-rw-r--r-- | media/filters/source_buffer_stream_unittest.cc | 103 | ||||
-rw-r--r-- | media/mp4/mp4_stream_parser.cc | 9 | ||||
-rw-r--r-- | media/mp4/mp4_stream_parser_unittest.cc | 5 |
9 files changed, 103 insertions, 277 deletions
diff --git a/media/filters/chunk_demuxer_unittest.cc b/media/filters/chunk_demuxer_unittest.cc index c1cec58..2d04f51 100644 --- a/media/filters/chunk_demuxer_unittest.cc +++ b/media/filters/chunk_demuxer_unittest.cc @@ -2056,6 +2056,10 @@ TEST_F(ChunkDemuxerTest, TestConfigChange_Video) { ASSERT_EQ(status, DemuxerStream::kConfigChanged); EXPECT_EQ(last_timestamp.InMilliseconds(), 501); + // Verify that another read will result in kConfigChanged being returned + // again. + ExpectConfigChanged(stream); + // Fetch the new decoder config. const VideoDecoderConfig& video_config_2 = stream->video_decoder_config(); ASSERT_TRUE(video_config_2.IsValidConfig()); @@ -2069,6 +2073,9 @@ TEST_F(ChunkDemuxerTest, TestConfigChange_Video) { ASSERT_EQ(status, DemuxerStream::kConfigChanged); EXPECT_EQ(last_timestamp.InMilliseconds(), 793); + // Verify we get another ConfigChanged status. + ExpectConfigChanged(stream); + // Get the new config and verify that it matches the first one. ASSERT_TRUE(video_config_1.Matches(stream->video_decoder_config())); @@ -2103,6 +2110,10 @@ TEST_F(ChunkDemuxerTest, TestConfigChange_Audio) { ASSERT_EQ(status, DemuxerStream::kConfigChanged); EXPECT_EQ(last_timestamp.InMilliseconds(), 524); + // Verify that another read will result in kConfigChanged being returned + // again. + ExpectConfigChanged(stream); + // Fetch the new decoder config. const AudioDecoderConfig& audio_config_2 = stream->audio_decoder_config(); ASSERT_TRUE(audio_config_2.IsValidConfig()); @@ -2116,6 +2127,9 @@ TEST_F(ChunkDemuxerTest, TestConfigChange_Audio) { ASSERT_EQ(status, DemuxerStream::kConfigChanged); EXPECT_EQ(last_timestamp.InMilliseconds(), 759); + // Verify we get another ConfigChanged status. + ExpectConfigChanged(stream); + // Get the new config and verify that it matches the first one. ASSERT_TRUE(audio_config_1.Matches(stream->audio_decoder_config())); diff --git a/media/filters/ffmpeg_video_decoder.cc b/media/filters/ffmpeg_video_decoder.cc index 7bfd4e8..6c9387a 100644 --- a/media/filters/ffmpeg_video_decoder.cc +++ b/media/filters/ffmpeg_video_decoder.cc @@ -158,13 +158,44 @@ void FFmpegVideoDecoder::Initialize(const scoped_refptr<DemuxerStream>& stream, demuxer_stream_ = stream; statistics_cb_ = statistics_cb; - if (!ConfigureDecoder()) { + const VideoDecoderConfig& config = stream->video_decoder_config(); + + // TODO(scherkus): this check should go in Pipeline prior to creating + // decoder objects. + if (!config.IsValidConfig()) { + DLOG(ERROR) << "Invalid video stream - " << config.AsHumanReadableString(); + status_cb.Run(PIPELINE_ERROR_DECODE); + return; + } + + // Initialize AVCodecContext structure. + codec_context_ = avcodec_alloc_context3(NULL); + VideoDecoderConfigToAVCodecContext(config, codec_context_); + + // Enable motion vector search (potentially slow), strong deblocking filter + // for damaged macroblocks, and set our error detection sensitivity. + codec_context_->error_concealment = FF_EC_GUESS_MVS | FF_EC_DEBLOCK; + codec_context_->err_recognition = AV_EF_CAREFUL; + codec_context_->thread_count = GetThreadCount(codec_context_->codec_id); + codec_context_->opaque = this; + codec_context_->flags |= CODEC_FLAG_EMU_EDGE; + codec_context_->get_buffer = GetVideoBufferImpl; + codec_context_->release_buffer = ReleaseVideoBufferImpl; + + AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id); + if (!codec) { + status_cb.Run(PIPELINE_ERROR_DECODE); + return; + } + + if (avcodec_open2(codec_context_, codec, NULL) < 0) { status_cb.Run(PIPELINE_ERROR_DECODE); return; } // Success! state_ = kNormal; + av_frame_ = avcodec_alloc_frame(); status_cb.Run(PIPELINE_OK); } @@ -289,18 +320,10 @@ void FFmpegVideoDecoder::DoDecryptOrDecodeBuffer( return; } - if (status == DemuxerStream::kAborted) { - base::ResetAndReturn(&read_cb_).Run(kOk, NULL); - return; - } - - if (status == DemuxerStream::kConfigChanged) { - if (!ConfigureDecoder()) { - base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); - return; - } - - ReadFromDemuxerStream(); + if (status != DemuxerStream::kOk) { + Status decoder_status = + (status == DemuxerStream::kAborted) ? kOk : kDecodeError; + base::ResetAndReturn(&read_cb_).Run(decoder_status, NULL); return; } @@ -501,40 +524,4 @@ void FFmpegVideoDecoder::ReleaseFFmpegResources() { } } -bool FFmpegVideoDecoder::ConfigureDecoder() { - const VideoDecoderConfig& config = demuxer_stream_->video_decoder_config(); - - if (!config.IsValidConfig()) { - DLOG(ERROR) << "Invalid video stream - " << config.AsHumanReadableString(); - return false; - } - - // Release existing decoder resources if necessary. - ReleaseFFmpegResources(); - - // Initialize AVCodecContext structure. - codec_context_ = avcodec_alloc_context3(NULL); - VideoDecoderConfigToAVCodecContext(config, codec_context_); - - // Enable motion vector search (potentially slow), strong deblocking filter - // for damaged macroblocks, and set our error detection sensitivity. - codec_context_->error_concealment = FF_EC_GUESS_MVS | FF_EC_DEBLOCK; - codec_context_->err_recognition = AV_EF_CAREFUL; - codec_context_->thread_count = GetThreadCount(codec_context_->codec_id); - codec_context_->opaque = this; - codec_context_->flags |= CODEC_FLAG_EMU_EDGE; - codec_context_->get_buffer = GetVideoBufferImpl; - codec_context_->release_buffer = ReleaseVideoBufferImpl; - - AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id); - if (!codec) - return false; - - if (avcodec_open2(codec_context_, codec, NULL) < 0) - return false; - - av_frame_ = avcodec_alloc_frame(); - return true; -} - } // namespace media diff --git a/media/filters/ffmpeg_video_decoder.h b/media/filters/ffmpeg_video_decoder.h index 340864d..a48e3b4 100644 --- a/media/filters/ffmpeg_video_decoder.h +++ b/media/filters/ffmpeg_video_decoder.h @@ -80,10 +80,6 @@ class MEDIA_EXPORT FFmpegVideoDecoder : public VideoDecoder { bool Decode(const scoped_refptr<DecoderBuffer>& buffer, scoped_refptr<VideoFrame>* video_frame); - // Handles (re-)initializing the decoder with a (new) config. - // Returns true if initialization was successful. - bool ConfigureDecoder(); - // Releases resources associated with |codec_context_| and |av_frame_| // and resets them to NULL. void ReleaseFFmpegResources(); diff --git a/media/filters/pipeline_integration_test.cc b/media/filters/pipeline_integration_test.cc index 3f00b09..c5353f3 100644 --- a/media/filters/pipeline_integration_test.cc +++ b/media/filters/pipeline_integration_test.cc @@ -5,7 +5,6 @@ #include "media/filters/pipeline_integration_test_base.h" #include "base/bind.h" -#include "base/string_util.h" #include "media/base/decoder_buffer.h" #include "media/base/decryptor_client.h" #include "media/base/test_data_util.h" @@ -18,34 +17,25 @@ static const char kSourceId[] = "SourceId"; static const char kClearKeySystem[] = "org.w3.clearkey"; static const uint8 kInitData[] = { 0x69, 0x6e, 0x69, 0x74 }; -static const char kWebM[] = "video/webm; codecs=\"vp8,vorbis\""; -static const char kAudioOnlyWebM[] = "video/webm; codecs=\"vorbis\""; -static const char kVideoOnlyWebM[] = "video/webm; codecs=\"vp8\""; -static const char kMP4[] = "video/mp4; codecs=\"avc1.4D4041,mp4a.40.2\""; - // Key used to encrypt video track in test file "bear-320x240-encrypted.webm". static const uint8 kSecretKey[] = { 0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b, 0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c }; -static const int kAppendWholeFile = -1; - // Helper class that emulates calls made on the ChunkDemuxer by the // Media Source API. class MockMediaSource : public ChunkDemuxerClient { public: - MockMediaSource(const std::string& filename, const std::string& mimetype, - int initial_append_size) + MockMediaSource(const std::string& filename, int initial_append_size, + bool has_audio, bool has_video) : url_(GetTestDataURL(filename)), current_position_(0), initial_append_size_(initial_append_size), - mimetype_(mimetype) { + has_audio_(has_audio), + has_video_(has_video) { file_data_ = ReadTestDataFile(filename); - if (initial_append_size_ == kAppendWholeFile) - initial_append_size_ = file_data_->GetDataSize(); - DCHECK_GT(initial_append_size_, 0); DCHECK_LE(initial_append_size_, file_data_->GetDataSize()); } @@ -77,13 +67,6 @@ class MockMediaSource : public ChunkDemuxerClient { current_position_ += size; } - void AppendAtTime(const base::TimeDelta& timestampOffset, - const uint8* pData, int size) { - CHECK(chunk_demuxer_->SetTimestampOffset(kSourceId, timestampOffset)); - CHECK(chunk_demuxer_->AppendData(kSourceId, pData, size)); - CHECK(chunk_demuxer_->SetTimestampOffset(kSourceId, base::TimeDelta())); - } - void EndOfStream() { chunk_demuxer_->EndOfStream(PIPELINE_OK); } @@ -98,15 +81,14 @@ class MockMediaSource : public ChunkDemuxerClient { virtual void DemuxerOpened(ChunkDemuxer* demuxer) { chunk_demuxer_ = demuxer; - size_t semicolon = mimetype_.find(";"); - std::string type = mimetype_.substr(0, semicolon); - size_t quote1 = mimetype_.find("\""); - size_t quote2 = mimetype_.find("\"", quote1 + 1); - std::string codecStr = mimetype_.substr(quote1 + 1, quote2 - quote1 - 1); std::vector<std::string> codecs; - Tokenize(codecStr, ",", &codecs); + if (has_audio_) + codecs.push_back("vorbis"); - CHECK_EQ(chunk_demuxer_->AddId(kSourceId, type, codecs), ChunkDemuxer::kOk); + if (has_video_) + codecs.push_back("vp8"); + + chunk_demuxer_->AddId(kSourceId, "video/webm", codecs); AppendData(initial_append_size_); } @@ -127,7 +109,8 @@ class MockMediaSource : public ChunkDemuxerClient { scoped_refptr<DecoderBuffer> file_data_; int current_position_; int initial_append_size_; - std::string mimetype_; + bool has_audio_; + bool has_video_; scoped_refptr<ChunkDemuxer> chunk_demuxer_; DecryptorClient* decryptor_client_; }; @@ -236,13 +219,14 @@ class PipelineIntegrationTest // seek happens while there is a pending read on the ChunkDemuxer // and no data is available. bool TestSeekDuringRead(const std::string& filename, - const std::string& mimetype, int initial_append_size, base::TimeDelta start_seek_time, base::TimeDelta seek_time, int seek_file_position, - int seek_append_size) { - MockMediaSource source(filename, mimetype, initial_append_size); + int seek_append_size, + bool has_audio, + bool has_video) { + MockMediaSource source(filename, initial_append_size, has_audio, has_video); StartPipelineWithMediaSource(&source); if (pipeline_status_ != PIPELINE_OK) @@ -285,7 +269,7 @@ TEST_F(PipelineIntegrationTest, BasicPlaybackHashed) { } TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource) { - MockMediaSource source("bear-320x240.webm", kWebM, 219229); + MockMediaSource source("bear-320x240.webm", 219229, true, true); StartPipelineWithMediaSource(&source); source.EndOfStream(); ASSERT_EQ(pipeline_status_, PIPELINE_OK); @@ -301,57 +285,6 @@ TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource) { Stop(); } -TEST_F(PipelineIntegrationTest, MediaSource_ConfigChange_WebM) { - MockMediaSource source("bear-320x240-16x9-aspect.webm", kWebM, - kAppendWholeFile); - StartPipelineWithMediaSource(&source); - - scoped_refptr<DecoderBuffer> second_file = - ReadTestDataFile("bear-640x360.webm"); - - source.AppendAtTime(base::TimeDelta::FromSeconds(2), - second_file->GetData(), second_file->GetDataSize()); - - source.EndOfStream(); - ASSERT_EQ(pipeline_status_, PIPELINE_OK); - - EXPECT_EQ(pipeline_->GetBufferedTimeRanges().size(), 1u); - EXPECT_EQ(pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds(), 0); - EXPECT_EQ(pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds(), 4763); - - Play(); - - ASSERT_TRUE(WaitUntilOnEnded()); - source.Abort(); - Stop(); -} - -#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS) -TEST_F(PipelineIntegrationTest, MediaSource_ConfigChange_MP4) { - MockMediaSource source("bear.640x360_dash.mp4", kMP4, kAppendWholeFile); - StartPipelineWithMediaSource(&source); - - scoped_refptr<DecoderBuffer> second_file = - ReadTestDataFile("bear.1280x720_dash.mp4"); - - source.AppendAtTime(base::TimeDelta::FromSeconds(2), - second_file->GetData(), second_file->GetDataSize()); - - source.EndOfStream(); - ASSERT_EQ(pipeline_status_, PIPELINE_OK); - - EXPECT_EQ(pipeline_->GetBufferedTimeRanges().size(), 1u); - EXPECT_EQ(pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds(), 0); - EXPECT_EQ(pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds(), 4736); - - Play(); - - ASSERT_TRUE(WaitUntilOnEnded()); - source.Abort(); - Stop(); -} -#endif - TEST_F(PipelineIntegrationTest, BasicPlayback_16x9AspectRatio) { ASSERT_TRUE(Start(GetTestDataURL("bear-320x240-16x9-aspect.webm"), PIPELINE_OK)); @@ -360,7 +293,7 @@ TEST_F(PipelineIntegrationTest, BasicPlayback_16x9AspectRatio) { } TEST_F(PipelineIntegrationTest, EncryptedPlayback) { - MockMediaSource source("bear-320x240-encrypted.webm", kWebM, 220788); + MockMediaSource source("bear-320x240-encrypted.webm", 220788, true, true); FakeDecryptorClient encrypted_media; StartPipelineWithEncryptedMedia(&source, &encrypted_media); @@ -420,20 +353,18 @@ TEST_F(PipelineIntegrationTest, DISABLED_SeekWhilePlaying) { // Verify audio decoder & renderer can handle aborted demuxer reads. TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_AudioOnly) { - ASSERT_TRUE(TestSeekDuringRead("bear-320x240-audio-only.webm", kAudioOnlyWebM, - 8192, + ASSERT_TRUE(TestSeekDuringRead("bear-320x240-audio-only.webm", 8192, base::TimeDelta::FromMilliseconds(464), base::TimeDelta::FromMilliseconds(617), - 0x10CA, 19730)); + 0x10CA, 19730, true, false)); } // Verify video decoder & renderer can handle aborted demuxer reads. TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_VideoOnly) { - ASSERT_TRUE(TestSeekDuringRead("bear-320x240-video-only.webm", kVideoOnlyWebM, - 32768, + ASSERT_TRUE(TestSeekDuringRead("bear-320x240-video-only.webm", 32768, base::TimeDelta::FromMilliseconds(200), base::TimeDelta::FromMilliseconds(1668), - 0x1C896, 65536)); + 0x1C896, 65536, false, true)); } } // namespace media diff --git a/media/filters/source_buffer_stream.cc b/media/filters/source_buffer_stream.cc index c92b5fe..c768423 100644 --- a/media/filters/source_buffer_stream.cc +++ b/media/filters/source_buffer_stream.cc @@ -270,6 +270,8 @@ namespace media { SourceBufferStream::SourceBufferStream(const AudioDecoderConfig& audio_config) : current_config_index_(0), append_config_index_(0), + audio_configs_(1), + video_configs_(0), stream_start_time_(kNoTimestamp()), seek_pending_(false), seek_buffer_timestamp_(kNoTimestamp()), @@ -280,14 +282,15 @@ SourceBufferStream::SourceBufferStream(const AudioDecoderConfig& audio_config) last_buffer_timestamp_(kNoTimestamp()), max_interbuffer_distance_(kNoTimestamp()), memory_limit_(kDefaultAudioMemoryLimit) { - DCHECK(audio_config.IsValidConfig()); - audio_configs_.push_back(new AudioDecoderConfig()); - audio_configs_.back()->CopyFrom(audio_config); + audio_configs_[0] = new AudioDecoderConfig(); + audio_configs_[0]->CopyFrom(audio_config); } SourceBufferStream::SourceBufferStream(const VideoDecoderConfig& video_config) : current_config_index_(0), append_config_index_(0), + audio_configs_(0), + video_configs_(1), stream_start_time_(kNoTimestamp()), seek_pending_(false), seek_buffer_timestamp_(kNoTimestamp()), @@ -298,9 +301,8 @@ SourceBufferStream::SourceBufferStream(const VideoDecoderConfig& video_config) last_buffer_timestamp_(kNoTimestamp()), max_interbuffer_distance_(kNoTimestamp()), memory_limit_(kDefaultVideoMemoryLimit) { - DCHECK(video_config.IsValidConfig()); - video_configs_.push_back(new VideoDecoderConfig()); - video_configs_.back()->CopyFrom(video_config); + video_configs_[0] = new VideoDecoderConfig(); + video_configs_[0]->CopyFrom(video_config); } SourceBufferStream::~SourceBufferStream() { @@ -734,7 +736,6 @@ void SourceBufferStream::Seek(base::TimeDelta timestamp) { DCHECK(timestamp >= stream_start_time_); SetSelectedRange(NULL); track_buffer_.clear(); - config_change_pending_ = false; if (ShouldSeekToStartOfBuffered(timestamp)) { SetSelectedRange(ranges_.front()); @@ -766,13 +767,9 @@ bool SourceBufferStream::IsSeekPending() const { SourceBufferStream::Status SourceBufferStream::GetNextBuffer( scoped_refptr<StreamParserBuffer>* out_buffer) { - CHECK(!config_change_pending_); - if (!track_buffer_.empty()) { - if (track_buffer_.front()->GetConfigId() != current_config_index_) { - config_change_pending_ = true; + if (track_buffer_.front()->GetConfigId() != current_config_index_) return kConfigChange; - } *out_buffer = track_buffer_.front(); track_buffer_.pop_front(); @@ -782,10 +779,8 @@ SourceBufferStream::Status SourceBufferStream::GetNextBuffer( if (!selected_range_ || !selected_range_->HasNextBuffer()) return kNeedBuffer; - if (selected_range_->GetNextConfigId() != current_config_index_) { - config_change_pending_ = true; + if (selected_range_->GetNextConfigId() != current_config_index_) return kConfigChange; - } CHECK(selected_range_->GetNextBuffer(out_buffer)); return kSuccess; @@ -857,14 +852,12 @@ bool SourceBufferStream::IsEndSelected() const { } const AudioDecoderConfig& SourceBufferStream::GetCurrentAudioDecoderConfig() { - if (config_change_pending_) - CompleteConfigChange(); + CompleteConfigChange(); return *audio_configs_[current_config_index_]; } const VideoDecoderConfig& SourceBufferStream::GetCurrentVideoDecoderConfig() { - if (config_change_pending_) - CompleteConfigChange(); + CompleteConfigChange(); return *video_configs_[current_config_index_]; } @@ -940,15 +933,15 @@ bool SourceBufferStream::UpdateVideoConfig(const VideoDecoderConfig& config) { } void SourceBufferStream::CompleteConfigChange() { - config_change_pending_ = false; - if (!track_buffer_.empty()) { current_config_index_ = track_buffer_.front()->GetConfigId(); return; } - if (selected_range_ && selected_range_->HasNextBuffer()) - current_config_index_ = selected_range_->GetNextConfigId(); + if (!selected_range_ || !selected_range_->HasNextBuffer()) + return; + + current_config_index_ = selected_range_->GetNextConfigId(); } SourceBufferRange::SourceBufferRange( diff --git a/media/filters/source_buffer_stream.h b/media/filters/source_buffer_stream.h index 0e08327..e67a84d 100644 --- a/media/filters/source_buffer_stream.h +++ b/media/filters/source_buffer_stream.h @@ -258,15 +258,9 @@ class MEDIA_EXPORT SourceBufferStream { // Stores the largest distance between two adjacent buffers in this stream. base::TimeDelta max_interbuffer_distance_; - // The maximum amount of data in bytes the stream will keep in memory. +// The maximum amount of data in bytes the stream will keep in memory. int memory_limit_; - // Indicates that a kConfigChanged status has been reported by GetNextBuffer() - // and GetCurrentXXXDecoderConfig() must be called to update the current - // config. GetNextBuffer() must not be called again until - // GetCurrentXXXDecoderConfig() has been called. - bool config_change_pending_; - DISALLOW_COPY_AND_ASSIGN(SourceBufferStream); }; diff --git a/media/filters/source_buffer_stream_unittest.cc b/media/filters/source_buffer_stream_unittest.cc index 1f46d0f..4033869 100644 --- a/media/filters/source_buffer_stream_unittest.cc +++ b/media/filters/source_buffer_stream_unittest.cc @@ -15,14 +15,10 @@ static const int kDefaultKeyframesPerSecond = 6; static const uint8 kDataA = 0x11; static const uint8 kDataB = 0x33; static const int kDataSize = 1; -static const gfx::Size kCodedSize(320, 240); class SourceBufferStreamTest : public testing::Test { protected: SourceBufferStreamTest() { - config_.Initialize(kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN, - VideoFrame::YV12, kCodedSize, gfx::Rect(kCodedSize), - kCodedSize, NULL, 0, false); stream_.reset(new SourceBufferStream(config_)); SetStreamInfo(kDefaultFramesPerSecond, kDefaultKeyframesPerSecond); @@ -123,10 +119,7 @@ class SourceBufferStreamTest : public testing::Test { int current_position = starting_position; for (; current_position <= ending_position; current_position++) { scoped_refptr<StreamParserBuffer> buffer; - SourceBufferStream::Status status = stream_->GetNextBuffer(&buffer); - - EXPECT_NE(status, SourceBufferStream::kConfigChange); - if (status != SourceBufferStream::kSuccess) + if (stream_->GetNextBuffer(&buffer) == SourceBufferStream::kNeedBuffer) break; if (expect_keyframe && current_position == starting_position) @@ -153,13 +146,6 @@ class SourceBufferStreamTest : public testing::Test { EXPECT_EQ(stream_->GetNextBuffer(&buffer), SourceBufferStream::kNeedBuffer); } - void CheckConfig(const VideoDecoderConfig& config) { - const VideoDecoderConfig& actual = stream_->GetCurrentVideoDecoderConfig(); - EXPECT_TRUE(actual.Matches(config)) - << "Expected: " << config.AsHumanReadableString() - << "\nActual: " << actual.AsHumanReadableString(); - } - base::TimeDelta frame_duration() const { return frame_duration_; } scoped_ptr<SourceBufferStream> stream_; @@ -1836,93 +1822,6 @@ TEST_F(SourceBufferStreamTest, DISABLED_GarbageCollection_WaitingForKeyframe) { CheckExpectedRanges("{ [15,15) [20,28) }"); } -TEST_F(SourceBufferStreamTest, ConfigChange_Basic) { - gfx::Size kNewCodedSize(kCodedSize.width() * 2, kCodedSize.height() * 2); - VideoDecoderConfig new_config( - kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN, VideoFrame::YV12, kNewCodedSize, - gfx::Rect(kNewCodedSize), kNewCodedSize, NULL, 0); - ASSERT_FALSE(new_config.Matches(config_)); - - Seek(0); - CheckConfig(config_); - - // Append 5 buffers at positions 0 through 4 - NewSegmentAppend(0, 5, &kDataA); - - CheckConfig(config_); - - // Signal a config change. - stream_->UpdateVideoConfig(new_config); - - // Make sure updating the config doesn't change anything since new_config - // should not be associated with the buffer GetNextBuffer() will return. - CheckConfig(config_); - - // Append 5 buffers at positions 5 through 9. - NewSegmentAppend(5, 5, &kDataB); - - // Consume the buffers associated with the initial config. - scoped_refptr<StreamParserBuffer> buffer; - for (int i = 0; i < 5; i++) { - EXPECT_EQ(stream_->GetNextBuffer(&buffer), SourceBufferStream::kSuccess); - CheckConfig(config_); - } - - // Verify the next attempt to get a buffer will signal that a config change - // has happened. - EXPECT_EQ(stream_->GetNextBuffer(&buffer), SourceBufferStream::kConfigChange); - - // Verify that the new config is now returned. - CheckConfig(new_config); - - // Consume the remaining buffers associated with the new config. - for (int i = 0; i < 5; i++) { - CheckConfig(new_config); - EXPECT_EQ(stream_->GetNextBuffer(&buffer), SourceBufferStream::kSuccess); - } -} - -TEST_F(SourceBufferStreamTest, ConfigChange_Seek) { - scoped_refptr<StreamParserBuffer> buffer; - gfx::Size kNewCodedSize(kCodedSize.width() * 2, kCodedSize.height() * 2); - VideoDecoderConfig new_config( - kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN, VideoFrame::YV12, kNewCodedSize, - gfx::Rect(kNewCodedSize), kNewCodedSize, NULL, 0); - - Seek(0); - NewSegmentAppend(0, 5, &kDataA); - stream_->UpdateVideoConfig(new_config); - NewSegmentAppend(5, 5, &kDataB); - - // Seek to the start of the buffers with the new config and make sure a - // config change is signalled. - CheckConfig(config_); - Seek(5); - CheckConfig(config_); - EXPECT_EQ(stream_->GetNextBuffer(&buffer), SourceBufferStream::kConfigChange); - CheckConfig(new_config); - CheckExpectedBuffers(5, 9, &kDataB); - - - // Seek to the start which has a different config. Don't fetch any buffers and - // seek back to buffers with the current config. Make sure a config change - // isn't signalled in this case. - CheckConfig(new_config); - Seek(0); - Seek(7); - CheckExpectedBuffers(5, 9, &kDataB); - - - // Seek to the start and make sure a config change is signalled. - CheckConfig(new_config); - Seek(0); - CheckConfig(new_config); - EXPECT_EQ(stream_->GetNextBuffer(&buffer), SourceBufferStream::kConfigChange); - CheckConfig(config_); - CheckExpectedBuffers(0, 4, &kDataA); -} - - // TODO(vrk): Add unit tests where keyframes are unaligned between streams. // (crbug.com/133557) diff --git a/media/mp4/mp4_stream_parser.cc b/media/mp4/mp4_stream_parser.cc index b025b7a..1aa8c70 100644 --- a/media/mp4/mp4_stream_parser.cc +++ b/media/mp4/mp4_stream_parser.cc @@ -237,7 +237,14 @@ bool MP4StreamParser::ParseMoov(BoxReader* reader) { } } - RCHECK(config_cb_.Run(audio_config, video_config)); + // TODO(strobe): For now, we avoid sending new configs on a new + // reinitialization segment, and instead simply embed the updated parameter + // sets into the video stream. The conditional should be removed when + // http://crbug.com/122913 is fixed. (We detect whether we've already sent + // configs by looking at init_cb_ instead of config_cb_, because init_cb_ + // should only be fired once even after that bug is fixed.) + if (!init_cb_.is_null()) + RCHECK(config_cb_.Run(audio_config, video_config)); base::TimeDelta duration; if (moov_->extends.header.fragment_duration > 0) { diff --git a/media/mp4/mp4_stream_parser_unittest.cc b/media/mp4/mp4_stream_parser_unittest.cc index 20c32f1..830f35b 100644 --- a/media/mp4/mp4_stream_parser_unittest.cc +++ b/media/mp4/mp4_stream_parser_unittest.cc @@ -62,6 +62,11 @@ class MP4StreamParserTest : public testing::Test { const VideoDecoderConfig& vc) { DVLOG(1) << "NewConfigF: audio=" << ac.IsValidConfig() << ", video=" << vc.IsValidConfig(); + + // TODO(strobe): Until http://crbug.com/122913 is fixed, we want to make + // sure that this callback isn't called more than once per stream. Remove + // when that bug is fixed. + EXPECT_FALSE(configs_received_); configs_received_ = true; return true; } |