Home | History | Annotate | Download | only in test
      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 // Implementation of codec data base test
     12 // testing is done via the VCM module, no specific CodecDataBase module functionality.
     13 
     14 #include "webrtc/modules/video_coding/main/test/codec_database_test.h"
     15 
     16 #include <assert.h>
     17 #include <stdio.h>
     18 
     19 #include "webrtc/engine_configurations.h"
     20 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h"
     21 #include "webrtc/modules/video_coding/main/interface/video_coding.h"
     22 #include "webrtc/modules/video_coding/main/test/test_callbacks.h"
     23 #include "webrtc/modules/video_coding/main/test/test_macros.h"
     24 #include "webrtc/modules/video_coding/main/test/test_util.h"
     25 #include "webrtc/test/testsupport/fileutils.h"
     26 #include "webrtc/test/testsupport/metrics/video_metrics.h"
     27 
     28 using namespace webrtc;
     29 
     30 int CodecDataBaseTest::RunTest(CmdArgs& args)
     31 {
     32     VideoCodingModule* vcm = VideoCodingModule::Create();
     33     CodecDataBaseTest* cdbt = new CodecDataBaseTest(vcm);
     34     cdbt->Perform(args);
     35     VideoCodingModule::Destroy(vcm);
     36     delete cdbt;
     37     return 0;
     38 
     39 }
     40 
     41 CodecDataBaseTest::CodecDataBaseTest(VideoCodingModule* vcm):
     42 _vcm(vcm),
     43 _width(0),
     44 _height(0),
     45 _lengthSourceFrame(0),
     46 _timeStamp(0)
     47 {
     48     //
     49 }
     50 CodecDataBaseTest::~CodecDataBaseTest()
     51 {
     52     //
     53 }
     54 void
     55 CodecDataBaseTest::Setup(CmdArgs& args)
     56 {
     57     _inname= args.inputFile;
     58     _width = args.width;
     59     _height = args.height;
     60     _frameRate = args.frameRate;
     61     _lengthSourceFrame  = 3*_width*_height/2;
     62     if (args.outputFile.compare(""))
     63         _outname = test::OutputPath() + "CDBtest_decoded.yuv";
     64     else
     65         _outname = args.outputFile;
     66     _outname = args.outputFile;
     67     _encodedName = test::OutputPath() + "CDBtest_encoded.vp8";
     68 
     69     if ((_sourceFile = fopen(_inname.c_str(), "rb")) == NULL)
     70     {
     71         printf("Cannot read file %s.\n", _inname.c_str());
     72         exit(1);
     73     }
     74 
     75     if ((_encodedFile = fopen(_encodedName.c_str(), "wb")) == NULL)
     76     {
     77         printf("Cannot write encoded file.\n");
     78         exit(1);
     79     }
     80 
     81     if ((_decodedFile = fopen(_outname.c_str(),  "wb")) == NULL)
     82     {
     83         printf("Cannot write file %s.\n", _outname.c_str());
     84         exit(1);
     85     }
     86 
     87     return;
     88 }
     89 
     90 
     91 
     92 int32_t
     93 CodecDataBaseTest::Perform(CmdArgs& args)
     94 {
     95 #ifndef VIDEOCODEC_VP8
     96     assert(false);
     97 #endif
     98     Setup(args);
     99     EventWrapper* waitEvent = EventWrapper::Create();
    100 
    101     /**************************/
    102     /* General Sanity Checks */
    103     /************************/
    104     VideoCodec sendCodec, receiveCodec;
    105     TEST(VideoCodingModule::NumberOfCodecs() > 0);
    106     _vcm->InitializeReceiver();
    107     _vcm->InitializeSender();
    108     VCMDecodeCompleteCallback *_decodeCallback = new VCMDecodeCompleteCallback(_decodedFile);
    109     VCMEncodeCompleteCallback *_encodeCompleteCallback = new VCMEncodeCompleteCallback(_encodedFile);
    110     _vcm->RegisterReceiveCallback(_decodeCallback);
    111     _vcm->RegisterTransportCallback(_encodeCompleteCallback);
    112     _encodeCompleteCallback->SetFrameDimensions(_width, _height);
    113     // registering the callback - encode and decode with the same vcm (could be later changed)
    114     _encodeCompleteCallback->RegisterReceiverVCM(_vcm);
    115     // preparing a frame to be encoded
    116     uint8_t* tmpBuffer = new uint8_t[_lengthSourceFrame];
    117     TEST(fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) > 0);
    118     I420VideoFrame sourceFrame;
    119     int half_width = (_width + 1) / 2;
    120     int half_height = (_height + 1) / 2;
    121     int size_y = _width * _height;
    122     int size_uv = half_width * half_height;
    123     sourceFrame.CreateFrame(size_y, tmpBuffer,
    124                             size_uv, tmpBuffer + size_y,
    125                             size_uv, tmpBuffer + size_y + size_uv,
    126                             _width, _height,
    127                             _width, half_width, half_width);
    128     _timeStamp += (uint32_t)(9e4 / _frameRate);
    129     sourceFrame.set_timestamp(_timeStamp);
    130     // Encoder registration
    131     TEST (VideoCodingModule::NumberOfCodecs() > 0);
    132     TEST(VideoCodingModule::Codec(-1, &sendCodec) < 0);
    133     TEST(VideoCodingModule::Codec(VideoCodingModule::NumberOfCodecs() + 1,
    134                                   &sendCodec) < 0);
    135     VideoCodingModule::Codec(1, &sendCodec);
    136     sendCodec.plType = 0; // random value
    137     TEST(_vcm->RegisterSendCodec(&sendCodec, 1, 1440) < 0);
    138     _vcm->InitializeReceiver();
    139     _vcm->InitializeSender();
    140     _vcm->RegisterReceiveCallback(_decodeCallback);
    141     _vcm->RegisterTransportCallback(_encodeCompleteCallback);
    142     printf(" \nNumber of Registered Codecs: %d \n\n", VideoCodingModule::NumberOfCodecs());
    143     printf("Registered codec names: ");
    144     for (int i=0; i < VideoCodingModule::NumberOfCodecs(); i++)
    145     {
    146         VideoCodingModule::Codec(i, &sendCodec);
    147         printf("%s   ", sendCodec.plName);
    148     }
    149     printf("\n\nVerify that all requested codecs are used\n \n \n");
    150 
    151     // Testing with VP8.
    152     VideoCodingModule::Codec(kVideoCodecVP8, &sendCodec);
    153     _vcm->RegisterSendCodec(&sendCodec, 1, 1440);
    154     _encodeCompleteCallback->SetCodecType(kRtpVideoVp8);
    155     _vcm->InitializeReceiver();
    156     TEST (_vcm->AddVideoFrame(sourceFrame) == VCM_OK );
    157     _vcm->InitializeSender();
    158     TEST (_vcm->AddVideoFrame(sourceFrame) < 0 );
    159 
    160     // Test changing frame size while keeping the same payload type
    161     VideoCodingModule::Codec(0, &sendCodec);
    162     sendCodec.width = 352;
    163     sendCodec.height = 288;
    164     VideoCodec currentSendCodec;
    165     _vcm->RegisterSendCodec(&sendCodec, 1, 1440);
    166     _vcm->SendCodec(&currentSendCodec);
    167     TEST(currentSendCodec.width == sendCodec.width &&
    168         currentSendCodec.height == sendCodec.height);
    169     sendCodec.width = 352/2;
    170     sendCodec.height = 288/2;
    171     _vcm->RegisterSendCodec(&sendCodec, 1, 1440);
    172     _vcm->SendCodec(&currentSendCodec);
    173     TEST(currentSendCodec.width == sendCodec.width &&
    174         currentSendCodec.height == sendCodec.height);
    175 
    176     delete _decodeCallback;
    177     _decodeCallback = NULL;
    178     delete _encodeCompleteCallback;
    179     _encodeCompleteCallback = NULL;
    180 
    181     VCMEncodeCompleteCallback *_encodeCallback = new VCMEncodeCompleteCallback(_encodedFile);
    182 
    183     /*************************/
    184     /* External codecs       */
    185     /*************************/
    186 
    187 
    188     _vcm->InitializeReceiver();
    189     VP8Decoder* decoder = VP8Decoder::Create();
    190     VideoCodec vp8DecSettings;
    191     VideoCodingModule::Codec(kVideoCodecVP8, &vp8DecSettings);
    192     TEST(_vcm->RegisterExternalDecoder(decoder, vp8DecSettings.plType, false) == VCM_OK);
    193     TEST(_vcm->RegisterReceiveCodec(&vp8DecSettings, 1, false) == VCM_OK);
    194     VP8Encoder* encoder = VP8Encoder::Create();
    195     VideoCodec vp8EncSettings;
    196     VideoCodingModule::Codec(kVideoCodecVP8, &vp8EncSettings);
    197     _vcm->RegisterTransportCallback(_encodeCallback); // encode returns error if callback uninitialized
    198     _encodeCallback->RegisterReceiverVCM(_vcm);
    199     _encodeCallback->SetCodecType(kRtpVideoVp8);
    200     TEST(_vcm->RegisterExternalEncoder(encoder, vp8EncSettings.plType) == VCM_OK);
    201     TEST(_vcm->RegisterSendCodec(&vp8EncSettings, 4, 1440) == VCM_OK);
    202     TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
    203     TEST(_vcm->Decode() == VCM_OK);
    204     waitEvent->Wait(33);
    205     _timeStamp += (uint32_t)(9e4 / _frameRate);
    206     sourceFrame.set_timestamp(_timeStamp);
    207     TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
    208     TEST(_vcm->Decode() == VCM_OK);
    209 
    210     // De-register and try again.
    211     TEST(_vcm->RegisterExternalDecoder(NULL, vp8DecSettings.plType, false) == VCM_OK);
    212     TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
    213     TEST(_vcm->Decode() < 0); // Expect an error since we have de-registered the decoder
    214     TEST(_vcm->RegisterExternalEncoder(NULL, vp8DecSettings.plType) == VCM_OK);
    215     TEST(_vcm->AddVideoFrame(sourceFrame) < 0); // No send codec registered
    216 
    217     delete decoder;
    218     decoder = NULL;
    219     delete encoder;
    220     encoder = NULL;
    221 
    222     /***************************************
    223      * Test the "require key frame" setting*
    224      ***************************************/
    225 
    226     TEST(_vcm->InitializeSender() == VCM_OK);
    227     TEST(_vcm->InitializeReceiver() == VCM_OK);
    228     VideoCodingModule::Codec(kVideoCodecVP8, &receiveCodec);
    229     receiveCodec.height = _height;
    230     receiveCodec.width = _width;
    231     TEST(_vcm->RegisterSendCodec(&receiveCodec, 4, 1440) == VCM_OK);
    232     TEST(_vcm->RegisterReceiveCodec(&receiveCodec, 1, true) == VCM_OK); // Require key frame
    233     _vcm->RegisterTransportCallback(_encodeCallback); // encode returns error if callback uninitialized
    234     _encodeCallback->RegisterReceiverVCM(_vcm);
    235     _encodeCallback->SetCodecType(kRtpVideoVp8);
    236     TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
    237     TEST(_vcm->Decode() == VCM_OK);
    238     TEST(_vcm->ResetDecoder() == VCM_OK);
    239     waitEvent->Wait(33);
    240     _timeStamp += (uint32_t)(9e4 / _frameRate);
    241     sourceFrame.set_timestamp(_timeStamp);
    242     TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
    243     // Try to decode a delta frame. Should get a warning since we have enabled the "require key frame" setting
    244     // and because no frame type request callback has been registered.
    245     TEST(_vcm->Decode() == VCM_MISSING_CALLBACK);
    246     TEST(_vcm->IntraFrameRequest(0) == VCM_OK);
    247     _timeStamp += (uint32_t)(9e4 / _frameRate);
    248     sourceFrame.set_timestamp(_timeStamp);
    249     TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
    250     TEST(_vcm->Decode() == VCM_OK);
    251 
    252     // Make sure we can register another codec with the same
    253     // payload type without crash.
    254     _vcm->InitializeReceiver();
    255     sendCodec.width = _width;
    256     sendCodec.height = _height;
    257     TEST(_vcm->RegisterReceiveCodec(&sendCodec, 1) == VCM_OK);
    258     TEST(_vcm->IntraFrameRequest(0) == VCM_OK);
    259     waitEvent->Wait(33);
    260     _timeStamp += (uint32_t)(9e4 / _frameRate);
    261     sourceFrame.set_timestamp(_timeStamp);
    262     TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
    263     TEST(_vcm->Decode() == VCM_OK);
    264     TEST(_vcm->RegisterReceiveCodec(&sendCodec, 1) == VCM_OK);
    265     waitEvent->Wait(33);
    266     _timeStamp += (uint32_t)(9e4 / _frameRate);
    267     sourceFrame.set_timestamp(_timeStamp);
    268     TEST(_vcm->IntraFrameRequest(0) == VCM_OK);
    269     TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
    270     TEST(_vcm->Decode() == VCM_OK);
    271     TEST(_vcm->ResetDecoder() == VCM_OK);
    272 
    273     delete _encodeCallback;
    274 
    275     /*************************/
    276     /* Send/Receive Control */
    277     /***********************/
    278     /*
    279     1. check available codecs (N)
    280     2. register all corresponding decoders
    281     3. encode 300/N frames with each encoder, and hope to properly decode
    282     4. encode without a matching decoder - expect an error
    283     */
    284     rewind(_sourceFile);
    285     _vcm->InitializeReceiver();
    286     _vcm->InitializeSender();
    287     VCMDecodeCompleteCallback* decodeCallCDT = new VCMDecodeCompleteCallback(_decodedFile);
    288     VCMEncodeCompleteCallback* encodeCallCDT = new VCMEncodeCompleteCallback(_encodedFile);
    289     _vcm->RegisterReceiveCallback(decodeCallCDT);
    290     _vcm->RegisterTransportCallback(encodeCallCDT);
    291     encodeCallCDT->RegisterReceiverVCM(_vcm);
    292     if (VideoCodingModule::NumberOfCodecs() > 0)
    293     {
    294         // Register all available decoders.
    295         int i, j;
    296         sourceFrame.CreateEmptyFrame(_width, _height, _width,
    297                                      (_width + 1) / 2, (_width + 1) / 2);
    298         _vcm->RegisterReceiveCallback(decodeCallCDT);
    299         for (i=0; i < VideoCodingModule::NumberOfCodecs(); i++)
    300         {
    301             VideoCodingModule::Codec(i, &receiveCodec);
    302             if (strcmp(receiveCodec.plName, "I420") == 0)
    303             {
    304                 receiveCodec.height = _height;
    305                 receiveCodec.width = _width;
    306             }
    307             _vcm->RegisterReceiveCodec(&receiveCodec, 1);
    308         }
    309         // start encoding - iterating over available encoders
    310         _vcm->RegisterTransportCallback(encodeCallCDT);
    311         encodeCallCDT->RegisterReceiverVCM(_vcm);
    312         encodeCallCDT->Initialize();
    313         int frameCnt = 0;
    314         for (i=0; i < VideoCodingModule::NumberOfCodecs(); i++)
    315         {
    316             encodeCallCDT->ResetByteCount();
    317             VideoCodingModule::Codec(i, &sendCodec);
    318             sendCodec.height = _height;
    319             sendCodec.width = _width;
    320             sendCodec.startBitrate = 1000;
    321             sendCodec.maxBitrate = 8000;
    322             encodeCallCDT->SetFrameDimensions(_width, _height);
    323             encodeCallCDT->SetCodecType(ConvertCodecType(sendCodec.plName));
    324             TEST(_vcm->RegisterSendCodec(&sendCodec, 1, 1440) == VCM_OK);
    325 
    326             // We disable the frame dropper to avoid dropping frames due to
    327             // bad rate control. This isn't a codec performance test, and the
    328             // I420 codec is expected to produce too many bits.
    329             _vcm->EnableFrameDropper(false);
    330 
    331             printf("Encoding with %s \n\n", sendCodec.plName);
    332             // Assuming 300 frames, NumberOfCodecs <= 10.
    333             for (j=0; j < int(300/VideoCodingModule::NumberOfCodecs()); j++)
    334             {
    335                 frameCnt++;
    336                 TEST(fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) > 0);
    337                 sourceFrame.CreateFrame(size_y, tmpBuffer,
    338                                         size_uv, tmpBuffer + size_y,
    339                                         size_uv, tmpBuffer + size_y + size_uv,
    340                                         _width, _height,
    341                                         _width, half_width, half_width);
    342                 _timeStamp += (uint32_t)(9e4 / _frameRate);
    343                 sourceFrame.set_timestamp(_timeStamp);
    344                 // send frame to the encoder
    345                 TEST (_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
    346                 waitEvent->Wait(33); // was 100
    347 
    348                 int ret =_vcm->Decode();
    349                 TEST(ret >= 0);
    350                 if (ret < 0)
    351                 {
    352                     printf("Error #%d in frame number %d \n",ret, frameCnt);
    353                 }
    354                  // verifying matching payload types:
    355                 _vcm->SendCodec(&sendCodec);
    356                 _vcm->ReceiveCodec(&receiveCodec);
    357                 TEST(sendCodec.plType == receiveCodec.plType);
    358                 if (sendCodec.plType != receiveCodec.plType)
    359                 {
    360                     printf("frame number:%d\n",frameCnt);
    361                 }
    362             }  // end for:encode-decode
    363            // byte count for codec specific
    364 
    365             printf("Total bytes encoded: %f \n\n",(8.0/1000)*(encodeCallCDT->EncodedBytes()/((int)10/VideoCodingModule::NumberOfCodecs())));
    366             // decode what's left in the buffer....
    367             _vcm->Decode();
    368             _vcm->Decode();
    369             // Don't measure PSNR for I420 since it will be perfect.
    370             if (sendCodec.codecType != kVideoCodecI420) {
    371                 webrtc::test::QualityMetricsResult psnr;
    372                 I420PSNRFromFiles(_inname.c_str(), _outname.c_str(), _width,
    373                                   _height, &psnr);
    374                 printf("\n @ %d KBPS:  ", sendCodec.startBitrate);
    375                 printf("PSNR from encoder-decoder send-receive control test"
    376                        "is %f\n\n", psnr.average);
    377             }
    378         }  // end: iterate codecs
    379         rewind(_sourceFile);
    380         delete [] tmpBuffer;
    381         delete decodeCallCDT;
    382         delete encodeCallCDT;
    383         // closing and calculating PSNR for prior encoder-decoder test
    384         TearDown(); // closing open files
    385     }  // end of #codecs >1
    386 
    387     delete waitEvent;
    388     Print();
    389     return 0;
    390 }
    391 void
    392 CodecDataBaseTest::Print()
    393 {
    394     printf("\nVCM Codec DataBase Test: \n\n%i tests completed\n", vcmMacrosTests);
    395     if (vcmMacrosErrors > 0)
    396     {
    397         printf("%i FAILED\n\n", vcmMacrosErrors);
    398     }
    399     else
    400     {
    401         printf("ALL PASSED\n\n");
    402     }
    403 }
    404 
    405 void
    406 CodecDataBaseTest::TearDown()
    407 {
    408     fclose(_sourceFile);
    409     fclose(_decodedFile);
    410     fclose(_encodedFile);
    411     return;
    412 }
    413