| /* |
| * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #include <math.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include <cassert> |
| |
| #include "gtest/gtest.h" |
| #include "testsupport/fileutils.h" |
| #include "tick_util.h" |
| #include "unit_test.h" |
| #include "video_source.h" |
| |
| using namespace webrtc; |
| |
| UnitTest::UnitTest() |
| : |
| Test("UnitTest", "Unit test"), |
| _tests(0), |
| _errors(0), |
| _source(NULL), |
| _refFrame(NULL), |
| _refEncFrame(NULL), |
| _refDecFrame(NULL), |
| _refEncFrameLength(0), |
| _sourceFile(NULL), |
| _encodeCompleteCallback(NULL), |
| _decodeCompleteCallback(NULL) |
| { |
| } |
| |
| UnitTest::UnitTest(std::string name, std::string description) |
| : |
| Test(name, description), |
| _tests(0), |
| _errors(0), |
| _source(NULL), |
| _refFrame(NULL), |
| _refEncFrame(NULL), |
| _refDecFrame(NULL), |
| _refEncFrameLength(0), |
| _sourceFile(NULL), |
| _encodeCompleteCallback(NULL), |
| _decodeCompleteCallback(NULL) |
| { |
| } |
| |
| UnitTest::~UnitTest() |
| { |
| if (_encodeCompleteCallback) { |
| delete _encodeCompleteCallback; |
| } |
| |
| if (_decodeCompleteCallback) { |
| delete _decodeCompleteCallback; |
| } |
| |
| if (_source) { |
| delete _source; |
| } |
| |
| if (_refFrame) { |
| delete [] _refFrame; |
| } |
| |
| if (_refDecFrame) { |
| delete [] _refDecFrame; |
| } |
| |
| if (_sourceBuffer) { |
| delete [] _sourceBuffer; |
| } |
| |
| if (_sourceFile) { |
| fclose(_sourceFile); |
| } |
| |
| if (_refEncFrame) { |
| delete [] _refEncFrame; |
| } |
| } |
| |
| WebRtc_Word32 |
| UnitTestEncodeCompleteCallback::Encoded(EncodedImage& encodedImage, |
| const webrtc::CodecSpecificInfo* codecSpecificInfo, |
| const webrtc::RTPFragmentationHeader* |
| fragmentation) |
| { |
| _encodedVideoBuffer->VerifyAndAllocate(encodedImage._size); |
| _encodedVideoBuffer->CopyBuffer(encodedImage._size, encodedImage._buffer); |
| _encodedVideoBuffer->UpdateLength(encodedImage._length); |
| _encodedVideoBuffer->SetFrameType(encodedImage._frameType); |
| _encodedVideoBuffer->SetCaptureWidth( |
| (WebRtc_UWord16)encodedImage._encodedWidth); |
| _encodedVideoBuffer->SetCaptureHeight( |
| (WebRtc_UWord16)encodedImage._encodedHeight); |
| _encodedVideoBuffer->SetTimeStamp(encodedImage._timeStamp); |
| _encodeComplete = true; |
| _encodedFrameType = encodedImage._frameType; |
| return 0; |
| } |
| |
| WebRtc_Word32 UnitTestDecodeCompleteCallback::Decoded(RawImage& image) |
| { |
| _decodedVideoBuffer->VerifyAndAllocate(image._length); |
| _decodedVideoBuffer->CopyBuffer(image._length, image._buffer); |
| _decodedVideoBuffer->SetWidth(image._width); |
| _decodedVideoBuffer->SetHeight(image._height); |
| _decodedVideoBuffer->SetTimeStamp(image._timeStamp); |
| _decodeComplete = true; |
| return 0; |
| } |
| |
| bool |
| UnitTestEncodeCompleteCallback::EncodeComplete() |
| { |
| if (_encodeComplete) |
| { |
| _encodeComplete = false; |
| return true; |
| } |
| return false; |
| } |
| |
| VideoFrameType |
| UnitTestEncodeCompleteCallback::EncodedFrameType() const |
| { |
| return _encodedFrameType; |
| } |
| |
| bool |
| UnitTestDecodeCompleteCallback::DecodeComplete() |
| { |
| if (_decodeComplete) |
| { |
| _decodeComplete = false; |
| return true; |
| } |
| return false; |
| } |
| |
| WebRtc_UWord32 |
| UnitTest::WaitForEncodedFrame() const |
| { |
| WebRtc_Word64 startTime = TickTime::MillisecondTimestamp(); |
| while (TickTime::MillisecondTimestamp() - startTime < kMaxWaitEncTimeMs) |
| { |
| if (_encodeCompleteCallback->EncodeComplete()) |
| { |
| return _encodedVideoBuffer.GetLength(); |
| } |
| } |
| return 0; |
| } |
| |
| WebRtc_UWord32 |
| UnitTest::WaitForDecodedFrame() const |
| { |
| WebRtc_Word64 startTime = TickTime::MillisecondTimestamp(); |
| while (TickTime::MillisecondTimestamp() - startTime < kMaxWaitDecTimeMs) |
| { |
| if (_decodeCompleteCallback->DecodeComplete()) |
| { |
| return _decodedVideoBuffer.GetLength(); |
| } |
| } |
| return 0; |
| } |
| |
| WebRtc_UWord32 |
| UnitTest::CodecSpecific_SetBitrate(WebRtc_UWord32 bitRate, |
| WebRtc_UWord32 /* frameRate */) |
| { |
| return _encoder->SetRates(bitRate, _inst.maxFramerate); |
| } |
| |
| void |
| UnitTest::Setup() |
| { |
| // Use _sourceFile as a check to prevent multiple Setup() calls. |
| if (_sourceFile != NULL) |
| { |
| return; |
| } |
| |
| if (_encodeCompleteCallback == NULL) |
| { |
| _encodeCompleteCallback = |
| new UnitTestEncodeCompleteCallback(&_encodedVideoBuffer); |
| } |
| if (_decodeCompleteCallback == NULL) |
| { |
| _decodeCompleteCallback = |
| new UnitTestDecodeCompleteCallback(&_decodedVideoBuffer); |
| } |
| |
| _encoder->RegisterEncodeCompleteCallback(_encodeCompleteCallback); |
| _decoder->RegisterDecodeCompleteCallback(_decodeCompleteCallback); |
| |
| _source = new VideoSource(webrtc::test::ProjectRootPath() + |
| "resources/foreman_cif.yuv", kCIF); |
| |
| _lengthSourceFrame = _source->GetFrameLength(); |
| _refFrame = new unsigned char[_lengthSourceFrame]; |
| _refDecFrame = new unsigned char[_lengthSourceFrame]; |
| _sourceBuffer = new unsigned char [_lengthSourceFrame]; |
| _sourceFile = fopen(_source->GetFileName().c_str(), "rb"); |
| ASSERT_TRUE(_sourceFile != NULL); |
| |
| _inst.maxFramerate = _source->GetFrameRate(); |
| _bitRate = 300; |
| _inst.startBitrate = 300; |
| _inst.maxBitrate = 4000; |
| _inst.width = _source->GetWidth(); |
| _inst.height = _source->GetHeight(); |
| |
| // Get input frame. |
| _inputVideoBuffer.VerifyAndAllocate(_lengthSourceFrame); |
| ASSERT_TRUE(fread(_refFrame, 1, _lengthSourceFrame, _sourceFile) |
| == _lengthSourceFrame); |
| _inputVideoBuffer.CopyBuffer(_lengthSourceFrame, _refFrame); |
| rewind(_sourceFile); |
| |
| // Get a reference encoded frame. |
| _encodedVideoBuffer.VerifyAndAllocate(_lengthSourceFrame); |
| |
| RawImage image; |
| VideoBufferToRawImage(_inputVideoBuffer, image); |
| |
| // Ensures our initial parameters are valid. |
| EXPECT_TRUE(_encoder->InitEncode(&_inst, 1, 1440) == WEBRTC_VIDEO_CODEC_OK); |
| VideoFrameType videoFrameType = kDeltaFrame; |
| _encoder->Encode(image, NULL, &videoFrameType); |
| _refEncFrameLength = WaitForEncodedFrame(); |
| ASSERT_TRUE(_refEncFrameLength > 0); |
| _refEncFrame = new unsigned char[_refEncFrameLength]; |
| memcpy(_refEncFrame, _encodedVideoBuffer.GetBuffer(), _refEncFrameLength); |
| |
| // Get a reference decoded frame. |
| _decodedVideoBuffer.VerifyAndAllocate(_lengthSourceFrame); |
| EXPECT_TRUE(_decoder->InitDecode(&_inst, 1) == WEBRTC_VIDEO_CODEC_OK); |
| |
| if (SetCodecSpecificParameters() != WEBRTC_VIDEO_CODEC_OK) |
| { |
| exit(EXIT_FAILURE); |
| } |
| |
| unsigned int frameLength = 0; |
| int i=0; |
| while (frameLength == 0) |
| { |
| if (i > 0) |
| { |
| // Insert yet another frame |
| _inputVideoBuffer.VerifyAndAllocate(_lengthSourceFrame); |
| ASSERT_TRUE(fread(_refFrame, 1, _lengthSourceFrame, |
| _sourceFile) == _lengthSourceFrame); |
| _inputVideoBuffer.CopyBuffer(_lengthSourceFrame, _refFrame); |
| _inputVideoBuffer.SetWidth(_source->GetWidth()); |
| _inputVideoBuffer.SetHeight(_source->GetHeight()); |
| VideoBufferToRawImage(_inputVideoBuffer, image); |
| _encoder->Encode(image, NULL, &videoFrameType); |
| ASSERT_TRUE(WaitForEncodedFrame() > 0); |
| } |
| EncodedImage encodedImage; |
| VideoEncodedBufferToEncodedImage(_encodedVideoBuffer, encodedImage); |
| ASSERT_TRUE(_decoder->Decode(encodedImage, 0, NULL) |
| == WEBRTC_VIDEO_CODEC_OK); |
| frameLength = WaitForDecodedFrame(); |
| _encodedVideoBuffer.Reset(); |
| _encodedVideoBuffer.UpdateLength(0); |
| i++; |
| } |
| rewind(_sourceFile); |
| EXPECT_TRUE(frameLength == _lengthSourceFrame); |
| memcpy(_refDecFrame, _decodedVideoBuffer.GetBuffer(), _lengthSourceFrame); |
| } |
| |
| void |
| UnitTest::Teardown() |
| { |
| // Use _sourceFile as a check to prevent multiple Teardown() calls. |
| if (_sourceFile == NULL) |
| { |
| return; |
| } |
| |
| _encoder->Release(); |
| _decoder->Release(); |
| |
| fclose(_sourceFile); |
| _sourceFile = NULL; |
| delete [] _refFrame; |
| _refFrame = NULL; |
| delete [] _refEncFrame; |
| _refEncFrame = NULL; |
| delete [] _refDecFrame; |
| _refDecFrame = NULL; |
| delete [] _sourceBuffer; |
| _sourceBuffer = NULL; |
| } |
| |
| void |
| UnitTest::Print() |
| { |
| printf("Unit Test\n\n%i tests completed\n", _tests); |
| if (_errors > 0) |
| { |
| printf("%i FAILED\n\n", _errors); |
| } |
| else |
| { |
| printf("ALL PASSED\n\n"); |
| } |
| } |
| |
| int |
| UnitTest::DecodeWithoutAssert() |
| { |
| EncodedImage encodedImage; |
| VideoEncodedBufferToEncodedImage(_encodedVideoBuffer, encodedImage); |
| int ret = _decoder->Decode(encodedImage, 0, NULL); |
| int frameLength = WaitForDecodedFrame(); |
| _encodedVideoBuffer.Reset(); |
| _encodedVideoBuffer.UpdateLength(0); |
| return ret == WEBRTC_VIDEO_CODEC_OK ? frameLength : ret; |
| } |
| |
| int |
| UnitTest::Decode() |
| { |
| EncodedImage encodedImage; |
| VideoEncodedBufferToEncodedImage(_encodedVideoBuffer, encodedImage); |
| if (encodedImage._length == 0) |
| { |
| return WEBRTC_VIDEO_CODEC_OK; |
| } |
| int ret = _decoder->Decode(encodedImage, 0, NULL); |
| unsigned int frameLength = WaitForDecodedFrame(); |
| assert(ret == WEBRTC_VIDEO_CODEC_OK && (frameLength == 0 || frameLength |
| == _lengthSourceFrame)); |
| EXPECT_TRUE(ret == WEBRTC_VIDEO_CODEC_OK && (frameLength == 0 || frameLength |
| == _lengthSourceFrame)); |
| _encodedVideoBuffer.Reset(); |
| _encodedVideoBuffer.UpdateLength(0); |
| return ret == WEBRTC_VIDEO_CODEC_OK ? frameLength : ret; |
| } |
| |
| // Test pure virtual VideoEncoder and VideoDecoder APIs. |
| void |
| UnitTest::Perform() |
| { |
| UnitTest::Setup(); |
| int frameLength; |
| RawImage inputImage; |
| EncodedImage encodedImage; |
| VideoFrameType videoFrameType = kDeltaFrame; |
| |
| //----- Encoder parameter tests ----- |
| |
| //-- Calls before InitEncode() -- |
| // We want to revert the initialization done in Setup(). |
| EXPECT_TRUE(_encoder->Release() == WEBRTC_VIDEO_CODEC_OK); |
| VideoBufferToRawImage(_inputVideoBuffer, inputImage); |
| EXPECT_TRUE(_encoder->Encode(inputImage, NULL, &videoFrameType ) |
| == WEBRTC_VIDEO_CODEC_UNINITIALIZED); |
| EXPECT_TRUE(_encoder->Reset() == WEBRTC_VIDEO_CODEC_UNINITIALIZED); |
| |
| //-- InitEncode() errors -- |
| // Null pointer. |
| EXPECT_TRUE(_encoder->InitEncode(NULL, 1, 1440) == |
| WEBRTC_VIDEO_CODEC_ERR_PARAMETER); |
| // bit rate exceeds max bit rate |
| WebRtc_Word32 tmpBitRate = _inst.startBitrate; |
| WebRtc_Word32 tmpMaxBitRate = _inst.maxBitrate; |
| _inst.startBitrate = 4000; |
| _inst.maxBitrate = 3000; |
| EXPECT_TRUE(_encoder->InitEncode(&_inst, 1, 1440) == |
| WEBRTC_VIDEO_CODEC_ERR_PARAMETER); |
| _inst.startBitrate = tmpBitRate; |
| _inst.maxBitrate = tmpMaxBitRate; //unspecified value |
| |
| // Bad framerate. |
| _inst.maxFramerate = 0; |
| EXPECT_TRUE(_encoder->InitEncode(&_inst, 1, 1440) == |
| WEBRTC_VIDEO_CODEC_ERR_PARAMETER); |
| // Seems like we should allow any framerate in range [0, 255]. |
| //_inst.frameRate = 100; |
| //EXPECT_TRUE(_encoder->InitEncode(&_inst, 1) == -1); // FAILS |
| _inst.maxFramerate = 30; |
| |
| // Bad bitrate. |
| _inst.startBitrate = -1; |
| EXPECT_TRUE(_encoder->InitEncode(&_inst, 1, 1440) == |
| WEBRTC_VIDEO_CODEC_ERR_PARAMETER); |
| _inst.maxBitrate = _inst.startBitrate - 1; |
| EXPECT_TRUE(_encoder->InitEncode(&_inst, 1, 1440) == |
| WEBRTC_VIDEO_CODEC_ERR_PARAMETER); |
| _inst.maxBitrate = 0; |
| _inst.startBitrate = 300; |
| |
| // Bad maxBitRate. |
| _inst.maxBitrate = 200; |
| EXPECT_TRUE(_encoder->InitEncode(&_inst, 1, 1440) == |
| WEBRTC_VIDEO_CODEC_ERR_PARAMETER); |
| _inst.maxBitrate = 4000; |
| |
| // Bad width. |
| _inst.width = 0; |
| EXPECT_TRUE(_encoder->InitEncode(&_inst, 1, 1440) < 0); |
| // Should there be a width and height cap? |
| //_inst.width = 10000; |
| //EXPECT_TRUE(_encoder->InitEncode(&_inst, 1) == -1); |
| _inst.width = _source->GetWidth(); |
| |
| // Bad height. |
| _inst.height = 0; |
| EXPECT_TRUE(_encoder->InitEncode(&_inst, 1, 1440) < 0); |
| _inst.height = _source->GetHeight(); |
| |
| // Bad number of cores. |
| EXPECT_TRUE(_encoder->InitEncode(&_inst, -1, 1440) == |
| WEBRTC_VIDEO_CODEC_ERR_PARAMETER); |
| |
| EXPECT_TRUE(_encoder->InitEncode(&_inst, 1, 1440) == WEBRTC_VIDEO_CODEC_OK); |
| |
| //-- Encode() errors -- |
| |
| // inputVideoBuffer unallocated. |
| _inputVideoBuffer.Free(); |
| VideoBufferToRawImage(_inputVideoBuffer, inputImage); |
| EXPECT_TRUE(_encoder->Encode(inputImage, NULL, &videoFrameType) == |
| WEBRTC_VIDEO_CODEC_ERR_PARAMETER); |
| _inputVideoBuffer.VerifyAndAllocate(_lengthSourceFrame); |
| _inputVideoBuffer.CopyBuffer(_lengthSourceFrame, _refFrame); |
| |
| //----- Encoder stress tests ----- |
| |
| // Vary frame rate and I-frame request. |
| VideoBufferToRawImage(_inputVideoBuffer, inputImage); |
| for (int i = 1; i <= 60; i++) |
| { |
| VideoFrameType frameType = !(i % 2) ? kKeyFrame : kDeltaFrame; |
| EXPECT_TRUE(_encoder->Encode(inputImage, NULL, &frameType) == |
| WEBRTC_VIDEO_CODEC_OK); |
| EXPECT_TRUE(WaitForEncodedFrame() > 0); |
| } |
| |
| // Init then encode. |
| _encodedVideoBuffer.UpdateLength(0); |
| _encodedVideoBuffer.Reset(); |
| EXPECT_TRUE(_encoder->Encode(inputImage, NULL, &videoFrameType) == |
| WEBRTC_VIDEO_CODEC_OK); |
| EXPECT_TRUE(WaitForEncodedFrame() > 0); |
| |
| EXPECT_TRUE(_encoder->InitEncode(&_inst, 1, 1440) == WEBRTC_VIDEO_CODEC_OK); |
| _encoder->Encode(inputImage, NULL, &videoFrameType); |
| frameLength = WaitForEncodedFrame(); |
| EXPECT_TRUE(frameLength > 0); |
| EXPECT_TRUE(CheckIfBitExact(_refEncFrame, _refEncFrameLength, |
| _encodedVideoBuffer.GetBuffer(), frameLength) == true); |
| |
| // Reset then encode. |
| _encodedVideoBuffer.UpdateLength(0); |
| _encodedVideoBuffer.Reset(); |
| EXPECT_TRUE(_encoder->Encode(inputImage, NULL, &videoFrameType) == |
| WEBRTC_VIDEO_CODEC_OK); |
| WaitForEncodedFrame(); |
| EXPECT_TRUE(_encoder->Reset() == WEBRTC_VIDEO_CODEC_OK); |
| EXPECT_TRUE(_encoder->InitEncode(&_inst, 1, 1440) == WEBRTC_VIDEO_CODEC_OK); |
| _encoder->Encode(inputImage, NULL, &videoFrameType); |
| frameLength = WaitForEncodedFrame(); |
| EXPECT_TRUE(frameLength > 0); |
| EXPECT_TRUE(CheckIfBitExact(_refEncFrame, _refEncFrameLength, |
| _encodedVideoBuffer.GetBuffer(), frameLength) == true); |
| |
| // Release then encode. |
| _encodedVideoBuffer.UpdateLength(0); |
| _encodedVideoBuffer.Reset(); |
| EXPECT_TRUE(_encoder->Encode(inputImage, NULL, &videoFrameType) == |
| WEBRTC_VIDEO_CODEC_OK); |
| WaitForEncodedFrame(); |
| EXPECT_TRUE(_encoder->Release() == WEBRTC_VIDEO_CODEC_OK); |
| EXPECT_TRUE(_encoder->InitEncode(&_inst, 1, 1440) == WEBRTC_VIDEO_CODEC_OK); |
| _encoder->Encode(inputImage, NULL, &videoFrameType); |
| frameLength = WaitForEncodedFrame(); |
| EXPECT_TRUE(frameLength > 0); |
| EXPECT_TRUE(CheckIfBitExact(_refEncFrame, _refEncFrameLength, |
| _encodedVideoBuffer.GetBuffer(), frameLength) == true); |
| |
| //----- Decoder parameter tests ----- |
| |
| //-- Calls before InitDecode() -- |
| // We want to revert the initialization done in Setup(). |
| EXPECT_TRUE(_decoder->Release() == WEBRTC_VIDEO_CODEC_OK); |
| VideoEncodedBufferToEncodedImage(_encodedVideoBuffer, encodedImage); |
| EXPECT_TRUE(_decoder->Decode(encodedImage, false, NULL) == |
| WEBRTC_VIDEO_CODEC_UNINITIALIZED); |
| WaitForDecodedFrame(); |
| EXPECT_TRUE(_decoder->Reset() == WEBRTC_VIDEO_CODEC_UNINITIALIZED); |
| EXPECT_TRUE(_decoder->InitDecode(&_inst, 1) == WEBRTC_VIDEO_CODEC_OK); |
| |
| if (SetCodecSpecificParameters() != WEBRTC_VIDEO_CODEC_OK) |
| { |
| exit(EXIT_FAILURE); |
| } |
| |
| //-- Decode() errors -- |
| // Unallocated encodedVideoBuffer. |
| _encodedVideoBuffer.Free(); |
| VideoEncodedBufferToEncodedImage(_encodedVideoBuffer, encodedImage); |
| encodedImage._length = 10; // Buffer NULL but length > 0 |
| EXPECT_EQ(_decoder->Decode(encodedImage, false, NULL), |
| WEBRTC_VIDEO_CODEC_ERR_PARAMETER); |
| _encodedVideoBuffer.VerifyAndAllocate(_lengthSourceFrame); |
| |
| //----- Decoder stress tests ----- |
| unsigned char* tmpBuf = new unsigned char[_lengthSourceFrame]; |
| |
| // "Random" and zero data. |
| // We either expect an error, or at the least, no output. |
| // This relies on the codec's ability to detect an erroneous bitstream. |
| /* |
| EXPECT_TRUE(_decoder->Reset() == WEBRTC_VIDEO_CODEC_OK); |
| EXPECT_TRUE(_decoder->InitDecode(&_inst, 1) == WEBRTC_VIDEO_CODEC_OK); |
| if (SetCodecSpecificParameters() != WEBRTC_VIDEO_CODEC_OK) |
| { |
| exit(EXIT_FAILURE); |
| } |
| for (int i = 0; i < 100; i++) |
| { |
| ASSERT_TRUE(fread(tmpBuf, 1, _refEncFrameLength, _sourceFile) |
| == _refEncFrameLength); |
| _encodedVideoBuffer.CopyBuffer(_refEncFrameLength, tmpBuf); |
| VideoEncodedBufferToEncodedImage(_encodedVideoBuffer, encodedImage); |
| FillDecoderSpecificInfo(encodedImage); |
| int ret = _decoder->Decode(encodedImage, false, _decoderSpecificInfo); |
| EXPECT_TRUE(ret <= 0); |
| if (ret == 0) |
| { |
| EXPECT_TRUE(WaitForDecodedFrame() == 0); |
| } |
| |
| memset(tmpBuf, 0, _refEncFrameLength); |
| _encodedVideoBuffer.CopyBuffer(_refEncFrameLength, tmpBuf); |
| VideoEncodedBufferToEncodedImage(_encodedVideoBuffer, encodedImage); |
| FillDecoderSpecificInfo(encodedImage); |
| ret = _decoder->Decode(encodedImage, false, _decoderSpecificInfo); |
| EXPECT_TRUE(ret <= 0); |
| if (ret == 0) |
| { |
| EXPECT_TRUE(WaitForDecodedFrame() == 0); |
| } |
| } |
| */ |
| rewind(_sourceFile); |
| |
| _encodedVideoBuffer.UpdateLength(_refEncFrameLength); |
| _encodedVideoBuffer.CopyBuffer(_refEncFrameLength, _refEncFrame); |
| |
| // Init then decode. |
| EXPECT_TRUE(_decoder->InitDecode(&_inst, 1) == WEBRTC_VIDEO_CODEC_OK); |
| if (SetCodecSpecificParameters() != WEBRTC_VIDEO_CODEC_OK) |
| { |
| exit(EXIT_FAILURE); |
| } |
| frameLength = 0; |
| VideoEncodedBufferToEncodedImage(_encodedVideoBuffer, encodedImage); |
| while (frameLength == 0) |
| { |
| _decoder->Decode(encodedImage, false, NULL); |
| frameLength = WaitForDecodedFrame(); |
| } |
| EXPECT_TRUE(CheckIfBitExact(_decodedVideoBuffer.GetBuffer(), frameLength, |
| _refDecFrame, _lengthSourceFrame) == true); |
| |
| // Reset then decode. |
| EXPECT_TRUE(_decoder->Reset() == WEBRTC_VIDEO_CODEC_OK); |
| frameLength = 0; |
| VideoEncodedBufferToEncodedImage(_encodedVideoBuffer, encodedImage); |
| while (frameLength == 0) |
| { |
| _decoder->Decode(encodedImage, false, NULL); |
| frameLength = WaitForDecodedFrame(); |
| } |
| EXPECT_TRUE(CheckIfBitExact(_decodedVideoBuffer.GetBuffer(), frameLength, |
| _refDecFrame, _lengthSourceFrame) == true); |
| |
| // Decode with other size, reset, then decode with original size again |
| // to verify that decoder is reset to a "fresh" state upon Reset(). |
| { |
| // assert that input frame size is a factor of two, so that we can use |
| // quarter size below |
| EXPECT_TRUE((_inst.width % 2 == 0) && (_inst.height % 2 == 0)); |
| |
| VideoCodec tempInst; |
| memcpy(&tempInst, &_inst, sizeof(VideoCodec)); |
| tempInst.width /= 2; |
| tempInst.height /= 2; |
| |
| // Encode reduced (quarter) frame size |
| EXPECT_TRUE(_encoder->Release() == WEBRTC_VIDEO_CODEC_OK); |
| EXPECT_TRUE(_encoder->InitEncode(&tempInst, 1, 1440) == |
| WEBRTC_VIDEO_CODEC_OK); |
| RawImage tempInput(inputImage._buffer, inputImage._length/4, |
| inputImage._size/4); |
| VideoFrameType videoFrameType = kDeltaFrame; |
| _encoder->Encode(tempInput, NULL, &videoFrameType); |
| frameLength = WaitForEncodedFrame(); |
| EXPECT_TRUE(frameLength > 0); |
| |
| // Reset then decode. |
| EXPECT_TRUE(_decoder->Reset() == WEBRTC_VIDEO_CODEC_OK); |
| frameLength = 0; |
| VideoEncodedBufferToEncodedImage(_encodedVideoBuffer, encodedImage); |
| while (frameLength == 0) |
| { |
| _decoder->Decode(encodedImage, false, NULL); |
| frameLength = WaitForDecodedFrame(); |
| } |
| |
| // Encode original frame again |
| EXPECT_TRUE(_encoder->Release() == WEBRTC_VIDEO_CODEC_OK); |
| EXPECT_TRUE(_encoder->InitEncode(&_inst, 1, 1440) == |
| WEBRTC_VIDEO_CODEC_OK); |
| _encoder->Encode(inputImage, NULL, &videoFrameType); |
| frameLength = WaitForEncodedFrame(); |
| EXPECT_TRUE(frameLength > 0); |
| |
| // Reset then decode original frame again. |
| EXPECT_TRUE(_decoder->Reset() == WEBRTC_VIDEO_CODEC_OK); |
| frameLength = 0; |
| VideoEncodedBufferToEncodedImage(_encodedVideoBuffer, encodedImage); |
| while (frameLength == 0) |
| { |
| _decoder->Decode(encodedImage, false, NULL); |
| frameLength = WaitForDecodedFrame(); |
| } |
| |
| // check that decoded frame matches with reference |
| EXPECT_TRUE(CheckIfBitExact(_decodedVideoBuffer.GetBuffer(), frameLength, |
| _refDecFrame, _lengthSourceFrame) == true); |
| |
| } |
| |
| // Release then decode. |
| EXPECT_TRUE(_decoder->Release() == WEBRTC_VIDEO_CODEC_OK); |
| EXPECT_TRUE(_decoder->InitDecode(&_inst, 1) == WEBRTC_VIDEO_CODEC_OK); |
| if (SetCodecSpecificParameters() != WEBRTC_VIDEO_CODEC_OK) |
| { |
| exit(EXIT_FAILURE); |
| } |
| frameLength = 0; |
| VideoEncodedBufferToEncodedImage(_encodedVideoBuffer, encodedImage); |
| while (frameLength == 0) |
| { |
| _decoder->Decode(encodedImage, false, NULL); |
| frameLength = WaitForDecodedFrame(); |
| } |
| EXPECT_TRUE(CheckIfBitExact(_decodedVideoBuffer.GetBuffer(), frameLength, |
| _refDecFrame, _lengthSourceFrame) == true); |
| _encodedVideoBuffer.UpdateLength(0); |
| _encodedVideoBuffer.Reset(); |
| |
| delete [] tmpBuf; |
| |
| //----- Function tests ----- |
| int frames = 0; |
| // Do not specify maxBitRate (as in ViE). |
| _inst.maxBitrate = 0; |
| |
| //-- Timestamp propagation -- |
| EXPECT_TRUE(_encoder->Reset() == WEBRTC_VIDEO_CODEC_OK); |
| EXPECT_TRUE(_encoder->InitEncode(&_inst, 1, 1440) == WEBRTC_VIDEO_CODEC_OK); |
| EXPECT_TRUE(_decoder->Reset() == WEBRTC_VIDEO_CODEC_OK); |
| EXPECT_TRUE(_decoder->InitDecode(&_inst, 1) == WEBRTC_VIDEO_CODEC_OK); |
| if (SetCodecSpecificParameters() != WEBRTC_VIDEO_CODEC_OK) |
| { |
| exit(EXIT_FAILURE); |
| } |
| |
| printf("\nTimestamp propagation test...\n"); |
| frames = 0; |
| int frameDelay = 0; |
| int encTimeStamp; |
| _decodedVideoBuffer.SetTimeStamp(0); |
| while (fread(_sourceBuffer, 1, _lengthSourceFrame, _sourceFile) == |
| _lengthSourceFrame) |
| { |
| _inputVideoBuffer.CopyBuffer(_lengthSourceFrame, _sourceBuffer); |
| _inputVideoBuffer.SetTimeStamp(frames); |
| VideoBufferToRawImage(_inputVideoBuffer, inputImage); |
| VideoFrameType videoFrameType = kDeltaFrame; |
| ASSERT_TRUE(_encoder->Encode(inputImage, |
| NULL, |
| &videoFrameType) == |
| WEBRTC_VIDEO_CODEC_OK); |
| frameLength = WaitForEncodedFrame(); |
| //ASSERT_TRUE(frameLength); |
| EXPECT_TRUE(frameLength > 0); |
| encTimeStamp = _encodedVideoBuffer.GetTimeStamp(); |
| EXPECT_TRUE(_inputVideoBuffer.GetTimeStamp() == |
| static_cast<unsigned>(encTimeStamp)); |
| |
| frameLength = Decode(); |
| if (frameLength == 0) |
| { |
| frameDelay++; |
| } |
| |
| encTimeStamp -= frameDelay; |
| if (encTimeStamp < 0) |
| { |
| encTimeStamp = 0; |
| } |
| EXPECT_TRUE(_decodedVideoBuffer.GetTimeStamp() == |
| static_cast<unsigned>(encTimeStamp)); |
| frames++; |
| } |
| ASSERT_TRUE(feof(_sourceFile) != 0); |
| rewind(_sourceFile); |
| |
| RateControlTests(); |
| |
| Teardown(); |
| } |
| |
| void |
| UnitTest::RateControlTests() |
| { |
| std::string outFileName; |
| int frames = 0; |
| RawImage inputImage; |
| WebRtc_UWord32 frameLength; |
| |
| // Do not specify maxBitRate (as in ViE). |
| _inst.maxBitrate = 0; |
| //-- Verify rate control -- |
| EXPECT_TRUE(_encoder->Reset() == WEBRTC_VIDEO_CODEC_OK); |
| EXPECT_TRUE(_encoder->InitEncode(&_inst, 1, 1440) == WEBRTC_VIDEO_CODEC_OK); |
| EXPECT_TRUE(_decoder->Reset() == WEBRTC_VIDEO_CODEC_OK); |
| EXPECT_TRUE(_decoder->InitDecode(&_inst, 1) == WEBRTC_VIDEO_CODEC_OK); |
| // add: should also be 0, and 1 |
| const int bitRate[] = |
| {100, 200, 300, 400, 500, 600, 800, 1000, 2000, 3000, 4000, 10000}; |
| const int nBitrates = sizeof(bitRate)/sizeof(*bitRate); |
| |
| printf("\nRate control test\n"); |
| for (int i = 0; i < nBitrates; i++) |
| { |
| _bitRate = bitRate[i]; |
| int totalBytes = 0; |
| _encoder->Reset(); |
| _inst.startBitrate = _bitRate; |
| _encoder->InitEncode(&_inst, 4, 1440); |
| _decoder->Reset(); |
| _decoder->InitDecode(&_inst, 1); |
| frames = 0; |
| |
| if (_bitRate > _inst.maxBitrate) |
| { |
| CodecSpecific_SetBitrate(_bitRate, _inst.maxFramerate); |
| } |
| else |
| { |
| CodecSpecific_SetBitrate(_bitRate, _inst.maxFramerate); |
| } |
| |
| while (fread(_sourceBuffer, 1, _lengthSourceFrame, _sourceFile) == |
| _lengthSourceFrame) |
| { |
| _inputVideoBuffer.CopyBuffer(_lengthSourceFrame, _sourceBuffer); |
| _inputVideoBuffer.SetTimeStamp(_inputVideoBuffer.GetTimeStamp() + |
| static_cast<WebRtc_UWord32>(9e4 / |
| static_cast<float>(_inst.maxFramerate))); |
| VideoBufferToRawImage(_inputVideoBuffer, inputImage); |
| VideoFrameType videoFrameType = kDeltaFrame; |
| ASSERT_EQ(_encoder->Encode(inputImage, NULL, &videoFrameType), |
| WEBRTC_VIDEO_CODEC_OK); |
| frameLength = WaitForEncodedFrame(); |
| ASSERT_GE(frameLength, 0u); |
| totalBytes += frameLength; |
| frames++; |
| |
| _encodedVideoBuffer.UpdateLength(0); |
| _encodedVideoBuffer.Reset(); |
| } |
| WebRtc_UWord32 actualBitrate = |
| (totalBytes / frames * _inst.maxFramerate * 8)/1000; |
| printf("Target bitrate: %d kbps, actual bitrate: %d kbps\n", _bitRate, |
| actualBitrate); |
| // Test for close match over reasonable range. |
| if (_bitRate >= 100 && _bitRate <= 2500) |
| { |
| EXPECT_TRUE(abs(WebRtc_Word32(actualBitrate - _bitRate)) < |
| 0.1 * _bitRate); // for VP8 |
| } |
| ASSERT_TRUE(feof(_sourceFile) != 0); |
| rewind(_sourceFile); |
| } |
| } |
| |
| bool |
| UnitTest::CheckIfBitExact(const void* ptrA, unsigned int aLengthBytes, |
| const void* ptrB, unsigned int bLengthBytes) |
| { |
| if (aLengthBytes != bLengthBytes) |
| { |
| return false; |
| } |
| |
| return memcmp(ptrA, ptrB, aLengthBytes) == 0; |
| } |