Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(385)

Unified Diff: media/filters/decrypting_video_decoder_unittest.cc

Issue 10969028: Add video decoding methods in Decryptor and add DecryptingVideoDecoder. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Move DVD to filters/ and rebase. Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: media/filters/decrypting_video_decoder_unittest.cc
diff --git a/media/filters/decrypting_video_decoder_unittest.cc b/media/filters/decrypting_video_decoder_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..455594d2393475b48a7a55e750583832d55f1855
--- /dev/null
+++ b/media/filters/decrypting_video_decoder_unittest.cc
@@ -0,0 +1,515 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/message_loop.h"
+#include "media/base/decoder_buffer.h"
+#include "media/base/decrypt_config.h"
+#include "media/base/mock_callback.h"
+#include "media/base/mock_filters.h"
+#include "media/base/video_frame.h"
+#include "media/filters/ffmpeg_decoder_unittest.h"
+#include "media/filters/decrypting_video_decoder.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using ::testing::_;
+using ::testing::Invoke;
+using ::testing::IsNull;
+using ::testing::ReturnRef;
+using ::testing::SaveArg;
+using ::testing::StrictMock;
+
+namespace media {
+
+static const VideoFrame::Format kVideoFormat = VideoFrame::YV12;
+static const gfx::Size kCodedSize(320, 240);
+static const gfx::Rect kVisibleRect(320, 240);
+static const gfx::Size kNaturalSize(320, 240);
+static const uint8 kFakeKeyId[] = { 0x4b, 0x65, 0x79, 0x20, 0x49, 0x44 };
+static const uint8 kFakeIv[DecryptConfig::kDecryptionKeySize] = { 0 };
+
+// Create a fake non-empty encrypted buffer.
+static scoped_refptr<DecoderBuffer> CreateFakeEncryptedBuffer() {
+ const int buffer_size = 16; // Need a non-empty buffer;
+ const int encrypted_frame_offset = 1; // This should be non-zero.
+ scoped_refptr<DecoderBuffer> buffer(new DecoderBuffer(buffer_size));
ddorwin 2012/09/28 17:36:40 Why?
xhwang 2012/09/30 19:58:51 Since the real decryptor is a mock, we don't reall
+ buffer->SetDecryptConfig(scoped_ptr<DecryptConfig>(new DecryptConfig(
+ std::string(reinterpret_cast<const char*>(kFakeKeyId),
+ arraysize(kFakeKeyId)),
+ std::string(reinterpret_cast<const char*>(kFakeIv),
+ DecryptConfig::kDecryptionKeySize),
ddorwin 2012/09/28 17:36:40 use arraysize() instead. It's not obvious this con
xhwang 2012/09/30 19:58:51 Done.
+ encrypted_frame_offset,
+ std::vector<SubsampleEntry>())));
+ return buffer;
+}
+
+ACTION_P(ReturnBuffer, buffer) {
+ arg0.Run(buffer ? DemuxerStream::kOk : DemuxerStream::kAborted, buffer);
+}
+
+ACTION(ReturnConfigChanged) {
+ arg0.Run(DemuxerStream::kConfigChanged, scoped_refptr<DecoderBuffer>(NULL));
+}
+
+ACTION_P(RunCallback1, param) {
+ arg1.Run(param);
+}
+
+ACTION_P2(RunCallback2, param1, param2) {
+ arg1.Run(param1, param2);
+}
+
+class DecryptingVideoDecoderTest : public testing::Test {
+ public:
+ DecryptingVideoDecoderTest()
+ : decryptor_(new StrictMock<MockDecryptor>()),
+ decoder_(NULL),
+ demuxer_(new StrictMock<MockDemuxerStream>()),
+ read_cb_(base::Bind(&DecryptingVideoDecoderTest::FrameReady,
+ base::Unretained(this))) {
+
+ decoder_ = new StrictMock<DecryptingVideoDecoder>(
ddorwin 2012/09/28 17:36:40 Why not done on 71?
xhwang 2012/09/30 19:58:51 Done.
+ base::Bind(&Identity<scoped_refptr<base::MessageLoopProxy> >,
+ message_loop_.message_loop_proxy()),
+ decryptor_.get());
+
+ // Initialize various test buffers.
+ encrypted_buffer_ = CreateFakeEncryptedBuffer();
+ end_of_stream_buffer_ = DecoderBuffer::CreateEOSBuffer();
+ decoded_video_frame_ = VideoFrame::CreateBlackFrame(kCodedSize);
+ }
+
+ virtual ~DecryptingVideoDecoderTest() {}
ddorwin 2012/09/28 17:36:40 Necessary?
xhwang 2012/09/30 19:58:51 Added Stop() as per http://codereview.chromium.org
+
+ void Initialize() {
+ EXPECT_CALL(*decryptor_, InitializeVideoDecoder(_, _))
+ .WillOnce(RunCallback1(true));
+
+ config_.Initialize(kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN, kVideoFormat,
+ kCodedSize, kVisibleRect, kNaturalSize,
+ NULL, 0, true, true);
+
+ InitializeWithConfig(config_);
+ }
+
+ void InitializeWithConfigAndStatus(const VideoDecoderConfig& config,
+ PipelineStatus status) {
+ EXPECT_CALL(*demuxer_, video_decoder_config())
+ .WillRepeatedly(ReturnRef(config));
+
+ decoder_->Initialize(demuxer_, NewExpectedStatusCB(status),
+ base::Bind(&MockStatisticsCB::OnStatistics,
+ base::Unretained(&statistics_cb_)));
+ message_loop_.RunAllPending();
+ }
+
+ void InitializeWithConfig(const VideoDecoderConfig& config) {
ddorwin 2012/09/28 17:36:40 This is only used once. Do we really need it to av
xhwang 2012/09/30 19:58:51 Done.
+ InitializeWithConfigAndStatus(config, PIPELINE_OK);
+ }
+
+ void RunPendingVideoDecodeCB() {
ddorwin 2012/09/28 17:36:40 Returns a NULL frame. that should probably be clea
xhwang 2012/09/30 19:58:51 Rename to Abort*
+ if (!video_decode_cb_.is_null()) {
+ base::ResetAndReturn(&video_decode_cb_).Run(
+ Decryptor::kSuccess, scoped_refptr<VideoFrame>(NULL));
+ }
+ }
+
+ void Reset() {
+ EXPECT_CALL(*decryptor_, CancelDecryptAndDecodeVideo())
+ .WillOnce(Invoke(this,
+ &DecryptingVideoDecoderTest::RunPendingVideoDecodeCB));
+
+ decoder_->Reset(NewExpectedClosure());
+ message_loop_.RunAllPending();
+ }
+
+ void Stop() {
+ EXPECT_CALL(*decryptor_, StopVideoDecoder())
+ .WillOnce(Invoke(this,
+ &DecryptingVideoDecoderTest::RunPendingVideoDecodeCB));
+
+ decoder_->Stop(NewExpectedClosure());
+ message_loop_.RunAllPending();
+ }
+
+ // Sets up expectations and actions to put DecryptingVideoDecoder in an active
+ // decoding state.
+ void EnterDecodingState() {
+ VideoDecoder::Status status;
ddorwin 2012/09/28 17:36:40 Should be initialized to non-expected value. Same
xhwang 2012/09/30 19:58:51 Fixed here and everywhere else.
+ scoped_refptr<VideoFrame> video_frame;
+ DecryptAndDecodeSingleFrame(encrypted_buffer_, &status, &video_frame);
+
+ EXPECT_EQ(VideoDecoder::kOk, status);
+ ASSERT_TRUE(video_frame);
+ EXPECT_FALSE(video_frame->IsEndOfStream());
+ }
+
+ // Sets up expectations and actions to put DecryptingVideoDecoder in an end
+ // of stream state.
+ void EnterEndOfStreamState() {
+ scoped_refptr<VideoFrame> video_frame;
+ VideoDecoder::Status status;
+ Read(&status, &video_frame);
+
+ EXPECT_EQ(VideoDecoder::kOk, status);
+ ASSERT_TRUE(video_frame);
+ EXPECT_TRUE(video_frame->IsEndOfStream());
+ }
+
+ // Decodes the single compressed frame in |buffer| and writes the
+ // uncompressed output to |video_frame|. This method works with single
+ // and multithreaded decoders. End of stream buffers are used to trigger
+ // the frame to be returned in the multithreaded decoder case.
+ void DecryptAndDecodeSingleFrame(const scoped_refptr<DecoderBuffer>& buffer,
+ VideoDecoder::Status* status,
+ scoped_refptr<VideoFrame>* video_frame) {
+ EXPECT_CALL(*demuxer_, Read(_))
+ .WillOnce(ReturnBuffer(buffer))
+ .WillRepeatedly(ReturnBuffer(end_of_stream_buffer_));
ddorwin 2012/09/28 17:36:40 Does end_of_stream_buffer_ need to be a member, or
xhwang 2012/09/30 19:58:51 Dropped end_of_stream_buffer_. But I need to keep
+
+ EXPECT_CALL(*decryptor_, DecryptAndDecodeVideo(_, _))
+ .WillOnce(RunCallback2(Decryptor::kSuccess, decoded_video_frame_))
+ .WillRepeatedly(RunCallback2(Decryptor::kSuccess,
+ VideoFrame::CreateEmptyFrame()));
+
ddorwin 2012/09/28 17:36:40 why newline here instead of after the last EXPECT_
xhwang 2012/09/30 19:58:51 Done.
+ EXPECT_CALL(statistics_cb_, OnStatistics(_));
+ Read(status, video_frame);
+ }
+
+ void Read(VideoDecoder::Status* status,
+ scoped_refptr<VideoFrame>* video_frame) {
+ EXPECT_CALL(*this, FrameReady(_, _))
+ .WillOnce(DoAll(SaveArg<0>(status), SaveArg<1>(video_frame)));
+
+ decoder_->Read(read_cb_);
+ message_loop_.RunAllPending();
+ }
+
+ MOCK_METHOD2(FrameReady, void(VideoDecoder::Status,
+ const scoped_refptr<VideoFrame>&));
+
+ MessageLoop message_loop_;
+ scoped_ptr<StrictMock<MockDecryptor> > decryptor_;
+ scoped_refptr<StrictMock<DecryptingVideoDecoder> > decoder_;
+ scoped_refptr<StrictMock<MockDemuxerStream> > demuxer_;
+ MockStatisticsCB statistics_cb_;
+ VideoDecoderConfig config_;
+
+ VideoDecoder::ReadCB read_cb_;
+ Decryptor::VideoDecodeCB video_decode_cb_;
+
+ scoped_refptr<DecoderBuffer> encrypted_buffer_;
+ scoped_refptr<DecoderBuffer> end_of_stream_buffer_;
+ scoped_refptr<VideoFrame> decoded_video_frame_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DecryptingVideoDecoderTest);
+};
+
+TEST_F(DecryptingVideoDecoderTest, Initialize_Normal) {
+ Initialize();
+}
+
+// Ensure that DecryptingVideoDecoder only acceptes encrypted video.
ddorwin 2012/09/28 17:36:40 accepts
xhwang 2012/09/30 19:58:51 Done.
+TEST_F(DecryptingVideoDecoderTest, Initialize_UnencryptedVideoConfig) {
+ VideoDecoderConfig config(kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN,
+ kVideoFormat,
+ kCodedSize, kVisibleRect, kNaturalSize,
+ NULL, 0, false);
+
+ InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
+}
+
+// Ensure decoder handles unsupported video configs without crashing.
ddorwin 2012/09/28 17:36:40 s/unsupported/invalid/
xhwang 2012/09/30 19:58:51 Done.
+TEST_F(DecryptingVideoDecoderTest, Initialize_InvalidVideoConfig) {
+ VideoDecoderConfig config(kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN,
+ VideoFrame::INVALID,
+ kCodedSize, kVisibleRect, kNaturalSize,
+ NULL, 0, true);
+
+ InitializeWithConfigAndStatus(config, PIPELINE_ERROR_DECODE);
+}
+
+// Ensure decoder handles unsupported video configs without crashing.
+TEST_F(DecryptingVideoDecoderTest, Initialize_UnsupportedVideoConfig) {
+ EXPECT_CALL(*decryptor_, InitializeVideoDecoder(_, _))
+ .WillOnce(RunCallback1(false));
+
+ VideoDecoderConfig config(kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN,
+ kVideoFormat,
+ kCodedSize, kVisibleRect, kNaturalSize,
+ NULL, 0, true);
+
+ InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
+}
+
+// Test normal decrypt and decode case.
+TEST_F(DecryptingVideoDecoderTest, DecryptAndDecode_Normal) {
+ Initialize();
+
+ // Simulate decoding a single frame.
+ VideoDecoder::Status status;
+ scoped_refptr<VideoFrame> video_frame;
+ DecryptAndDecodeSingleFrame(encrypted_buffer_, &status, &video_frame);
+
+ EXPECT_EQ(VideoDecoder::kOk, status);
+ ASSERT_TRUE(video_frame);
+ EXPECT_FALSE(video_frame->IsEndOfStream());
+}
+
+// Test the case where the decryptor returns error when doing decrypt and
+// decode.
+TEST_F(DecryptingVideoDecoderTest, DecryptAndDecode_DecodeError) {
+ Initialize();
+
+ EXPECT_CALL(*demuxer_, Read(_))
+ .WillRepeatedly(ReturnBuffer(encrypted_buffer_));
+
+ EXPECT_CALL(*decryptor_, DecryptAndDecodeVideo(_, _))
+ .WillRepeatedly(RunCallback2(Decryptor::kError,
+ scoped_refptr<VideoFrame>(NULL)));
+
+ VideoDecoder::Status status;
ddorwin 2012/09/28 17:36:40 init
xhwang 2012/09/30 19:58:51 Done.
+ scoped_refptr<VideoFrame> video_frame;
+ Read(&status, &video_frame);
+
+ EXPECT_EQ(VideoDecoder::kDecodeError, status);
+ EXPECT_FALSE(video_frame);
+}
+
+// Test the case where the decryptor does not have the decryption key to do
+// decrypt and decode.
+TEST_F(DecryptingVideoDecoderTest, DecryptAndDecode_NoKey) {
+ Initialize();
+
+ EXPECT_CALL(*demuxer_, Read(_))
+ .WillRepeatedly(ReturnBuffer(encrypted_buffer_));
+
+ EXPECT_CALL(*decryptor_, DecryptAndDecodeVideo(_, _))
+ .WillRepeatedly(RunCallback2(Decryptor::kNoKey,
+ scoped_refptr<VideoFrame>(NULL)));
+
+ VideoDecoder::Status status;
+ scoped_refptr<VideoFrame> video_frame;
+ Read(&status, &video_frame);
+
+ EXPECT_EQ(VideoDecoder::kDecodeError, status);
+ EXPECT_FALSE(video_frame);
+}
+
+// Test the case where the decryptor returns kNeedMoreData to ask for more
+// buffers before it can produce a frame.
+TEST_F(DecryptingVideoDecoderTest, DecryptAndDecode_NeedMoreData) {
+ Initialize();
+
+ EXPECT_CALL(*demuxer_, Read(_))
+ .Times(2)
+ .WillRepeatedly(ReturnBuffer(encrypted_buffer_));
+
+ EXPECT_CALL(*decryptor_, DecryptAndDecodeVideo(_, _))
+ .WillOnce(RunCallback2(Decryptor::kNeedMoreData,
+ scoped_refptr<VideoFrame>(NULL)))
+ .WillRepeatedly(RunCallback2(Decryptor::kSuccess, decoded_video_frame_));
+
+ EXPECT_CALL(statistics_cb_, OnStatistics(_))
+ .Times(2);
+
+ VideoDecoder::Status status;
+ scoped_refptr<VideoFrame> video_frame;
+ Read(&status, &video_frame);
+
+ EXPECT_EQ(VideoDecoder::kOk, status);
+ EXPECT_EQ(decoded_video_frame_, video_frame);
+}
+
+// Test the case where the decryptor receives end-of-stream buffer.
+TEST_F(DecryptingVideoDecoderTest, DecryptAndDecode_EndOfStream) {
+ Initialize();
+ EnterDecodingState();
+ EnterEndOfStreamState();
ddorwin 2012/09/28 17:36:40 Inconsistency: DecryptAndDecode_Normal could just
xhwang 2012/09/30 19:58:51 Changed DecryptAndDecode_Normal to use EnterDecodi
+}
+
+// Test resetting when decoder has initialized but has not decoded any frame.
+TEST_F(DecryptingVideoDecoderTest, Reset_Initialized) {
+ Initialize();
+ Reset();
+}
+
+// Test resetting when decoder has decoded single frame.
+TEST_F(DecryptingVideoDecoderTest, Reset_Decoding) {
+ Initialize();
+ EnterDecodingState();
+ Reset();
+}
+
+// Test resetting when decoder has hit end of stream.
+TEST_F(DecryptingVideoDecoderTest, Reset_EndOfStream) {
+ Initialize();
+ EnterDecodingState();
+ EnterEndOfStreamState();
+ Reset();
+}
ddorwin 2012/09/28 17:36:40 Test multiple Reset()s (and multiple Stop()s below
xhwang 2012/09/30 19:58:51 Done.
+
+// Test resetting when there is a pending read on the demuxer.
ddorwin 2012/09/28 17:36:40 What causes the read to be pending?
xhwang 2012/09/30 19:58:51 The read is pending because we save the read_cb_ i
+TEST_F(DecryptingVideoDecoderTest, Reset_DuringPendingRead) {
ddorwin 2012/09/28 17:36:40 Reset_DuringPendingDemuxerRead
xhwang 2012/09/30 19:58:51 Done.
+ Initialize();
+
+ DemuxerStream::ReadCB read_cb;
+ EXPECT_CALL(*demuxer_, Read(_))
+ .WillOnce(SaveArg<0>(&read_cb));
+ decoder_->Read(read_cb_);
+ message_loop_.RunAllPending();
+ // Make sure the Read() on the decoder triggers a Read() on the demuxer.
+ EXPECT_FALSE(read_cb.is_null());
+
+ Reset();
+
+ EXPECT_CALL(*this, FrameReady(VideoDecoder::kOk, IsNull()));
+ read_cb.Run(DemuxerStream::kOk, encrypted_buffer_);
+ message_loop_.RunAllPending();
+}
+
+// Test resetting when there is a pending decrypt on the decryptor.
ddorwin 2012/09/28 17:36:40 Same.
xhwang 2012/09/30 19:58:51 Done.
+TEST_F(DecryptingVideoDecoderTest, Reset_DuringPendingDecryptAndDecode) {
+ Initialize();
+
+ EXPECT_CALL(*demuxer_, Read(_))
+ .WillRepeatedly(ReturnBuffer(encrypted_buffer_));
+
+ EXPECT_CALL(*decryptor_, DecryptAndDecodeVideo(encrypted_buffer_, _))
+ .WillOnce(SaveArg<1>(&video_decode_cb_));
+
+ decoder_->Read(read_cb_);
+ message_loop_.RunAllPending();
+ // Make sure the Read() on the decoder triggers a DecryptAndDecode() on the
+ // decryptor.
+ EXPECT_FALSE(video_decode_cb_.is_null());
+
+ EXPECT_CALL(*this, FrameReady(VideoDecoder::kOk, IsNull()));
+ Reset();
+}
+
+// Test stopping when decoder has initialized but has not decoded any frame.
+TEST_F(DecryptingVideoDecoderTest, Stop_Initialized) {
+ Initialize();
+ Stop();
+}
+
+// Test stopping when decoder has decoded single frame.
+TEST_F(DecryptingVideoDecoderTest, Stop_Decoding) {
+ Initialize();
+ EnterDecodingState();
+ Stop();
+}
+
+// Test stopping when decoder has hit end of stream.
+TEST_F(DecryptingVideoDecoderTest, Stop_EndOfStream) {
+ Initialize();
+ EnterDecodingState();
+ EnterEndOfStreamState();
+ Stop();
+}
+
+// Test stopping when there is a pending read on the demuxer.
ddorwin 2012/09/28 17:36:40 Same question about how pending works here and bel
xhwang 2012/09/30 19:58:51 Done.
+TEST_F(DecryptingVideoDecoderTest, Stop_DuringPendingRead) {
+ Initialize();
+
+ DemuxerStream::ReadCB read_cb;
+ EXPECT_CALL(*demuxer_, Read(_))
+ .WillOnce(SaveArg<0>(&read_cb));
+
+ decoder_->Read(read_cb_);
+ message_loop_.RunAllPending();
+
+ // Make sure the Read() on the decoder triggers a Read() on the demuxer.
+ EXPECT_FALSE(read_cb.is_null());
+
+ Stop();
+
+ EXPECT_CALL(*this, FrameReady(VideoDecoder::kOk, IsNull()));
+
+ read_cb.Run(DemuxerStream::kOk, encrypted_buffer_);
+ message_loop_.RunAllPending();
+}
+
+// Test stopping when there is a pending decrypt on the decryptor.
+TEST_F(DecryptingVideoDecoderTest, Stop_DuringPendingDecryptAndDecode) {
+ Initialize();
+
+ EXPECT_CALL(*demuxer_, Read(_))
+ .WillRepeatedly(ReturnBuffer(encrypted_buffer_));
+
+ EXPECT_CALL(*decryptor_, DecryptAndDecodeVideo(encrypted_buffer_, _))
+ .WillOnce(SaveArg<1>(&video_decode_cb_));
+
+ decoder_->Read(read_cb_);
+ message_loop_.RunAllPending();
+ // Make sure the Read() on the decoder triggers a DecryptAndDecode() on the
+ // decryptor.
+ EXPECT_FALSE(video_decode_cb_.is_null());
+
+ EXPECT_CALL(*this, FrameReady(VideoDecoder::kOk, IsNull()));
+ Stop();
+}
+
+// Test aborted read on the demuxer stream.
ddorwin 2012/09/28 17:36:40 What makes it aborted?
xhwang 2012/09/30 19:58:51 Added comments.
+TEST_F(DecryptingVideoDecoderTest, AbortPendingRead) {
+ Initialize();
+
+ EXPECT_CALL(*demuxer_, Read(_))
+ .WillOnce(ReturnBuffer(scoped_refptr<DecoderBuffer>()));
+
+ VideoDecoder::Status status;
ddorwin 2012/09/28 17:36:40 init
xhwang 2012/09/30 19:58:51 Done.
+ scoped_refptr<VideoFrame> video_frame;
+
+ Read(&status, &video_frame);
+
+ EXPECT_EQ(VideoDecoder::kOk, status);
+ EXPECT_FALSE(video_frame);
+}
+
+// Test aborted read on the demuxer stream when the decoder is being reset.
+TEST_F(DecryptingVideoDecoderTest, AbortPendingReadDuringReset) {
+ Initialize();
+
+ // Issue Read on demuxer and save the ReadCB in |read_cb|.
+ DemuxerStream::ReadCB read_cb;
+ EXPECT_CALL(*demuxer_, Read(_))
+ .WillOnce(SaveArg<0>(&read_cb));
+ decoder_->Read(read_cb_);
+ message_loop_.RunAllPending();
ddorwin 2012/09/28 17:36:40 // Run so that the read_cb is obtained.
xhwang 2012/09/30 19:58:51 Done.
+ ASSERT_FALSE(read_cb.is_null());
+
+ Reset();
ddorwin 2012/09/28 17:36:40 Why Reset before aborting?
xhwang 2012/09/30 19:58:51 Reset cannot complete (pending) when read callback
+
+ // Signal an aborted demuxer read.
+ read_cb.Run(DemuxerStream::kAborted, NULL);
+
+ // Make sure we get a NULL video frame returned.
+ EXPECT_CALL(*this, FrameReady(VideoDecoder::kOk, IsNull()));
+ message_loop_.RunAllPending();
+}
+
+// Test config change on the demuxer stream.
+TEST_F(DecryptingVideoDecoderTest, ConfigChanged) {
+ Initialize();
+
+ EXPECT_CALL(*demuxer_, Read(_))
+ .WillOnce(ReturnConfigChanged());
+
+ VideoDecoder::Status status;
+ scoped_refptr<VideoFrame> video_frame;
+
+ Read(&status, &video_frame);
+ // TODO(xhwang): Update this test when kConfigChanged is supported in
+ // DecryptingVideoDecoder.
+ EXPECT_EQ(VideoDecoder::kDecodeError, status);
+ EXPECT_FALSE(video_frame);
+}
+
+} // namespace media

Powered by Google App Engine
This is Rietveld 408576698