| Index: webrtc/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc
|
| diff --git a/webrtc/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc b/webrtc/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..fd4cbfd3bc787e0bf48c3c08c8e081d3541642db
|
| --- /dev/null
|
| +++ b/webrtc/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc
|
| @@ -0,0 +1,201 @@
|
| +/*
|
| + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
|
| + *
|
| + * Use of this source code is governed by a BSD-style license
|
| + * that can be found in the LICENSE file in the root of the source
|
| + * tree. An additional intellectual property rights grant can be found
|
| + * in the file PATENTS. All contributing project authors may
|
| + * be found in the AUTHORS file in the root of the source tree.
|
| + */
|
| +
|
| +#include "webrtc/base/criticalsection.h"
|
| +#include "webrtc/base/event.h"
|
| +#include "webrtc/base/thread_annotations.h"
|
| +#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
|
| +#include "webrtc/modules/video_coding/codecs/vp9/include/vp9.h"
|
| +#include "webrtc/test/frame_utils.h"
|
| +#include "webrtc/test/gtest.h"
|
| +#include "webrtc/test/testsupport/fileutils.h"
|
| +
|
| +namespace webrtc {
|
| +
|
| +static const int kEncodeTimeoutMs = 100;
|
| +static const int kDecodeTimeoutMs = 25;
|
| +// Set a start bitrate to get higher quality.
|
| +static const int kStartBitrate = 300;
|
| +static const int kWidth = 172; // Width of the input image.
|
| +static const int kHeight = 144; // Height of the input image.
|
| +static const int kMaxFramerate = 30; // Arbitrary value.
|
| +
|
| +class TestVp9Impl : public ::testing::Test {
|
| + public:
|
| + TestVp9Impl()
|
| + : encode_complete_callback_(this),
|
| + decode_complete_callback_(this),
|
| + encoded_frame_event_(false /* manual reset */,
|
| + false /* initially signaled */),
|
| + decoded_frame_event_(false /* manual reset */,
|
| + false /* initially signaled */) {}
|
| +
|
| + protected:
|
| + class FakeEncodeCompleteCallback : public webrtc::EncodedImageCallback {
|
| + public:
|
| + explicit FakeEncodeCompleteCallback(TestVp9Impl* test) : test_(test) {}
|
| +
|
| + Result OnEncodedImage(const EncodedImage& frame,
|
| + const CodecSpecificInfo* codec_specific_info,
|
| + const RTPFragmentationHeader* fragmentation) {
|
| + rtc::CritScope lock(&test_->encoded_frame_section_);
|
| + test_->encoded_frame_ = rtc::Optional<EncodedImage>(frame);
|
| + test_->encoded_frame_event_.Set();
|
| + return Result(Result::OK);
|
| + }
|
| +
|
| + private:
|
| + TestVp9Impl* const test_;
|
| + };
|
| +
|
| + class FakeDecodeCompleteCallback : public webrtc::DecodedImageCallback {
|
| + public:
|
| + explicit FakeDecodeCompleteCallback(TestVp9Impl* test) : test_(test) {}
|
| +
|
| + int32_t Decoded(VideoFrame& frame) override {
|
| + RTC_NOTREACHED();
|
| + return -1;
|
| + }
|
| + int32_t Decoded(VideoFrame& frame, int64_t decode_time_ms) override {
|
| + RTC_NOTREACHED();
|
| + return -1;
|
| + }
|
| + void Decoded(VideoFrame& frame,
|
| + rtc::Optional<int32_t> decode_time_ms,
|
| + rtc::Optional<uint8_t> qp) override {
|
| + rtc::CritScope lock(&test_->decoded_frame_section_);
|
| + test_->decoded_frame_ = rtc::Optional<VideoFrame>(frame);
|
| + test_->decoded_qp_ = qp;
|
| + test_->decoded_frame_event_.Set();
|
| + }
|
| +
|
| + private:
|
| + TestVp9Impl* const test_;
|
| + };
|
| +
|
| + void SetUp() override {
|
| + // Using a QCIF image. Processing only one frame.
|
| + FILE* source_file_ =
|
| + fopen(test::ResourcePath("paris_qcif", "yuv").c_str(), "rb");
|
| + ASSERT_TRUE(source_file_ != NULL);
|
| + rtc::scoped_refptr<VideoFrameBuffer> video_frame_buffer(
|
| + test::ReadI420Buffer(kWidth, kHeight, source_file_));
|
| + input_frame_.reset(new VideoFrame(video_frame_buffer, kVideoRotation_0, 0));
|
| + fclose(source_file_);
|
| +
|
| + encoder_.reset(VP9Encoder::Create());
|
| + decoder_.reset(VP9Decoder::Create());
|
| + encoder_->RegisterEncodeCompleteCallback(&encode_complete_callback_);
|
| + decoder_->RegisterDecodeCompleteCallback(&decode_complete_callback_);
|
| +
|
| + InitCodecs();
|
| + }
|
| +
|
| + void InitCodecs() {
|
| + VideoCodec codec_inst_;
|
| + codec_inst_.startBitrate = kStartBitrate;
|
| + codec_inst_.codecType = webrtc::kVideoCodecVP9;
|
| + codec_inst_.maxFramerate = kMaxFramerate;
|
| + codec_inst_.width = kWidth;
|
| + codec_inst_.height = kHeight;
|
| + codec_inst_.VP9()->numberOfTemporalLayers = 1;
|
| + codec_inst_.VP9()->numberOfSpatialLayers = 1;
|
| + EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
|
| + encoder_->InitEncode(&codec_inst_, 1 /* number of cores */,
|
| + 0 /* max payload size (unused) */));
|
| + EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
|
| + decoder_->InitDecode(&codec_inst_, 1 /* number of cores */));
|
| + }
|
| +
|
| + bool WaitForEncodedFrame(EncodedImage* frame) {
|
| + bool ret = encoded_frame_event_.Wait(kEncodeTimeoutMs);
|
| + EXPECT_TRUE(ret) << "Timed out while waiting for an encoded frame.";
|
| + // This becomes unsafe if there are multiple threads waiting for frames.
|
| + rtc::CritScope lock(&encoded_frame_section_);
|
| + EXPECT_TRUE(encoded_frame_);
|
| + if (encoded_frame_) {
|
| + *frame = std::move(*encoded_frame_);
|
| + encoded_frame_.reset();
|
| + return true;
|
| + } else {
|
| + return false;
|
| + }
|
| + }
|
| +
|
| + bool WaitForDecodedFrame(std::unique_ptr<VideoFrame>* frame,
|
| + rtc::Optional<uint8_t>* qp) {
|
| + bool ret = decoded_frame_event_.Wait(kDecodeTimeoutMs);
|
| + EXPECT_TRUE(ret) << "Timed out while waiting for a decoded frame.";
|
| + // This becomes unsafe if there are multiple threads waiting for frames.
|
| + rtc::CritScope lock(&decoded_frame_section_);
|
| + EXPECT_TRUE(decoded_frame_);
|
| + if (decoded_frame_) {
|
| + frame->reset(new VideoFrame(std::move(*decoded_frame_)));
|
| + *qp = decoded_qp_;
|
| + decoded_frame_.reset();
|
| + return true;
|
| + } else {
|
| + return false;
|
| + }
|
| + }
|
| +
|
| + std::unique_ptr<VideoFrame> input_frame_;
|
| +
|
| + std::unique_ptr<VideoEncoder> encoder_;
|
| + std::unique_ptr<VideoDecoder> decoder_;
|
| +
|
| + private:
|
| + FakeEncodeCompleteCallback encode_complete_callback_;
|
| + FakeDecodeCompleteCallback decode_complete_callback_;
|
| +
|
| + rtc::Event encoded_frame_event_;
|
| + rtc::CriticalSection encoded_frame_section_;
|
| + rtc::Optional<EncodedImage> encoded_frame_ GUARDED_BY(encoded_frame_section_);
|
| +
|
| + rtc::Event decoded_frame_event_;
|
| + rtc::CriticalSection decoded_frame_section_;
|
| + rtc::Optional<VideoFrame> decoded_frame_ GUARDED_BY(decoded_frame_section_);
|
| + rtc::Optional<uint8_t> decoded_qp_ GUARDED_BY(decoded_frame_section_);
|
| +};
|
| +
|
| +TEST_F(TestVp9Impl, EncodeDecode) {
|
| + EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
|
| + encoder_->Encode(*input_frame_, nullptr, nullptr));
|
| + EncodedImage encoded_frame;
|
| + ASSERT_TRUE(WaitForEncodedFrame(&encoded_frame));
|
| + // First frame should be a key frame.
|
| + encoded_frame._frameType = kVideoFrameKey;
|
| + EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
|
| + decoder_->Decode(encoded_frame, false, nullptr));
|
| + std::unique_ptr<VideoFrame> decoded_frame;
|
| + rtc::Optional<uint8_t> decoded_qp;
|
| + ASSERT_TRUE(WaitForDecodedFrame(&decoded_frame, &decoded_qp));
|
| + ASSERT_TRUE(decoded_frame);
|
| + EXPECT_GT(I420PSNR(input_frame_.get(), decoded_frame.get()), 36);
|
| +}
|
| +
|
| +TEST_F(TestVp9Impl, DecodedQpEqualsEncodedQp) {
|
| + EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
|
| + encoder_->Encode(*input_frame_, nullptr, nullptr));
|
| + EncodedImage encoded_frame;
|
| + ASSERT_TRUE(WaitForEncodedFrame(&encoded_frame));
|
| + // First frame should be a key frame.
|
| + encoded_frame._frameType = kVideoFrameKey;
|
| + EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
|
| + decoder_->Decode(encoded_frame, false, nullptr));
|
| + std::unique_ptr<VideoFrame> decoded_frame;
|
| + rtc::Optional<uint8_t> decoded_qp;
|
| + ASSERT_TRUE(WaitForDecodedFrame(&decoded_frame, &decoded_qp));
|
| + ASSERT_TRUE(decoded_frame);
|
| + ASSERT_TRUE(decoded_qp);
|
| + EXPECT_EQ(encoded_frame.qp_, *decoded_qp);
|
| +}
|
| +
|
| +} // namespace webrtc
|
|
|