OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include <stdio.h> | 11 #include <stdio.h> |
12 | 12 |
13 #include <memory> | 13 #include <memory> |
14 | 14 |
15 #include "webrtc/api/video/i420_buffer.h" | 15 #include "webrtc/api/video/i420_buffer.h" |
16 #include "webrtc/base/checks.h" | 16 #include "webrtc/base/checks.h" |
17 #include "webrtc/base/optional.h" | 17 #include "webrtc/base/optional.h" |
18 #include "webrtc/base/timeutils.h" | 18 #include "webrtc/base/timeutils.h" |
19 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" | 19 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" |
20 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h" | 20 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h" |
21 #include "webrtc/modules/video_coding/codecs/vp8/temporal_layers.h" | 21 #include "webrtc/modules/video_coding/codecs/vp8/temporal_layers.h" |
22 #include "webrtc/modules/video_coding/include/video_codec_interface.h" | |
22 #include "webrtc/test/frame_utils.h" | 23 #include "webrtc/test/frame_utils.h" |
23 #include "webrtc/test/gtest.h" | 24 #include "webrtc/test/gtest.h" |
24 #include "webrtc/test/testsupport/fileutils.h" | 25 #include "webrtc/test/testsupport/fileutils.h" |
25 | 26 |
26 namespace webrtc { | 27 namespace webrtc { |
27 | 28 |
28 namespace { | 29 namespace { |
29 void Calc16ByteAlignedStride(int width, int* stride_y, int* stride_uv) { | 30 void Calc16ByteAlignedStride(int width, int* stride_y, int* stride_uv) { |
30 *stride_y = 16 * ((width + 15) / 16); | 31 *stride_y = 16 * ((width + 15) / 16); |
31 *stride_uv = 16 * ((width + 31) / 32); | 32 *stride_uv = 16 * ((width + 31) / 32); |
32 } | 33 } |
33 | 34 |
34 } // Anonymous namespace | 35 } // Anonymous namespace |
35 | 36 |
36 enum { kMaxWaitEncTimeMs = 100 }; | 37 enum { kMaxWaitEncTimeMs = 100 }; |
37 enum { kMaxWaitDecTimeMs = 25 }; | 38 enum { kMaxWaitDecTimeMs = 25 }; |
38 | 39 |
39 static const uint32_t kTestTimestamp = 123; | 40 static const uint32_t kTestTimestamp = 123; |
40 static const int64_t kTestNtpTimeMs = 456; | 41 static const int64_t kTestNtpTimeMs = 456; |
41 | 42 |
42 // TODO(mikhal): Replace these with mocks. | 43 // TODO(mikhal): Replace these with mocks. |
43 class Vp8UnitTestEncodeCompleteCallback : public webrtc::EncodedImageCallback { | 44 class Vp8UnitTestEncodeCompleteCallback : public webrtc::EncodedImageCallback { |
44 public: | 45 public: |
45 Vp8UnitTestEncodeCompleteCallback(EncodedImage* frame, | 46 Vp8UnitTestEncodeCompleteCallback(EncodedImage* frame, |
47 CodecSpecificInfo* codec_specific_info, | |
46 unsigned int decoderSpecificSize, | 48 unsigned int decoderSpecificSize, |
47 void* decoderSpecificInfo) | 49 void* decoderSpecificInfo) |
48 : encoded_frame_(frame), encode_complete_(false) {} | 50 : encoded_frame_(frame), |
51 codec_specific_info_(codec_specific_info), | |
52 encode_complete_(false) {} | |
49 | 53 |
50 Result OnEncodedImage(const EncodedImage& encoded_frame_, | 54 Result OnEncodedImage(const EncodedImage& encoded_frame_, |
51 const CodecSpecificInfo* codec_specific_info, | 55 const CodecSpecificInfo* codec_specific_info, |
52 const RTPFragmentationHeader* fragmentation) override; | 56 const RTPFragmentationHeader* fragmentation) override; |
53 bool EncodeComplete(); | 57 bool EncodeComplete(); |
54 | 58 |
55 private: | 59 private: |
56 EncodedImage* const encoded_frame_; | 60 EncodedImage* const encoded_frame_; |
61 CodecSpecificInfo* const codec_specific_info_; | |
57 std::unique_ptr<uint8_t[]> frame_buffer_; | 62 std::unique_ptr<uint8_t[]> frame_buffer_; |
58 bool encode_complete_; | 63 bool encode_complete_; |
59 }; | 64 }; |
60 | 65 |
61 webrtc::EncodedImageCallback::Result | 66 webrtc::EncodedImageCallback::Result |
62 Vp8UnitTestEncodeCompleteCallback::OnEncodedImage( | 67 Vp8UnitTestEncodeCompleteCallback::OnEncodedImage( |
63 const EncodedImage& encoded_frame, | 68 const EncodedImage& encoded_frame, |
64 const CodecSpecificInfo* codec_specific_info, | 69 const CodecSpecificInfo* codec_specific_info, |
65 const RTPFragmentationHeader* fragmentation) { | 70 const RTPFragmentationHeader* fragmentation) { |
66 if (encoded_frame_->_size < encoded_frame._length) { | 71 if (encoded_frame_->_size < encoded_frame._length) { |
67 delete[] encoded_frame_->_buffer; | 72 delete[] encoded_frame_->_buffer; |
68 frame_buffer_.reset(new uint8_t[encoded_frame._length]); | 73 frame_buffer_.reset(new uint8_t[encoded_frame._length]); |
69 encoded_frame_->_buffer = frame_buffer_.get(); | 74 encoded_frame_->_buffer = frame_buffer_.get(); |
70 encoded_frame_->_size = encoded_frame._length; | 75 encoded_frame_->_size = encoded_frame._length; |
71 } | 76 } |
72 memcpy(encoded_frame_->_buffer, encoded_frame._buffer, encoded_frame._length); | 77 memcpy(encoded_frame_->_buffer, encoded_frame._buffer, encoded_frame._length); |
73 encoded_frame_->_length = encoded_frame._length; | 78 encoded_frame_->_length = encoded_frame._length; |
74 encoded_frame_->_encodedWidth = encoded_frame._encodedWidth; | 79 encoded_frame_->_encodedWidth = encoded_frame._encodedWidth; |
75 encoded_frame_->_encodedHeight = encoded_frame._encodedHeight; | 80 encoded_frame_->_encodedHeight = encoded_frame._encodedHeight; |
76 encoded_frame_->_timeStamp = encoded_frame._timeStamp; | 81 encoded_frame_->_timeStamp = encoded_frame._timeStamp; |
77 encoded_frame_->_frameType = encoded_frame._frameType; | 82 encoded_frame_->_frameType = encoded_frame._frameType; |
78 encoded_frame_->_completeFrame = encoded_frame._completeFrame; | 83 encoded_frame_->_completeFrame = encoded_frame._completeFrame; |
79 encoded_frame_->qp_ = encoded_frame.qp_; | 84 encoded_frame_->qp_ = encoded_frame.qp_; |
85 codec_specific_info_->codecType = codec_specific_info->codecType; | |
86 // Skip |codec_name|, to avoid allocating. | |
87 codec_specific_info_->codecSpecific = codec_specific_info->codecSpecific; | |
80 encode_complete_ = true; | 88 encode_complete_ = true; |
81 return Result(Result::OK, 0); | 89 return Result(Result::OK, 0); |
82 } | 90 } |
83 | 91 |
84 bool Vp8UnitTestEncodeCompleteCallback::EncodeComplete() { | 92 bool Vp8UnitTestEncodeCompleteCallback::EncodeComplete() { |
85 if (encode_complete_) { | 93 if (encode_complete_) { |
86 encode_complete_ = false; | 94 encode_complete_ = false; |
87 return true; | 95 return true; |
88 } | 96 } |
89 return false; | 97 return false; |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
129 *decoded_qp_ = qp; | 137 *decoded_qp_ = qp; |
130 decode_complete = true; | 138 decode_complete = true; |
131 } | 139 } |
132 | 140 |
133 class TestVp8Impl : public ::testing::Test { | 141 class TestVp8Impl : public ::testing::Test { |
134 protected: | 142 protected: |
135 virtual void SetUp() { | 143 virtual void SetUp() { |
136 encoder_.reset(VP8Encoder::Create()); | 144 encoder_.reset(VP8Encoder::Create()); |
137 decoder_.reset(VP8Decoder::Create()); | 145 decoder_.reset(VP8Decoder::Create()); |
138 memset(&codec_inst_, 0, sizeof(codec_inst_)); | 146 memset(&codec_inst_, 0, sizeof(codec_inst_)); |
139 encode_complete_callback_.reset( | 147 encode_complete_callback_.reset(new Vp8UnitTestEncodeCompleteCallback( |
140 new Vp8UnitTestEncodeCompleteCallback(&encoded_frame_, 0, NULL)); | 148 &encoded_frame_, &codec_specific_info_, 0, nullptr)); |
141 decode_complete_callback_.reset( | 149 decode_complete_callback_.reset( |
142 new Vp8UnitTestDecodeCompleteCallback(&decoded_frame_, &decoded_qp_)); | 150 new Vp8UnitTestDecodeCompleteCallback(&decoded_frame_, &decoded_qp_)); |
143 encoder_->RegisterEncodeCompleteCallback(encode_complete_callback_.get()); | 151 encoder_->RegisterEncodeCompleteCallback(encode_complete_callback_.get()); |
144 decoder_->RegisterDecodeCompleteCallback(decode_complete_callback_.get()); | 152 decoder_->RegisterDecodeCompleteCallback(decode_complete_callback_.get()); |
145 // Using a QCIF image (aligned stride (u,v planes) > width). | 153 // Using a QCIF image (aligned stride (u,v planes) > width). |
146 // Processing only one frame. | 154 // Processing only one frame. |
147 source_file_ = fopen(test::ResourcePath("paris_qcif", "yuv").c_str(), "rb"); | 155 source_file_ = fopen(test::ResourcePath("paris_qcif", "yuv").c_str(), "rb"); |
148 ASSERT_TRUE(source_file_ != NULL); | 156 ASSERT_TRUE(source_file_ != nullptr); |
149 rtc::scoped_refptr<VideoFrameBuffer> compact_buffer( | 157 rtc::scoped_refptr<VideoFrameBuffer> compact_buffer( |
150 test::ReadI420Buffer(kWidth, kHeight, source_file_)); | 158 test::ReadI420Buffer(kWidth, kHeight, source_file_)); |
151 ASSERT_TRUE(compact_buffer); | 159 ASSERT_TRUE(compact_buffer); |
152 codec_inst_.width = kWidth; | 160 codec_inst_.width = kWidth; |
153 codec_inst_.height = kHeight; | 161 codec_inst_.height = kHeight; |
154 const int kFramerate = 30; | 162 const int kFramerate = 30; |
155 codec_inst_.maxFramerate = kFramerate; | 163 codec_inst_.maxFramerate = kFramerate; |
156 // Setting aligned stride values. | 164 // Setting aligned stride values. |
157 int stride_uv; | 165 int stride_uv; |
158 int stride_y; | 166 int stride_y; |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
209 const int kHeight = 144; | 217 const int kHeight = 144; |
210 | 218 |
211 std::unique_ptr<Vp8UnitTestEncodeCompleteCallback> encode_complete_callback_; | 219 std::unique_ptr<Vp8UnitTestEncodeCompleteCallback> encode_complete_callback_; |
212 std::unique_ptr<Vp8UnitTestDecodeCompleteCallback> decode_complete_callback_; | 220 std::unique_ptr<Vp8UnitTestDecodeCompleteCallback> decode_complete_callback_; |
213 std::unique_ptr<uint8_t[]> source_buffer_; | 221 std::unique_ptr<uint8_t[]> source_buffer_; |
214 FILE* source_file_; | 222 FILE* source_file_; |
215 std::unique_ptr<VideoFrame> input_frame_; | 223 std::unique_ptr<VideoFrame> input_frame_; |
216 std::unique_ptr<VideoEncoder> encoder_; | 224 std::unique_ptr<VideoEncoder> encoder_; |
217 std::unique_ptr<VideoDecoder> decoder_; | 225 std::unique_ptr<VideoDecoder> decoder_; |
218 EncodedImage encoded_frame_; | 226 EncodedImage encoded_frame_; |
227 CodecSpecificInfo codec_specific_info_; | |
219 rtc::Optional<VideoFrame> decoded_frame_; | 228 rtc::Optional<VideoFrame> decoded_frame_; |
220 rtc::Optional<uint8_t> decoded_qp_; | 229 rtc::Optional<uint8_t> decoded_qp_; |
221 VideoCodec codec_inst_; | 230 VideoCodec codec_inst_; |
222 TemporalLayersFactory tl_factory_; | 231 TemporalLayersFactory tl_factory_; |
223 }; | 232 }; |
224 | 233 |
225 TEST_F(TestVp8Impl, EncoderParameterTest) { | 234 TEST_F(TestVp8Impl, EncoderParameterTest) { |
226 strncpy(codec_inst_.plName, "VP8", 31); | 235 strncpy(codec_inst_.plName, "VP8", 31); |
227 codec_inst_.plType = 126; | 236 codec_inst_.plType = 126; |
228 codec_inst_.maxBitrate = 0; | 237 codec_inst_.maxBitrate = 0; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
267 EXPECT_EQ(encoded_frame_.qp_, *decoded_qp_); | 276 EXPECT_EQ(encoded_frame_.qp_, *decoded_qp_); |
268 } | 277 } |
269 | 278 |
270 #if defined(WEBRTC_ANDROID) | 279 #if defined(WEBRTC_ANDROID) |
271 #define MAYBE_AlignedStrideEncodeDecode DISABLED_AlignedStrideEncodeDecode | 280 #define MAYBE_AlignedStrideEncodeDecode DISABLED_AlignedStrideEncodeDecode |
272 #else | 281 #else |
273 #define MAYBE_AlignedStrideEncodeDecode AlignedStrideEncodeDecode | 282 #define MAYBE_AlignedStrideEncodeDecode AlignedStrideEncodeDecode |
274 #endif | 283 #endif |
275 TEST_F(TestVp8Impl, MAYBE_AlignedStrideEncodeDecode) { | 284 TEST_F(TestVp8Impl, MAYBE_AlignedStrideEncodeDecode) { |
276 SetUpEncodeDecode(); | 285 SetUpEncodeDecode(); |
277 encoder_->Encode(*input_frame_, NULL, NULL); | 286 encoder_->Encode(*input_frame_, nullptr, nullptr); |
278 EXPECT_GT(WaitForEncodedFrame(), 0u); | 287 EXPECT_GT(WaitForEncodedFrame(), 0u); |
279 // First frame should be a key frame. | 288 // First frame should be a key frame. |
280 encoded_frame_._frameType = kVideoFrameKey; | 289 encoded_frame_._frameType = kVideoFrameKey; |
281 encoded_frame_.ntp_time_ms_ = kTestNtpTimeMs; | 290 encoded_frame_.ntp_time_ms_ = kTestNtpTimeMs; |
282 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, | 291 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, |
283 decoder_->Decode(encoded_frame_, false, NULL)); | 292 decoder_->Decode(encoded_frame_, false, nullptr)); |
284 EXPECT_GT(WaitForDecodedFrame(), 0u); | 293 EXPECT_GT(WaitForDecodedFrame(), 0u); |
285 ASSERT_TRUE(decoded_frame_); | 294 ASSERT_TRUE(decoded_frame_); |
286 // Compute PSNR on all planes (faster than SSIM). | 295 // Compute PSNR on all planes (faster than SSIM). |
287 EXPECT_GT(I420PSNR(input_frame_.get(), &*decoded_frame_), 36); | 296 EXPECT_GT(I420PSNR(input_frame_.get(), &*decoded_frame_), 36); |
288 EXPECT_EQ(kTestTimestamp, decoded_frame_->timestamp()); | 297 EXPECT_EQ(kTestTimestamp, decoded_frame_->timestamp()); |
289 EXPECT_EQ(kTestNtpTimeMs, decoded_frame_->ntp_time_ms()); | 298 EXPECT_EQ(kTestNtpTimeMs, decoded_frame_->ntp_time_ms()); |
290 } | 299 } |
291 | 300 |
292 #if defined(WEBRTC_ANDROID) | 301 #if defined(WEBRTC_ANDROID) |
293 #define MAYBE_DecodeWithACompleteKeyFrame DISABLED_DecodeWithACompleteKeyFrame | 302 #define MAYBE_DecodeWithACompleteKeyFrame DISABLED_DecodeWithACompleteKeyFrame |
294 #else | 303 #else |
295 #define MAYBE_DecodeWithACompleteKeyFrame DecodeWithACompleteKeyFrame | 304 #define MAYBE_DecodeWithACompleteKeyFrame DecodeWithACompleteKeyFrame |
296 #endif | 305 #endif |
297 TEST_F(TestVp8Impl, MAYBE_DecodeWithACompleteKeyFrame) { | 306 TEST_F(TestVp8Impl, MAYBE_DecodeWithACompleteKeyFrame) { |
298 SetUpEncodeDecode(); | 307 SetUpEncodeDecode(); |
299 encoder_->Encode(*input_frame_, NULL, NULL); | 308 encoder_->Encode(*input_frame_, nullptr, nullptr); |
300 EXPECT_GT(WaitForEncodedFrame(), 0u); | 309 EXPECT_GT(WaitForEncodedFrame(), 0u); |
301 // Setting complete to false -> should return an error. | 310 // Setting complete to false -> should return an error. |
302 encoded_frame_._completeFrame = false; | 311 encoded_frame_._completeFrame = false; |
303 EXPECT_EQ(WEBRTC_VIDEO_CODEC_ERROR, | 312 EXPECT_EQ(WEBRTC_VIDEO_CODEC_ERROR, |
304 decoder_->Decode(encoded_frame_, false, NULL)); | 313 decoder_->Decode(encoded_frame_, false, nullptr)); |
305 // Setting complete back to true. Forcing a delta frame. | 314 // Setting complete back to true. Forcing a delta frame. |
306 encoded_frame_._frameType = kVideoFrameDelta; | 315 encoded_frame_._frameType = kVideoFrameDelta; |
307 encoded_frame_._completeFrame = true; | 316 encoded_frame_._completeFrame = true; |
308 EXPECT_EQ(WEBRTC_VIDEO_CODEC_ERROR, | 317 EXPECT_EQ(WEBRTC_VIDEO_CODEC_ERROR, |
309 decoder_->Decode(encoded_frame_, false, NULL)); | 318 decoder_->Decode(encoded_frame_, false, nullptr)); |
310 // Now setting a key frame. | 319 // Now setting a key frame. |
311 encoded_frame_._frameType = kVideoFrameKey; | 320 encoded_frame_._frameType = kVideoFrameKey; |
312 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, | 321 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, |
313 decoder_->Decode(encoded_frame_, false, NULL)); | 322 decoder_->Decode(encoded_frame_, false, nullptr)); |
314 ASSERT_TRUE(decoded_frame_); | 323 ASSERT_TRUE(decoded_frame_); |
315 EXPECT_GT(I420PSNR(input_frame_.get(), &*decoded_frame_), 36); | 324 EXPECT_GT(I420PSNR(input_frame_.get(), &*decoded_frame_), 36); |
316 } | 325 } |
317 | 326 |
327 TEST_F(TestVp8Impl, EncoderRetainsRtpStateAfterRelease) { | |
328 SetUpEncodeDecode(); | |
329 // Override default settings. | |
330 codec_inst_.VP8()->numberOfTemporalLayers = 2; | |
331 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, encoder_->InitEncode(&codec_inst_, 1, 1440)); | |
332 | |
333 // Temporal layer 0. | |
334 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, | |
335 encoder_->Encode(*input_frame_, nullptr, nullptr)); | |
336 ASSERT_TRUE(WaitForEncodedFrame()); | |
337 EXPECT_EQ(0, codec_specific_info_.codecSpecific.VP8.temporalIdx); | |
338 uint16_t picture_id = codec_specific_info_.codecSpecific.VP8.pictureId; | |
339 uint8_t tl0_pic_idx = codec_specific_info_.codecSpecific.VP8.tl0PicIdx; | |
340 | |
341 // Temporal layer 1. | |
342 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, | |
343 encoder_->Encode(*input_frame_, nullptr, nullptr)); | |
åsapersson
2017/04/27 12:09:39
increase timestamp for new frames (since it is use
| |
344 ASSERT_TRUE(WaitForEncodedFrame()); | |
345 EXPECT_EQ(1, codec_specific_info_.codecSpecific.VP8.temporalIdx); | |
346 EXPECT_EQ((picture_id + 1) % (1 << 15), | |
347 codec_specific_info_.codecSpecific.VP8.pictureId); | |
348 EXPECT_EQ(tl0_pic_idx, codec_specific_info_.codecSpecific.VP8.tl0PicIdx); | |
349 | |
350 // Reinit. | |
351 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, encoder_->Release()); | |
352 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, encoder_->InitEncode(&codec_inst_, 1, 1440)); | |
353 | |
354 // Temporal layer 0. | |
355 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, | |
356 encoder_->Encode(*input_frame_, nullptr, nullptr)); | |
357 ASSERT_TRUE(WaitForEncodedFrame()); | |
358 EXPECT_EQ(0, codec_specific_info_.codecSpecific.VP8.temporalIdx); | |
359 EXPECT_EQ((picture_id + 2) % (1 << 15), | |
360 codec_specific_info_.codecSpecific.VP8.pictureId); | |
361 EXPECT_EQ((tl0_pic_idx + 1) % (1 << 8), | |
362 codec_specific_info_.codecSpecific.VP8.tl0PicIdx); | |
363 | |
364 // Temporal layer 1. | |
365 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, | |
366 encoder_->Encode(*input_frame_, nullptr, nullptr)); | |
367 ASSERT_TRUE(WaitForEncodedFrame()); | |
368 EXPECT_EQ(1, codec_specific_info_.codecSpecific.VP8.temporalIdx); | |
369 EXPECT_EQ((picture_id + 3) % (1 << 15), | |
370 codec_specific_info_.codecSpecific.VP8.pictureId); | |
371 EXPECT_EQ((tl0_pic_idx + 1) % (1 << 8), | |
372 codec_specific_info_.codecSpecific.VP8.tl0PicIdx); | |
373 } | |
374 | |
318 } // namespace webrtc | 375 } // namespace webrtc |
OLD | NEW |