Home | History | Annotate | Download | only in source
      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 "webrtc/modules/utility/source/file_player_impl.h"
     12 #include "webrtc/system_wrappers/interface/logging.h"
     13 
     14 #ifdef WEBRTC_MODULE_UTILITY_VIDEO
     15     #include "frame_scaler.h"
     16     #include "tick_util.h"
     17     #include "video_coder.h"
     18 #endif
     19 
     20 namespace webrtc {
     21 FilePlayer* FilePlayer::CreateFilePlayer(uint32_t instanceID,
     22                                          FileFormats fileFormat)
     23 {
     24     switch(fileFormat)
     25     {
     26     case kFileFormatWavFile:
     27     case kFileFormatCompressedFile:
     28     case kFileFormatPreencodedFile:
     29     case kFileFormatPcm16kHzFile:
     30     case kFileFormatPcm8kHzFile:
     31     case kFileFormatPcm32kHzFile:
     32         // audio formats
     33         return new FilePlayerImpl(instanceID, fileFormat);
     34     case kFileFormatAviFile:
     35 #ifdef WEBRTC_MODULE_UTILITY_VIDEO
     36         return new VideoFilePlayerImpl(instanceID, fileFormat);
     37 #else
     38         assert(false);
     39         return NULL;
     40 #endif
     41     }
     42     assert(false);
     43     return NULL;
     44 }
     45 
     46 void FilePlayer::DestroyFilePlayer(FilePlayer* player)
     47 {
     48     delete player;
     49 }
     50 
     51 FilePlayerImpl::FilePlayerImpl(const uint32_t instanceID,
     52                                const FileFormats fileFormat)
     53     : _instanceID(instanceID),
     54       _fileFormat(fileFormat),
     55       _fileModule(*MediaFile::CreateMediaFile(instanceID)),
     56       _decodedLengthInMS(0),
     57       _audioDecoder(instanceID),
     58       _codec(),
     59       _numberOf10MsPerFrame(0),
     60       _numberOf10MsInDecoder(0),
     61       _resampler(),
     62       _scaling(1.0)
     63 {
     64     _codec.plfreq = 0;
     65 }
     66 
     67 FilePlayerImpl::~FilePlayerImpl()
     68 {
     69     MediaFile::DestroyMediaFile(&_fileModule);
     70 }
     71 
     72 int32_t FilePlayerImpl::Frequency() const
     73 {
     74     if(_codec.plfreq == 0)
     75     {
     76         return -1;
     77     }
     78     // Make sure that sample rate is 8,16 or 32 kHz. E.g. WAVE files may have
     79     // other sampling rates.
     80     if(_codec.plfreq == 11000)
     81     {
     82         return 16000;
     83     }
     84     else if(_codec.plfreq == 22000)
     85     {
     86         return 32000;
     87     }
     88     else if(_codec.plfreq == 44000)
     89     {
     90         return 32000;
     91     }
     92     else if(_codec.plfreq == 48000)
     93     {
     94         return 32000;
     95     }
     96     else
     97     {
     98         return _codec.plfreq;
     99     }
    100 }
    101 
    102 int32_t FilePlayerImpl::AudioCodec(CodecInst& audioCodec) const
    103 {
    104     audioCodec = _codec;
    105     return 0;
    106 }
    107 
    108 int32_t FilePlayerImpl::Get10msAudioFromFile(
    109     int16_t* outBuffer,
    110     int& lengthInSamples,
    111     int frequencyInHz)
    112 {
    113     if(_codec.plfreq == 0)
    114     {
    115         LOG(LS_WARNING) << "Get10msAudioFromFile() playing not started!"
    116                         << " codec freq = " << _codec.plfreq
    117                         << ", wanted freq = " << frequencyInHz;
    118         return -1;
    119     }
    120 
    121     AudioFrame unresampledAudioFrame;
    122     if(STR_CASE_CMP(_codec.plname, "L16") == 0)
    123     {
    124         unresampledAudioFrame.sample_rate_hz_ = _codec.plfreq;
    125 
    126         // L16 is un-encoded data. Just pull 10 ms.
    127         uint32_t lengthInBytes =
    128             sizeof(unresampledAudioFrame.data_);
    129         if (_fileModule.PlayoutAudioData(
    130                 (int8_t*)unresampledAudioFrame.data_,
    131                 lengthInBytes) == -1)
    132         {
    133             // End of file reached.
    134             return -1;
    135         }
    136         if(lengthInBytes == 0)
    137         {
    138             lengthInSamples = 0;
    139             return 0;
    140         }
    141         // One sample is two bytes.
    142         unresampledAudioFrame.samples_per_channel_ =
    143             (uint16_t)lengthInBytes >> 1;
    144 
    145     }else {
    146         // Decode will generate 10 ms of audio data. PlayoutAudioData(..)
    147         // expects a full frame. If the frame size is larger than 10 ms,
    148         // PlayoutAudioData(..) data should be called proportionally less often.
    149         int16_t encodedBuffer[MAX_AUDIO_BUFFER_IN_SAMPLES];
    150         uint32_t encodedLengthInBytes = 0;
    151         if(++_numberOf10MsInDecoder >= _numberOf10MsPerFrame)
    152         {
    153             _numberOf10MsInDecoder = 0;
    154             uint32_t bytesFromFile = sizeof(encodedBuffer);
    155             if (_fileModule.PlayoutAudioData((int8_t*)encodedBuffer,
    156                                              bytesFromFile) == -1)
    157             {
    158                 // End of file reached.
    159                 return -1;
    160             }
    161             encodedLengthInBytes = bytesFromFile;
    162         }
    163         if(_audioDecoder.Decode(unresampledAudioFrame,frequencyInHz,
    164                                 (int8_t*)encodedBuffer,
    165                                 encodedLengthInBytes) == -1)
    166         {
    167             return -1;
    168         }
    169     }
    170 
    171     int outLen = 0;
    172     if(_resampler.ResetIfNeeded(unresampledAudioFrame.sample_rate_hz_,
    173                                 frequencyInHz, kResamplerSynchronous))
    174     {
    175         LOG(LS_WARNING) << "Get10msAudioFromFile() unexpected codec.";
    176 
    177         // New sampling frequency. Update state.
    178         outLen = frequencyInHz / 100;
    179         memset(outBuffer, 0, outLen * sizeof(int16_t));
    180         return 0;
    181     }
    182     _resampler.Push(unresampledAudioFrame.data_,
    183                     unresampledAudioFrame.samples_per_channel_,
    184                     outBuffer,
    185                     MAX_AUDIO_BUFFER_IN_SAMPLES,
    186                     outLen);
    187 
    188     lengthInSamples = outLen;
    189 
    190     if(_scaling != 1.0)
    191     {
    192         for (int i = 0;i < outLen; i++)
    193         {
    194             outBuffer[i] = (int16_t)(outBuffer[i] * _scaling);
    195         }
    196     }
    197     _decodedLengthInMS += 10;
    198     return 0;
    199 }
    200 
    201 int32_t FilePlayerImpl::RegisterModuleFileCallback(FileCallback* callback)
    202 {
    203     return _fileModule.SetModuleFileCallback(callback);
    204 }
    205 
    206 int32_t FilePlayerImpl::SetAudioScaling(float scaleFactor)
    207 {
    208     if((scaleFactor >= 0)&&(scaleFactor <= 2.0))
    209     {
    210         _scaling = scaleFactor;
    211         return 0;
    212     }
    213     LOG(LS_WARNING) << "SetAudioScaling() non-allowed scale factor.";
    214     return -1;
    215 }
    216 
    217 int32_t FilePlayerImpl::StartPlayingFile(const char* fileName,
    218                                          bool loop,
    219                                          uint32_t startPosition,
    220                                          float volumeScaling,
    221                                          uint32_t notification,
    222                                          uint32_t stopPosition,
    223                                          const CodecInst* codecInst)
    224 {
    225     if (_fileFormat == kFileFormatPcm16kHzFile ||
    226         _fileFormat == kFileFormatPcm8kHzFile||
    227         _fileFormat == kFileFormatPcm32kHzFile )
    228     {
    229         CodecInst codecInstL16;
    230         strncpy(codecInstL16.plname,"L16",32);
    231         codecInstL16.pltype   = 93;
    232         codecInstL16.channels = 1;
    233 
    234         if (_fileFormat == kFileFormatPcm8kHzFile)
    235         {
    236             codecInstL16.rate     = 128000;
    237             codecInstL16.plfreq   = 8000;
    238             codecInstL16.pacsize  = 80;
    239 
    240         } else if(_fileFormat == kFileFormatPcm16kHzFile)
    241         {
    242             codecInstL16.rate     = 256000;
    243             codecInstL16.plfreq   = 16000;
    244             codecInstL16.pacsize  = 160;
    245 
    246         }else if(_fileFormat == kFileFormatPcm32kHzFile)
    247         {
    248             codecInstL16.rate     = 512000;
    249             codecInstL16.plfreq   = 32000;
    250             codecInstL16.pacsize  = 160;
    251         } else
    252         {
    253             LOG(LS_ERROR) << "StartPlayingFile() sample frequency not "
    254                           << "supported for PCM format.";
    255             return -1;
    256         }
    257 
    258         if (_fileModule.StartPlayingAudioFile(fileName, notification, loop,
    259                                               _fileFormat, &codecInstL16,
    260                                               startPosition,
    261                                               stopPosition) == -1)
    262         {
    263             LOG(LS_WARNING) << "StartPlayingFile() failed to initialize "
    264                             << "pcm file " << fileName;
    265             return -1;
    266         }
    267         SetAudioScaling(volumeScaling);
    268     }else if(_fileFormat == kFileFormatPreencodedFile)
    269     {
    270         if (_fileModule.StartPlayingAudioFile(fileName, notification, loop,
    271                                               _fileFormat, codecInst) == -1)
    272         {
    273             LOG(LS_WARNING) << "StartPlayingFile() failed to initialize "
    274                             << "pre-encoded file " << fileName;
    275             return -1;
    276         }
    277     } else
    278     {
    279         CodecInst* no_inst = NULL;
    280         if (_fileModule.StartPlayingAudioFile(fileName, notification, loop,
    281                                               _fileFormat, no_inst,
    282                                               startPosition,
    283                                               stopPosition) == -1)
    284         {
    285             LOG(LS_WARNING) << "StartPlayingFile() failed to initialize file "
    286                             << fileName;
    287             return -1;
    288         }
    289         SetAudioScaling(volumeScaling);
    290     }
    291     if (SetUpAudioDecoder() == -1)
    292     {
    293         StopPlayingFile();
    294         return -1;
    295     }
    296     return 0;
    297 }
    298 
    299 int32_t FilePlayerImpl::StartPlayingFile(InStream& sourceStream,
    300                                          uint32_t startPosition,
    301                                          float volumeScaling,
    302                                          uint32_t notification,
    303                                          uint32_t stopPosition,
    304                                          const CodecInst* codecInst)
    305 {
    306     if (_fileFormat == kFileFormatPcm16kHzFile ||
    307         _fileFormat == kFileFormatPcm32kHzFile ||
    308         _fileFormat == kFileFormatPcm8kHzFile)
    309     {
    310         CodecInst codecInstL16;
    311         strncpy(codecInstL16.plname,"L16",32);
    312         codecInstL16.pltype   = 93;
    313         codecInstL16.channels = 1;
    314 
    315         if (_fileFormat == kFileFormatPcm8kHzFile)
    316         {
    317             codecInstL16.rate     = 128000;
    318             codecInstL16.plfreq   = 8000;
    319             codecInstL16.pacsize  = 80;
    320 
    321         }else if (_fileFormat == kFileFormatPcm16kHzFile)
    322         {
    323             codecInstL16.rate     = 256000;
    324             codecInstL16.plfreq   = 16000;
    325             codecInstL16.pacsize  = 160;
    326 
    327         }else if (_fileFormat == kFileFormatPcm32kHzFile)
    328         {
    329             codecInstL16.rate     = 512000;
    330             codecInstL16.plfreq   = 32000;
    331             codecInstL16.pacsize  = 160;
    332         }else
    333         {
    334             LOG(LS_ERROR) << "StartPlayingFile() sample frequency not "
    335                           << "supported for PCM format.";
    336             return -1;
    337         }
    338         if (_fileModule.StartPlayingAudioStream(sourceStream, notification,
    339                                                 _fileFormat, &codecInstL16,
    340                                                 startPosition,
    341                                                 stopPosition) == -1)
    342         {
    343             LOG(LS_ERROR) << "StartPlayingFile() failed to initialize stream "
    344                           << "playout.";
    345             return -1;
    346         }
    347 
    348     }else if(_fileFormat == kFileFormatPreencodedFile)
    349     {
    350         if (_fileModule.StartPlayingAudioStream(sourceStream, notification,
    351                                                 _fileFormat, codecInst) == -1)
    352         {
    353             LOG(LS_ERROR) << "StartPlayingFile() failed to initialize stream "
    354                           << "playout.";
    355             return -1;
    356         }
    357     } else {
    358         CodecInst* no_inst = NULL;
    359         if (_fileModule.StartPlayingAudioStream(sourceStream, notification,
    360                                                 _fileFormat, no_inst,
    361                                                 startPosition,
    362                                                 stopPosition) == -1)
    363         {
    364             LOG(LS_ERROR) << "StartPlayingFile() failed to initialize stream "
    365                           << "playout.";
    366             return -1;
    367         }
    368     }
    369     SetAudioScaling(volumeScaling);
    370 
    371     if (SetUpAudioDecoder() == -1)
    372     {
    373         StopPlayingFile();
    374         return -1;
    375     }
    376     return 0;
    377 }
    378 
    379 int32_t FilePlayerImpl::StopPlayingFile()
    380 {
    381     memset(&_codec, 0, sizeof(CodecInst));
    382     _numberOf10MsPerFrame  = 0;
    383     _numberOf10MsInDecoder = 0;
    384     return _fileModule.StopPlaying();
    385 }
    386 
    387 bool FilePlayerImpl::IsPlayingFile() const
    388 {
    389     return _fileModule.IsPlaying();
    390 }
    391 
    392 int32_t FilePlayerImpl::GetPlayoutPosition(uint32_t& durationMs)
    393 {
    394     return _fileModule.PlayoutPositionMs(durationMs);
    395 }
    396 
    397 int32_t FilePlayerImpl::SetUpAudioDecoder()
    398 {
    399     if ((_fileModule.codec_info(_codec) == -1))
    400     {
    401         LOG(LS_WARNING) << "Failed to retrieve codec info of file data.";
    402         return -1;
    403     }
    404     if( STR_CASE_CMP(_codec.plname, "L16") != 0 &&
    405         _audioDecoder.SetDecodeCodec(_codec,AMRFileStorage) == -1)
    406     {
    407         LOG(LS_WARNING) << "SetUpAudioDecoder() codec " << _codec.plname
    408                         << " not supported.";
    409         return -1;
    410     }
    411     _numberOf10MsPerFrame = _codec.pacsize / (_codec.plfreq / 100);
    412     _numberOf10MsInDecoder = 0;
    413     return 0;
    414 }
    415 
    416 #ifdef WEBRTC_MODULE_UTILITY_VIDEO
    417 VideoFilePlayerImpl::VideoFilePlayerImpl(uint32_t instanceID,
    418                                          FileFormats fileFormat)
    419     : FilePlayerImpl(instanceID, fileFormat),
    420       video_decoder_(new VideoCoder()),
    421       video_codec_info_(),
    422       _decodedVideoFrames(0),
    423       _encodedData(*new EncodedVideoData()),
    424       _frameScaler(*new FrameScaler()),
    425       _critSec(CriticalSectionWrapper::CreateCriticalSection()),
    426       _startTime(),
    427       _accumulatedRenderTimeMs(0),
    428       _frameLengthMS(0),
    429       _numberOfFramesRead(0),
    430       _videoOnly(false) {
    431   memset(&video_codec_info_, 0, sizeof(video_codec_info_));
    432 }
    433 
    434 VideoFilePlayerImpl::~VideoFilePlayerImpl()
    435 {
    436     delete _critSec;
    437     delete &_frameScaler;
    438     video_decoder_.reset();
    439     delete &_encodedData;
    440 }
    441 
    442 int32_t VideoFilePlayerImpl::StartPlayingVideoFile(
    443     const char* fileName,
    444     bool loop,
    445     bool videoOnly)
    446 {
    447     CriticalSectionScoped lock( _critSec);
    448 
    449     if(_fileModule.StartPlayingVideoFile(fileName, loop, videoOnly,
    450                                          _fileFormat) != 0)
    451     {
    452         return -1;
    453     }
    454 
    455     _decodedVideoFrames = 0;
    456     _accumulatedRenderTimeMs = 0;
    457     _frameLengthMS = 0;
    458     _numberOfFramesRead = 0;
    459     _videoOnly = videoOnly;
    460 
    461     // Set up video_codec_info_ according to file,
    462     if(SetUpVideoDecoder() != 0)
    463     {
    464         StopPlayingFile();
    465         return -1;
    466     }
    467     if(!videoOnly)
    468     {
    469         // Set up _codec according to file,
    470         if(SetUpAudioDecoder() != 0)
    471         {
    472             StopPlayingFile();
    473             return -1;
    474         }
    475     }
    476     return 0;
    477 }
    478 
    479 int32_t VideoFilePlayerImpl::StopPlayingFile()
    480 {
    481     CriticalSectionScoped lock( _critSec);
    482 
    483     _decodedVideoFrames = 0;
    484     video_decoder_.reset(new VideoCoder());
    485 
    486     return FilePlayerImpl::StopPlayingFile();
    487 }
    488 
    489 int32_t VideoFilePlayerImpl::GetVideoFromFile(I420VideoFrame& videoFrame,
    490                                               uint32_t outWidth,
    491                                               uint32_t outHeight)
    492 {
    493     CriticalSectionScoped lock( _critSec);
    494 
    495     int32_t retVal = GetVideoFromFile(videoFrame);
    496     if(retVal != 0)
    497     {
    498         return retVal;
    499     }
    500     if (!videoFrame.IsZeroSize())
    501     {
    502         retVal = _frameScaler.ResizeFrameIfNeeded(&videoFrame, outWidth,
    503                                                   outHeight);
    504     }
    505     return retVal;
    506 }
    507 
    508 int32_t VideoFilePlayerImpl::GetVideoFromFile(I420VideoFrame& videoFrame)
    509 {
    510     CriticalSectionScoped lock( _critSec);
    511     // No new video data read from file.
    512     if(_encodedData.payloadSize == 0)
    513     {
    514         videoFrame.ResetSize();
    515         return -1;
    516     }
    517     int32_t retVal = 0;
    518     if(strncmp(video_codec_info_.plName, "I420", 5) == 0)
    519     {
    520       int size_y = video_codec_info_.width * video_codec_info_.height;
    521       int half_width = (video_codec_info_.width + 1) / 2;
    522       int half_height = (video_codec_info_.height + 1) / 2;
    523       int size_uv = half_width * half_height;
    524 
    525       // TODO(mikhal): Do we need to align the stride here?
    526       const uint8_t* buffer_y = _encodedData.payloadData;
    527       const uint8_t* buffer_u = buffer_y + size_y;
    528       const uint8_t* buffer_v = buffer_u + size_uv;
    529       videoFrame.CreateFrame(size_y, buffer_y,
    530                              size_uv, buffer_u,
    531                              size_uv, buffer_v,
    532                              video_codec_info_.width, video_codec_info_.height,
    533                              video_codec_info_.height, half_width, half_width);
    534     }else
    535     {
    536         // Set the timestamp manually since there is no timestamp in the file.
    537         // Update timestam according to 90 kHz stream.
    538         _encodedData.timeStamp += (90000 / video_codec_info_.maxFramerate);
    539         retVal = video_decoder_->Decode(videoFrame, _encodedData);
    540     }
    541 
    542     int64_t renderTimeMs = TickTime::MillisecondTimestamp();
    543     videoFrame.set_render_time_ms(renderTimeMs);
    544 
    545      // Indicate that the current frame in the encoded buffer is old/has
    546      // already been read.
    547     _encodedData.payloadSize = 0;
    548     if( retVal == 0)
    549     {
    550         _decodedVideoFrames++;
    551     }
    552     return retVal;
    553 }
    554 
    555 int32_t VideoFilePlayerImpl::video_codec_info(
    556     VideoCodec& videoCodec) const
    557 {
    558     if(video_codec_info_.plName[0] == 0)
    559     {
    560         return -1;
    561     }
    562     memcpy(&videoCodec, &video_codec_info_, sizeof(VideoCodec));
    563     return 0;
    564 }
    565 
    566 int32_t VideoFilePlayerImpl::TimeUntilNextVideoFrame()
    567 {
    568     if(_fileFormat != kFileFormatAviFile)
    569     {
    570         return -1;
    571     }
    572     if(!_fileModule.IsPlaying())
    573     {
    574         return -1;
    575     }
    576     if(_encodedData.payloadSize <= 0)
    577     {
    578         // Read next frame from file.
    579         CriticalSectionScoped lock( _critSec);
    580 
    581         if(_fileFormat == kFileFormatAviFile)
    582         {
    583             // Get next video frame
    584             uint32_t encodedBufferLengthInBytes = _encodedData.bufferSize;
    585             if(_fileModule.PlayoutAVIVideoData(
    586                    reinterpret_cast< int8_t*>(_encodedData.payloadData),
    587                    encodedBufferLengthInBytes) != 0)
    588             {
    589                 LOG(LS_WARNING) << "Error reading video data.";
    590                 return -1;
    591             }
    592             _encodedData.payloadSize = encodedBufferLengthInBytes;
    593             _encodedData.codec = video_codec_info_.codecType;
    594             _numberOfFramesRead++;
    595 
    596             if(_accumulatedRenderTimeMs == 0)
    597             {
    598                 _startTime = TickTime::Now();
    599                 // This if-statement should only trigger once.
    600                 _accumulatedRenderTimeMs = 1;
    601             } else {
    602                 // A full seconds worth of frames have been read.
    603                 if(_numberOfFramesRead % video_codec_info_.maxFramerate == 0)
    604                 {
    605                     // Frame rate is in frames per seconds. Frame length is
    606                     // calculated as an integer division which means it may
    607                     // be rounded down. Compensate for this every second.
    608                     uint32_t rest = 1000%_frameLengthMS;
    609                     _accumulatedRenderTimeMs += rest;
    610                 }
    611                 _accumulatedRenderTimeMs += _frameLengthMS;
    612             }
    613         }
    614     }
    615 
    616     int64_t timeToNextFrame;
    617     if(_videoOnly)
    618     {
    619         timeToNextFrame = _accumulatedRenderTimeMs -
    620             (TickTime::Now() - _startTime).Milliseconds();
    621 
    622     } else {
    623         // Synchronize with the audio stream instead of system clock.
    624         timeToNextFrame = _accumulatedRenderTimeMs - _decodedLengthInMS;
    625     }
    626     if(timeToNextFrame < 0)
    627     {
    628         return 0;
    629 
    630     } else if(timeToNextFrame > 0x0fffffff)
    631     {
    632         // Wraparound or audio stream has gone to far ahead of the video stream.
    633         return -1;
    634     }
    635     return static_cast<int32_t>(timeToNextFrame);
    636 }
    637 
    638 int32_t VideoFilePlayerImpl::SetUpVideoDecoder()
    639 {
    640     if (_fileModule.VideoCodecInst(video_codec_info_) != 0)
    641     {
    642         LOG(LS_WARNING) << "SetVideoDecoder() failed to retrieve codec info of "
    643                         << "file data.";
    644         return -1;
    645     }
    646 
    647     int32_t useNumberOfCores = 1;
    648     if (video_decoder_->SetDecodeCodec(video_codec_info_, useNumberOfCores) !=
    649         0) {
    650         LOG(LS_WARNING) << "SetUpVideoDecoder() codec "
    651                         << video_codec_info_.plName << " not supported.";
    652         return -1;
    653     }
    654 
    655     _frameLengthMS = 1000/video_codec_info_.maxFramerate;
    656 
    657     // Size of unencoded data (I420) should be the largest possible frame size
    658     // in a file.
    659     const uint32_t KReadBufferSize = 3 * video_codec_info_.width *
    660         video_codec_info_.height / 2;
    661     _encodedData.VerifyAndAllocate(KReadBufferSize);
    662     _encodedData.encodedHeight = video_codec_info_.height;
    663     _encodedData.encodedWidth = video_codec_info_.width;
    664     _encodedData.payloadType = video_codec_info_.plType;
    665     _encodedData.timeStamp = 0;
    666     return 0;
    667 }
    668 #endif // WEBRTC_MODULE_UTILITY_VIDEO
    669 }  // namespace webrtc
    670