AVI created with AVIStreamWrite has incorrect length and playback speed

2.9k views Asked by At

I'm trying to write to an AVI file using AVIStreamWrite but the resulting avi file is a bit messed up. The images in the avi contain the proper image and colors but the duration and speed of the video is off. I recorded a video that should have been around 7 seconds and looking at the file properties in Windows explorer it showed it had a duration of about 2 seconds. When I played it in Media Player it was too short and seemed to be playing very rapidly (motion in the video was like fast forward). I also can't seem to seek within the video using Media Player. Here is what I'm doing...

//initialization

HRESULT AVIWriter::Init()
{
HRESULT hr = S_OK;
_hAVIFile = NULL;
_videoStream = NULL;


_frameCount = 0;
AVIFileInit();

::DeleteFileW(_filename);

hr = AVIFileOpen(&_hAVIFile,_filename,OF_WRITE|OF_CREATE, NULL);
if (hr != AVIERR_OK)
{
    ::cout << "AVI ERROR";
    return 0;
}
/**************************************/
// Create a raw video stream in the file
::ZeroMemory(&_streamInfo, sizeof(_streamInfo));
_streamInfo.fccType                = streamtypeVIDEO;    // stream type
_streamInfo.fccHandler             = 0;                  // No compressor
_streamInfo.dwScale                = 1;                                       
_streamInfo.dwRate                 = _aviFps;   //this is 30
_streamInfo.dwSuggestedBufferSize  = 0;
_streamInfo.dwSampleSize = 0;
SetRect( &_streamInfo.rcFrame, 0, 0,_bmi.biWidth , _bmi.biHeight );

hr = AVIFileCreateStream(   _hAVIFile,      // file pointer
                            &_videoStream,// returned stream pointer
                            &_streamInfo);  // stream header

hr = AVIStreamSetFormat(_videoStream, 0,
                            &_bmi,   
                            sizeof(_bmi));

return hr;
}

//call this when I receive a frame from my camera

HRESULT AVIWriter::AddFrameToAVI(BYTE* buffer)
{ 
HRESULT hr;
long size = _bmi.biHeight * _bmi.biWidth * 3;

hr = AVIStreamWrite(_videoStream,           // stream pointer
                _frameCount++,              // time of this frame
                1,                      // number to write
                buffer, // pointer to data
                size,// size of this frame
                AVIIF_KEYFRAME,         // flags....
                NULL,
                NULL);  

return hr;

}

//call this when I am done

    void AVIWriter::CloseAVI()

   {
    AVIStreamClose(_videoStream);
    AVIFileClose(_hAVIFile);
    AVIFileExit();

    }

Now as a test I used DirectShow's GraphEdit to create a graph consisting of a VideoCapture Filter for this same camera and an AVI mux and created an avi file. The resulting AVI file was fine. The frame rate was 30 fps, the same that I am using. I queried both avi files (my 'bad' one and the 'good' one created with GraphEdit) using a call to AVIStreamInfo and the stream info was pretty much the same for both files. I would have expected either the samples per second or number of frames to be way off for my 'bad' avi but it wasn't. Am I doing something wrong that would cause my AVI to have the incorrect length and seem to play back at an increased speed?? I'm new to using VFW so any help is appreciated. Thanks

1

There are 1 answers

1
Roman Ryltsov On BEST ANSWER

Frame time in the will will eventually be _frameCount / _aviFps, so it is either you are dropping your frames and they don't reach AVIStreamWrite, or alternatively if you prefer to skip a few frames in the file, you need to increment _frameCount respectively, to jump over frames to skip.