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

Unified Diff: content/renderer/media/gpu/rtc_video_decoder_unittest.cc

Issue 2418613002: Proxy RtcVideoDecoder calls to a media::VideoDecoder.
Patch Set: Comments addressed and unittests updated. Created 4 years, 2 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: content/renderer/media/gpu/rtc_video_decoder_unittest.cc
diff --git a/content/renderer/media/gpu/rtc_video_decoder_unittest.cc b/content/renderer/media/gpu/rtc_video_decoder_unittest.cc
index 151e8fcb285357374854cc834e384f08a1c02c9f..2310cb858a7c052bc4799e43db68342925ef06ae 100644
--- a/content/renderer/media/gpu/rtc_video_decoder_unittest.cc
+++ b/content/renderer/media/gpu/rtc_video_decoder_unittest.cc
@@ -7,12 +7,16 @@
#include "base/bind.h"
#include "base/location.h"
+#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/synchronization/waitable_event.h"
+#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread.h"
#include "base/threading/thread_task_runner_handle.h"
#include "content/renderer/media/gpu/rtc_video_decoder.h"
#include "media/base/gmock_callback_support.h"
+#include "media/base/mock_filters.h"
+#include "media/filters/fake_video_decoder.h"
#include "media/renderers/mock_gpu_video_accelerator_factories.h"
#include "media/video/mock_video_decode_accelerator.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -33,10 +37,130 @@ namespace content {
namespace {
-static const int kMinResolutionWidth = 16;
-static const int kMinResolutionHeight = 16;
-static const int kMaxResolutionWidth = 1920;
-static const int kMaxResolutionHeight = 1088;
+const int kVideoFrameWidth = 1280;
+const int kVideoFrameHeight = 720;
+
+const int kMaxParallelVideoDecoderRequests = 4;
+
+void OnBytesDecoded(int numbytes) {}
+
+// This class creates and manages a thread to which tasks may be posted, and
+// which exposes BlockUntilTaskRunnerIdle(), allowing callers on other threads
+// to block until the thread this idle.
+// This is accomplished via two task runners on the underlying thread. Tasks may
+// be posted to the one returned by task_runner(), while another, which is
+// private to the implementation, pumps and controls the first. To the caller,
+// this interface appears as a Thread on which one can block.
+class ThreadHelper {
+ public:
+ explicit ThreadHelper(const std::string& thread_name);
+ ~ThreadHelper();
+
+ // Start the underlying thread. Return true on success. After this call,
+ // task_runner() will return a valid base::SingleThreadTaskRunner.
+ bool Start();
+
+ // Return true if the underlying thread is running, false otherwise.
+ bool IsRunning();
+
+ // Block the calling thread until task_runner() is idle. If tasks are posted
+ // to the task_runner() during execution of other tasks, those will run too.
+ // Thus, this call may never return.
+ void BlockUntilTaskRunnerIdle();
+
+ // Stop the underlying thread. task_runner() will return nullptr after this
+ // is called.
+ void Stop();
+
+ // Tasks may be posted to this task_runner. Will when this is not running,
+ // returns nullptr.
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner() const {
+ return postable_task_runner_;
+ }
+
+ private:
+ void StartPumping();
+ void Pump();
+ void StopPumping();
+
+ base::Thread thread_;
+ base::WaitableEvent waiter_;
+ bool pumping_ = false;
+ scoped_refptr<base::SingleThreadTaskRunner> control_task_runner_;
+ scoped_refptr<base::TestSimpleTaskRunner> postable_task_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThreadHelper);
+};
+
+ThreadHelper::ThreadHelper(const std::string& thread_name)
+ : thread_(thread_name),
+ waiter_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
+ base::WaitableEvent::InitialState::NOT_SIGNALED) {}
+
+ThreadHelper::~ThreadHelper() {
+ if (thread_.IsRunning())
+ Stop();
+}
+
+bool ThreadHelper::Start() {
+ if (!thread_.Start())
+ return false;
+ control_task_runner_ = thread_.task_runner();
+ control_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&ThreadHelper::StartPumping, base::Unretained(this)));
+ waiter_.Wait();
+ return true;
+}
+
+bool ThreadHelper::IsRunning() {
+ return thread_.IsRunning();
+}
+
+void ThreadHelper::BlockUntilTaskRunnerIdle() {
+ waiter_.Wait();
+}
+
+void ThreadHelper::Stop() {
+ BlockUntilTaskRunnerIdle();
+ control_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&ThreadHelper::StopPumping, base::Unretained(this)));
+ waiter_.Wait();
+ thread_.Stop();
+}
+
+// Start pumping the task_runner(), so that it executes tasks. Called in
+// Start(). Must be called on the |control_task_runner_|.
+void ThreadHelper::StartPumping() {
+ DCHECK(!postable_task_runner_);
+ postable_task_runner_ = new base::TestSimpleTaskRunner();
+ thread_.message_loop()->SetTaskRunner(postable_task_runner_);
+
+ // Start pumping.
+ pumping_ = true;
+ Pump();
+}
+
+// Recurring task which causes tasks posted to task_runner() to run.
+// BlockUntilTaskRunnerIdle() will block the calling thread while this is
+// running. Must be called on the |control_task_runner_|.
+void ThreadHelper::Pump() {
+ postable_task_runner_->RunUntilIdle();
+ if (pumping_) {
+ control_task_runner_->PostDelayedTask(
+ FROM_HERE, base::Bind(&ThreadHelper::Pump, base::Unretained(this)),
+ base::TimeDelta::FromMilliseconds(10));
+ }
+ waiter_.Signal();
+}
+
+// Stop pumping the task_runner(). Called in Stop(). Must be called on the
+// control_task_runner_|.
+void ThreadHelper::StopPumping() {
+ thread_.message_loop()->SetTaskRunner(control_task_runner_);
+ pumping_ = false;
+}
} // namespace
@@ -46,40 +170,17 @@ class RTCVideoDecoderTest
webrtc::DecodedImageCallback {
public:
RTCVideoDecoderTest()
- : mock_gpu_factories_(
- new media::MockGpuVideoAcceleratorFactories(nullptr)),
- vda_thread_("vda_thread"),
- idle_waiter_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
- base::WaitableEvent::InitialState::NOT_SIGNALED) {
+ : fake_video_decoder_(nullptr), video_decoder_thread_("decoder_thread") {
memset(&codec_, 0, sizeof(codec_));
}
void SetUp() override {
- ASSERT_TRUE(vda_thread_.Start());
- vda_task_runner_ = vda_thread_.task_runner();
- mock_vda_ = new media::MockVideoDecodeAccelerator;
-
- media::VideoDecodeAccelerator::SupportedProfile supported_profile;
- supported_profile.min_resolution.SetSize(kMinResolutionWidth,
- kMinResolutionHeight);
- supported_profile.max_resolution.SetSize(kMaxResolutionWidth,
- kMaxResolutionHeight);
- supported_profile.profile = media::H264PROFILE_MAIN;
- capabilities_.supported_profiles.push_back(supported_profile);
- supported_profile.profile = media::VP8PROFILE_ANY;
- capabilities_.supported_profiles.push_back(supported_profile);
-
- EXPECT_CALL(*mock_gpu_factories_.get(), GetTaskRunner())
- .WillRepeatedly(Return(vda_task_runner_));
- EXPECT_CALL(*mock_gpu_factories_.get(),
- GetVideoDecodeAcceleratorCapabilities())
- .WillRepeatedly(Return(capabilities_));
- EXPECT_CALL(*mock_gpu_factories_.get(), DoCreateVideoDecodeAccelerator())
- .WillRepeatedly(Return(mock_vda_));
- EXPECT_CALL(*mock_vda_, Initialize(_, _))
- .Times(1)
- .WillRepeatedly(Return(true));
- EXPECT_CALL(*mock_vda_, Destroy()).Times(1);
+ ASSERT_TRUE(video_decoder_thread_.Start());
+ video_decoder_task_runner_ = video_decoder_thread_.task_runner();
+
+ // If any frames are passed in, they should match these values.
+ codec_.width = kVideoFrameWidth;
+ codec_.height = kVideoFrameWidth;
#if defined(OS_WIN)
base::CommandLine::ForCurrentProcess()->AppendSwitch(
@@ -89,94 +190,85 @@ class RTCVideoDecoderTest
void TearDown() override {
DVLOG(2) << "TearDown";
- EXPECT_TRUE(vda_thread_.IsRunning());
- RunUntilIdle(); // Wait until all callbascks complete.
- vda_task_runner_->DeleteSoon(FROM_HERE, rtc_decoder_.release());
+ EXPECT_TRUE(video_decoder_thread_.IsRunning());
+ RTCVideoDecoder::Destroy(rtc_decoder_.release(),
+ video_decoder_task_runner_);
// Make sure the decoder is released before stopping the thread.
RunUntilIdle();
- vda_thread_.Stop();
+ video_decoder_thread_.Stop();
}
int32_t Decoded(webrtc::VideoFrame& decoded_image) override {
DVLOG(2) << "Decoded";
- EXPECT_EQ(vda_task_runner_, base::ThreadTaskRunnerHandle::Get());
+ EXPECT_EQ(video_decoder_task_runner_, base::ThreadTaskRunnerHandle::Get());
return WEBRTC_VIDEO_CODEC_OK;
}
void CreateDecoder(webrtc::VideoCodecType codec_type) {
DVLOG(2) << "CreateDecoder";
+
+ // If a decoder already exists, delete the old one.
+ if (rtc_decoder_) {
+ RTCVideoDecoder::Destroy(rtc_decoder_.release(),
+ video_decoder_task_runner_);
+ }
+
codec_.codecType = codec_type;
- rtc_decoder_ =
- RTCVideoDecoder::Create(codec_type, mock_gpu_factories_.get());
+ rtc_decoder_ = RTCVideoDecoder::Create(
+ codec_type, base::Bind(&RTCVideoDecoderTest::CreateFakeVideoDecoder,
+ base::Unretained(this)),
+ video_decoder_task_runner_);
+ RunUntilIdle();
}
void Initialize() {
DVLOG(2) << "Initialize";
+ DCHECK(rtc_decoder_);
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, rtc_decoder_->InitDecode(&codec_, 1));
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
rtc_decoder_->RegisterDecodeCompleteCallback(this));
}
- void NotifyResetDone() {
- DVLOG(2) << "NotifyResetDone";
- vda_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&RTCVideoDecoder::NotifyResetDone,
- base::Unretained(rtc_decoder_.get())));
- }
-
- void NotifyError(media::VideoDecodeAccelerator::Error error) {
- DVLOG(2) << "NotifyError";
- vda_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&RTCVideoDecoder::NotifyError,
- base::Unretained(rtc_decoder_.get()), error));
- }
-
+ // This function blocks the calling thread until |video_decoder_thread_| is
+ // idle.
void RunUntilIdle() {
DVLOG(2) << "RunUntilIdle";
- vda_task_runner_->PostTask(FROM_HERE,
- base::Bind(&base::WaitableEvent::Signal,
- base::Unretained(&idle_waiter_)));
- idle_waiter_.Wait();
- }
-
- void SetUpResetVDA() {
- mock_vda_after_reset_ = new media::MockVideoDecodeAccelerator;
- EXPECT_CALL(*mock_gpu_factories_.get(), DoCreateVideoDecodeAccelerator())
- .WillRepeatedly(Return(mock_vda_after_reset_));
- EXPECT_CALL(*mock_vda_after_reset_, Initialize(_, _))
- .Times(1)
- .WillRepeatedly(Return(true));
- EXPECT_CALL(*mock_vda_after_reset_, Destroy()).Times(1);
+ video_decoder_thread_.BlockUntilTaskRunnerIdle();
}
protected:
- std::unique_ptr<media::MockGpuVideoAcceleratorFactories> mock_gpu_factories_;
- media::MockVideoDecodeAccelerator* mock_vda_;
- media::MockVideoDecodeAccelerator* mock_vda_after_reset_;
+ media::FakeVideoDecoder* fake_video_decoder_;
std::unique_ptr<RTCVideoDecoder> rtc_decoder_;
webrtc::VideoCodec codec_;
- base::Thread vda_thread_;
- media::VideoDecodeAccelerator::Capabilities capabilities_;
+ scoped_refptr<base::SingleThreadTaskRunner> video_decoder_task_runner_;
private:
- scoped_refptr<base::SingleThreadTaskRunner> vda_task_runner_;
+ std::unique_ptr<media::VideoDecoder> CreateFakeVideoDecoder() {
+ std::unique_ptr<media::FakeVideoDecoder> fake_decoder(
+ new media::FakeVideoDecoder(0, /* decode_delay */
+ kMaxParallelVideoDecoderRequests,
+ base::Bind(&OnBytesDecoded)));
+ fake_video_decoder_ = fake_decoder.get();
+ return fake_decoder;
+ }
- base::Lock lock_;
- base::WaitableEvent idle_waiter_;
+ ThreadHelper video_decoder_thread_;
};
TEST_F(RTCVideoDecoderTest, CreateReturnsNullOnUnsupportedCodec) {
+ // VP8 is supported, so |rtc_decoder_| should be non-null.
CreateDecoder(webrtc::kVideoCodecVP8);
- std::unique_ptr<RTCVideoDecoder> null_rtc_decoder(RTCVideoDecoder::Create(
- webrtc::kVideoCodecI420, mock_gpu_factories_.get()));
- EXPECT_EQ(NULL, null_rtc_decoder.get());
+ EXPECT_NE(nullptr, rtc_decoder_.get());
+
+ // I420 is not supported, so |rtc_decoder_| should be null.
+ CreateDecoder(webrtc::kVideoCodecI420);
+ EXPECT_EQ(nullptr, rtc_decoder_.get());
}
-TEST_P(RTCVideoDecoderTest, CreateAndInitSucceeds) {
+TEST_P(RTCVideoDecoderTest, CreateAndInitSucceedsForSupportedCodec) {
const webrtc::VideoCodecType codec_type = GetParam();
CreateDecoder(codec_type);
+ ASSERT_NE(nullptr, rtc_decoder_.get());
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, rtc_decoder_->InitDecode(&codec_, 1));
}
@@ -216,110 +308,113 @@ TEST_F(RTCVideoDecoderTest, DecodeReturnsErrorOnMissingFrames) {
TEST_F(RTCVideoDecoderTest, ReleaseReturnsOk) {
CreateDecoder(webrtc::kVideoCodecVP8);
Initialize();
- EXPECT_CALL(*mock_vda_, Reset())
- .WillOnce(Invoke(this, &RTCVideoDecoderTest::NotifyResetDone));
+
+ // TODO(slan): Mock Reset() call here.
+
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, rtc_decoder_->Release());
}
TEST_F(RTCVideoDecoderTest, InitDecodeAfterRelease) {
CreateDecoder(webrtc::kVideoCodecVP8);
- EXPECT_CALL(*mock_vda_, Reset())
- .WillRepeatedly(Invoke(this, &RTCVideoDecoderTest::NotifyResetDone));
Initialize();
+
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, rtc_decoder_->Release());
Initialize();
- EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, rtc_decoder_->Release());
-}
-
-TEST_F(RTCVideoDecoderTest, IsBufferAfterReset) {
- CreateDecoder(webrtc::kVideoCodecVP8);
- EXPECT_TRUE(rtc_decoder_->IsBufferAfterReset(0, RTCVideoDecoder::ID_INVALID));
- EXPECT_TRUE(rtc_decoder_->IsBufferAfterReset(RTCVideoDecoder::ID_LAST,
- RTCVideoDecoder::ID_INVALID));
- EXPECT_FALSE(rtc_decoder_->IsBufferAfterReset(RTCVideoDecoder::ID_HALF - 2,
- RTCVideoDecoder::ID_HALF + 2));
- EXPECT_TRUE(rtc_decoder_->IsBufferAfterReset(RTCVideoDecoder::ID_HALF + 2,
- RTCVideoDecoder::ID_HALF - 2));
-
- EXPECT_FALSE(rtc_decoder_->IsBufferAfterReset(0, 0));
- EXPECT_TRUE(rtc_decoder_->IsBufferAfterReset(0, RTCVideoDecoder::ID_LAST));
- EXPECT_FALSE(
- rtc_decoder_->IsBufferAfterReset(0, RTCVideoDecoder::ID_HALF - 2));
- EXPECT_TRUE(
- rtc_decoder_->IsBufferAfterReset(0, RTCVideoDecoder::ID_HALF + 2));
-
- EXPECT_FALSE(rtc_decoder_->IsBufferAfterReset(RTCVideoDecoder::ID_LAST, 0));
- EXPECT_FALSE(rtc_decoder_->IsBufferAfterReset(RTCVideoDecoder::ID_LAST,
- RTCVideoDecoder::ID_HALF - 2));
- EXPECT_TRUE(rtc_decoder_->IsBufferAfterReset(RTCVideoDecoder::ID_LAST,
- RTCVideoDecoder::ID_HALF + 2));
- EXPECT_FALSE(rtc_decoder_->IsBufferAfterReset(RTCVideoDecoder::ID_LAST,
- RTCVideoDecoder::ID_LAST));
-}
-TEST_F(RTCVideoDecoderTest, IsFirstBufferAfterReset) {
- CreateDecoder(webrtc::kVideoCodecVP8);
- EXPECT_TRUE(
- rtc_decoder_->IsFirstBufferAfterReset(0, RTCVideoDecoder::ID_INVALID));
- EXPECT_FALSE(
- rtc_decoder_->IsFirstBufferAfterReset(1, RTCVideoDecoder::ID_INVALID));
- EXPECT_FALSE(rtc_decoder_->IsFirstBufferAfterReset(0, 0));
- EXPECT_TRUE(rtc_decoder_->IsFirstBufferAfterReset(1, 0));
- EXPECT_FALSE(rtc_decoder_->IsFirstBufferAfterReset(2, 0));
-
- EXPECT_FALSE(rtc_decoder_->IsFirstBufferAfterReset(RTCVideoDecoder::ID_HALF,
- RTCVideoDecoder::ID_HALF));
- EXPECT_TRUE(rtc_decoder_->IsFirstBufferAfterReset(
- RTCVideoDecoder::ID_HALF + 1, RTCVideoDecoder::ID_HALF));
- EXPECT_FALSE(rtc_decoder_->IsFirstBufferAfterReset(
- RTCVideoDecoder::ID_HALF + 2, RTCVideoDecoder::ID_HALF));
-
- EXPECT_FALSE(rtc_decoder_->IsFirstBufferAfterReset(RTCVideoDecoder::ID_LAST,
- RTCVideoDecoder::ID_LAST));
- EXPECT_TRUE(
- rtc_decoder_->IsFirstBufferAfterReset(0, RTCVideoDecoder::ID_LAST));
- EXPECT_FALSE(
- rtc_decoder_->IsFirstBufferAfterReset(1, RTCVideoDecoder::ID_LAST));
+ EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, rtc_decoder_->Release());
}
// Tests/Verifies that |rtc_encoder_| drops incoming frames and its error
// counter is increased when in an error condition.
-TEST_P(RTCVideoDecoderTest, GetVDAErrorCounterForTesting) {
+TEST_P(RTCVideoDecoderTest, GetDecoderErrorCounterForTesting) {
const webrtc::VideoCodecType codec_type = GetParam();
CreateDecoder(codec_type);
Initialize();
- webrtc::EncodedImage input_image;
+ // Hold the next decode, so that we can trigger an error.
+ ASSERT_NE(nullptr, fake_video_decoder_);
+ video_decoder_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&media::FakeVideoDecoder::HoldDecode,
+ base::Unretained(fake_video_decoder_)));
+ RunUntilIdle();
+
+ // Send a valid key frame to the decoder.
+ uint8_t buffer[kVideoFrameWidth * kVideoFrameHeight];
+ webrtc::EncodedImage input_image(buffer, sizeof(buffer), sizeof(buffer));
input_image._completeFrame = true;
- input_image._encodedWidth = kMinResolutionWidth;
- input_image._encodedHeight = kMaxResolutionHeight;
- input_image._frameType = webrtc::kVideoFrameDelta;
- input_image._length = kMinResolutionWidth * kMaxResolutionHeight;
- EXPECT_EQ(WEBRTC_VIDEO_CODEC_ERROR,
+ input_image._encodedWidth = kVideoFrameWidth;
+ input_image._encodedHeight = kVideoFrameHeight;
+ input_image._frameType = webrtc::kVideoFrameKey;
+ EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
rtc_decoder_->Decode(input_image, false, nullptr, nullptr, 0));
- RunUntilIdle();
- // Notify the decoder about a platform error.
- NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE);
+ // Simulate an error from the decoder. This will run the held decode callback
+ // with DECODE_ERROR.
+ video_decoder_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&media::FakeVideoDecoder::SimulateError,
+ base::Unretained(fake_video_decoder_)));
RunUntilIdle();
- EXPECT_EQ(1, rtc_decoder_->GetVDAErrorCounterForTesting());
+ EXPECT_EQ(1, rtc_decoder_->GetDecoderErrorCounterForTesting());
+
+ // We will continue to push this frame, but each one will not be a key frame.
+ input_image._frameType = webrtc::kVideoFrameDelta;
- // Expect decode call to reset decoder, and set up a new VDA to track it.
- SetUpResetVDA();
+ // This should trigger a Reset() on the decoder.
EXPECT_EQ(WEBRTC_VIDEO_CODEC_ERROR,
rtc_decoder_->Decode(input_image, false, nullptr, nullptr, 0));
- EXPECT_EQ(1, rtc_decoder_->GetVDAErrorCounterForTesting());
+ EXPECT_EQ(1, rtc_decoder_->GetDecoderErrorCounterForTesting());
// Decoder expects a keyframe after reset, so drops any other frames. However,
// we should still increment the error counter.
EXPECT_EQ(WEBRTC_VIDEO_CODEC_ERROR,
rtc_decoder_->Decode(input_image, false, nullptr, nullptr, 0));
- EXPECT_EQ(2, rtc_decoder_->GetVDAErrorCounterForTesting());
+ EXPECT_EQ(2, rtc_decoder_->GetDecoderErrorCounterForTesting());
+}
+
+// Verify that there are never more than GetMaxDecodeRequests() issued to the
+// decoder concurrently.
+TEST_F(RTCVideoDecoderTest, MaxNumberOfRequestsIsNotExceeded) {
+ CreateDecoder(webrtc::kVideoCodecVP8);
+ Initialize();
+
+ // Hold incoming decode requests.
+ ASSERT_NE(nullptr, fake_video_decoder_);
+ video_decoder_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&media::FakeVideoDecoder::HoldDecode,
+ base::Unretained(fake_video_decoder_)));
+ RunUntilIdle();
+
+ uint8_t buffer[kVideoFrameWidth * kVideoFrameHeight];
+ webrtc::EncodedImage input_image(buffer, sizeof(buffer), sizeof(buffer));
+ input_image._completeFrame = true;
+ input_image._encodedWidth = kVideoFrameWidth;
+ input_image._encodedHeight = kVideoFrameHeight;
+ input_image._frameType = webrtc::kVideoFrameKey;
+
+ // Determine how many concurrent decode requests the remote decoder can
+ // handle, and send more than that into the RTCVideoDecoder. Frames
+ // should buffer until the remote decoder calls back.
+ const int numRequests = fake_video_decoder_->GetMaxDecodeRequests();
+ EXPECT_EQ(kMaxParallelVideoDecoderRequests, numRequests);
+ for (int i = 0; i < numRequests + 1; ++i) {
+ if (i > 0)
+ input_image._frameType = webrtc::kVideoFrameDelta;
+ EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
+ rtc_decoder_->Decode(input_image, false, nullptr, nullptr, 0));
+ }
+ RunUntilIdle();
+
+ // Release the pending decodes.
+ video_decoder_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&media::FakeVideoDecoder::SatisfyDecode,
+ base::Unretained(fake_video_decoder_)));
+ RunUntilIdle();
}
INSTANTIATE_TEST_CASE_P(CodecProfiles,
RTCVideoDecoderTest,
Values(webrtc::kVideoCodecVP8,
+ webrtc::kVideoCodecVP9,
webrtc::kVideoCodecH264));
} // content

Powered by Google App Engine
This is Rietveld 408576698