1 /* 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "testing/gtest/include/gtest/gtest.h" 12 #include "webrtc/modules/video_coding/codecs/test_framework/unit_test.h" 13 #include "webrtc/modules/video_coding/codecs/test_framework/video_source.h" 14 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h" 15 #include "webrtc/system_wrappers/interface/scoped_ptr.h" 16 #include "webrtc/system_wrappers/interface/tick_util.h" 17 #include "webrtc/test/testsupport/fileutils.h" 18 #include "webrtc/test/testsupport/gtest_disable.h" 19 20 namespace webrtc { 21 22 enum { kMaxWaitEncTimeMs = 100 }; 23 enum { kMaxWaitDecTimeMs = 25 }; 24 25 static const uint32_t kTestTimestamp = 123; 26 static const int64_t kTestNtpTimeMs = 456; 27 28 // TODO(mikhal): Replace these with mocks. 29 class Vp8UnitTestEncodeCompleteCallback : public webrtc::EncodedImageCallback { 30 public: 31 Vp8UnitTestEncodeCompleteCallback(VideoFrame* frame, 32 unsigned int decoderSpecificSize, 33 void* decoderSpecificInfo) 34 : encoded_video_frame_(frame), 35 encode_complete_(false) {} 36 int Encoded(EncodedImage& encodedImage, 37 const CodecSpecificInfo* codecSpecificInfo, 38 const RTPFragmentationHeader*); 39 bool EncodeComplete(); 40 // Note that this only makes sense if an encode has been completed 41 VideoFrameType EncodedFrameType() const {return encoded_frame_type_;} 42 43 private: 44 VideoFrame* encoded_video_frame_; 45 bool encode_complete_; 46 VideoFrameType encoded_frame_type_; 47 }; 48 49 int Vp8UnitTestEncodeCompleteCallback::Encoded(EncodedImage& encodedImage, 50 const CodecSpecificInfo* codecSpecificInfo, 51 const RTPFragmentationHeader* fragmentation) { 52 encoded_video_frame_->VerifyAndAllocate(encodedImage._size); 53 encoded_video_frame_->CopyFrame(encodedImage._size, encodedImage._buffer); 54 encoded_video_frame_->SetLength(encodedImage._length); 55 // TODO(mikhal): Update frame type API. 56 // encoded_video_frame_->SetFrameType(encodedImage._frameType); 57 encoded_video_frame_->SetWidth(encodedImage._encodedWidth); 58 encoded_video_frame_->SetHeight(encodedImage._encodedHeight); 59 encoded_video_frame_->SetTimeStamp(encodedImage._timeStamp); 60 encode_complete_ = true; 61 encoded_frame_type_ = encodedImage._frameType; 62 return 0; 63 } 64 65 bool Vp8UnitTestEncodeCompleteCallback::EncodeComplete() { 66 if (encode_complete_) { 67 encode_complete_ = false; 68 return true; 69 } 70 return false; 71 } 72 73 class Vp8UnitTestDecodeCompleteCallback : public webrtc::DecodedImageCallback { 74 public: 75 explicit Vp8UnitTestDecodeCompleteCallback(I420VideoFrame* frame) 76 : decoded_video_frame_(frame), 77 decode_complete(false) {} 78 int Decoded(webrtc::I420VideoFrame& frame); 79 bool DecodeComplete(); 80 private: 81 I420VideoFrame* decoded_video_frame_; 82 bool decode_complete; 83 }; 84 85 bool Vp8UnitTestDecodeCompleteCallback::DecodeComplete() { 86 if (decode_complete) { 87 decode_complete = false; 88 return true; 89 } 90 return false; 91 } 92 93 int Vp8UnitTestDecodeCompleteCallback::Decoded(I420VideoFrame& image) { 94 decoded_video_frame_->CopyFrame(image); 95 decode_complete = true; 96 return 0; 97 } 98 99 class TestVp8Impl : public ::testing::Test { 100 protected: 101 virtual void SetUp() { 102 encoder_.reset(VP8Encoder::Create()); 103 decoder_.reset(VP8Decoder::Create()); 104 memset(&codec_inst_, 0, sizeof(codec_inst_)); 105 encode_complete_callback_.reset(new 106 Vp8UnitTestEncodeCompleteCallback(&encoded_video_frame_, 0, NULL)); 107 decode_complete_callback_.reset(new 108 Vp8UnitTestDecodeCompleteCallback(&decoded_video_frame_)); 109 encoder_->RegisterEncodeCompleteCallback(encode_complete_callback_.get()); 110 decoder_->RegisterDecodeCompleteCallback(decode_complete_callback_.get()); 111 // Using a QCIF image (aligned stride (u,v planes) > width). 112 // Processing only one frame. 113 const VideoSource source(test::ResourcePath("paris_qcif", "yuv"), kQCIF); 114 length_source_frame_ = source.GetFrameLength(); 115 source_buffer_.reset(new uint8_t[length_source_frame_]); 116 source_file_ = fopen(source.GetFileName().c_str(), "rb"); 117 ASSERT_TRUE(source_file_ != NULL); 118 // Set input frame. 119 ASSERT_EQ(fread(source_buffer_.get(), 1, length_source_frame_, 120 source_file_), length_source_frame_); 121 codec_inst_.width = source.GetWidth(); 122 codec_inst_.height = source.GetHeight(); 123 codec_inst_.maxFramerate = source.GetFrameRate(); 124 // Setting aligned stride values. 125 int stride_uv = 0; 126 int stride_y = 0; 127 Calc16ByteAlignedStride(codec_inst_.width, &stride_y, &stride_uv); 128 EXPECT_EQ(stride_y, 176); 129 EXPECT_EQ(stride_uv, 96); 130 131 input_frame_.CreateEmptyFrame(codec_inst_.width, codec_inst_.height, 132 stride_y, stride_uv, stride_uv); 133 input_frame_.set_timestamp(kTestTimestamp); 134 // Using ConvertToI420 to add stride to the image. 135 EXPECT_EQ(0, ConvertToI420(kI420, source_buffer_.get(), 0, 0, 136 codec_inst_.width, codec_inst_.height, 137 0, kRotateNone, &input_frame_)); 138 } 139 140 void SetUpEncodeDecode() { 141 codec_inst_.startBitrate = 300; 142 codec_inst_.maxBitrate = 4000; 143 codec_inst_.qpMax = 56; 144 codec_inst_.codecSpecific.VP8.denoisingOn = true; 145 146 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, 147 encoder_->InitEncode(&codec_inst_, 1, 1440)); 148 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, decoder_->InitDecode(&codec_inst_, 1)); 149 } 150 151 int WaitForEncodedFrame() const { 152 int64_t startTime = TickTime::MillisecondTimestamp(); 153 while (TickTime::MillisecondTimestamp() - startTime < kMaxWaitEncTimeMs) { 154 if (encode_complete_callback_->EncodeComplete()) { 155 return encoded_video_frame_.Length(); 156 } 157 } 158 return 0; 159 } 160 161 int WaitForDecodedFrame() const { 162 int64_t startTime = TickTime::MillisecondTimestamp(); 163 while (TickTime::MillisecondTimestamp() - startTime < kMaxWaitDecTimeMs) { 164 if (decode_complete_callback_->DecodeComplete()) { 165 return CalcBufferSize(kI420, decoded_video_frame_.width(), 166 decoded_video_frame_.height()); 167 } 168 } 169 return 0; 170 } 171 172 void VideoFrameToEncodedImage(VideoFrame& frame, EncodedImage &image) { 173 image._buffer = frame.Buffer(); 174 image._length = frame.Length(); 175 image._size = frame.Size(); 176 image._timeStamp = frame.TimeStamp(); 177 image._encodedWidth = frame.Width(); 178 image._encodedHeight = frame.Height(); 179 image._completeFrame = true; 180 } 181 182 scoped_ptr<Vp8UnitTestEncodeCompleteCallback> encode_complete_callback_; 183 scoped_ptr<Vp8UnitTestDecodeCompleteCallback> decode_complete_callback_; 184 scoped_ptr<uint8_t[]> source_buffer_; 185 FILE* source_file_; 186 I420VideoFrame input_frame_; 187 scoped_ptr<VideoEncoder> encoder_; 188 scoped_ptr<VideoDecoder> decoder_; 189 VideoFrame encoded_video_frame_; 190 I420VideoFrame decoded_video_frame_; 191 unsigned int length_source_frame_; 192 VideoCodec codec_inst_; 193 }; 194 195 TEST_F(TestVp8Impl, DISABLED_ON_ANDROID(BaseUnitTest)) { 196 // TODO(mikhal): Remove dependency. Move all test code here. 197 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, encoder_->Release()); 198 UnitTest unittest; 199 unittest.SetEncoder(encoder_.get()); 200 unittest.SetDecoder(decoder_.get()); 201 unittest.Setup(); 202 unittest.Perform(); 203 unittest.Print(); 204 } 205 206 TEST_F(TestVp8Impl, EncoderParameterTest) { 207 strncpy(codec_inst_.plName, "VP8", 31); 208 codec_inst_.plType = 126; 209 codec_inst_.maxBitrate = 0; 210 codec_inst_.minBitrate = 0; 211 codec_inst_.width = 1440; 212 codec_inst_.height = 1080; 213 codec_inst_.maxFramerate = 30; 214 codec_inst_.startBitrate = 300; 215 codec_inst_.qpMax = 56; 216 codec_inst_.codecSpecific.VP8.complexity = kComplexityNormal; 217 codec_inst_.codecSpecific.VP8.numberOfTemporalLayers = 1; 218 // Calls before InitEncode(). 219 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, encoder_->Release()); 220 int bit_rate = 300; 221 EXPECT_EQ(WEBRTC_VIDEO_CODEC_UNINITIALIZED, 222 encoder_->SetRates(bit_rate, codec_inst_.maxFramerate)); 223 224 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, 225 encoder_->InitEncode(&codec_inst_, 1, 1440)); 226 227 // Decoder parameter tests. 228 // Calls before InitDecode(). 229 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, decoder_->Release()); 230 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, decoder_->InitDecode(&codec_inst_, 1)); 231 } 232 233 TEST_F(TestVp8Impl, DISABLED_ON_ANDROID(AlignedStrideEncodeDecode)) { 234 SetUpEncodeDecode(); 235 encoder_->Encode(input_frame_, NULL, NULL); 236 EXPECT_GT(WaitForEncodedFrame(), 0); 237 EncodedImage encodedImage; 238 VideoFrameToEncodedImage(encoded_video_frame_, encodedImage); 239 // First frame should be a key frame. 240 encodedImage._frameType = kKeyFrame; 241 encodedImage.ntp_time_ms_ = kTestNtpTimeMs; 242 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, decoder_->Decode(encodedImage, false, NULL)); 243 EXPECT_GT(WaitForDecodedFrame(), 0); 244 // Compute PSNR on all planes (faster than SSIM). 245 EXPECT_GT(I420PSNR(&input_frame_, &decoded_video_frame_), 36); 246 EXPECT_EQ(kTestTimestamp, decoded_video_frame_.timestamp()); 247 EXPECT_EQ(kTestNtpTimeMs, decoded_video_frame_.ntp_time_ms()); 248 } 249 250 TEST_F(TestVp8Impl, DISABLED_ON_ANDROID(DecodeWithACompleteKeyFrame)) { 251 SetUpEncodeDecode(); 252 encoder_->Encode(input_frame_, NULL, NULL); 253 EXPECT_GT(WaitForEncodedFrame(), 0); 254 EncodedImage encodedImage; 255 VideoFrameToEncodedImage(encoded_video_frame_, encodedImage); 256 // Setting complete to false -> should return an error. 257 encodedImage._completeFrame = false; 258 EXPECT_EQ(WEBRTC_VIDEO_CODEC_ERROR, 259 decoder_->Decode(encodedImage, false, NULL)); 260 // Setting complete back to true. Forcing a delta frame. 261 encodedImage._frameType = kDeltaFrame; 262 encodedImage._completeFrame = true; 263 EXPECT_EQ(WEBRTC_VIDEO_CODEC_ERROR, 264 decoder_->Decode(encodedImage, false, NULL)); 265 // Now setting a key frame. 266 encodedImage._frameType = kKeyFrame; 267 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, 268 decoder_->Decode(encodedImage, false, NULL)); 269 EXPECT_GT(I420PSNR(&input_frame_, &decoded_video_frame_), 36); 270 } 271 272 } // namespace webrtc 273