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 // TODO(henrike): reassess the error handling in this class. Currently failure
     12 // is detected by asserts in many places. Also a refactoring of this class would
     13 // be beneficial.
     14 
     15 #include "webrtc/modules/media_file/source/avi_file.h"
     16 
     17 #include <assert.h>
     18 #include <string.h>
     19 
     20 #ifdef _WIN32
     21 #include <windows.h>
     22 #endif
     23 
     24 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
     25 #include "webrtc/system_wrappers/interface/file_wrapper.h"
     26 #include "webrtc/system_wrappers/interface/trace.h"
     27 
     28 // http://msdn2.microsoft.com/en-us/library/ms779636.aspx
     29 // A chunk has the following form:
     30 // ckID ckSize ckData
     31 // where ckID is a FOURCC that identifies the data contained in the
     32 // chunk, ckData is a 4-byte value giving the size of the data in
     33 // ckData, and ckData is zero or more bytes of data. The data is always
     34 // padded to nearest WORD boundary. ckSize gives the size of the valid
     35 // data in the chunk; it does not include the padding, the size of
     36 // ckID, or the size of ckSize.
     37 //http://msdn2.microsoft.com/en-us/library/ms779632.aspx
     38 //NOTE: Workaround to make MPEG4 files play on WMP. MPEG files
     39 //      place the config parameters efter the BITMAPINFOHEADER and
     40 //      *NOT* in the 'strd'!
     41 // http://msdn.microsoft.com/en-us/library/dd183375.aspx
     42 // http://msdn.microsoft.com/en-us/library/dd183376.aspx
     43 
     44 namespace webrtc {
     45 namespace {
     46 static const uint32_t kAvifHasindex       = 0x00000010;
     47 static const uint32_t kAvifMustuseindex   = 0x00000020;
     48 static const uint32_t kAvifIsinterleaved  = 0x00000100;
     49 static const uint32_t kAvifTrustcktype    = 0x00000800;
     50 static const uint32_t kAvifWascapturefile = 0x00010000;
     51 
     52 template <class T>
     53 T MinValue(T a, T b)
     54 {
     55     return a < b ? a : b;
     56 }
     57 }  // namespace
     58 
     59 AviFile::AVIMAINHEADER::AVIMAINHEADER()
     60     : fcc(                  0),
     61       cb(                   0),
     62       dwMicroSecPerFrame(   0),
     63       dwMaxBytesPerSec(     0),
     64       dwPaddingGranularity( 0),
     65       dwFlags(              0),
     66       dwTotalFrames(        0),
     67       dwInitialFrames(      0),
     68       dwStreams(            0),
     69       dwSuggestedBufferSize(0),
     70       dwWidth(              0),
     71       dwHeight(             0)
     72 {
     73     dwReserved[0] = 0;
     74     dwReserved[1] = 0;
     75     dwReserved[2] = 0;
     76     dwReserved[3] = 0;
     77 }
     78 
     79 AVISTREAMHEADER::AVISTREAMHEADER()
     80     : fcc(                  0),
     81       cb(                   0),
     82       fccType(              0),
     83       fccHandler(           0),
     84       dwFlags(              0),
     85       wPriority(            0),
     86       wLanguage(            0),
     87       dwInitialFrames(      0),
     88       dwScale(              0),
     89       dwRate(               0),
     90       dwStart(              0),
     91       dwLength(             0),
     92       dwSuggestedBufferSize(0),
     93       dwQuality(            0),
     94       dwSampleSize(         0)
     95 {
     96     rcFrame.left   = 0;
     97     rcFrame.top    = 0;
     98     rcFrame.right  = 0;
     99     rcFrame.bottom = 0;
    100 }
    101 
    102 BITMAPINFOHEADER::BITMAPINFOHEADER()
    103     : biSize(         0),
    104       biWidth(        0),
    105       biHeight(       0),
    106       biPlanes(       0),
    107       biBitCount(     0),
    108       biCompression(  0),
    109       biSizeImage(    0),
    110       biXPelsPerMeter(0),
    111       biYPelsPerMeter(0),
    112       biClrUsed(      0),
    113       biClrImportant( 0)
    114 {
    115 }
    116 
    117 WAVEFORMATEX::WAVEFORMATEX()
    118     : wFormatTag(     0),
    119       nChannels(      0),
    120       nSamplesPerSec( 0),
    121       nAvgBytesPerSec(0),
    122       nBlockAlign(    0),
    123       wBitsPerSample( 0),
    124       cbSize(         0)
    125 {
    126 }
    127 
    128 AviFile::AVIINDEXENTRY::AVIINDEXENTRY(uint32_t inckid,
    129                                       uint32_t indwFlags,
    130                                       uint32_t indwChunkOffset,
    131                                       uint32_t indwChunkLength)
    132     : ckid(inckid),
    133       dwFlags(indwFlags),
    134       dwChunkOffset(indwChunkOffset),
    135       dwChunkLength(indwChunkLength)
    136 {
    137 }
    138 
    139 AviFile::AviFile()
    140     : _crit(CriticalSectionWrapper::CreateCriticalSection()),
    141       _aviFile(NULL),
    142       _aviHeader(),
    143       _videoStreamHeader(),
    144       _audioStreamHeader(),
    145       _videoFormatHeader(),
    146       _audioFormatHeader(),
    147       _videoConfigParameters(),
    148       _videoConfigLength(0),
    149       _videoStreamName(),
    150       _audioConfigParameters(),
    151       _audioStreamName(),
    152       _videoStream(),
    153       _audioStream(),
    154       _nrStreams(0),
    155       _aviLength(0),
    156       _dataLength(0),
    157       _bytesRead(0),
    158       _dataStartByte(0),
    159       _framesRead(0),
    160       _videoFrames(0),
    161       _audioFrames(0),
    162       _reading(false),
    163       _openedAs(AVI_AUDIO),
    164       _loop(false),
    165       _writing(false),
    166       _bytesWritten(0),
    167       _riffSizeMark(0),
    168       _moviSizeMark(0),
    169       _totNumFramesMark(0),
    170       _videoStreamLengthMark(0),
    171       _audioStreamLengthMark(0),
    172       _moviListOffset(0),
    173       _writeAudioStream(false),
    174       _writeVideoStream(false),
    175       _aviMode(NotSet),
    176       _videoCodecConfigParams(NULL),
    177       _videoCodecConfigParamsLength(0),
    178       _videoStreamDataChunkPrefix(0),
    179       _audioStreamDataChunkPrefix(0),
    180       _created(false)
    181 {
    182   ResetComplexMembers();
    183 }
    184 
    185 AviFile::~AviFile()
    186 {
    187     Close();
    188 
    189     delete[] _videoCodecConfigParams;
    190     delete _crit;
    191 }
    192 
    193 int32_t AviFile::Open(AVIStreamType streamType, const char* fileName, bool loop)
    194 {
    195     WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, -1,  "OpenAVIFile(%s)",
    196                  fileName);
    197     _crit->Enter();
    198 
    199     if (_aviMode != NotSet)
    200     {
    201         _crit->Leave();
    202         return -1;
    203     }
    204 
    205     _aviMode = Read;
    206 
    207     if (!fileName)
    208     {
    209         _crit->Leave();
    210         WEBRTC_TRACE(kTraceError, kTraceVideo, -1,  "\tfileName not valid!");
    211         return -1;
    212     }
    213 
    214 #ifdef _WIN32
    215     // fopen does not support wide characters on Windows, ergo _wfopen.
    216     wchar_t wideFileName[FileWrapper::kMaxFileNameSize];
    217     wideFileName[0] = 0;
    218     MultiByteToWideChar(CP_UTF8,0,fileName, -1, // convert the whole string
    219                         wideFileName, FileWrapper::kMaxFileNameSize);
    220 
    221     _aviFile = _wfopen(wideFileName, L"rb");
    222 #else
    223     _aviFile = fopen(fileName, "rb");
    224 #endif
    225 
    226     if (!_aviFile)
    227     {
    228         _crit->Leave();
    229         WEBRTC_TRACE(kTraceError, kTraceVideo, -1,  "Could not open file!");
    230         return -1;
    231     }
    232 
    233     // ReadRIFF verifies that the file is AVI and figures out the file length.
    234     int32_t err = ReadRIFF();
    235     if (err)
    236     {
    237         if (_aviFile)
    238         {
    239             fclose(_aviFile);
    240             _aviFile = NULL;
    241         }
    242         _crit->Leave();
    243         return -1;
    244     }
    245 
    246    err = ReadHeaders();
    247     if (err)
    248     {
    249         if (_aviFile)
    250         {
    251             fclose(_aviFile);
    252             _aviFile = NULL;
    253         }
    254         _crit->Leave();
    255         WEBRTC_TRACE(kTraceError, kTraceVideo, -1,
    256                      "Unsupported or corrupt AVI format");
    257         return -1;
    258     }
    259 
    260     _dataStartByte = _bytesRead;
    261     _reading = true;
    262     _openedAs = streamType;
    263     _loop = loop;
    264     _crit->Leave();
    265     return 0;
    266 }
    267 
    268 int32_t AviFile::Close()
    269 {
    270     _crit->Enter();
    271     switch (_aviMode)
    272     {
    273     case Read:
    274         CloseRead();
    275         break;
    276     case Write:
    277         CloseWrite();
    278         break;
    279     default:
    280         break;
    281     }
    282 
    283     if (_videoCodecConfigParams)
    284     {
    285         delete [] _videoCodecConfigParams;
    286         _videoCodecConfigParams = 0;
    287     }
    288     ResetMembers();
    289     _crit->Leave();
    290     return 0;
    291 }
    292 
    293 uint32_t AviFile::MakeFourCc(uint8_t ch0, uint8_t ch1, uint8_t ch2, uint8_t ch3)
    294 {
    295     return ((uint32_t)(uint8_t)(ch0)         |
    296             ((uint32_t)(uint8_t)(ch1) << 8)  |
    297             ((uint32_t)(uint8_t)(ch2) << 16) |
    298             ((uint32_t)(uint8_t)(ch3) << 24 ));
    299 }
    300 
    301 int32_t AviFile::GetVideoStreamInfo(AVISTREAMHEADER& videoStreamHeader,
    302                                     BITMAPINFOHEADER& bitmapInfo,
    303                                     char* codecConfigParameters,
    304                                     int32_t& configLength)
    305 {
    306     _crit->Enter();
    307     if (!_reading && !_created)
    308     {
    309         _crit->Leave();
    310         return -1;
    311     }
    312 
    313     memcpy(&videoStreamHeader, &_videoStreamHeader, sizeof(_videoStreamHeader));
    314     memcpy(&bitmapInfo, &_videoFormatHeader, sizeof(_videoFormatHeader));
    315 
    316     if (configLength <= _videoConfigLength)
    317     {
    318         memcpy(codecConfigParameters, _videoConfigParameters,
    319                _videoConfigLength);
    320         configLength = _videoConfigLength;
    321     }
    322     else
    323     {
    324         configLength = 0;
    325     }
    326     _crit->Leave();
    327     return 0;
    328 }
    329 
    330 int32_t AviFile::GetDuration(int32_t& durationMs)
    331 {
    332     _crit->Enter();
    333     if (_videoStreamHeader.dwRate==0 || _videoStreamHeader.dwScale==0)
    334     {
    335         _crit->Leave();
    336         return -1;
    337     }
    338 
    339     durationMs = _videoStreamHeader.dwLength * 1000 /
    340         (_videoStreamHeader.dwRate/_videoStreamHeader.dwScale);
    341     _crit->Leave();
    342     return 0;
    343 }
    344 
    345 int32_t AviFile::GetAudioStreamInfo(WAVEFORMATEX& waveHeader)
    346 {
    347     _crit->Enter();
    348     if (_aviMode != Read)
    349     {
    350         _crit->Leave();
    351         return -1;
    352     }
    353     if (!_reading && !_created)
    354     {
    355         _crit->Leave();
    356         return -1;
    357     }
    358     memcpy(&waveHeader, &_audioFormatHeader, sizeof(_audioFormatHeader));
    359     _crit->Leave();
    360     return 0;
    361 }
    362 
    363 int32_t AviFile::WriteAudio(const uint8_t* data, int32_t length)
    364 {
    365     _crit->Enter();
    366     size_t newBytesWritten = _bytesWritten;
    367 
    368     if (_aviMode != Write)
    369     {
    370         _crit->Leave();
    371         return -1;
    372     }
    373     if (!_created)
    374     {
    375         _crit->Leave();
    376         return -1;
    377     }
    378     if (!_writeAudioStream)
    379     {
    380         _crit->Leave();
    381         return -1;
    382     }
    383 
    384     // Start of chunk.
    385     const uint32_t chunkOffset = ftell(_aviFile) - _moviListOffset;
    386     _bytesWritten += PutLE32(_audioStreamDataChunkPrefix);
    387     // Size is unknown at this point. Update later.
    388     _bytesWritten += PutLE32(0);
    389     const size_t chunkSizeMark = _bytesWritten;
    390 
    391     _bytesWritten += PutBuffer(data, length);
    392 
    393     const long chunkSize = PutLE32LengthFromCurrent(
    394         static_cast<long>(chunkSizeMark));
    395 
    396     // Make sure that the chunk is aligned on 2 bytes (= 1 sample).
    397     if (chunkSize % 2)
    398     {
    399         _bytesWritten += PutByte(0);
    400     }
    401     // End of chunk
    402 
    403     // Save chunk information for use when closing file.
    404     AddChunkToIndexList(_audioStreamDataChunkPrefix, 0, // No flags.
    405                         chunkOffset, chunkSize);
    406 
    407     ++_audioFrames;
    408     newBytesWritten = _bytesWritten - newBytesWritten;
    409     _crit->Leave();
    410     return static_cast<int32_t>(newBytesWritten);
    411 }
    412 
    413 int32_t AviFile::WriteVideo(const uint8_t* data, int32_t length)
    414 {
    415     _crit->Enter();
    416     size_t newBytesWritten = _bytesWritten;
    417     if (_aviMode != Write)
    418     {
    419         _crit->Leave();
    420         return -1;
    421     }
    422     if (!_created)
    423     {
    424         _crit->Leave();
    425         return -1;
    426     }
    427     if (!_writeVideoStream)
    428     {
    429         _crit->Leave();
    430         return -1;
    431     }
    432 
    433     // Start of chunk.
    434     const uint32_t chunkOffset = ftell(_aviFile) - _moviListOffset;
    435     _bytesWritten += PutLE32(_videoStreamDataChunkPrefix);
    436     // Size is unknown at this point. Update later.
    437     _bytesWritten += PutLE32(0);
    438     const size_t chunkSizeMark = _bytesWritten;
    439 
    440     _bytesWritten += PutBuffer(data, length);
    441 
    442     const long chunkSize = PutLE32LengthFromCurrent(
    443         static_cast<long>(chunkSizeMark));
    444 
    445     // Make sure that the chunk is aligned on 2 bytes (= 1 sample).
    446     if (chunkSize % 2)
    447     {
    448         //Pad one byte, to WORD align.
    449         _bytesWritten += PutByte(0);
    450     }
    451      //End chunk!
    452     AddChunkToIndexList(_videoStreamDataChunkPrefix, 0, // No flags.
    453                         chunkOffset, static_cast<uint32_t>(chunkSize));
    454 
    455     ++_videoFrames;
    456     newBytesWritten = _bytesWritten - newBytesWritten;
    457     _crit->Leave();
    458     return static_cast<int32_t>(newBytesWritten);
    459 }
    460 
    461 int32_t AviFile::PrepareDataChunkHeaders()
    462 {
    463     // 00 video stream, 01 audio stream.
    464     // db uncompresses video,  dc compressed video, wb WAV audio
    465     if (_writeVideoStream)
    466     {
    467         if (strncmp((const char*) &_videoStreamHeader.fccHandler, "I420", 4) ==
    468             0)
    469         {
    470             _videoStreamDataChunkPrefix = MakeFourCc('0', '0', 'd', 'b');
    471         }
    472         else
    473         {
    474             _videoStreamDataChunkPrefix = MakeFourCc('0', '0', 'd', 'c');
    475         }
    476         _audioStreamDataChunkPrefix = MakeFourCc('0', '1', 'w', 'b');
    477     }
    478     else
    479     {
    480         _audioStreamDataChunkPrefix = MakeFourCc('0', '0', 'w', 'b');
    481     }
    482     return 0;
    483 }
    484 
    485 int32_t AviFile::ReadMoviSubChunk(uint8_t* data, int32_t& length, uint32_t tag1,
    486                                   uint32_t tag2)
    487 {
    488     if (!_reading)
    489     {
    490         WEBRTC_TRACE(kTraceDebug, kTraceVideo, -1,
    491                      "AviFile::ReadMoviSubChunk(): File not open!");
    492         length = 0;
    493         return -1;
    494     }
    495 
    496     uint32_t size;
    497     bool isEOFReached = false;
    498     // Try to read one data chunk header
    499     while (true)
    500     {
    501         // TODO (hellner): what happens if an empty AVI file is opened with
    502         // _loop set to true? Seems like this while-loop would never exit!
    503 
    504         // tag = db uncompresses video,  dc compressed video or wb WAV audio.
    505         uint32_t tag;
    506         _bytesRead += GetLE32(tag);
    507         _bytesRead += GetLE32(size);
    508 
    509         const int32_t eof = feof(_aviFile);
    510         if (!eof)
    511         {
    512             if (tag == tag1)
    513             {
    514                 // Supported tag found.
    515                 break;
    516             }
    517             else if ((tag == tag2) && (tag2 != 0))
    518             {
    519                 // Supported tag found.
    520                 break;
    521             }
    522 
    523             // Jump to next chunk. The size is in bytes but chunks are aligned
    524             // on 2 byte boundaries.
    525             const uint32_t seekSize = (size % 2) ? size + 1 : size;
    526             const int32_t err = fseek(_aviFile, seekSize, SEEK_CUR);
    527 
    528             if (err)
    529             {
    530                 isEOFReached = true;
    531             }
    532         }
    533         else
    534         {
    535             isEOFReached = true;
    536         }
    537 
    538         if (isEOFReached)
    539         {
    540             clearerr(_aviFile);
    541 
    542             if (_loop)
    543             {
    544                 WEBRTC_TRACE(kTraceDebug, kTraceVideo, -1,
    545                              "AviFile::ReadMoviSubChunk(): Reached end of AVI\
    546                               data file, starting from the beginning.");
    547 
    548                 fseek(_aviFile, static_cast<long>(_dataStartByte), SEEK_SET);
    549 
    550                 _bytesRead = _dataStartByte;
    551                 _framesRead = 0;
    552                 isEOFReached = false;
    553             }
    554             else
    555             {
    556                 WEBRTC_TRACE(kTraceDebug, kTraceVideo, -1,
    557                              "AviFile::ReadMoviSubChunk(): Reached end of AVI\
    558                              file!");
    559                 length = 0;
    560                 return -1;
    561             }
    562         }
    563         _bytesRead += size;
    564     }
    565 
    566     if (static_cast<int32_t>(size) > length)
    567     {
    568         WEBRTC_TRACE(kTraceDebug, kTraceVideo, -1,
    569                      "AviFile::ReadMoviSubChunk(): AVI read buffer too small!");
    570 
    571         // Jump to next chunk. The size is in bytes but chunks are aligned
    572         // on 2 byte boundaries.
    573         const uint32_t seekSize = (size % 2) ? size + 1 : size;
    574         fseek(_aviFile, seekSize, SEEK_CUR);
    575         _bytesRead += seekSize;
    576         length = 0;
    577         return -1;
    578     }
    579     _bytesRead += GetBuffer(data, size);
    580 
    581     // The size is in bytes but chunks are aligned on 2 byte boundaries.
    582     if (size % 2)
    583     {
    584         uint8_t dummy_byte;
    585         _bytesRead += GetByte(dummy_byte);
    586     }
    587     length = size;
    588     ++_framesRead;
    589     return 0;
    590 }
    591 
    592 int32_t AviFile::ReadAudio(uint8_t* data, int32_t& length)
    593 {
    594     _crit->Enter();
    595     WEBRTC_TRACE(kTraceDebug, kTraceVideo, -1,  "AviFile::ReadAudio()");
    596 
    597     if (_aviMode != Read)
    598     {
    599         _crit->Leave();
    600         return -1;
    601     }
    602     if (_openedAs != AVI_AUDIO)
    603     {
    604         length = 0;
    605         _crit->Leave();
    606         WEBRTC_TRACE(kTraceDebug, kTraceVideo, -1,  "File not open as audio!");
    607         return -1;
    608     }
    609 
    610     const int32_t ret = ReadMoviSubChunk(
    611         data,
    612         length,
    613         StreamAndTwoCharCodeToTag(_audioStream.streamNumber, "wb"));
    614 
    615     _crit->Leave();
    616     return ret;
    617 }
    618 
    619 int32_t AviFile::ReadVideo(uint8_t* data, int32_t& length)
    620 {
    621     WEBRTC_TRACE(kTraceDebug, kTraceVideo, -1, "AviFile::ReadVideo()");
    622 
    623     _crit->Enter();
    624     if (_aviMode != Read)
    625     {
    626         //Has to be Read!
    627         _crit->Leave();
    628         return -1;
    629     }
    630     if (_openedAs != AVI_VIDEO)
    631     {
    632         length = 0;
    633         _crit->Leave();
    634         WEBRTC_TRACE(kTraceDebug, kTraceVideo, -1, "File not open as video!");
    635         return -1;
    636     }
    637 
    638     const int32_t ret = ReadMoviSubChunk(
    639         data,
    640         length,
    641         StreamAndTwoCharCodeToTag(_videoStream.streamNumber, "dc"),
    642         StreamAndTwoCharCodeToTag(_videoStream.streamNumber, "db"));
    643     _crit->Leave();
    644     return ret;
    645 }
    646 
    647 int32_t AviFile::Create(const char* fileName)
    648 {
    649     _crit->Enter();
    650     if (_aviMode != Write)
    651     {
    652         _crit->Leave();
    653         return -1;
    654     }
    655 
    656     if (!_writeVideoStream && !_writeAudioStream)
    657     {
    658         _crit->Leave();
    659         return -1;
    660     }
    661     if (_created)
    662     {
    663         _crit->Leave();
    664         return -1;
    665     }
    666 
    667 #ifdef _WIN32
    668     // fopen does not support wide characters on Windows, ergo _wfopen.
    669     wchar_t wideFileName[FileWrapper::kMaxFileNameSize];
    670     wideFileName[0] = 0;
    671 
    672     MultiByteToWideChar(CP_UTF8,0,fileName, -1, // convert the whole string
    673                         wideFileName, FileWrapper::kMaxFileNameSize);
    674 
    675     _aviFile = _wfopen(wideFileName, L"w+b");
    676     if (!_aviFile)
    677     {
    678         _crit->Leave();
    679         return -1;
    680     }
    681 #else
    682     _aviFile = fopen(fileName, "w+b");
    683     if (!_aviFile)
    684     {
    685         _crit->Leave();
    686         return -1;
    687     }
    688 #endif
    689 
    690     WriteRIFF();
    691     WriteHeaders();
    692 
    693     _created = true;
    694 
    695     PrepareDataChunkHeaders();
    696     ClearIndexList();
    697     WriteMoviStart();
    698     _aviMode = Write;
    699     _crit->Leave();
    700     return 0;
    701 }
    702 
    703 int32_t AviFile::CreateVideoStream(
    704     const AVISTREAMHEADER& videoStreamHeader,
    705     const BITMAPINFOHEADER& bitMapInfoHeader,
    706     const uint8_t* codecConfigParams,
    707     int32_t codecConfigParamsLength)
    708 {
    709     _crit->Enter();
    710     if (_aviMode == Read)
    711     {
    712         _crit->Leave();
    713         return -1;
    714     }
    715 
    716     if (_created)
    717     {
    718         _crit->Leave();
    719         return -1;
    720     }
    721 
    722     _aviMode = Write;
    723     _writeVideoStream = true;
    724 
    725     _videoStreamHeader = videoStreamHeader;
    726     _videoFormatHeader = bitMapInfoHeader;
    727 
    728     if (codecConfigParams && codecConfigParamsLength > 0)
    729     {
    730         if (_videoCodecConfigParams)
    731         {
    732             delete [] _videoCodecConfigParams;
    733             _videoCodecConfigParams = 0;
    734         }
    735 
    736         _videoCodecConfigParams = new uint8_t[codecConfigParamsLength];
    737         _videoCodecConfigParamsLength = codecConfigParamsLength;
    738 
    739         memcpy(_videoCodecConfigParams, codecConfigParams,
    740                _videoCodecConfigParamsLength);
    741     }
    742     _crit->Leave();
    743     return 0;
    744 }
    745 
    746 int32_t AviFile::CreateAudioStream(
    747     const AVISTREAMHEADER& audioStreamHeader,
    748     const WAVEFORMATEX& waveFormatHeader)
    749 {
    750     _crit->Enter();
    751 
    752     if (_aviMode == Read)
    753     {
    754         _crit->Leave();
    755         return -1;
    756     }
    757 
    758     if (_created)
    759     {
    760         _crit->Leave();
    761         return -1;
    762     }
    763 
    764     _aviMode = Write;
    765     _writeAudioStream = true;
    766     _audioStreamHeader = audioStreamHeader;
    767     _audioFormatHeader = waveFormatHeader;
    768     _crit->Leave();
    769     return 0;
    770 }
    771 
    772 int32_t AviFile::WriteRIFF()
    773 {
    774     const uint32_t riffTag = MakeFourCc('R', 'I', 'F', 'F');
    775     _bytesWritten += PutLE32(riffTag);
    776 
    777     // Size is unknown at this point. Update later.
    778     _bytesWritten += PutLE32(0);
    779     _riffSizeMark = _bytesWritten;
    780 
    781     const uint32_t aviTag = MakeFourCc('A', 'V', 'I', ' ');
    782     _bytesWritten += PutLE32(aviTag);
    783 
    784     return 0;
    785 }
    786 
    787 
    788 int32_t AviFile::WriteHeaders()
    789 {
    790     // Main AVI header list.
    791     const uint32_t listTag = MakeFourCc('L', 'I', 'S', 'T');
    792     _bytesWritten += PutLE32(listTag);
    793 
    794     // Size is unknown at this point. Update later.
    795     _bytesWritten += PutLE32(0);
    796     const size_t listhdrlSizeMark = _bytesWritten;
    797 
    798     const uint32_t hdrlTag = MakeFourCc('h', 'd', 'r', 'l');
    799     _bytesWritten += PutLE32(hdrlTag);
    800 
    801     WriteAVIMainHeader();
    802     WriteAVIStreamHeaders();
    803 
    804     const long hdrlLen = PutLE32LengthFromCurrent(
    805         static_cast<long>(listhdrlSizeMark));
    806 
    807     // Junk chunk to align on 2048 boundry (CD-ROM sector boundary).
    808     const uint32_t junkTag = MakeFourCc('J', 'U', 'N', 'K');
    809     _bytesWritten += PutLE32(junkTag);
    810     // Size is unknown at this point. Update later.
    811     _bytesWritten += PutLE32(0);
    812     const size_t junkSizeMark = _bytesWritten;
    813 
    814     const uint32_t junkBufferSize =
    815         0x800     // 2048 byte alignment
    816         - 12      // RIFF SIZE 'AVI '
    817         - 8       // LIST SIZE
    818         - hdrlLen //
    819         - 8       // JUNK SIZE
    820         - 12;     // LIST SIZE 'MOVI'
    821 
    822     // TODO (hellner): why not just fseek here?
    823     uint8_t* junkBuffer = new uint8_t[junkBufferSize];
    824     memset(junkBuffer, 0, junkBufferSize);
    825     _bytesWritten += PutBuffer(junkBuffer, junkBufferSize);
    826     delete [] junkBuffer;
    827 
    828     PutLE32LengthFromCurrent(static_cast<long>(junkSizeMark));
    829     // End of JUNK chunk.
    830     // End of main AVI header list.
    831     return 0;
    832 }
    833 
    834 int32_t AviFile::WriteAVIMainHeader()
    835 {
    836     const uint32_t avihTag = MakeFourCc('a', 'v', 'i', 'h');
    837     _bytesWritten += PutLE32(avihTag);
    838     _bytesWritten += PutLE32(14 * sizeof(uint32_t));
    839 
    840     const uint32_t scale = _videoStreamHeader.dwScale ?
    841         _videoStreamHeader.dwScale : 1;
    842     const uint32_t microSecPerFrame = 1000000 /
    843         (_videoStreamHeader.dwRate / scale);
    844     _bytesWritten += PutLE32(microSecPerFrame);
    845     _bytesWritten += PutLE32(0);
    846     _bytesWritten += PutLE32(0);
    847 
    848     uint32_t numStreams = 0;
    849     if (_writeVideoStream)
    850     {
    851         ++numStreams;
    852     }
    853     if (_writeAudioStream)
    854     {
    855         ++numStreams;
    856     }
    857 
    858     if (numStreams == 1)
    859     {
    860         _bytesWritten += PutLE32(
    861             kAvifTrustcktype
    862             | kAvifHasindex
    863             | kAvifWascapturefile);
    864     }
    865     else
    866     {
    867         _bytesWritten += PutLE32(
    868             kAvifTrustcktype
    869             | kAvifHasindex
    870             | kAvifWascapturefile
    871             | kAvifIsinterleaved);
    872     }
    873 
    874     _totNumFramesMark = _bytesWritten;
    875     _bytesWritten += PutLE32(0);
    876     _bytesWritten += PutLE32(0);
    877     _bytesWritten += PutLE32(numStreams);
    878 
    879     if (_writeVideoStream)
    880     {
    881         _bytesWritten += PutLE32(
    882             _videoStreamHeader.dwSuggestedBufferSize);
    883         _bytesWritten += PutLE32(
    884             _videoStreamHeader.rcFrame.right-_videoStreamHeader.rcFrame.left);
    885         _bytesWritten += PutLE32(
    886             _videoStreamHeader.rcFrame.bottom-_videoStreamHeader.rcFrame.top);
    887     } else {
    888         _bytesWritten += PutLE32(0);
    889         _bytesWritten += PutLE32(0);
    890         _bytesWritten += PutLE32(0);
    891     }
    892     _bytesWritten += PutLE32(0);
    893     _bytesWritten += PutLE32(0);
    894     _bytesWritten += PutLE32(0);
    895     _bytesWritten += PutLE32(0);
    896     return 0;
    897 }
    898 
    899 int32_t AviFile::WriteAVIStreamHeaders()
    900 {
    901     if (_writeVideoStream)
    902     {
    903         WriteAVIVideoStreamHeaders();
    904     }
    905     if (_writeAudioStream)
    906     {
    907         WriteAVIAudioStreamHeaders();
    908     }
    909     return 0;
    910 }
    911 
    912 int32_t AviFile::WriteAVIVideoStreamHeaders()
    913 {
    914     const uint32_t listTag = MakeFourCc('L', 'I', 'S', 'T');
    915     _bytesWritten += PutLE32(listTag);
    916 
    917     // Size is unknown at this point. Update later.
    918     _bytesWritten += PutLE32(0);
    919     const size_t liststrlSizeMark = _bytesWritten;
    920 
    921     const uint32_t hdrlTag = MakeFourCc('s', 't', 'r', 'l');
    922     _bytesWritten += PutLE32(hdrlTag);
    923 
    924     WriteAVIVideoStreamHeaderChunks();
    925 
    926     PutLE32LengthFromCurrent(static_cast<long>(liststrlSizeMark));
    927 
    928     return 0;
    929 }
    930 
    931 int32_t AviFile::WriteAVIVideoStreamHeaderChunks()
    932 {
    933     // Start of strh
    934     const uint32_t strhTag = MakeFourCc('s', 't', 'r', 'h');
    935     _bytesWritten += PutLE32(strhTag);
    936 
    937     // Size is unknown at this point. Update later.
    938     _bytesWritten += PutLE32(0);
    939     const size_t strhSizeMark = _bytesWritten;
    940 
    941     _bytesWritten += PutLE32(_videoStreamHeader.fccType);
    942     _bytesWritten += PutLE32(_videoStreamHeader.fccHandler);
    943     _bytesWritten += PutLE32(_videoStreamHeader.dwFlags);
    944     _bytesWritten += PutLE16(_videoStreamHeader.wPriority);
    945     _bytesWritten += PutLE16(_videoStreamHeader.wLanguage);
    946     _bytesWritten += PutLE32(_videoStreamHeader.dwInitialFrames);
    947     _bytesWritten += PutLE32(_videoStreamHeader.dwScale);
    948     _bytesWritten += PutLE32(_videoStreamHeader.dwRate);
    949     _bytesWritten += PutLE32(_videoStreamHeader.dwStart);
    950 
    951     _videoStreamLengthMark = _bytesWritten;
    952     _bytesWritten += PutLE32(_videoStreamHeader.dwLength);
    953 
    954     _bytesWritten += PutLE32(_videoStreamHeader.dwSuggestedBufferSize);
    955     _bytesWritten += PutLE32(_videoStreamHeader.dwQuality);
    956     _bytesWritten += PutLE32(_videoStreamHeader.dwSampleSize);
    957     _bytesWritten += PutLE16(_videoStreamHeader.rcFrame.left);
    958     _bytesWritten += PutLE16(_videoStreamHeader.rcFrame.top);
    959     _bytesWritten += PutLE16(_videoStreamHeader.rcFrame.right);
    960     _bytesWritten += PutLE16(_videoStreamHeader.rcFrame.bottom);
    961 
    962     PutLE32LengthFromCurrent(static_cast<long>(strhSizeMark));
    963     // End of strh
    964 
    965     // Start of strf
    966     const uint32_t strfTag = MakeFourCc('s', 't', 'r', 'f');
    967     _bytesWritten += PutLE32(strfTag);
    968 
    969     // Size is unknown at this point. Update later.
    970     _bytesWritten += PutLE32(0);
    971     const size_t strfSizeMark = _bytesWritten;
    972 
    973     _bytesWritten += PutLE32(_videoFormatHeader.biSize);
    974     _bytesWritten += PutLE32(_videoFormatHeader.biWidth);
    975     _bytesWritten += PutLE32(_videoFormatHeader.biHeight);
    976     _bytesWritten += PutLE16(_videoFormatHeader.biPlanes);
    977     _bytesWritten += PutLE16(_videoFormatHeader.biBitCount);
    978     _bytesWritten += PutLE32(_videoFormatHeader.biCompression);
    979     _bytesWritten += PutLE32(_videoFormatHeader.biSizeImage);
    980     _bytesWritten += PutLE32(_videoFormatHeader.biXPelsPerMeter);
    981     _bytesWritten += PutLE32(_videoFormatHeader.biYPelsPerMeter);
    982     _bytesWritten += PutLE32(_videoFormatHeader.biClrUsed);
    983     _bytesWritten += PutLE32(_videoFormatHeader.biClrImportant);
    984 
    985     const bool isMpegFile = _videoStreamHeader.fccHandler ==
    986         AviFile::MakeFourCc('M','4','S','2');
    987     if (isMpegFile)
    988     {
    989         if (_videoCodecConfigParams && _videoCodecConfigParamsLength > 0)
    990         {
    991             _bytesWritten += PutBuffer(_videoCodecConfigParams,
    992                                        _videoCodecConfigParamsLength);
    993         }
    994     }
    995 
    996     PutLE32LengthFromCurrent(static_cast<long>(strfSizeMark));
    997     // End of strf
    998 
    999     if ( _videoCodecConfigParams
   1000          && (_videoCodecConfigParamsLength > 0)
   1001          && !isMpegFile)
   1002     {
   1003         // Write strd, unless it's an MPEG file
   1004         const uint32_t strdTag = MakeFourCc('s', 't', 'r', 'd');
   1005         _bytesWritten += PutLE32(strdTag);
   1006 
   1007         // Size is unknown at this point. Update later.
   1008         _bytesWritten += PutLE32(0);
   1009         const size_t strdSizeMark = _bytesWritten;
   1010 
   1011         _bytesWritten += PutBuffer(_videoCodecConfigParams,
   1012                                    _videoCodecConfigParamsLength);
   1013 
   1014         PutLE32LengthFromCurrent(static_cast<long>(strdSizeMark));
   1015         // End of strd
   1016     }
   1017 
   1018     // Start of strn
   1019     const uint32_t strnTag = MakeFourCc('s', 't', 'r', 'n');
   1020     _bytesWritten += PutLE32(strnTag);
   1021 
   1022     // Size is unknown at this point. Update later.
   1023     _bytesWritten += PutLE32(0);
   1024     const size_t strnSizeMark = _bytesWritten;
   1025 
   1026     _bytesWritten += PutBufferZ("WebRtc.avi ");
   1027 
   1028     PutLE32LengthFromCurrent(static_cast<long>(strnSizeMark));
   1029     // End of strd
   1030 
   1031     return 0;
   1032 }
   1033 
   1034 int32_t AviFile::WriteAVIAudioStreamHeaders()
   1035 {
   1036     // Start of LIST
   1037     uint32_t listTag = MakeFourCc('L', 'I', 'S', 'T');
   1038     _bytesWritten += PutLE32(listTag);
   1039 
   1040     // Size is unknown at this point. Update later.
   1041     _bytesWritten += PutLE32(0);
   1042     const size_t liststrlSizeMark = _bytesWritten;
   1043 
   1044     uint32_t hdrlTag = MakeFourCc('s', 't', 'r', 'l');
   1045     _bytesWritten += PutLE32(hdrlTag);
   1046 
   1047     WriteAVIAudioStreamHeaderChunks();
   1048 
   1049     PutLE32LengthFromCurrent(static_cast<long>(liststrlSizeMark));
   1050     //End of LIST
   1051     return 0;
   1052 }
   1053 
   1054 int32_t AviFile::WriteAVIAudioStreamHeaderChunks()
   1055 {
   1056     // Start of strh
   1057     const uint32_t strhTag = MakeFourCc('s', 't', 'r', 'h');
   1058     _bytesWritten += PutLE32(strhTag);
   1059 
   1060     // Size is unknown at this point. Update later.
   1061     _bytesWritten += PutLE32(0);
   1062     const size_t strhSizeMark = _bytesWritten;
   1063 
   1064     _bytesWritten += PutLE32(_audioStreamHeader.fccType);
   1065     _bytesWritten += PutLE32(_audioStreamHeader.fccHandler);
   1066     _bytesWritten += PutLE32(_audioStreamHeader.dwFlags);
   1067     _bytesWritten += PutLE16(_audioStreamHeader.wPriority);
   1068     _bytesWritten += PutLE16(_audioStreamHeader.wLanguage);
   1069     _bytesWritten += PutLE32(_audioStreamHeader.dwInitialFrames);
   1070     _bytesWritten += PutLE32(_audioStreamHeader.dwScale);
   1071     _bytesWritten += PutLE32(_audioStreamHeader.dwRate);
   1072     _bytesWritten += PutLE32(_audioStreamHeader.dwStart);
   1073 
   1074     _audioStreamLengthMark = _bytesWritten;
   1075     _bytesWritten += PutLE32(_audioStreamHeader.dwLength);
   1076 
   1077     _bytesWritten += PutLE32(_audioStreamHeader.dwSuggestedBufferSize);
   1078     _bytesWritten += PutLE32(_audioStreamHeader.dwQuality);
   1079     _bytesWritten += PutLE32(_audioStreamHeader.dwSampleSize);
   1080     _bytesWritten += PutLE16(_audioStreamHeader.rcFrame.left);
   1081     _bytesWritten += PutLE16(_audioStreamHeader.rcFrame.top);
   1082     _bytesWritten += PutLE16(_audioStreamHeader.rcFrame.right);
   1083     _bytesWritten += PutLE16(_audioStreamHeader.rcFrame.bottom);
   1084 
   1085     PutLE32LengthFromCurrent(static_cast<long>(strhSizeMark));
   1086     // End of strh
   1087 
   1088     // Start of strf
   1089     const uint32_t strfTag = MakeFourCc('s', 't', 'r', 'f');
   1090     _bytesWritten += PutLE32(strfTag);
   1091 
   1092     // Size is unknown at this point. Update later.
   1093     _bytesWritten += PutLE32(0);
   1094     const size_t strfSizeMark = _bytesWritten;
   1095 
   1096     _bytesWritten += PutLE16(_audioFormatHeader.wFormatTag);
   1097     _bytesWritten += PutLE16(_audioFormatHeader.nChannels);
   1098     _bytesWritten += PutLE32(_audioFormatHeader.nSamplesPerSec);
   1099     _bytesWritten += PutLE32(_audioFormatHeader.nAvgBytesPerSec);
   1100     _bytesWritten += PutLE16(_audioFormatHeader.nBlockAlign);
   1101     _bytesWritten += PutLE16(_audioFormatHeader.wBitsPerSample);
   1102     _bytesWritten += PutLE16(_audioFormatHeader.cbSize);
   1103 
   1104     PutLE32LengthFromCurrent(static_cast<long>(strfSizeMark));
   1105     // End end of strf.
   1106 
   1107     // Audio doesn't have strd.
   1108 
   1109     // Start of strn
   1110     const uint32_t strnTag = MakeFourCc('s', 't', 'r', 'n');
   1111     _bytesWritten += PutLE32(strnTag);
   1112 
   1113     // Size is unknown at this point. Update later.
   1114     _bytesWritten += PutLE32(0);
   1115     const size_t strnSizeMark = _bytesWritten;
   1116 
   1117     _bytesWritten += PutBufferZ("WebRtc.avi ");
   1118 
   1119     PutLE32LengthFromCurrent(static_cast<long>(strnSizeMark));
   1120     // End of strd.
   1121 
   1122     return 0;
   1123 }
   1124 
   1125 int32_t AviFile::WriteMoviStart()
   1126 {
   1127     // Create template movi list. Fill out size when known (i.e. when closing
   1128     // file).
   1129     const uint32_t listTag = MakeFourCc('L', 'I', 'S', 'T');
   1130     _bytesWritten += PutLE32(listTag);
   1131 
   1132     _bytesWritten += PutLE32(0); //Size! Change later!
   1133     _moviSizeMark = _bytesWritten;
   1134     _moviListOffset = ftell(_aviFile);
   1135 
   1136     const uint32_t moviTag = MakeFourCc('m', 'o', 'v', 'i');
   1137     _bytesWritten += PutLE32(moviTag);
   1138 
   1139     return 0;
   1140 }
   1141 
   1142 size_t AviFile::PutByte(uint8_t byte)
   1143 {
   1144     return fwrite(&byte, sizeof(uint8_t), sizeof(uint8_t),
   1145                   _aviFile);
   1146 }
   1147 
   1148 size_t AviFile::PutLE16(uint16_t word)
   1149 {
   1150     return fwrite(&word, sizeof(uint8_t), sizeof(uint16_t),
   1151                   _aviFile);
   1152 }
   1153 
   1154 size_t AviFile::PutLE32(uint32_t word)
   1155 {
   1156     return fwrite(&word, sizeof(uint8_t), sizeof(uint32_t),
   1157                   _aviFile);
   1158 }
   1159 
   1160 size_t AviFile::PutBuffer(const uint8_t* str, size_t size)
   1161 {
   1162     return fwrite(str, sizeof(uint8_t), size,
   1163                   _aviFile);
   1164 }
   1165 
   1166 size_t AviFile::PutBufferZ(const char* str)
   1167 {
   1168     // Include NULL charachter, hence the + 1
   1169     return PutBuffer(reinterpret_cast<const uint8_t*>(str),
   1170                      strlen(str) + 1);
   1171 }
   1172 
   1173 long AviFile::PutLE32LengthFromCurrent(long startPos)
   1174 {
   1175     const long endPos = ftell(_aviFile);
   1176     if (endPos < 0) {
   1177         return 0;
   1178     }
   1179     bool success = (0 == fseek(_aviFile, startPos - 4, SEEK_SET));
   1180     if (!success) {
   1181         assert(false);
   1182         return 0;
   1183     }
   1184     const long len = endPos - startPos;
   1185     if (endPos > startPos) {
   1186         PutLE32(len);
   1187     }
   1188     else {
   1189         assert(false);
   1190     }
   1191     success = (0 == fseek(_aviFile, endPos, SEEK_SET));
   1192     assert(success);
   1193     return len;
   1194 }
   1195 
   1196 void AviFile::PutLE32AtPos(long pos, uint32_t word)
   1197 {
   1198     const long currPos = ftell(_aviFile);
   1199     if (currPos < 0) {
   1200         assert(false);
   1201         return;
   1202     }
   1203     bool success = (0 == fseek(_aviFile, pos, SEEK_SET));
   1204     if (!success) {
   1205       assert(false);
   1206       return;
   1207     }
   1208     PutLE32(word);
   1209     success = (0 == fseek(_aviFile, currPos, SEEK_SET));
   1210     assert(success);
   1211 }
   1212 
   1213 void AviFile::CloseRead()
   1214 {
   1215     if (_aviFile)
   1216     {
   1217         fclose(_aviFile);
   1218         _aviFile = NULL;
   1219     }
   1220 }
   1221 
   1222 void AviFile::CloseWrite()
   1223 {
   1224     if (_created)
   1225     {
   1226         // Update everything that isn't known until the file is closed. The
   1227         // marks indicate where in the headers this update should be.
   1228         PutLE32LengthFromCurrent(static_cast<long>(_moviSizeMark));
   1229 
   1230         PutLE32AtPos(static_cast<long>(_totNumFramesMark), _videoFrames);
   1231 
   1232         if (_writeVideoStream)
   1233         {
   1234             PutLE32AtPos(static_cast<long>(_videoStreamLengthMark),
   1235                          _videoFrames);
   1236         }
   1237 
   1238         if (_writeAudioStream)
   1239         {
   1240             PutLE32AtPos(static_cast<long>(_audioStreamLengthMark),
   1241                          _audioFrames);
   1242         }
   1243 
   1244         WriteIndex();
   1245         PutLE32LengthFromCurrent(static_cast<long>(_riffSizeMark));
   1246         ClearIndexList();
   1247 
   1248         if (_aviFile)
   1249         {
   1250             fclose(_aviFile);
   1251             _aviFile = NULL;
   1252         }
   1253     }
   1254 }
   1255 
   1256 void AviFile::ResetMembers()
   1257 {
   1258     ResetComplexMembers();
   1259 
   1260     _aviFile = NULL;
   1261 
   1262     _nrStreams     = 0;
   1263     _aviLength     = 0;
   1264     _dataLength    = 0;
   1265     _bytesRead     = 0;
   1266     _dataStartByte = 0;
   1267     _framesRead    = 0;
   1268     _videoFrames   = 0;
   1269     _audioFrames   = 0;
   1270 
   1271     _reading = false;
   1272     _openedAs = AVI_AUDIO;
   1273     _loop = false;
   1274     _writing = false;
   1275 
   1276     _bytesWritten          = 0;
   1277 
   1278     _riffSizeMark          = 0;
   1279     _moviSizeMark          = 0;
   1280     _totNumFramesMark      = 0;
   1281     _videoStreamLengthMark = 0;
   1282     _audioStreamLengthMark = 0;
   1283 
   1284     _writeAudioStream = false;
   1285     _writeVideoStream = false;
   1286 
   1287     _aviMode                      = NotSet;
   1288     _videoCodecConfigParams       = 0;
   1289     _videoCodecConfigParamsLength = 0;
   1290 
   1291     _videoStreamDataChunkPrefix = 0;
   1292     _audioStreamDataChunkPrefix = 0;
   1293 
   1294     _created = false;
   1295 
   1296     _moviListOffset = 0;
   1297 
   1298     _videoConfigLength = 0;
   1299 }
   1300 
   1301 void AviFile::ResetComplexMembers()
   1302 {
   1303     memset(&_aviHeader, 0, sizeof(AVIMAINHEADER));
   1304     memset(&_videoStreamHeader, 0, sizeof(AVISTREAMHEADER));
   1305     memset(&_audioStreamHeader, 0, sizeof(AVISTREAMHEADER));
   1306     memset(&_videoFormatHeader, 0, sizeof(BITMAPINFOHEADER));
   1307     memset(&_audioFormatHeader, 0, sizeof(WAVEFORMATEX));
   1308     memset(_videoConfigParameters, 0, CODEC_CONFIG_LENGTH);
   1309     memset(_videoStreamName, 0, STREAM_NAME_LENGTH);
   1310     memset(_audioStreamName, 0, STREAM_NAME_LENGTH);
   1311     memset(&_videoStream, 0, sizeof(AVIStream));
   1312     memset(&_audioStream, 0, sizeof(AVIStream));
   1313 }
   1314 
   1315 size_t AviFile::GetByte(uint8_t& word)
   1316 {
   1317     return fread(&word, sizeof(uint8_t), sizeof(uint8_t), _aviFile);
   1318 }
   1319 
   1320 size_t AviFile::GetLE16(uint16_t& word)
   1321 {
   1322     return fread(&word, sizeof(uint8_t), sizeof(uint16_t),
   1323                  _aviFile);
   1324 }
   1325 
   1326 size_t AviFile::GetLE32(uint32_t& word)
   1327 {
   1328     return fread(&word, sizeof(uint8_t), sizeof(uint32_t),
   1329                  _aviFile);
   1330 }
   1331 
   1332 size_t AviFile::GetBuffer(uint8_t* str, size_t size)
   1333 {
   1334     return fread(str, sizeof(uint8_t), size, _aviFile);
   1335 }
   1336 
   1337 int32_t AviFile::ReadRIFF()
   1338 {
   1339     uint32_t tag;
   1340     _bytesRead = GetLE32(tag);
   1341     if (tag != MakeFourCc('R', 'I', 'F', 'F'))
   1342     {
   1343         WEBRTC_TRACE(kTraceError, kTraceVideo, -1,  "Not a RIFF file!");
   1344         return -1;
   1345     }
   1346 
   1347     uint32_t size;
   1348     _bytesRead += GetLE32(size);
   1349     _aviLength = size;
   1350 
   1351     _bytesRead += GetLE32(tag);
   1352     if (tag != MakeFourCc('A', 'V', 'I', ' '))
   1353     {
   1354         WEBRTC_TRACE(kTraceError, kTraceVideo, -1,  "Not an AVI file!");
   1355         return -1;
   1356     }
   1357 
   1358     return 0;
   1359 }
   1360 
   1361 int32_t AviFile::ReadHeaders()
   1362 {
   1363     uint32_t tag;
   1364     _bytesRead += GetLE32(tag);
   1365     uint32_t size;
   1366     _bytesRead += GetLE32(size);
   1367 
   1368     if (tag != MakeFourCc('L', 'I', 'S', 'T'))
   1369     {
   1370         return -1;
   1371     }
   1372 
   1373     uint32_t listTag;
   1374     _bytesRead += GetLE32(listTag);
   1375     if (listTag != MakeFourCc('h', 'd', 'r', 'l'))
   1376     {
   1377         return -1;
   1378     }
   1379 
   1380     int32_t err = ReadAVIMainHeader();
   1381     if (err)
   1382     {
   1383         return -1;
   1384     }
   1385 
   1386     return 0;
   1387 }
   1388 
   1389 int32_t AviFile::ReadAVIMainHeader()
   1390 {
   1391     _bytesRead += GetLE32(_aviHeader.fcc);
   1392     _bytesRead += GetLE32(_aviHeader.cb);
   1393     _bytesRead += GetLE32(_aviHeader.dwMicroSecPerFrame);
   1394     _bytesRead += GetLE32(_aviHeader.dwMaxBytesPerSec);
   1395     _bytesRead += GetLE32(_aviHeader.dwPaddingGranularity);
   1396     _bytesRead += GetLE32(_aviHeader.dwFlags);
   1397     _bytesRead += GetLE32(_aviHeader.dwTotalFrames);
   1398     _bytesRead += GetLE32(_aviHeader.dwInitialFrames);
   1399     _bytesRead += GetLE32(_aviHeader.dwStreams);
   1400     _bytesRead += GetLE32(_aviHeader.dwSuggestedBufferSize);
   1401     _bytesRead += GetLE32(_aviHeader.dwWidth);
   1402     _bytesRead += GetLE32(_aviHeader.dwHeight);
   1403     _bytesRead += GetLE32(_aviHeader.dwReserved[0]);
   1404     _bytesRead += GetLE32(_aviHeader.dwReserved[1]);
   1405     _bytesRead += GetLE32(_aviHeader.dwReserved[2]);
   1406     _bytesRead += GetLE32(_aviHeader.dwReserved[3]);
   1407 
   1408     if (_aviHeader.fcc != MakeFourCc('a', 'v', 'i', 'h'))
   1409     {
   1410         return -1;
   1411     }
   1412 
   1413     if (_aviHeader.dwFlags & kAvifMustuseindex)
   1414     {
   1415         return -1;
   1416     }
   1417 
   1418     bool readVideoStreamHeader = false;
   1419     bool readAudioStreamHeader = false;
   1420     unsigned int streamsRead = 0;
   1421     while (_aviHeader.dwStreams > streamsRead)
   1422     {
   1423         uint32_t strltag;
   1424         _bytesRead += GetLE32(strltag);
   1425         uint32_t strlsize;
   1426         _bytesRead += GetLE32(strlsize);
   1427         const long endSeekPos = ftell(_aviFile) +
   1428             static_cast<int32_t>(strlsize);
   1429 
   1430         if (strltag != MakeFourCc('L', 'I', 'S', 'T'))
   1431         {
   1432             return -1;
   1433         }
   1434 
   1435         uint32_t listTag;
   1436         _bytesRead += GetLE32(listTag);
   1437         if (listTag != MakeFourCc('s', 't', 'r', 'l'))
   1438         {
   1439             return -1;
   1440         }
   1441 
   1442         uint32_t chunktag;
   1443         _bytesRead += GetLE32(chunktag);
   1444         uint32_t chunksize;
   1445         _bytesRead += GetLE32(chunksize);
   1446 
   1447         if (chunktag != MakeFourCc('s', 't', 'r', 'h'))
   1448         {
   1449             return -1;
   1450         }
   1451 
   1452         AVISTREAMHEADER tmpStreamHeader;
   1453         tmpStreamHeader.fcc = chunktag;
   1454         tmpStreamHeader.cb  = chunksize;
   1455 
   1456         _bytesRead += GetLE32(tmpStreamHeader.fccType);
   1457         _bytesRead += GetLE32(tmpStreamHeader.fccHandler);
   1458         _bytesRead += GetLE32(tmpStreamHeader.dwFlags);
   1459         _bytesRead += GetLE16(tmpStreamHeader.wPriority);
   1460         _bytesRead += GetLE16(tmpStreamHeader.wLanguage);
   1461         _bytesRead += GetLE32(tmpStreamHeader.dwInitialFrames);
   1462         _bytesRead += GetLE32(tmpStreamHeader.dwScale);
   1463         _bytesRead += GetLE32(tmpStreamHeader.dwRate);
   1464         _bytesRead += GetLE32(tmpStreamHeader.dwStart);
   1465         _bytesRead += GetLE32(tmpStreamHeader.dwLength);
   1466         _bytesRead += GetLE32(tmpStreamHeader.dwSuggestedBufferSize);
   1467         _bytesRead += GetLE32(tmpStreamHeader.dwQuality);
   1468         _bytesRead += GetLE32(tmpStreamHeader.dwSampleSize);
   1469 
   1470         uint16_t left;
   1471         _bytesRead += GetLE16(left);
   1472         tmpStreamHeader.rcFrame.left = left;
   1473         uint16_t top;
   1474         _bytesRead += GetLE16(top);
   1475         tmpStreamHeader.rcFrame.top = top;
   1476         uint16_t right;
   1477         _bytesRead += GetLE16(right);
   1478         tmpStreamHeader.rcFrame.right = right;
   1479         uint16_t bottom;
   1480         _bytesRead += GetLE16(bottom);
   1481         tmpStreamHeader.rcFrame.bottom = bottom;
   1482 
   1483         if (!readVideoStreamHeader
   1484             && (tmpStreamHeader.fccType == MakeFourCc('v', 'i', 'd', 's')))
   1485         {
   1486             _videoStreamHeader = tmpStreamHeader; //Bitwise copy is OK!
   1487             const int32_t err = ReadAVIVideoStreamHeader(endSeekPos);
   1488             if (err)
   1489             {
   1490                 return -1;
   1491             }
   1492             // Make sure there actually is video data in the file...
   1493             if (_videoStreamHeader.dwLength == 0)
   1494             {
   1495                 return -1;
   1496             }
   1497             readVideoStreamHeader = true;
   1498         } else if(!readAudioStreamHeader &&
   1499                   (tmpStreamHeader.fccType == MakeFourCc('a', 'u', 'd', 's'))) {
   1500             _audioStreamHeader = tmpStreamHeader;
   1501             const int32_t err = ReadAVIAudioStreamHeader(endSeekPos);
   1502             if (err)
   1503             {
   1504                 return -1;
   1505             }
   1506             readAudioStreamHeader = true;
   1507         }
   1508         else
   1509         {
   1510             fseek(_aviFile, endSeekPos, SEEK_SET);
   1511             _bytesRead += endSeekPos;
   1512         }
   1513 
   1514         ++streamsRead;
   1515     }
   1516 
   1517     if (!readVideoStreamHeader && !readAudioStreamHeader)
   1518     {
   1519         return -1;
   1520     }
   1521 
   1522     uint32_t tag;
   1523     _bytesRead += GetLE32(tag);
   1524     uint32_t size;
   1525     _bytesRead += GetLE32(size);
   1526 
   1527     if (tag == MakeFourCc('J', 'U', 'N', 'K'))
   1528     {
   1529         fseek(_aviFile, size, SEEK_CUR);
   1530         _bytesRead += size;
   1531         _bytesRead += GetLE32(tag);
   1532         _bytesRead += GetLE32(size);
   1533     }
   1534     if (tag != MakeFourCc('L', 'I', 'S', 'T'))
   1535     {
   1536         return -1;
   1537     }
   1538     uint32_t listTag;
   1539     _bytesRead += GetLE32(listTag);
   1540     if (listTag != MakeFourCc('m', 'o', 'v', 'i'))
   1541     {
   1542         return -1;
   1543     }
   1544     _dataLength = size;
   1545     return 0;
   1546 }
   1547 
   1548 int32_t AviFile::ReadAVIVideoStreamHeader(int32_t endpos)
   1549 {
   1550     uint32_t chunktag;
   1551     _bytesRead += GetLE32(chunktag);
   1552     uint32_t chunksize;
   1553     _bytesRead += GetLE32(chunksize);
   1554 
   1555     if (chunktag != MakeFourCc('s', 't', 'r', 'f'))
   1556     {
   1557         return -1;
   1558     }
   1559 
   1560     _bytesRead += GetLE32(_videoFormatHeader.biSize);
   1561     _bytesRead += GetLE32(_videoFormatHeader.biWidth);
   1562     _bytesRead += GetLE32(_videoFormatHeader.biHeight);
   1563     _bytesRead += GetLE16(_videoFormatHeader.biPlanes);
   1564     _bytesRead += GetLE16(_videoFormatHeader.biBitCount);
   1565     _bytesRead += GetLE32(_videoFormatHeader.biCompression);
   1566     _bytesRead += GetLE32(_videoFormatHeader.biSizeImage);
   1567     _bytesRead += GetLE32(_videoFormatHeader.biXPelsPerMeter);
   1568     _bytesRead += GetLE32(_videoFormatHeader.biYPelsPerMeter);
   1569     _bytesRead += GetLE32(_videoFormatHeader.biClrUsed);
   1570     _bytesRead += GetLE32(_videoFormatHeader.biClrImportant);
   1571 
   1572     if (chunksize >  _videoFormatHeader.biSize)
   1573     {
   1574         const uint32_t size = chunksize - _videoFormatHeader.biSize;
   1575         const uint32_t readSize = MinValue(size, CODEC_CONFIG_LENGTH);
   1576         _bytesRead += GetBuffer(
   1577             reinterpret_cast<uint8_t*>(_videoConfigParameters), readSize);
   1578         _videoConfigLength = readSize;
   1579         int32_t skipSize = chunksize - _videoFormatHeader.biSize -
   1580             readSize;
   1581         if (skipSize > 0)
   1582         {
   1583             fseek(_aviFile, skipSize, SEEK_CUR);
   1584             _bytesRead += skipSize;
   1585         }
   1586     }
   1587 
   1588     while (static_cast<long>(_bytesRead) < endpos)
   1589     {
   1590         uint32_t chunktag;
   1591         _bytesRead += GetLE32(chunktag);
   1592         uint32_t chunksize;
   1593         _bytesRead += GetLE32(chunksize);
   1594 
   1595         if (chunktag == MakeFourCc('s', 't', 'r', 'n'))
   1596         {
   1597             const uint32_t size = MinValue(chunksize, STREAM_NAME_LENGTH);
   1598             _bytesRead += GetBuffer(
   1599                 reinterpret_cast<uint8_t*>(_videoStreamName), size);
   1600         }
   1601         else if (chunktag == MakeFourCc('s', 't', 'r', 'd'))
   1602         {
   1603             const uint32_t size = MinValue(chunksize, CODEC_CONFIG_LENGTH);
   1604             _bytesRead += GetBuffer(
   1605                 reinterpret_cast<uint8_t*>(_videoConfigParameters), size);
   1606             _videoConfigLength = size;
   1607         }
   1608         else
   1609         {
   1610             fseek(_aviFile, chunksize, SEEK_CUR);
   1611             _bytesRead += chunksize;
   1612         }
   1613 
   1614         if (feof(_aviFile))
   1615         {
   1616             return -1;
   1617         }
   1618     }
   1619     _videoStream.streamType = AviFile::AVI_VIDEO;
   1620     _videoStream.streamNumber = _nrStreams++;
   1621 
   1622     return 0;
   1623 }
   1624 
   1625 int32_t AviFile::ReadAVIAudioStreamHeader(int32_t endpos)
   1626 {
   1627     uint32_t chunktag;
   1628     _bytesRead += GetLE32(chunktag);
   1629     uint32_t chunksize;
   1630     _bytesRead += GetLE32(chunksize);
   1631 
   1632     if (chunktag != MakeFourCc('s', 't', 'r', 'f'))
   1633     {
   1634         return -1;
   1635     }
   1636 
   1637     const size_t startRead = _bytesRead;
   1638     _bytesRead += GetLE16(_audioFormatHeader.wFormatTag);
   1639     _bytesRead += GetLE16(_audioFormatHeader.nChannels);
   1640     _bytesRead += GetLE32(_audioFormatHeader.nSamplesPerSec);
   1641     _bytesRead += GetLE32(_audioFormatHeader.nAvgBytesPerSec);
   1642     _bytesRead += GetLE16(_audioFormatHeader.nBlockAlign);
   1643     _bytesRead += GetLE16(_audioFormatHeader.wBitsPerSample);
   1644     if (chunksize > 0x10) {
   1645         _bytesRead += GetLE16(_audioFormatHeader.cbSize);
   1646     }
   1647 
   1648     const uint32_t diffRead = chunksize - (_bytesRead - startRead);
   1649     if (diffRead > 0)
   1650     {
   1651         const uint32_t size = MinValue(diffRead, CODEC_CONFIG_LENGTH);
   1652         _bytesRead += GetBuffer(
   1653             reinterpret_cast<uint8_t*>(_audioConfigParameters), size);
   1654     }
   1655 
   1656     while (static_cast<long>(_bytesRead) < endpos)
   1657     {
   1658         uint32_t chunktag;
   1659         _bytesRead += GetLE32(chunktag);
   1660         uint32_t chunksize;
   1661         _bytesRead += GetLE32(chunksize);
   1662 
   1663         if (chunktag == MakeFourCc('s', 't', 'r', 'n'))
   1664         {
   1665             const uint32_t size = MinValue(chunksize, STREAM_NAME_LENGTH);
   1666             _bytesRead += GetBuffer(
   1667                 reinterpret_cast<uint8_t*>(_audioStreamName), size);
   1668         }
   1669         else if (chunktag == MakeFourCc('s', 't', 'r', 'd'))
   1670         {
   1671             const uint32_t size = MinValue(chunksize, CODEC_CONFIG_LENGTH);
   1672             _bytesRead += GetBuffer(
   1673                 reinterpret_cast<uint8_t*>(_audioConfigParameters), size);
   1674         }
   1675         else
   1676         {
   1677             fseek(_aviFile, chunksize, SEEK_CUR);
   1678             _bytesRead += chunksize;
   1679         }
   1680 
   1681         if (feof(_aviFile))
   1682         {
   1683             return -1;
   1684         }
   1685     }
   1686     _audioStream.streamType = AviFile::AVI_AUDIO;
   1687     _audioStream.streamNumber = _nrStreams++;
   1688     return 0;
   1689 }
   1690 
   1691 uint32_t AviFile::StreamAndTwoCharCodeToTag(int32_t streamNum,
   1692                                             const char* twoCharCode)
   1693 {
   1694     uint8_t a = '0';
   1695     uint8_t b;
   1696     switch (streamNum)
   1697     {
   1698     case 1:
   1699         b = '1';
   1700         break;
   1701     case 2:
   1702         b = '2';
   1703         break;
   1704     default:
   1705         b = '0';
   1706     }
   1707     return MakeFourCc(a, b, twoCharCode[0], twoCharCode[1]);
   1708 }
   1709 
   1710 void AviFile::ClearIndexList()
   1711 {
   1712   for (IndexList::iterator iter = _indexList.begin();
   1713        iter != _indexList.end(); ++iter) {
   1714       delete *iter;
   1715   }
   1716   _indexList.clear();
   1717 }
   1718 
   1719 void AviFile::AddChunkToIndexList(uint32_t inChunkId,
   1720                                   uint32_t inFlags,
   1721                                   uint32_t inOffset,
   1722                                   uint32_t inSize)
   1723 {
   1724     _indexList.push_back(new AVIINDEXENTRY(inChunkId, inFlags, inOffset,
   1725                                            inSize));
   1726 }
   1727 
   1728 void AviFile::WriteIndex()
   1729 {
   1730     const uint32_t idxTag = MakeFourCc('i', 'd', 'x', '1');
   1731     _bytesWritten += PutLE32(idxTag);
   1732 
   1733     // Size is unknown at this point. Update later.
   1734     _bytesWritten += PutLE32(0);
   1735     const size_t idxChunkSize = _bytesWritten;
   1736 
   1737     for (IndexList::iterator iter = _indexList.begin();
   1738          iter != _indexList.end(); ++iter) {
   1739         const AVIINDEXENTRY* item = *iter;
   1740         _bytesWritten += PutLE32(item->ckid);
   1741         _bytesWritten += PutLE32(item->dwFlags);
   1742         _bytesWritten += PutLE32(item->dwChunkOffset);
   1743         _bytesWritten += PutLE32(item->dwChunkLength);
   1744     }
   1745     PutLE32LengthFromCurrent(static_cast<long>(idxChunkSize));
   1746 }
   1747 }  // namespace webrtc
   1748