diff --git a/webrtc/common_video/libyuv/libyuv_unittest.cc b/webrtc/common_video/libyuv/libyuv_unittest.cc index 7545168244..98546f079a 100644 --- a/webrtc/common_video/libyuv/libyuv_unittest.cc +++ b/webrtc/common_video/libyuv/libyuv_unittest.cc @@ -15,6 +15,7 @@ #include "webrtc/test/gtest.h" #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" +#include "webrtc/test/frame_utils.h" #include "webrtc/test/testsupport/fileutils.h" #include "webrtc/video_frame.h" @@ -35,8 +36,7 @@ class TestLibYuv : public ::testing::Test { virtual void TearDown(); FILE* source_file_; - VideoFrame orig_frame_; - std::unique_ptr orig_buffer_; + std::unique_ptr orig_frame_; const int width_; const int height_; const int size_y_; @@ -51,9 +51,7 @@ TestLibYuv::TestLibYuv() height_(288), size_y_(width_ * height_), size_uv_(((width_ + 1) / 2) * ((height_ + 1) / 2)), - frame_length_(CalcBufferSize(kI420, 352, 288)) { - orig_buffer_.reset(new uint8_t[frame_length_]); -} + frame_length_(CalcBufferSize(kI420, 352, 288)) {} void TestLibYuv::SetUp() { const std::string input_file_name = webrtc::test::ResourcePath("foreman_cif", @@ -62,16 +60,10 @@ void TestLibYuv::SetUp() { ASSERT_TRUE(source_file_ != NULL) << "Cannot read file: "<< input_file_name << "\n"; - EXPECT_EQ(frame_length_, - fread(orig_buffer_.get(), 1, frame_length_, source_file_)); - orig_frame_.CreateFrame(orig_buffer_.get(), - orig_buffer_.get() + size_y_, - orig_buffer_.get() + - size_y_ + size_uv_, - width_, height_, - width_, (width_ + 1) / 2, - (width_ + 1) / 2, - kVideoRotation_0); + rtc::scoped_refptr buffer( + test::ReadI420Buffer(width_, height_, source_file_)); + + orig_frame_.reset(new VideoFrame(buffer, kVideoRotation_0, 0)); } void TestLibYuv::TearDown() { @@ -100,7 +92,7 @@ TEST_F(TestLibYuv, ConvertTest) { printf("\nConvert #%d I420 <-> I420 \n", j); std::unique_ptr out_i420_buffer(new uint8_t[frame_length_]); - EXPECT_EQ(0, ConvertFromI420(orig_frame_, kI420, 0, out_i420_buffer.get())); + EXPECT_EQ(0, ConvertFromI420(*orig_frame_, kI420, 0, out_i420_buffer.get())); EXPECT_EQ(0, ConvertToI420(kI420, out_i420_buffer.get(), 0, 0, width_, height_, 0, kVideoRotation_0, res_i420_buffer.get())); @@ -108,7 +100,7 @@ TEST_F(TestLibYuv, ConvertTest) { if (PrintVideoFrame(*res_i420_buffer, output_file) < 0) { return; } - psnr = I420PSNR(*orig_frame_.video_frame_buffer(), *res_i420_buffer); + psnr = I420PSNR(*orig_frame_->video_frame_buffer(), *res_i420_buffer); EXPECT_EQ(48.0, psnr); j++; @@ -120,7 +112,7 @@ TEST_F(TestLibYuv, ConvertTest) { Calc16ByteAlignedStride(width_, &stride_y, &stride_uv); res_i420_buffer = I420Buffer::Create(width_, height_, stride_y, stride_uv, stride_uv); - EXPECT_EQ(0, ConvertFromI420(orig_frame_, kRGB24, 0, res_rgb_buffer2.get())); + EXPECT_EQ(0, ConvertFromI420(*orig_frame_, kRGB24, 0, res_rgb_buffer2.get())); EXPECT_EQ(0, ConvertToI420(kRGB24, res_rgb_buffer2.get(), 0, 0, width_, height_, 0, kVideoRotation_0, @@ -129,7 +121,7 @@ TEST_F(TestLibYuv, ConvertTest) { if (PrintVideoFrame(*res_i420_buffer, output_file) < 0) { return; } - psnr = I420PSNR(*orig_frame_.video_frame_buffer(), *res_i420_buffer); + psnr = I420PSNR(*orig_frame_->video_frame_buffer(), *res_i420_buffer); // Optimization Speed- quality trade-off => 45 dB only (platform dependant). EXPECT_GT(ceil(psnr), 44); @@ -137,11 +129,11 @@ TEST_F(TestLibYuv, ConvertTest) { printf("\nConvert #%d I420 <-> UYVY\n", j); std::unique_ptr out_uyvy_buffer(new uint8_t[width_ * height_ * 2]); - EXPECT_EQ(0, ConvertFromI420(orig_frame_, kUYVY, 0, out_uyvy_buffer.get())); + EXPECT_EQ(0, ConvertFromI420(*orig_frame_, kUYVY, 0, out_uyvy_buffer.get())); EXPECT_EQ(0, ConvertToI420(kUYVY, out_uyvy_buffer.get(), 0, 0, width_, height_, 0, kVideoRotation_0, res_i420_buffer.get())); - psnr = I420PSNR(*orig_frame_.video_frame_buffer(), *res_i420_buffer); + psnr = I420PSNR(*orig_frame_->video_frame_buffer(), *res_i420_buffer); EXPECT_EQ(48.0, psnr); if (PrintVideoFrame(*res_i420_buffer, output_file) < 0) { return; @@ -150,7 +142,7 @@ TEST_F(TestLibYuv, ConvertTest) { printf("\nConvert #%d I420 <-> YUY2\n", j); std::unique_ptr out_yuy2_buffer(new uint8_t[width_ * height_ * 2]); - EXPECT_EQ(0, ConvertFromI420(orig_frame_, kYUY2, 0, out_yuy2_buffer.get())); + EXPECT_EQ(0, ConvertFromI420(*orig_frame_, kYUY2, 0, out_yuy2_buffer.get())); EXPECT_EQ(0, ConvertToI420(kYUY2, out_yuy2_buffer.get(), 0, 0, width_, height_, 0, @@ -160,14 +152,14 @@ TEST_F(TestLibYuv, ConvertTest) { return; } - psnr = I420PSNR(*orig_frame_.video_frame_buffer(), *res_i420_buffer); + psnr = I420PSNR(*orig_frame_->video_frame_buffer(), *res_i420_buffer); EXPECT_EQ(48.0, psnr); printf("\nConvert #%d I420 <-> RGB565\n", j); std::unique_ptr out_rgb565_buffer( new uint8_t[width_ * height_ * 2]); EXPECT_EQ(0, - ConvertFromI420(orig_frame_, kRGB565, 0, out_rgb565_buffer.get())); + ConvertFromI420(*orig_frame_, kRGB565, 0, out_rgb565_buffer.get())); EXPECT_EQ(0, ConvertToI420(kRGB565, out_rgb565_buffer.get(), 0, 0, width_, height_, 0, @@ -177,7 +169,7 @@ TEST_F(TestLibYuv, ConvertTest) { } j++; - psnr = I420PSNR(*orig_frame_.video_frame_buffer(), *res_i420_buffer); + psnr = I420PSNR(*orig_frame_->video_frame_buffer(), *res_i420_buffer); // TODO(leozwang) Investigate the right psnr should be set for I420ToRGB565, // Another example is I420ToRGB24, the psnr is 44 // TODO(mikhal): Add psnr for RGB565, 1555, 4444, convert to ARGB. @@ -187,7 +179,7 @@ TEST_F(TestLibYuv, ConvertTest) { std::unique_ptr out_argb8888_buffer( new uint8_t[width_ * height_ * 4]); EXPECT_EQ(0, - ConvertFromI420(orig_frame_, kARGB, 0, out_argb8888_buffer.get())); + ConvertFromI420(*orig_frame_, kARGB, 0, out_argb8888_buffer.get())); EXPECT_EQ(0, ConvertToI420(kARGB, out_argb8888_buffer.get(), 0, 0, width_, height_, 0, kVideoRotation_0, @@ -197,7 +189,7 @@ TEST_F(TestLibYuv, ConvertTest) { return; } - psnr = I420PSNR(*orig_frame_.video_frame_buffer(), *res_i420_buffer); + psnr = I420PSNR(*orig_frame_->video_frame_buffer(), *res_i420_buffer); // TODO(leozwang) Investigate the right psnr should be set for // I420ToARGB8888, EXPECT_GT(ceil(psnr), 42); @@ -221,7 +213,7 @@ TEST_F(TestLibYuv, ConvertAlignedFrame) { rtc::scoped_refptr res_i420_buffer = I420Buffer::Create(width_, height_, stride_y, stride_uv, stride_uv); std::unique_ptr out_i420_buffer(new uint8_t[frame_length_]); - EXPECT_EQ(0, ConvertFromI420(orig_frame_, kI420, 0, + EXPECT_EQ(0, ConvertFromI420(*orig_frame_, kI420, 0, out_i420_buffer.get())); EXPECT_EQ(0, ConvertToI420(kI420, out_i420_buffer.get(), 0, 0, width_, height_, 0, kVideoRotation_0, @@ -230,11 +222,10 @@ TEST_F(TestLibYuv, ConvertAlignedFrame) { if (PrintVideoFrame(*res_i420_buffer, output_file) < 0) { return; } - psnr = I420PSNR(*orig_frame_.video_frame_buffer(), *res_i420_buffer); + psnr = I420PSNR(*orig_frame_->video_frame_buffer(), *res_i420_buffer); EXPECT_EQ(48.0, psnr); } - TEST_F(TestLibYuv, RotateTest) { // Use ConvertToI420 for multiple rotations - see that nothing breaks, all // memory is properly allocated and end result is equal to the starting point. @@ -242,18 +233,22 @@ TEST_F(TestLibYuv, RotateTest) { int rotated_height = width_; int stride_y; int stride_uv; + + // Assume compact layout, no padding. + const uint8_t *orig_buffer = orig_frame_->video_frame_buffer()->DataY(); + Calc16ByteAlignedStride(rotated_width, &stride_y, &stride_uv); rtc::scoped_refptr rotated_res_i420_buffer = I420Buffer::Create( rotated_width, rotated_height, stride_y, stride_uv, stride_uv); - EXPECT_EQ(0, ConvertToI420(kI420, orig_buffer_.get(), 0, 0, width_, height_, + EXPECT_EQ(0, ConvertToI420(kI420, orig_buffer, 0, 0, width_, height_, 0, kVideoRotation_90, rotated_res_i420_buffer.get())); - EXPECT_EQ(0, ConvertToI420(kI420, orig_buffer_.get(), 0, 0, width_, height_, + EXPECT_EQ(0, ConvertToI420(kI420, orig_buffer, 0, 0, width_, height_, 0, kVideoRotation_270, rotated_res_i420_buffer.get())); rotated_res_i420_buffer = I420Buffer::Create( width_, height_, width_, (width_ + 1) / 2, (width_ + 1) / 2); - EXPECT_EQ(0, ConvertToI420(kI420, orig_buffer_.get(), 0, 0, width_, height_, + EXPECT_EQ(0, ConvertToI420(kI420, orig_buffer, 0, 0, width_, height_, 0, kVideoRotation_180, rotated_res_i420_buffer.get())); } diff --git a/webrtc/modules/video_coding/codecs/test/videoprocessor.cc b/webrtc/modules/video_coding/codecs/test/videoprocessor.cc index 7b0c8e397e..8436eb0042 100644 --- a/webrtc/modules/video_coding/codecs/test/videoprocessor.cc +++ b/webrtc/modules/video_coding/codecs/test/videoprocessor.cc @@ -56,7 +56,6 @@ VideoProcessorImpl::VideoProcessorImpl(webrtc::VideoEncoder* encoder, stats_(stats), encode_callback_(NULL), decode_callback_(NULL), - source_buffer_(NULL), first_key_frame_has_been_excluded_(false), last_frame_missing_(false), initialized_(false), @@ -81,7 +80,6 @@ bool VideoProcessorImpl::Init() { // Initialize data structures used by the encoder/decoder APIs size_t frame_length_in_bytes = frame_reader_->FrameLength(); - source_buffer_ = new uint8_t[frame_length_in_bytes]; last_successful_frame_buffer_ = new uint8_t[frame_length_in_bytes]; // Set fixed properties common for all frames. // To keep track of spatial resize actions by encoder. @@ -143,7 +141,6 @@ bool VideoProcessorImpl::Init() { } VideoProcessorImpl::~VideoProcessorImpl() { - delete[] source_buffer_; delete[] last_successful_frame_buffer_; encoder_->RegisterEncodeCompleteCallback(NULL); delete encode_callback_; @@ -190,17 +187,15 @@ bool VideoProcessorImpl::ProcessFrame(int frame_number) { if (frame_number == 0) { prev_time_stamp_ = -1; } - if (frame_reader_->ReadFrame(source_buffer_)) { - // Copy the source frame to the newly read frame data. - source_frame_.CreateFrame(source_buffer_, config_.codec_settings->width, - config_.codec_settings->height, kVideoRotation_0); + rtc::scoped_refptr buffer(frame_reader_->ReadFrame()); + if (buffer) { + // Use the frame number as "timestamp" to identify frames + VideoFrame source_frame(buffer, frame_number, 0, webrtc::kVideoRotation_0); // Ensure we have a new statistics data object we can fill: FrameStatistic& stat = stats_->NewFrame(frame_number); encode_start_ns_ = rtc::TimeNanos(); - // Use the frame number as "timestamp" to identify frames - source_frame_.set_timestamp(frame_number); // Decide if we're going to force a keyframe: std::vector frame_types(1, kVideoFrameDelta); @@ -213,7 +208,7 @@ bool VideoProcessorImpl::ProcessFrame(int frame_number) { encoded_frame_size_ = 0; encoded_frame_type_ = kVideoFrameDelta; - int32_t encode_result = encoder_->Encode(source_frame_, NULL, &frame_types); + int32_t encode_result = encoder_->Encode(source_frame, NULL, &frame_types); if (encode_result != WEBRTC_VIDEO_CODEC_OK) { fprintf(stderr, "Failed to encode frame %d, return code: %d\n", diff --git a/webrtc/modules/video_coding/codecs/test/videoprocessor.h b/webrtc/modules/video_coding/codecs/test/videoprocessor.h index 21ed55ee9f..0887f4cc68 100644 --- a/webrtc/modules/video_coding/codecs/test/videoprocessor.h +++ b/webrtc/modules/video_coding/codecs/test/videoprocessor.h @@ -199,8 +199,6 @@ class VideoProcessorImpl : public VideoProcessor { EncodedImageCallback* encode_callback_; DecodedImageCallback* decode_callback_; - // Buffer used for reading the source video file: - uint8_t* source_buffer_; // Keep track of the last successful frame, since we need to write that // when decoding fails: uint8_t* last_successful_frame_buffer_; diff --git a/webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest.cc b/webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest.cc index 214020bc6c..3d54d5db74 100644 --- a/webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest.cc +++ b/webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest.cc @@ -226,7 +226,8 @@ class VideoProcessorIntegrationTest : public testing::Test { break; } frame_reader_ = new webrtc::test::FrameReaderImpl( - config_.input_filename, config_.frame_length_in_bytes); + config_.input_filename, config_.codec_settings->width, + config_.codec_settings->height); frame_writer_ = new webrtc::test::FrameWriterImpl( config_.output_filename, config_.frame_length_in_bytes); ASSERT_TRUE(frame_reader_->Init()); diff --git a/webrtc/modules/video_coding/codecs/test/videoprocessor_unittest.cc b/webrtc/modules/video_coding/codecs/test/videoprocessor_unittest.cc index 77ea472dc6..92445d6fe8 100644 --- a/webrtc/modules/video_coding/codecs/test/videoprocessor_unittest.cc +++ b/webrtc/modules/video_coding/codecs/test/videoprocessor_unittest.cc @@ -75,7 +75,8 @@ TEST_F(VideoProcessorTest, Init) { TEST_F(VideoProcessorTest, ProcessFrame) { ExpectInit(); EXPECT_CALL(encoder_mock_, Encode(_, _, _)).Times(1); - EXPECT_CALL(frame_reader_mock_, ReadFrame(_)).WillOnce(Return(true)); + 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( diff --git a/webrtc/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc b/webrtc/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc index 252eb71210..40203a4d75 100644 --- a/webrtc/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc +++ b/webrtc/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc @@ -17,6 +17,7 @@ #include "webrtc/base/timeutils.h" #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" #include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h" +#include "webrtc/test/frame_utils.h" #include "webrtc/test/testsupport/fileutils.h" namespace webrtc { @@ -128,14 +129,11 @@ class TestVp8Impl : public ::testing::Test { decoder_->RegisterDecodeCompleteCallback(decode_complete_callback_.get()); // Using a QCIF image (aligned stride (u,v planes) > width). // Processing only one frame. - length_source_frame_ = CalcBufferSize(kI420, kWidth, kHeight); - source_buffer_.reset(new uint8_t[length_source_frame_]); source_file_ = fopen(test::ResourcePath("paris_qcif", "yuv").c_str(), "rb"); ASSERT_TRUE(source_file_ != NULL); - // Set input frame. - ASSERT_EQ( - fread(source_buffer_.get(), 1, length_source_frame_, source_file_), - length_source_frame_); + rtc::scoped_refptr compact_buffer( + test::ReadI420Buffer(kWidth, kHeight, source_file_)); + ASSERT_TRUE(compact_buffer); codec_inst_.width = kWidth; codec_inst_.height = kHeight; const int kFramerate = 30; @@ -147,15 +145,15 @@ class TestVp8Impl : public ::testing::Test { EXPECT_EQ(stride_y, 176); EXPECT_EQ(stride_uv, 96); - rtc::scoped_refptr buffer = I420Buffer::Create( - codec_inst_.width, codec_inst_.height, stride_y, stride_uv, stride_uv); - // Using ConvertToI420 to add stride to the image. - EXPECT_EQ( - 0, ConvertToI420(kI420, source_buffer_.get(), 0, 0, codec_inst_.width, - codec_inst_.height, 0, kVideoRotation_0, - buffer.get())); + rtc::scoped_refptr stride_buffer( + I420Buffer::Create(kWidth, kHeight, stride_y, stride_uv, stride_uv)); + + // No scaling in our case, just a copy, to add stride to the image. + stride_buffer->ScaleFrom(compact_buffer); + input_frame_.reset( - new VideoFrame(buffer, kTestTimestamp, 0, webrtc::kVideoRotation_0)); + new VideoFrame(stride_buffer, kVideoRotation_0, 0)); + input_frame_->set_timestamp(kTestTimestamp); } void SetUpEncodeDecode() { @@ -202,7 +200,6 @@ class TestVp8Impl : public ::testing::Test { std::unique_ptr decoder_; EncodedImage encoded_frame_; VideoFrame decoded_frame_; - size_t length_source_frame_; VideoCodec codec_inst_; }; diff --git a/webrtc/modules/video_coding/codecs/vp8/vp8_sequence_coder.cc b/webrtc/modules/video_coding/codecs/vp8/vp8_sequence_coder.cc index 8a374db3bc..8eb091e291 100644 --- a/webrtc/modules/video_coding/codecs/vp8/vp8_sequence_coder.cc +++ b/webrtc/modules/video_coding/codecs/vp8/vp8_sequence_coder.cc @@ -163,19 +163,16 @@ int SequenceCoder(webrtc::test::CommandLineParser* parser) { int64_t starttime = rtc::TimeMillis(); int frame_cnt = 1; int frames_processed = 0; - rtc::scoped_refptr i420_buffer = - webrtc::I420Buffer::Create(width, height, width, half_width, half_width); - - while (!feof(input_file) && - (num_frames == -1 || frames_processed < num_frames)) { - if (fread(frame_buffer.get(), 1, length, input_file) != length) - continue; + while (num_frames == -1 || frames_processed < num_frames) { + rtc::scoped_refptr buffer( + test::ReadI420Buffer(width, height, input_file)); + if (!buffer) { + // EOF or read error. + break; + } if (frame_cnt >= start_frame) { - webrtc::ConvertToI420(webrtc::kI420, frame_buffer.get(), 0, 0, width, - height, 0, webrtc::kVideoRotation_0, &i420_buffer); - webrtc::VideoFrame input_frame(i420_buffer, 0, 0, - webrtc::kVideoRotation_0); - encoder->Encode(input_frame, NULL, NULL); + encoder->Encode(VideoFrame(buffer, webrtc::kVideoRotation_0, 0), + NULL, NULL); decoder->Decode(encoder_callback.encoded_image(), false, NULL); ++frames_processed; } diff --git a/webrtc/modules/video_processing/test/denoiser_test.cc b/webrtc/modules/video_processing/test/denoiser_test.cc index a96885926e..e6a7fa62d0 100644 --- a/webrtc/modules/video_processing/test/denoiser_test.cc +++ b/webrtc/modules/video_processing/test/denoiser_test.cc @@ -125,6 +125,8 @@ TEST_F(VideoProcessingTest, MbDenoise) { EXPECT_EQ(COPY_BLOCK, decision); } +// TODO(nisse): Refactor to not use test fixture. Can use some static +// helper method to open the input file. TEST_F(VideoProcessingTest, Denoiser) { // Used in swap buffer. int denoised_frame_toggle = 0; @@ -137,14 +139,11 @@ TEST_F(VideoProcessingTest, Denoiser) { rtc::scoped_refptr denoised_frame_sse_neon; rtc::scoped_refptr denoised_frame_prev_sse_neon; - std::unique_ptr video_buffer(new uint8_t[frame_length_]); - while (fread(video_buffer.get(), 1, frame_length_, source_file_) == - frame_length_) { - // Using ConvertToI420 to add stride to the image. - rtc::scoped_refptr input_buffer = - I420Buffer::Create(width_, height_, width_, half_width_, half_width_); - EXPECT_EQ(0, ConvertToI420(kI420, video_buffer.get(), 0, 0, width_, height_, - 0, kVideoRotation_0, input_buffer.get())); + for (;;) { + rtc::scoped_refptr video_frame_buffer( + test::ReadI420Buffer(width_, height_, source_file_)); + if (!video_frame_buffer) + break; rtc::scoped_refptr* p_denoised_c = &denoised_frame_c; rtc::scoped_refptr* p_denoised_prev_c = &denoised_frame_prev_c; @@ -159,9 +158,11 @@ TEST_F(VideoProcessingTest, Denoiser) { p_denoised_sse_neon = &denoised_frame_prev_sse_neon; p_denoised_prev_sse_neon = &denoised_frame_sse_neon; } - denoiser_c.DenoiseFrame(input_buffer, p_denoised_c, p_denoised_prev_c, + denoiser_c.DenoiseFrame(video_frame_buffer, + p_denoised_c, p_denoised_prev_c, false); - denoiser_sse_neon.DenoiseFrame(input_buffer, p_denoised_sse_neon, + denoiser_sse_neon.DenoiseFrame(video_frame_buffer, + p_denoised_sse_neon, p_denoised_prev_sse_neon, false); // Invert the flag. denoised_frame_toggle ^= 1; diff --git a/webrtc/modules/video_processing/test/video_processing_unittest.cc b/webrtc/modules/video_processing/test/video_processing_unittest.cc index 8c1154acad..43238bcd18 100644 --- a/webrtc/modules/video_processing/test/video_processing_unittest.cc +++ b/webrtc/modules/video_processing/test/video_processing_unittest.cc @@ -18,6 +18,7 @@ #include "webrtc/base/keep_ref_until_done.h" #include "webrtc/base/timeutils.h" #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" +#include "webrtc/test/frame_utils.h" #include "webrtc/test/testsupport/fileutils.h" namespace webrtc { @@ -34,10 +35,8 @@ static void PreprocessFrameAndVerify(const VideoFrame& source, int target_height, VideoProcessing* vpm, const VideoFrame* out_frame); -rtc::scoped_refptr CropBuffer( - const rtc::scoped_refptr& source_buffer, - int source_width, - int source_height, +static rtc::scoped_refptr CropBuffer( + rtc::scoped_refptr source_buffer, int offset_x, int offset_y, int cropped_width, @@ -48,7 +47,7 @@ rtc::scoped_refptr CropBuffer( // verified under the same conditions. static void TestSize( const VideoFrame& source_frame, - const rtc::scoped_refptr& cropped_source_buffer, + const VideoFrameBuffer& cropped_source_buffer, int target_width, int target_height, double expected_psnr, @@ -133,15 +132,9 @@ TEST_F(VideoProcessingTest, Resampler) { vp_->EnableTemporalDecimation(false); // Reading test frame - rtc::scoped_refptr buffer = - I420Buffer::Create(width_, height_, width_, half_width_, half_width_); - - ASSERT_EQ(static_cast(size_y_), - fread(buffer->MutableDataY(), 1, size_y_, source_file_)); - ASSERT_EQ(static_cast(size_uv_), - fread(buffer->MutableDataU(), 1, size_uv_, source_file_)); - ASSERT_EQ(static_cast(size_uv_), - fread(buffer->MutableDataV(), 1, size_uv_, source_file_)); + rtc::scoped_refptr video_buffer( + test::ReadI420Buffer(width_, height_, source_file_)); + ASSERT_TRUE(video_buffer); for (uint32_t run_idx = 0; run_idx < NumRuns; run_idx++) { // Initiate test timer. @@ -149,36 +142,36 @@ TEST_F(VideoProcessingTest, Resampler) { // Init the sourceFrame with a timestamp. int64_t time_start_ms = time_start / rtc::kNumNanosecsPerMillisec; - VideoFrame video_frame(buffer, time_start_ms * 90, time_start_ms, + VideoFrame video_frame(video_buffer, time_start_ms * 90, time_start_ms, webrtc::kVideoRotation_0); // Test scaling to different sizes: source is of |width|/|height| = 352/288. // Pure scaling: - TestSize(video_frame, buffer, width_ / 4, height_ / 4, 25.2, vp_); - TestSize(video_frame, buffer, width_ / 2, height_ / 2, 28.1, vp_); + TestSize(video_frame, *video_buffer, width_ / 4, height_ / 4, 25.2, vp_); + TestSize(video_frame, *video_buffer, width_ / 2, height_ / 2, 28.1, vp_); // No resampling: - TestSize(video_frame, buffer, width_, height_, -1, vp_); - TestSize(video_frame, buffer, 2 * width_, 2 * height_, 32.2, vp_); + TestSize(video_frame, *video_buffer, width_, height_, -1, vp_); + TestSize(video_frame, *video_buffer, 2 * width_, 2 * height_, 32.2, vp_); // Scaling and cropping. The cropped source frame is the largest center // aligned region that can be used from the source while preserving aspect // ratio. - TestSize(video_frame, CropBuffer(buffer, width_, height_, 0, 56, 352, 176), + TestSize(video_frame, *CropBuffer(video_buffer, 0, 56, 352, 176), 100, 50, 24.0, vp_); - TestSize(video_frame, CropBuffer(buffer, width_, height_, 0, 30, 352, 225), + TestSize(video_frame, *CropBuffer(video_buffer, 0, 30, 352, 225), 400, 256, 31.3, vp_); - TestSize(video_frame, CropBuffer(buffer, width_, height_, 68, 0, 216, 288), + TestSize(video_frame, *CropBuffer(video_buffer, 68, 0, 216, 288), 480, 640, 32.15, vp_); - TestSize(video_frame, CropBuffer(buffer, width_, height_, 0, 12, 352, 264), + TestSize(video_frame, *CropBuffer(video_buffer, 0, 12, 352, 264), 960, 720, 32.2, vp_); - TestSize(video_frame, CropBuffer(buffer, width_, height_, 0, 44, 352, 198), + TestSize(video_frame, *CropBuffer(video_buffer, 0, 44, 352, 198), 1280, 720, 32.15, vp_); // Upsampling to odd size. - TestSize(video_frame, CropBuffer(buffer, width_, height_, 0, 26, 352, 233), + TestSize(video_frame, *CropBuffer(video_buffer, 0, 26, 352, 233), 501, 333, 32.05, vp_); // Downsample to odd size. - TestSize(video_frame, CropBuffer(buffer, width_, height_, 0, 34, 352, 219), + TestSize(video_frame, *CropBuffer(video_buffer, 0, 34, 352, 219), 281, 175, 29.3, vp_); // Stop timer. @@ -219,20 +212,18 @@ void PreprocessFrameAndVerify(const VideoFrame& source, } rtc::scoped_refptr CropBuffer( - const rtc::scoped_refptr& source_buffer, - int source_width, - int source_height, + rtc::scoped_refptr source_buffer, int offset_x, int offset_y, int cropped_width, int cropped_height) { // Force even. - offset_x &= 1; - offset_y &= 1; + offset_x &= ~1; + offset_y &= ~1; size_t y_start = offset_x + offset_y * source_buffer->StrideY(); size_t u_start = (offset_x / 2) + (offset_y / 2) * source_buffer->StrideU(); - size_t v_start = (offset_x / 2) + (offset_y / 2) * source_buffer->StrideU(); + size_t v_start = (offset_x / 2) + (offset_y / 2) * source_buffer->StrideV(); return rtc::scoped_refptr( new rtc::RefCountedObject( @@ -243,7 +234,7 @@ rtc::scoped_refptr CropBuffer( } void TestSize(const VideoFrame& source_frame, - const rtc::scoped_refptr& cropped_source_buffer, + const VideoFrameBuffer& cropped_source, int target_width, int target_height, double expected_psnr, @@ -260,14 +251,14 @@ void TestSize(const VideoFrame& source_frame, // Scale |resampled_source_frame| back to the source scale. VideoFrame resampled_source_frame; resampled_source_frame.CopyFrame(*out_frame); - PreprocessFrameAndVerify(resampled_source_frame, - cropped_source_buffer->width(), - cropped_source_buffer->height(), vpm, out_frame); + // Compute PSNR against the cropped source frame and check expectation. + PreprocessFrameAndVerify(resampled_source_frame, cropped_source.width(), + cropped_source.height(), vpm, out_frame); WriteProcessedFrameForVisualInspection(resampled_source_frame, *out_frame); // Compute PSNR against the cropped source frame and check expectation. double psnr = - I420PSNR(*cropped_source_buffer, *out_frame->video_frame_buffer()); + I420PSNR(cropped_source, *out_frame->video_frame_buffer()); EXPECT_GT(psnr, expected_psnr); printf( "PSNR: %f. PSNR is between source of size %d %d, and a modified " diff --git a/webrtc/test/BUILD.gn b/webrtc/test/BUILD.gn index 94cf7bed29..8de7ae187c 100644 --- a/webrtc/test/BUILD.gn +++ b/webrtc/test/BUILD.gn @@ -128,6 +128,7 @@ rtc_source_set("test_support") { ] deps = [ + ":video_test_common", "../base:gtest_prod", "../base:rtc_base_approved", "../common_video", @@ -320,7 +321,6 @@ rtc_source_set("test_common") { deps = [ ":rtp_test_utils", ":test_support", - ":video_test_common", "..:webrtc_common", "../audio", "../base:rtc_base_approved", diff --git a/webrtc/test/frame_generator.cc b/webrtc/test/frame_generator.cc index 27935e4b26..2f911d8024 100644 --- a/webrtc/test/frame_generator.cc +++ b/webrtc/test/frame_generator.cc @@ -18,7 +18,7 @@ #include "webrtc/base/checks.h" #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" #include "webrtc/system_wrappers/include/clock.h" -#include "libyuv/convert.h" +#include "webrtc/test/frame_utils.h" namespace webrtc { namespace test { @@ -101,35 +101,21 @@ class YuvFileGenerator : public FrameGenerator { return temp_frame_.get(); } - // TODO(nisse): Have a frame reader in one place. And read directly - // into the planes of an I420Buffer, the extra copying below is silly. void ReadNextFrame() { - size_t bytes_read = - fread(frame_buffer_.get(), 1, frame_size_, files_[file_index_]); - if (bytes_read < frame_size_) { + last_read_buffer_ = + test::ReadI420Buffer(static_cast(width_), + static_cast(height_), + files_[file_index_]); + if (!last_read_buffer_) { // No more frames to read in this file, rewind and move to next file. rewind(files_[file_index_]); file_index_ = (file_index_ + 1) % files_.size(); - bytes_read = fread(frame_buffer_.get(), 1, frame_size_, - files_[file_index_]); - assert(bytes_read >= frame_size_); + last_read_buffer_ = + test::ReadI420Buffer(static_cast(width_), + static_cast(height_), + files_[file_index_]); + RTC_CHECK(last_read_buffer_); } - - size_t half_width = (width_ + 1) / 2; - size_t size_y = width_ * height_; - size_t size_uv = half_width * ((height_ + 1) / 2); - last_read_buffer_ = I420Buffer::Create( - static_cast(width_), static_cast(height_), - static_cast(width_), static_cast(half_width), - static_cast(half_width)); - libyuv::I420Copy( - frame_buffer_.get(), static_cast(width_), - frame_buffer_.get() + size_y, static_cast(half_width), - frame_buffer_.get() + size_y + size_uv, static_cast(half_width), - last_read_buffer_->MutableDataY(), last_read_buffer_->StrideY(), - last_read_buffer_->MutableDataU(), last_read_buffer_->StrideU(), - last_read_buffer_->MutableDataV(), last_read_buffer_->StrideV(), - static_cast(width_), static_cast(height_)); } private: diff --git a/webrtc/test/frame_utils.cc b/webrtc/test/frame_utils.cc index 0fad3adec8..b332b8fb91 100644 --- a/webrtc/test/frame_utils.cc +++ b/webrtc/test/frame_utils.cc @@ -72,5 +72,22 @@ bool FrameBufsEqual(const rtc::scoped_refptr& f1, half_width, half_height); } +rtc::scoped_refptr ReadI420Buffer(int width, int height, FILE *f) { + int half_width = (width + 1) / 2; + rtc::scoped_refptr buffer( + // Explicit stride, no padding between rows. + I420Buffer::Create(width, height, width, half_width, half_width)); + size_t size_y = static_cast(width) * height; + size_t size_uv = static_cast(half_width) * ((height + 1) / 2); + + if (fread(buffer->MutableDataY(), 1, size_y, f) < size_y) + return nullptr; + if (fread(buffer->MutableDataU(), 1, size_uv, f) < size_uv) + return nullptr; + if (fread(buffer->MutableDataV(), 1, size_uv, f) < size_uv) + return nullptr; + return buffer; +} + } // namespace test } // namespace webrtc diff --git a/webrtc/test/frame_utils.h b/webrtc/test/frame_utils.h index aef3c9ff2a..28a7e45925 100644 --- a/webrtc/test/frame_utils.h +++ b/webrtc/test/frame_utils.h @@ -14,6 +14,7 @@ #include "webrtc/base/scoped_ref_ptr.h" namespace webrtc { +class I420Buffer; class VideoFrame; class VideoFrameBuffer; namespace test { @@ -38,6 +39,8 @@ bool FramesEqual(const webrtc::VideoFrame& f1, const webrtc::VideoFrame& f2); bool FrameBufsEqual(const rtc::scoped_refptr& f1, const rtc::scoped_refptr& f2); +rtc::scoped_refptr ReadI420Buffer(int width, int height, FILE *); + } // namespace test } // namespace webrtc diff --git a/webrtc/test/test.gyp b/webrtc/test/test.gyp index 1d476a96c6..c2223a8495 100644 --- a/webrtc/test/test.gyp +++ b/webrtc/test/test.gyp @@ -81,6 +81,7 @@ '<(webrtc_root)/base/base.gyp:rtc_base_approved', '<(webrtc_root)/common_video/common_video.gyp:common_video', '<(webrtc_root)/system_wrappers/system_wrappers.gyp:system_wrappers', + 'video_test_common', ], 'sources': [ 'gmock.h', @@ -211,7 +212,6 @@ '<(webrtc_root)/webrtc.gyp:webrtc', 'rtp_test_utils', 'test_support', - 'video_test_common', ], }, { diff --git a/webrtc/test/testsupport/frame_reader.cc b/webrtc/test/testsupport/frame_reader.cc index b03616aa44..dc0d822e9b 100644 --- a/webrtc/test/testsupport/frame_reader.cc +++ b/webrtc/test/testsupport/frame_reader.cc @@ -12,15 +12,17 @@ #include +#include "webrtc/test/frame_utils.h" #include "webrtc/test/testsupport/fileutils.h" +#include "webrtc/common_video/include/video_frame_buffer.h" namespace webrtc { namespace test { FrameReaderImpl::FrameReaderImpl(std::string input_filename, - size_t frame_length_in_bytes) + int width, int height) : input_filename_(input_filename), - frame_length_in_bytes_(frame_length_in_bytes), + width_(width), height_(height), input_file_(NULL) { } @@ -29,11 +31,14 @@ FrameReaderImpl::~FrameReaderImpl() { } bool FrameReaderImpl::Init() { - if (frame_length_in_bytes_ <= 0) { - fprintf(stderr, "Frame length must be >0, was %zu\n", - frame_length_in_bytes_); + if (width_ <= 0 || height_ <= 0) { + fprintf(stderr, "Frame width and height must be >0, was %d x %d\n", + width_, height_); return false; } + frame_length_in_bytes_ = + width_ * height_ + 2 * ((width_ + 1) / 2) * ((height_ + 1) / 2); + input_file_ = fopen(input_filename_.c_str(), "rb"); if (input_file_ == NULL) { fprintf(stderr, "Couldn't open input file for reading: %s\n", @@ -58,24 +63,18 @@ void FrameReaderImpl::Close() { } } -bool FrameReaderImpl::ReadFrame(uint8_t* source_buffer) { - assert(source_buffer); +rtc::scoped_refptr FrameReaderImpl::ReadFrame() { if (input_file_ == NULL) { fprintf(stderr, "FrameReader is not initialized (input file is NULL)\n"); - return false; + return nullptr; } - size_t nbr_read = fread(source_buffer, 1, frame_length_in_bytes_, - input_file_); - if (nbr_read != static_cast(frame_length_in_bytes_) && - ferror(input_file_)) { + rtc::scoped_refptr buffer( + ReadI420Buffer(width_, height_, input_file_)); + if (!buffer && ferror(input_file_)) { fprintf(stderr, "Error reading from input file: %s\n", input_filename_.c_str()); - return false; } - if (feof(input_file_) != 0) { - return false; // No more frames to process. - } - return true; + return buffer; } size_t FrameReaderImpl::FrameLength() { return frame_length_in_bytes_; } diff --git a/webrtc/test/testsupport/frame_reader.h b/webrtc/test/testsupport/frame_reader.h index 9b50ec7bf4..13800cdc6f 100644 --- a/webrtc/test/testsupport/frame_reader.h +++ b/webrtc/test/testsupport/frame_reader.h @@ -15,12 +15,14 @@ #include +#include "webrtc/base/scoped_ref_ptr.h" #include "webrtc/typedefs.h" namespace webrtc { +class I420Buffer; namespace test { -// Handles reading of frames from video files. +// Handles reading of I420 frames from video files. class FrameReader { public: virtual ~FrameReader() {} @@ -30,11 +32,9 @@ class FrameReader { // Returns false if an error has occurred, in addition to printing to stderr. virtual bool Init() = 0; - // Reads a frame into the supplied buffer, which must contain enough space - // for the frame size. - // Returns true if there are more frames to read, false if we've already - // read the last frame (in the previous call). - virtual bool ReadFrame(uint8_t* source_buffer) = 0; + // Reads a frame from the input file. On success, returns the frame. + // Returns nullptr if encountering end of file or a read error. + virtual rtc::scoped_refptr ReadFrame() = 0; // Closes the input file if open. Essentially makes this class impossible // to use anymore. Will also be invoked by the destructor. @@ -51,12 +51,11 @@ class FrameReaderImpl : public FrameReader { // Creates a file handler. The input file is assumed to exist and be readable. // Parameters: // input_filename The file to read from. - // frame_length_in_bytes The size of each frame. - // For YUV this is 3 * width * height / 2 - FrameReaderImpl(std::string input_filename, size_t frame_length_in_bytes); + // width, height Size of each frame to read. + FrameReaderImpl(std::string input_filename, int width, int height); ~FrameReaderImpl() override; bool Init() override; - bool ReadFrame(uint8_t* source_buffer) override; + rtc::scoped_refptr ReadFrame() override; void Close() override; size_t FrameLength() override; int NumberOfFrames() override; @@ -64,6 +63,8 @@ class FrameReaderImpl : public FrameReader { private: std::string input_filename_; size_t frame_length_in_bytes_; + int width_; + int height_; int number_of_frames_; FILE* input_file_; }; diff --git a/webrtc/test/testsupport/frame_reader_unittest.cc b/webrtc/test/testsupport/frame_reader_unittest.cc index 8b16926b5e..d0b286e059 100644 --- a/webrtc/test/testsupport/frame_reader_unittest.cc +++ b/webrtc/test/testsupport/frame_reader_unittest.cc @@ -12,14 +12,13 @@ #include "webrtc/test/gtest.h" #include "webrtc/test/testsupport/fileutils.h" +#include "webrtc/common_video/include/video_frame_buffer.h" namespace webrtc { namespace test { const std::string kInputFileContents = "baz"; -// Setting the kFrameLength value to a value much larger than the -// file to test causes the ReadFrame test to fail on Windows. -const size_t kFrameLength = 1000; +const size_t kFrameLength = 3; class FrameReaderTest: public testing::Test { protected: @@ -33,7 +32,7 @@ class FrameReaderTest: public testing::Test { fprintf(dummy, "%s", kInputFileContents.c_str()); fclose(dummy); - frame_reader_ = new FrameReaderImpl(temp_filename_, kFrameLength); + frame_reader_ = new FrameReaderImpl(temp_filename_, 1, 1); ASSERT_TRUE(frame_reader_->Init()); } void TearDown() { @@ -46,25 +45,25 @@ class FrameReaderTest: public testing::Test { }; TEST_F(FrameReaderTest, InitSuccess) { - FrameReaderImpl frame_reader(temp_filename_, kFrameLength); + FrameReaderImpl frame_reader(temp_filename_, 1, 1); ASSERT_TRUE(frame_reader.Init()); ASSERT_EQ(kFrameLength, frame_reader.FrameLength()); - ASSERT_EQ(0, frame_reader.NumberOfFrames()); + ASSERT_EQ(1, frame_reader.NumberOfFrames()); } TEST_F(FrameReaderTest, ReadFrame) { - uint8_t buffer[3]; - bool result = frame_reader_->ReadFrame(buffer); - ASSERT_FALSE(result); // No more files to read. - ASSERT_EQ(kInputFileContents[0], buffer[0]); - ASSERT_EQ(kInputFileContents[1], buffer[1]); - ASSERT_EQ(kInputFileContents[2], buffer[2]); + rtc::scoped_refptr buffer; + buffer = frame_reader_->ReadFrame(); + ASSERT_TRUE(buffer); + ASSERT_EQ(kInputFileContents[0], buffer->DataY()[0]); + ASSERT_EQ(kInputFileContents[1], buffer->DataU()[0]); + ASSERT_EQ(kInputFileContents[2], buffer->DataV()[0]); + ASSERT_FALSE(frame_reader_->ReadFrame()); // End of file } TEST_F(FrameReaderTest, ReadFrameUninitialized) { - uint8_t buffer[3]; - FrameReaderImpl file_reader(temp_filename_, kFrameLength); - ASSERT_FALSE(file_reader.ReadFrame(buffer)); + FrameReaderImpl file_reader(temp_filename_, 1, 1); + ASSERT_FALSE(file_reader.ReadFrame()); } } // namespace test diff --git a/webrtc/test/testsupport/metrics/video_metrics.cc b/webrtc/test/testsupport/metrics/video_metrics.cc index 75bbc61fce..3013b61355 100644 --- a/webrtc/test/testsupport/metrics/video_metrics.cc +++ b/webrtc/test/testsupport/metrics/video_metrics.cc @@ -17,6 +17,7 @@ #include #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" +#include "webrtc/test/frame_utils.h" #include "webrtc/video_frame.h" #include "libyuv/convert.h" @@ -110,44 +111,17 @@ int CalculateMetrics(VideoMetricsType video_metrics_type, int frame_number = 0; // Read reference and test frames. - const size_t frame_length = 3 * width * height >> 1; - rtc::scoped_refptr ref_i420_buffer; - rtc::scoped_refptr test_i420_buffer; - std::unique_ptr ref_buffer(new uint8_t[frame_length]); - std::unique_ptr test_buffer(new uint8_t[frame_length]); + for (;;) { + rtc::scoped_refptr ref_i420_buffer( + test::ReadI420Buffer(width, height, ref_fp)); + if (!ref_i420_buffer) + break; - // Set decoded image parameters. - int half_width = (width + 1) / 2; - ref_i420_buffer = - I420Buffer::Create(width, height, width, half_width, half_width); - test_i420_buffer = - I420Buffer::Create(width, height, width, half_width, half_width); + rtc::scoped_refptr test_i420_buffer( + test::ReadI420Buffer(width, height, test_fp)); - // TODO(nisse): Have a frame reader in one place. And read directly - // into the planes of an I420Buffer, the extra copying below is silly. - size_t ref_bytes = fread(ref_buffer.get(), 1, frame_length, ref_fp); - size_t test_bytes = fread(test_buffer.get(), 1, frame_length, test_fp); - while (ref_bytes == frame_length && test_bytes == frame_length) { - // Converting from buffer to plane representation. - size_t size_y = width * height; - size_t size_uv = half_width * ((height + 1) / 2); - libyuv::I420Copy( - ref_buffer.get(), width, - ref_buffer.get() + size_y, half_width, - ref_buffer.get() + size_y + size_uv, half_width, - ref_i420_buffer->MutableDataY(), ref_i420_buffer->StrideY(), - ref_i420_buffer->MutableDataU(), ref_i420_buffer->StrideU(), - ref_i420_buffer->MutableDataV(), ref_i420_buffer->StrideV(), - width, height); - - libyuv::I420Copy( - test_buffer.get(), width, - test_buffer.get() + size_y, half_width, - test_buffer.get() + size_y + size_uv, half_width, - test_i420_buffer->MutableDataY(), test_i420_buffer->StrideY(), - test_i420_buffer->MutableDataU(), test_i420_buffer->StrideU(), - test_i420_buffer->MutableDataV(), test_i420_buffer->StrideV(), - width, height); + if (!test_i420_buffer) + break; switch (video_metrics_type) { case kPSNR: @@ -166,8 +140,6 @@ int CalculateMetrics(VideoMetricsType video_metrics_type, break; } frame_number++; - ref_bytes = fread(ref_buffer.get(), 1, frame_length, ref_fp); - test_bytes = fread(test_buffer.get(), 1, frame_length, test_fp); } int return_code = 0; if (frame_number == 0) { diff --git a/webrtc/test/testsupport/mock/mock_frame_reader.h b/webrtc/test/testsupport/mock/mock_frame_reader.h index 8d1c66998c..5fd28737a7 100644 --- a/webrtc/test/testsupport/mock/mock_frame_reader.h +++ b/webrtc/test/testsupport/mock/mock_frame_reader.h @@ -21,7 +21,7 @@ namespace test { class MockFrameReader : public FrameReader { public: MOCK_METHOD0(Init, bool()); - MOCK_METHOD1(ReadFrame, bool(uint8_t* source_buffer)); + MOCK_METHOD0(ReadFrame, rtc::scoped_refptr()); MOCK_METHOD0(Close, void()); MOCK_METHOD0(FrameLength, size_t()); MOCK_METHOD0(NumberOfFrames, int());