diff --git a/webrtc/modules/video_coding/codecs/test/plot_webrtc_test_logs.py b/webrtc/modules/video_coding/codecs/test/plot_webrtc_test_logs.py index 70b942d457..d598ffb66d 100755 --- a/webrtc/modules/video_coding/codecs/test/plot_webrtc_test_logs.py +++ b/webrtc/modules/video_coding/codecs/test/plot_webrtc_test_logs.py @@ -22,7 +22,7 @@ EVENT_START = 'RUN ] CodecSettings/PlotVideoProcessorIntegrationTest.' EVENT_END = 'OK ] CodecSettings/PlotVideoProcessorIntegrationTest.' # Metrics to plot, tuple: (name to parse in file, label to use when plotting). -BITRATE = ('Target Bitrate', 'target bitrate (kbps)') +BITRATE = ('Target bitrate', 'target bitrate (kbps)') WIDTH = ('Width', 'width') HEIGHT = ('Height', 'height') FILENAME = ('Filename', 'clip') @@ -30,18 +30,18 @@ CODEC_TYPE = ('Codec type', 'Codec') ENCODER_IMPLEMENTATION_NAME = ('Encoder implementation name', 'enc name') DECODER_IMPLEMENTATION_NAME = ('Decoder implementation name', 'dec name') CODEC_IMPLEMENTATION_NAME = ('Codec implementation name', 'codec name') -CORES = ('#CPU cores used', 'CPU cores used') +CORES = ('# CPU cores used', 'CPU cores used') DENOISING = ('Denoising', 'denoising') RESILIENCE = ('Resilience', 'resilience') ERROR_CONCEALMENT = ('Error concealment', 'error concealment') QP = ('Average QP', 'avg QP') PSNR = ('PSNR avg', 'PSNR (dB)') SSIM = ('SSIM avg', 'SSIM') -ENC_BITRATE = ('Encoding bitrate', 'encoded bitrate (kbps)') +ENC_BITRATE = ('Encoded bitrate', 'encoded bitrate (kbps)') FRAMERATE = ('Frame rate', 'fps') -NUM_FRAMES = ('Number of processed frames', 'num frames') -NUM_DROPPED_FRAMES = ('Number of dropped frames', 'num dropped frames') -NUM_FRAMES_TO_TARGET = ('Number of frames to approach target rate', +NUM_FRAMES = ('# processed frames', 'num frames') +NUM_DROPPED_FRAMES = ('# dropped frames', 'num dropped frames') +NUM_FRAMES_TO_TARGET = ('# frames to convergence', 'frames to reach target rate') ENCODE_TIME = ('Encoding time', 'encode time (us)') ENCODE_TIME_AVG = ('Encoding time', 'encode time (us) avg') diff --git a/webrtc/modules/video_coding/codecs/test/stats.cc b/webrtc/modules/video_coding/codecs/test/stats.cc index 173cd16fcb..649c0d549a 100644 --- a/webrtc/modules/video_coding/codecs/test/stats.cc +++ b/webrtc/modules/video_coding/codecs/test/stats.cc @@ -50,7 +50,6 @@ FrameStatistic& Stats::NewFrame(int frame_number) { } void Stats::PrintSummary() { - printf("Processing summary:\n"); if (stats_.empty()) { printf("No frame statistics have been logged yet.\n"); return; @@ -145,22 +144,22 @@ void Stats::PrintSummary() { } // Bitrate stats. - printf("Bit rates:\n"); + printf("Bitrates:\n"); frame = std::min_element(stats_.begin(), stats_.end(), LessForBitRate); - printf(" Min bit rate: %7d kbps (frame %d)\n", frame->bit_rate_in_kbps, + printf(" Min bitrate: %7d kbps (frame %d)\n", frame->bit_rate_in_kbps, frame->frame_number); frame = std::max_element(stats_.begin(), stats_.end(), LessForBitRate); - printf(" Max bit rate: %7d kbps (frame %d)\n", frame->bit_rate_in_kbps, + printf(" Max bitrate: %7d kbps (frame %d)\n", frame->bit_rate_in_kbps, frame->frame_number); - int avg_qp = (total_qp_count > 0) ? (total_qp / total_qp_count) : -1; - printf("Average QP: %d\n", avg_qp); - printf("\n"); printf("Total encoding time : %7d ms.\n", total_encoding_time_in_us / 1000); printf("Total decoding time : %7d ms.\n", total_decoding_time_in_us / 1000); printf("Total processing time: %7d ms.\n", (total_encoding_time_in_us + total_decoding_time_in_us) / 1000); + + int avg_qp = (total_qp_count > 0) ? (total_qp / total_qp_count) : -1; + printf("Average QP: %d\n", avg_qp); } } // namespace test diff --git a/webrtc/modules/video_coding/codecs/test/videoprocessor.cc b/webrtc/modules/video_coding/codecs/test/videoprocessor.cc index 8d60307e8c..0417c05575 100644 --- a/webrtc/modules/video_coding/codecs/test/videoprocessor.cc +++ b/webrtc/modules/video_coding/codecs/test/videoprocessor.cc @@ -23,6 +23,7 @@ #include "webrtc/modules/video_coding/include/video_codec_initializer.h" #include "webrtc/modules/video_coding/utility/default_video_bitrate_allocator.h" #include "webrtc/rtc_base/checks.h" +#include "webrtc/rtc_base/logging.h" #include "webrtc/rtc_base/timeutils.h" #include "webrtc/system_wrappers/include/cpu_info.h" @@ -31,22 +32,7 @@ namespace test { namespace { -// TODO(brandtr): Update this to use the real frame rate. -const int k90khzTimestampFrameDiff = 3000; // Assuming 30 fps. - -// Use the frame number as the basis for timestamp to identify frames. Let the -// first timestamp be non-zero, to not make the IvfFileWriter believe that we -// want to use capture timestamps in the IVF files. -uint32_t FrameNumberToTimestamp(int frame_number) { - RTC_DCHECK_GE(frame_number, 0); - return (frame_number + 1) * k90khzTimestampFrameDiff; -} - -int TimestampToFrameNumber(uint32_t timestamp) { - RTC_DCHECK_GT(timestamp, 0); - RTC_DCHECK_EQ(timestamp % k90khzTimestampFrameDiff, 0); - return (timestamp / k90khzTimestampFrameDiff) - 1; -} +const int kRtpClockRateHz = 90000; std::unique_ptr CreateBitrateAllocator( const TestConfig& config) { @@ -60,21 +46,41 @@ std::unique_ptr CreateBitrateAllocator( std::move(tl_factory))); } -void PrintCodecSettings(const VideoCodec* config) { - printf(" Start bitrate : %d kbps\n", config->startBitrate); - printf(" Width : %d\n", config->width); - printf(" Height : %d\n", config->height); - printf(" Codec type : %s\n", - CodecTypeToPayloadName(config->codecType).value_or("Unknown")); - if (config->codecType == kVideoCodecVP8) { - printf(" Denoising : %d\n", config->VP8().denoisingOn); - printf(" Error concealment: %d\n", config->VP8().errorConcealmentOn); - printf(" Frame dropping : %d\n", config->VP8().frameDroppingOn); - printf(" Resilience : %d\n", config->VP8().resilience); - } else if (config->codecType == kVideoCodecVP9) { - printf(" Denoising : %d\n", config->VP9().denoisingOn); - printf(" Frame dropping : %d\n", config->VP9().frameDroppingOn); - printf(" Resilience : %d\n", config->VP9().resilienceOn); +void PrintCodecSettings(const VideoCodec* codec_settings) { + RTC_DCHECK(codec_settings); + printf(" Codec settings:\n"); + printf(" Codec type : %s\n", + CodecTypeToPayloadName(codec_settings->codecType).value_or("Unknown")); + printf(" Start bitrate : %d kbps\n", codec_settings->startBitrate); + printf(" Max bitrate : %d kbps\n", codec_settings->maxBitrate); + printf(" Min bitrate : %d kbps\n", codec_settings->minBitrate); + printf(" Width : %d\n", codec_settings->width); + printf(" Height : %d\n", codec_settings->height); + printf(" Max frame rate : %d\n", codec_settings->maxFramerate); + printf(" QPmax : %d\n", codec_settings->qpMax); + if (codec_settings->codecType == kVideoCodecVP8) { + printf(" Complexity : %d\n", codec_settings->VP8().complexity); + printf(" Denoising : %d\n", codec_settings->VP8().denoisingOn); + printf(" Error concealment : %d\n", + codec_settings->VP8().errorConcealmentOn); + printf(" Frame dropping : %d\n", codec_settings->VP8().frameDroppingOn); + printf(" Resilience : %d\n", codec_settings->VP8().resilience); + printf(" Key frame interval: %d\n", + codec_settings->VP8().keyFrameInterval); + } else if (codec_settings->codecType == kVideoCodecVP9) { + printf(" Complexity : %d\n", codec_settings->VP9().complexity); + printf(" Denoising : %d\n", codec_settings->VP9().denoisingOn); + printf(" Frame dropping : %d\n", codec_settings->VP9().frameDroppingOn); + printf(" Resilience : %d\n", codec_settings->VP9().resilienceOn); + printf(" Key frame interval: %d\n", + codec_settings->VP9().keyFrameInterval); + printf(" Adaptive QP mode : %d\n", codec_settings->VP9().adaptiveQpMode); + } else if (codec_settings->codecType == kVideoCodecH264) { + printf(" Frame dropping : %d\n", + codec_settings->H264().frameDroppingOn); + printf(" Key frame interval: %d\n", + codec_settings->H264().keyFrameInterval); + printf(" Profile : %d\n", codec_settings->H264().profile); } } @@ -138,11 +144,17 @@ VideoProcessorImpl::VideoProcessorImpl(webrtc::VideoEncoder* encoder, frame_infos_.reserve(analysis_frame_reader->NumberOfFrames()); } +VideoProcessorImpl::~VideoProcessorImpl() { + encoder_->RegisterEncodeCompleteCallback(nullptr); + decoder_->RegisterDecodeCompleteCallback(nullptr); +} + void VideoProcessorImpl::Init() { RTC_DCHECK(!initialized_) << "VideoProcessor already initialized."; + RTC_DCHECK(config_.codec_settings) << "No codec settings supplied."; initialized_ = true; - // Setup required callbacks for the encoder/decoder. + // Setup required callbacks for the encoder and decoder. RTC_CHECK_EQ(encoder_->RegisterEncodeCompleteCallback(encode_callback_.get()), WEBRTC_VIDEO_CODEC_OK) << "Failed to register encode complete callback"; @@ -164,70 +176,26 @@ void VideoProcessorImpl::Init() { << "Failed to initialize VideoDecoder"; if (config_.verbose) { - printf("Filename: %s\n", config_.filename.c_str()); printf("Video Processor:\n"); - printf(" #CPU cores used : %d\n", num_cores); - printf(" Total # of frames: %d\n", + printf(" Filename : %s\n", config_.filename.c_str()); + printf(" Total # of frames: %d\n", analysis_frame_reader_->NumberOfFrames()); - printf(" Codec settings:\n"); - printf(" Encoder implementation name: %s\n", - encoder_->ImplementationName()); - printf(" Decoder implementation name: %s\n", - decoder_->ImplementationName()); - if (strcmp(encoder_->ImplementationName(), - decoder_->ImplementationName()) == 0) { - printf(" Codec implementation name: %s_%s\n", + printf(" # CPU cores used : %d\n", num_cores); + const char* encoder_name = encoder_->ImplementationName(); + printf(" Encoder implementation name: %s\n", encoder_name); + const char* decoder_name = decoder_->ImplementationName(); + printf(" Decoder implementation name: %s\n", decoder_name); + if (strcmp(encoder_name, decoder_name) == 0) { + printf(" Codec implementation name : %s_%s\n", CodecTypeToPayloadName(config_.codec_settings->codecType) .value_or("Unknown"), encoder_->ImplementationName()); } PrintCodecSettings(config_.codec_settings); + printf("\n"); } } -VideoProcessorImpl::~VideoProcessorImpl() { - encoder_->RegisterEncodeCompleteCallback(nullptr); - decoder_->RegisterDecodeCompleteCallback(nullptr); -} - -void VideoProcessorImpl::SetRates(int bit_rate, int frame_rate) { - int set_rates_result = encoder_->SetRateAllocation( - bitrate_allocator_->GetAllocation(bit_rate * 1000, frame_rate), - frame_rate); - RTC_DCHECK_GE(set_rates_result, 0) - << "Failed to update encoder with new rate " << bit_rate; - num_dropped_frames_ = 0; - num_spatial_resizes_ = 0; -} - -size_t VideoProcessorImpl::EncodedFrameSize(int frame_number) { - RTC_DCHECK_LT(frame_number, frame_infos_.size()); - return frame_infos_[frame_number].encoded_frame_size; -} - -FrameType VideoProcessorImpl::EncodedFrameType(int frame_number) { - RTC_DCHECK_LT(frame_number, frame_infos_.size()); - return frame_infos_[frame_number].encoded_frame_type; -} - -int VideoProcessorImpl::GetQpFromEncoder(int frame_number) { - RTC_DCHECK_LT(frame_number, frame_infos_.size()); - return frame_infos_[frame_number].qp_encoder; -} - -int VideoProcessorImpl::GetQpFromBitstream(int frame_number) { - RTC_DCHECK_LT(frame_number, frame_infos_.size()); - return frame_infos_[frame_number].qp_bitstream; -} - -int VideoProcessorImpl::NumberDroppedFrames() { - return num_dropped_frames_; -} - -int VideoProcessorImpl::NumberSpatialResizes() { - return num_spatial_resizes_; -} - bool VideoProcessorImpl::ProcessFrame(int frame_number) { RTC_DCHECK_GE(frame_number, 0); RTC_DCHECK_LE(frame_number, frame_infos_.size()) @@ -277,13 +245,53 @@ bool VideoProcessorImpl::ProcessFrame(int frame_number) { encoder_->Encode(source_frame, nullptr, &frame_types); if (frame_stat->encode_return_code != WEBRTC_VIDEO_CODEC_OK) { - fprintf(stderr, "Failed to encode frame %d, return code: %d\n", - frame_number, frame_stat->encode_return_code); + LOG(LS_WARNING) << "Failed to encode frame " << frame_number + << ", return code: " << frame_stat->encode_return_code + << "."; } return true; } +void VideoProcessorImpl::SetRates(int bit_rate, int frame_rate) { + config_.codec_settings->maxFramerate = frame_rate; + int set_rates_result = encoder_->SetRateAllocation( + bitrate_allocator_->GetAllocation(bit_rate * 1000, frame_rate), + frame_rate); + RTC_DCHECK_GE(set_rates_result, 0) + << "Failed to update encoder with new rate " << bit_rate; + num_dropped_frames_ = 0; + num_spatial_resizes_ = 0; +} + +size_t VideoProcessorImpl::EncodedFrameSize(int frame_number) { + RTC_DCHECK_LT(frame_number, frame_infos_.size()); + return frame_infos_[frame_number].encoded_frame_size; +} + +FrameType VideoProcessorImpl::EncodedFrameType(int frame_number) { + RTC_DCHECK_LT(frame_number, frame_infos_.size()); + return frame_infos_[frame_number].encoded_frame_type; +} + +int VideoProcessorImpl::GetQpFromEncoder(int frame_number) { + RTC_DCHECK_LT(frame_number, frame_infos_.size()); + return frame_infos_[frame_number].qp_encoder; +} + +int VideoProcessorImpl::GetQpFromBitstream(int frame_number) { + RTC_DCHECK_LT(frame_number, frame_infos_.size()); + return frame_infos_[frame_number].qp_bitstream; +} + +int VideoProcessorImpl::NumberDroppedFrames() { + return num_dropped_frames_; +} + +int VideoProcessorImpl::NumberSpatialResizes() { + return num_spatial_resizes_; +} + void VideoProcessorImpl::FrameEncoded( webrtc::VideoCodecType codec, const EncodedImage& encoded_image, @@ -488,5 +496,20 @@ void VideoProcessorImpl::FrameDecoded(const VideoFrame& image) { last_decoded_frame_buffer_ = std::move(extracted_buffer); } +uint32_t VideoProcessorImpl::FrameNumberToTimestamp(int frame_number) { + RTC_DCHECK_GE(frame_number, 0); + const int ticks_per_frame = + kRtpClockRateHz / config_.codec_settings->maxFramerate; + return (frame_number + 1) * ticks_per_frame; +} + +int VideoProcessorImpl::TimestampToFrameNumber(uint32_t timestamp) { + RTC_DCHECK_GT(timestamp, 0); + const int ticks_per_frame = + kRtpClockRateHz / config_.codec_settings->maxFramerate; + RTC_DCHECK_EQ(timestamp % ticks_per_frame, 0); + return (timestamp / ticks_per_frame) - 1; +} + } // namespace test } // namespace webrtc diff --git a/webrtc/modules/video_coding/codecs/test/videoprocessor.h b/webrtc/modules/video_coding/codecs/test/videoprocessor.h index d0b21de585..2775e0a8d5 100644 --- a/webrtc/modules/video_coding/codecs/test/videoprocessor.h +++ b/webrtc/modules/video_coding/codecs/test/videoprocessor.h @@ -136,6 +136,8 @@ struct TestConfig { // // Note this class is not thread safe in any way and is meant for simple testing // purposes. +// +// TODO(brandtr): Remove this interface. class VideoProcessor { public: virtual ~VideoProcessor() {} @@ -183,9 +185,18 @@ class VideoProcessorImpl : public VideoProcessor { FrameWriter* source_frame_writer, IvfFileWriter* encoded_frame_writer, FrameWriter* decoded_frame_writer); - virtual ~VideoProcessorImpl(); + ~VideoProcessorImpl() override; + + // Implements VideoProcessor. void Init() override; bool ProcessFrame(int frame_number) override; + void SetRates(int bit_rate, int frame_rate) override; + size_t EncodedFrameSize(int frame_number) override; + FrameType EncodedFrameType(int frame_number) override; + int GetQpFromEncoder(int frame_number) override; + int GetQpFromBitstream(int frame_number) override; + int NumberDroppedFrames() override; + int NumberSpatialResizes() override; private: // Container that holds per-frame information that needs to be stored between @@ -255,8 +266,7 @@ class VideoProcessorImpl : public VideoProcessor { void Decoded(webrtc::VideoFrame& image, rtc::Optional decode_time_ms, rtc::Optional qp) override { - Decoded(image, - decode_time_ms ? static_cast(*decode_time_ms) : -1); + Decoded(image); } private: @@ -271,26 +281,11 @@ class VideoProcessorImpl : public VideoProcessor { // Invoked by the callback when a frame has completed decoding. void FrameDecoded(const webrtc::VideoFrame& image); - // Updates the encoder with the target bit rate and the frame rate. - void SetRates(int bit_rate, int frame_rate) override; - - // Return the size of the encoded frame in bytes. - size_t EncodedFrameSize(int frame_number) override; - - // Return the encoded frame type (key or delta). - FrameType EncodedFrameType(int frame_number) override; - - // Return the qp used by encoder. - int GetQpFromEncoder(int frame_number) override; - - // Return the qp from the qp parser. - int GetQpFromBitstream(int frame_number) override; - - // Return the number of dropped frames. - int NumberDroppedFrames() override; - - // Return the number of spatial resizes. - int NumberSpatialResizes() override; + // Use the frame number as the basis for timestamp to identify frames. Let the + // first timestamp be non-zero, to not make the IvfFileWriter believe that we + // want to use capture timestamps in the IVF files. + uint32_t FrameNumberToTimestamp(int frame_number); + int TimestampToFrameNumber(uint32_t timestamp); webrtc::VideoEncoder* const encoder_; webrtc::VideoDecoder* const decoder_; diff --git a/webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest.h b/webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest.h index 3d9d8af972..b90a85bba6 100644 --- a/webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest.h +++ b/webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest.h @@ -231,7 +231,6 @@ class VideoProcessorIntegrationTest : public testing::Test { "_cd-" + CodecTypeToPayloadName( config_.codec_settings->codecType).value_or("") + "_hw-" + std::to_string(config_.hw_codec) + - "_fr-" + std::to_string(start_frame_rate_) + "_br-" + std::to_string( static_cast(config_.codec_settings->startBitrate)); // clang-format on @@ -343,16 +342,16 @@ class VideoProcessorIntegrationTest : public testing::Test { int num_dropped_frames = processor_->NumberDroppedFrames(); int num_resize_actions = processor_->NumberSpatialResizes(); printf( - "For update #: %d,\n" - " Target Bitrate: %d,\n" - " Encoding bitrate: %f,\n" - " Frame rate: %d \n", + "Rate update #%d:\n" + " Target bitrate : %d\n" + " Encoded bitrate : %f\n" + " Frame rate : %d\n", update_index, bit_rate_, encoding_bitrate_total_, frame_rate_); printf( - " Number of processed frames: %d, \n" - " Number of frames to approach target rate: %d, \n" - " Number of dropped frames: %d, \n" - " Number of spatial resizes: %d, \n", + " # processed frames : %d\n" + " # frames to convergence: %d\n" + " # dropped frames : %d\n" + " # spatial resizes : %d\n", num_frames_total_, num_frames_to_hit_target_, num_dropped_frames, num_resize_actions); EXPECT_LE(perc_encoding_rate_mismatch_, @@ -361,29 +360,27 @@ class VideoProcessorIntegrationTest : public testing::Test { int perc_key_frame_size_mismatch = 100 * sum_key_frame_size_mismatch_ / num_key_frames_; printf( - " Number of Key frames: %d \n" - " Key frame rate mismatch: %d \n", + " # key frames : %d\n" + " Key frame rate mismatch: %d\n", num_key_frames_, perc_key_frame_size_mismatch); EXPECT_LE(perc_key_frame_size_mismatch, rc_expected.max_key_frame_size_mismatch); } - printf("\n"); - printf("Rates statistics for Layer data \n"); for (int i = 0; i < num_temporal_layers_; i++) { - printf("Temporal layer #%d \n", i); + printf(" Temporal layer #%d:\n", i); int perc_frame_size_mismatch = 100 * sum_frame_size_mismatch_[i] / num_frames_per_update_[i]; int perc_encoding_rate_mismatch = 100 * fabs(encoding_bitrate_[i] - bit_rate_layer_[i]) / bit_rate_layer_[i]; printf( - " Target Layer Bit rate: %f \n" - " Layer frame rate: %f, \n" - " Layer per frame bandwidth: %f, \n" - " Layer Encoding bit rate: %f, \n" - " Layer Percent frame size mismatch: %d, \n" - " Layer Percent encoding rate mismatch: %d, \n" - " Number of frame processed per layer: %d \n", + " Target layer bitrate : %f\n" + " Layer frame rate : %f\n" + " Layer per frame bandwidth : %f\n" + " Layer encoding bitrate : %f\n" + " Layer percent frame size mismatch : %d\n" + " Layer percent encoding rate mismatch: %d\n" + " # frame processed per layer : %d\n", bit_rate_layer_[i], frame_rate_layer_[i], per_frame_bandwidth_[i], encoding_bitrate_[i], perc_frame_size_mismatch, perc_encoding_rate_mismatch, num_frames_per_update_[i]); @@ -601,11 +598,12 @@ class VideoProcessorIntegrationTest : public testing::Test { config_.codec_settings->width, config_.codec_settings->height, &psnr_result, &ssim_result)); + VerifyQuality(psnr_result, ssim_result, quality_thresholds); + stats_.PrintSummary(); printf("PSNR avg: %f, min: %f\nSSIM avg: %f, min: %f\n", psnr_result.average, psnr_result.min, ssim_result.average, ssim_result.min); - VerifyQuality(psnr_result, ssim_result, quality_thresholds); - stats_.PrintSummary(); + printf("\n"); // Remove analysis file. if (remove(config_.output_filename.c_str()) < 0) { diff --git a/webrtc/modules/video_coding/codecs/test/videoprocessor_unittest.cc b/webrtc/modules/video_coding/codecs/test/videoprocessor_unittest.cc index 2a54358e0d..9dd7547373 100644 --- a/webrtc/modules/video_coding/codecs/test/videoprocessor_unittest.cc +++ b/webrtc/modules/video_coding/codecs/test/videoprocessor_unittest.cc @@ -8,11 +8,14 @@ * be found in the AUTHORS file in the root of the source tree. */ +#include + #include "webrtc/api/video/i420_buffer.h" #include "webrtc/modules/video_coding/codecs/test/mock/mock_packet_manipulator.h" #include "webrtc/modules/video_coding/codecs/test/videoprocessor.h" #include "webrtc/modules/video_coding/include/mock/mock_video_codec_interface.h" #include "webrtc/modules/video_coding/include/video_coding.h" +#include "webrtc/rtc_base/ptr_util.h" #include "webrtc/test/gmock.h" #include "webrtc/test/gtest.h" #include "webrtc/test/testsupport/mock/mock_frame_reader.h" @@ -28,30 +31,37 @@ using ::testing::Return; namespace webrtc { namespace test { -// Very basic testing for VideoProcessor. It's mostly tested by running the -// video_quality_measurement program. +namespace { + +const int kWidth = 352; +const int kHeight = 288; +const int kFrameSize = kWidth * kHeight * 3 / 2; // I420. +const int kFramerate = 30; +const int kNumFrames = 2; + +} // namespace + class VideoProcessorTest : public testing::Test { protected: - MockVideoEncoder encoder_mock_; - MockVideoDecoder decoder_mock_; - MockFrameReader frame_reader_mock_; - MockFrameWriter frame_writer_mock_; - MockPacketManipulator packet_manipulator_mock_; - Stats stats_; - TestConfig config_; - VideoCodec codec_settings_; - - VideoProcessorTest() {} - virtual ~VideoProcessorTest() {} - void SetUp() { + VideoProcessorTest() { // Get a codec configuration struct and configure it. VideoCodingModule::Codec(kVideoCodecVP8, &codec_settings_); config_.codec_settings = &codec_settings_; config_.codec_settings->startBitrate = 100; - config_.codec_settings->width = 352; - config_.codec_settings->height = 288; + config_.codec_settings->width = kWidth; + config_.codec_settings->height = kHeight; + config_.codec_settings->maxFramerate = kFramerate; + + EXPECT_CALL(frame_reader_mock_, NumberOfFrames()) + .WillRepeatedly(Return(kNumFrames)); + EXPECT_CALL(frame_reader_mock_, FrameLength()) + .WillRepeatedly(Return(kFrameSize)); + video_processor_ = rtc::MakeUnique( + &encoder_mock_, &decoder_mock_, &frame_reader_mock_, + &frame_writer_mock_, &packet_manipulator_mock_, config_, &stats_, + nullptr /* source_frame_writer */, nullptr /* encoded_frame_writer */, + nullptr /* decoded_frame_writer */); } - void TearDown() {} void ExpectInit() { EXPECT_CALL(encoder_mock_, InitEncode(_, _, _)).Times(1); @@ -60,35 +70,41 @@ class VideoProcessorTest : public testing::Test { EXPECT_CALL(decoder_mock_, InitDecode(_, _)).Times(1); EXPECT_CALL(decoder_mock_, RegisterDecodeCompleteCallback(_)) .Times(AtLeast(1)); - EXPECT_CALL(frame_reader_mock_, NumberOfFrames()).WillRepeatedly(Return(1)); - EXPECT_CALL(frame_reader_mock_, FrameLength()).WillOnce(Return(152064)); } + + MockVideoEncoder encoder_mock_; + MockVideoDecoder decoder_mock_; + MockFrameReader frame_reader_mock_; + MockFrameWriter frame_writer_mock_; + MockPacketManipulator packet_manipulator_mock_; + VideoCodec codec_settings_; + TestConfig config_; + Stats stats_; + std::unique_ptr video_processor_; }; TEST_F(VideoProcessorTest, Init) { ExpectInit(); - VideoProcessorImpl video_processor( - &encoder_mock_, &decoder_mock_, &frame_reader_mock_, &frame_writer_mock_, - &packet_manipulator_mock_, config_, &stats_, - nullptr /* source_frame_writer */, nullptr /* encoded_frame_writer */, - nullptr /* decoded_frame_writer */); - video_processor.Init(); + video_processor_->Init(); } -TEST_F(VideoProcessorTest, ProcessFrame) { +TEST_F(VideoProcessorTest, ProcessFrames) { ExpectInit(); - EXPECT_CALL(encoder_mock_, Encode(_, _, _)).Times(1); + video_processor_->Init(); + EXPECT_CALL(frame_reader_mock_, ReadFrame()) - .WillOnce(Return(I420Buffer::Create(50, 50))); - // Since we don't return any callback from the mock, the decoder will not - // be more than initialized... - VideoProcessorImpl video_processor( - &encoder_mock_, &decoder_mock_, &frame_reader_mock_, &frame_writer_mock_, - &packet_manipulator_mock_, config_, &stats_, - nullptr /* source_frame_writer */, nullptr /* encoded_frame_writer */, - nullptr /* decoded_frame_writer */); - video_processor.Init(); - video_processor.ProcessFrame(0); + .WillRepeatedly(Return(I420Buffer::Create(kWidth, kHeight))); + EXPECT_CALL(encoder_mock_, Encode(testing::Property(&VideoFrame::timestamp, + 1 * 90000 / kFramerate), + _, _)) + .Times(1); + video_processor_->ProcessFrame(0); + + EXPECT_CALL(encoder_mock_, Encode(testing::Property(&VideoFrame::timestamp, + 2 * 90000 / kFramerate), + _, _)) + .Times(1); + video_processor_->ProcessFrame(1); } } // namespace test