diff options
Diffstat (limited to '')
-rw-r--r-- | third_party/libwebrtc/test/testsupport/ivf_video_frame_generator_unittest.cc | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/third_party/libwebrtc/test/testsupport/ivf_video_frame_generator_unittest.cc b/third_party/libwebrtc/test/testsupport/ivf_video_frame_generator_unittest.cc new file mode 100644 index 0000000000..dd60f3d3fc --- /dev/null +++ b/third_party/libwebrtc/test/testsupport/ivf_video_frame_generator_unittest.cc @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2019 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 "test/testsupport/ivf_video_frame_generator.h" + +#include <memory> +#include <vector> + +#include "absl/types/optional.h" +#include "api/test/create_frame_generator.h" +#include "api/units/time_delta.h" +#include "api/video/encoded_image.h" +#include "api/video/video_codec_type.h" +#include "api/video_codecs/video_codec.h" +#include "api/video_codecs/video_encoder.h" +#include "common_video/libyuv/include/webrtc_libyuv.h" +#include "media/base/codec.h" +#include "media/base/media_constants.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/video_coding/codecs/vp8/include/vp8.h" +#include "modules/video_coding/codecs/vp9/include/vp9.h" +#include "modules/video_coding/include/video_error_codes.h" +#include "modules/video_coding/utility/ivf_file_writer.h" +#include "rtc_base/event.h" +#include "test/gtest.h" +#include "test/testsupport/file_utils.h" +#include "test/video_codec_settings.h" + +#if defined(WEBRTC_USE_H264) +#include "modules/video_coding/codecs/h264/include/h264.h" +#include "rtc_base/synchronization/mutex.h" + +#endif + +namespace webrtc { +namespace test { +namespace { + +constexpr int kWidth = 320; +constexpr int kHeight = 240; +constexpr int kVideoFramesCount = 30; +constexpr int kMaxFramerate = 30; +constexpr TimeDelta kMaxFrameEncodeWaitTimeout = TimeDelta::Seconds(2); +static const VideoEncoder::Capabilities kCapabilities(false); + +#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) || defined(WEBRTC_ARCH_ARM64) +constexpr double kExpectedMinPsnr = 35; +#else +constexpr double kExpectedMinPsnr = 39; +#endif + +class IvfFileWriterEncodedCallback : public EncodedImageCallback { + public: + IvfFileWriterEncodedCallback(const std::string& file_name, + VideoCodecType video_codec_type, + int expected_frames_count) + : file_writer_( + IvfFileWriter::Wrap(FileWrapper::OpenWriteOnly(file_name), 0)), + video_codec_type_(video_codec_type), + expected_frames_count_(expected_frames_count) { + EXPECT_TRUE(file_writer_.get()); + } + ~IvfFileWriterEncodedCallback() { EXPECT_TRUE(file_writer_->Close()); } + + Result OnEncodedImage(const EncodedImage& encoded_image, + const CodecSpecificInfo* codec_specific_info) override { + EXPECT_TRUE(file_writer_->WriteFrame(encoded_image, video_codec_type_)); + + MutexLock lock(&lock_); + received_frames_count_++; + RTC_CHECK_LE(received_frames_count_, expected_frames_count_); + if (received_frames_count_ == expected_frames_count_) { + expected_frames_count_received_.Set(); + } + return Result(Result::Error::OK); + } + + bool WaitForExpectedFramesReceived(TimeDelta timeout) { + return expected_frames_count_received_.Wait(timeout); + } + + private: + std::unique_ptr<IvfFileWriter> file_writer_; + const VideoCodecType video_codec_type_; + const int expected_frames_count_; + + Mutex lock_; + int received_frames_count_ RTC_GUARDED_BY(lock_) = 0; + rtc::Event expected_frames_count_received_; +}; + +class IvfVideoFrameGeneratorTest : public ::testing::Test { + protected: + void SetUp() override { + file_name_ = + webrtc::test::TempFilename(webrtc::test::OutputPath(), "test_file.ivf"); + } + void TearDown() override { webrtc::test::RemoveFile(file_name_); } + + VideoFrame BuildFrame(FrameGeneratorInterface::VideoFrameData frame_data) { + return VideoFrame::Builder() + .set_video_frame_buffer(frame_data.buffer) + .set_update_rect(frame_data.update_rect) + .build(); + } + + void CreateTestVideoFile(VideoCodecType video_codec_type, + std::unique_ptr<VideoEncoder> video_encoder) { + std::unique_ptr<test::FrameGeneratorInterface> frame_generator = + test::CreateSquareFrameGenerator( + kWidth, kHeight, test::FrameGeneratorInterface::OutputType::kI420, + absl::nullopt); + + VideoCodec codec_settings; + webrtc::test::CodecSettings(video_codec_type, &codec_settings); + codec_settings.width = kWidth; + codec_settings.height = kHeight; + codec_settings.maxFramerate = kMaxFramerate; + const uint32_t kBitrateBps = 500000; + VideoBitrateAllocation bitrate_allocation; + bitrate_allocation.SetBitrate(0, 0, kBitrateBps); + + IvfFileWriterEncodedCallback ivf_writer_callback( + file_name_, video_codec_type, kVideoFramesCount); + + video_encoder->RegisterEncodeCompleteCallback(&ivf_writer_callback); + video_encoder->SetRates(VideoEncoder::RateControlParameters( + bitrate_allocation, static_cast<double>(codec_settings.maxFramerate))); + ASSERT_EQ(WEBRTC_VIDEO_CODEC_OK, + video_encoder->InitEncode( + &codec_settings, + VideoEncoder::Settings(kCapabilities, /*number_of_cores=*/1, + /*max_payload_size=*/0))); + + uint32_t last_frame_timestamp = 0; + + for (int i = 0; i < kVideoFramesCount; ++i) { + VideoFrame frame = BuildFrame(frame_generator->NextFrame()); + const uint32_t timestamp = + last_frame_timestamp + + kVideoPayloadTypeFrequency / codec_settings.maxFramerate; + frame.set_timestamp(timestamp); + + last_frame_timestamp = timestamp; + + ASSERT_EQ(WEBRTC_VIDEO_CODEC_OK, video_encoder->Encode(frame, nullptr)); + video_frames_.push_back(frame); + } + + ASSERT_TRUE(ivf_writer_callback.WaitForExpectedFramesReceived( + kMaxFrameEncodeWaitTimeout)); + } + + std::string file_name_; + std::vector<VideoFrame> video_frames_; +}; + +} // namespace + +TEST_F(IvfVideoFrameGeneratorTest, Vp8) { + CreateTestVideoFile(VideoCodecType::kVideoCodecVP8, VP8Encoder::Create()); + IvfVideoFrameGenerator generator(file_name_); + for (size_t i = 0; i < video_frames_.size(); ++i) { + auto& expected_frame = video_frames_[i]; + VideoFrame actual_frame = BuildFrame(generator.NextFrame()); + EXPECT_GT(I420PSNR(&expected_frame, &actual_frame), kExpectedMinPsnr); + } +} + +TEST_F(IvfVideoFrameGeneratorTest, Vp8DoubleRead) { + CreateTestVideoFile(VideoCodecType::kVideoCodecVP8, VP8Encoder::Create()); + IvfVideoFrameGenerator generator(file_name_); + for (size_t i = 0; i < video_frames_.size() * 2; ++i) { + auto& expected_frame = video_frames_[i % video_frames_.size()]; + VideoFrame actual_frame = BuildFrame(generator.NextFrame()); + EXPECT_GT(I420PSNR(&expected_frame, &actual_frame), kExpectedMinPsnr); + } +} + +TEST_F(IvfVideoFrameGeneratorTest, Vp9) { + CreateTestVideoFile(VideoCodecType::kVideoCodecVP9, VP9Encoder::Create()); + IvfVideoFrameGenerator generator(file_name_); + for (size_t i = 0; i < video_frames_.size(); ++i) { + auto& expected_frame = video_frames_[i]; + VideoFrame actual_frame = BuildFrame(generator.NextFrame()); + EXPECT_GT(I420PSNR(&expected_frame, &actual_frame), kExpectedMinPsnr); + } +} + +#if defined(WEBRTC_USE_H264) +TEST_F(IvfVideoFrameGeneratorTest, H264) { + CreateTestVideoFile( + VideoCodecType::kVideoCodecH264, + H264Encoder::Create(cricket::VideoCodec(cricket::kH264CodecName))); + IvfVideoFrameGenerator generator(file_name_); + for (size_t i = 0; i < video_frames_.size(); ++i) { + auto& expected_frame = video_frames_[i]; + VideoFrame actual_frame = BuildFrame(generator.NextFrame()); + EXPECT_GT(I420PSNR(&expected_frame, &actual_frame), kExpectedMinPsnr); + } +} +#endif + +} // namespace test +} // namespace webrtc |