/* * 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 "modules/video_coding/codecs/test/video_codec_unittest.h" #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" #include "modules/video_coding/include/video_error_codes.h" #include "test/video_codec_settings.h" static const int kEncodeTimeoutMs = 100; static const int kDecodeTimeoutMs = 25; // Set bitrate to get higher quality. static const int kStartBitrate = 300; static const int kMaxBitrate = 4000; static const int kWidth = 176; // Width of the input image. static const int kHeight = 144; // Height of the input image. static const int kMaxFramerate = 30; // Arbitrary value. namespace webrtc { EncodedImageCallback::Result VideoCodecUnitTest::FakeEncodeCompleteCallback::OnEncodedImage( const EncodedImage& frame, const CodecSpecificInfo* codec_specific_info, const RTPFragmentationHeader* fragmentation) { rtc::CritScope lock(&test_->encoded_frame_section_); test_->encoded_frames_.push_back(frame); RTC_DCHECK(codec_specific_info); test_->codec_specific_infos_.push_back(*codec_specific_info); if (!test_->wait_for_encoded_frames_threshold_) { test_->encoded_frame_event_.Set(); return Result(Result::OK); } if (test_->encoded_frames_.size() == test_->wait_for_encoded_frames_threshold_) { test_->wait_for_encoded_frames_threshold_ = 1; test_->encoded_frame_event_.Set(); } return Result(Result::OK); } void VideoCodecUnitTest::FakeDecodeCompleteCallback::Decoded( VideoFrame& frame, absl::optional decode_time_ms, absl::optional qp) { rtc::CritScope lock(&test_->decoded_frame_section_); test_->decoded_frame_.emplace(frame); test_->decoded_qp_ = qp; test_->decoded_frame_event_.Set(); } void VideoCodecUnitTest::SetUp() { webrtc::test::CodecSettings(kVideoCodecVP8, &codec_settings_); codec_settings_.startBitrate = kStartBitrate; codec_settings_.maxBitrate = kMaxBitrate; codec_settings_.maxFramerate = kMaxFramerate; codec_settings_.width = kWidth; codec_settings_.height = kHeight; ModifyCodecSettings(&codec_settings_); input_frame_generator_ = test::FrameGenerator::CreateSquareGenerator( codec_settings_.width, codec_settings_.height, absl::optional(), absl::optional()); encoder_ = CreateEncoder(); decoder_ = CreateDecoder(); encoder_->RegisterEncodeCompleteCallback(&encode_complete_callback_); decoder_->RegisterDecodeCompleteCallback(&decode_complete_callback_); EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, encoder_->InitEncode(&codec_settings_, 1 /* number of cores */, 0 /* max payload size (unused) */)); EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, decoder_->InitDecode(&codec_settings_, 1 /* number of cores */)); } void VideoCodecUnitTest::ModifyCodecSettings(VideoCodec* codec_settings) {} VideoFrame* VideoCodecUnitTest::NextInputFrame() { VideoFrame* input_frame = input_frame_generator_->NextFrame(); const uint32_t timestamp = last_input_frame_timestamp_ + kVideoPayloadTypeFrequency / codec_settings_.maxFramerate; input_frame->set_timestamp(timestamp); last_input_frame_timestamp_ = timestamp; return input_frame; } bool VideoCodecUnitTest::WaitForEncodedFrame( EncodedImage* frame, CodecSpecificInfo* codec_specific_info) { std::vector frames; std::vector codec_specific_infos; if (!WaitForEncodedFrames(&frames, &codec_specific_infos)) return false; EXPECT_EQ(frames.size(), static_cast(1)); EXPECT_EQ(frames.size(), codec_specific_infos.size()); *frame = frames[0]; *codec_specific_info = codec_specific_infos[0]; return true; } void VideoCodecUnitTest::SetWaitForEncodedFramesThreshold(size_t num_frames) { rtc::CritScope lock(&encoded_frame_section_); wait_for_encoded_frames_threshold_ = num_frames; } bool VideoCodecUnitTest::WaitForEncodedFrames( std::vector* frames, std::vector* codec_specific_info) { EXPECT_TRUE(encoded_frame_event_.Wait(kEncodeTimeoutMs)) << "Timed out while waiting for encoded frame."; // This becomes unsafe if there are multiple threads waiting for frames. rtc::CritScope lock(&encoded_frame_section_); EXPECT_FALSE(encoded_frames_.empty()); EXPECT_FALSE(codec_specific_infos_.empty()); EXPECT_EQ(encoded_frames_.size(), codec_specific_infos_.size()); if (!encoded_frames_.empty()) { *frames = encoded_frames_; encoded_frames_.clear(); RTC_DCHECK(!codec_specific_infos_.empty()); *codec_specific_info = codec_specific_infos_; codec_specific_infos_.clear(); return true; } else { return false; } } bool VideoCodecUnitTest::WaitForDecodedFrame(std::unique_ptr* frame, absl::optional* 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; } } size_t VideoCodecUnitTest::GetNumEncodedFrames() { rtc::CritScope lock(&encoded_frame_section_); return encoded_frames_.size(); } } // namespace webrtc