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
20namespace webrtc {
21
22enum { kMaxWaitEncTimeMs = 100 };
23enum { kMaxWaitDecTimeMs = 25 };
24
25static const uint32_t kTestTimestamp = 123;
26static const int64_t kTestNtpTimeMs = 456;
27
28// TODO(mikhal): Replace these with mocks.
29class 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
49int 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
65bool Vp8UnitTestEncodeCompleteCallback::EncodeComplete() {
66  if (encode_complete_) {
67    encode_complete_ = false;
68    return true;
69  }
70  return false;
71}
72
73class 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
85bool Vp8UnitTestDecodeCompleteCallback::DecodeComplete() {
86  if (decode_complete) {
87    decode_complete = false;
88    return true;
89  }
90  return false;
91}
92
93int Vp8UnitTestDecodeCompleteCallback::Decoded(I420VideoFrame& image) {
94  decoded_video_frame_->CopyFrame(image);
95  decode_complete = true;
96  return 0;
97}
98
99class 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
195TEST_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
206TEST_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
233TEST_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
250TEST_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