开发者

Am i incorrectly setting up avi info for saving a file in C++ vfw?

I am using a specialized network streaming camera and I am trying to save the video stream off in a file. at the moment the code saves the video but in an ackward RGB format which screws up the color and then saves it using VFW. Am i doing this correctly and this is supposed to create avi with mismatched colors or did i setup something wrong in the BITMAPINFOHEADER areas?

void PvSbProUISampleDlg::OnBnClickedSave()
{
// TODO: Add your control notification handler code here

CString StringValue;
mMovieSave.GetWindowTextW(StringValue);

if (StringValue == L"Save")
{
    CString codecValue;
    mMovieCodecSelected.GetWindowTextW(codecValue);
    if (codecValue.IsEmpty()){
        MessageBox( L"Please select a codec before saving to file",
                    L"Select Codec!",
                    MB_OK | MB_ICONEXCLAMATION );
        return;
    }

    CString fileNameValue;
    mFileName.GetWindowTextW(fileNameValue);
    if (fileNameValue.IsEmpty()){
        MessageBox( L"Please select a file location",
                    L"Select File!",
                    MB_OK | MB_ICONEXCLAMATION );
        return;
    }


    if (!StartMovie())
        return;

    mSavingMovie = true;
    mMovieSave.SetWindowTextW(L"Saving");
}
else
{
    mVideoMutex.Lock();
    PvResult aResult = mVideoCompressor->Stop();
    mSavingMovie = false;
    mVideoMutex.Unlock();
    if (!aResult.IsOK())
    {
        MessageBox( mLocation,
                    L"Can't Stop Video Compressor!",
                    MB_OK | MB_ICONEXCLAMATION );
        return;
    }

    mMovieSave.SetWindowTextW(L"Save");
}

}

I set up the video stream and select uncompressed AVI for my codec. I click "save" button which then calls the function below

bool PvSbProUISampleDlg::StartMovie()
{
 if ( !mDevice.IsConnected() )
{
    MessageBox( L"Need to connect to device",
                L"Cannot start Video Compressor!",
                MB_OK | MB_ICONEXCLAMATION );
    return false;
}

if (!mPipeline.IsStarted() )
{
    return false;
} 

if (mSavingMovie)
    return false;

PvInt64 width;
PvInt64 height;
PvInt64 bitCount;

if (!GetImageWidth(width).IsOK())
    return false;

if (!GetImageHeight(height).IsOK())
    return false;

if (!GetPixelBitCount(bitCount).IsOK())
    return false;

// Start the movie compressor
if ( !mVideoCompressor->Start( mLocation,
                            width,
                            height,
                            bitCount/8,
                            59).IsOK())
{
    MessageBox( mLocation,
                L"Cannot start Video Compressor!",
                MB_OK | MB_ICONEXCLAMATION );
    return false;
}

return true;
}

the function gets the video size info and then calls the actually compression to start

PvResult VideoCompressor::Start(const CString& aFileName, unsigned short aSizeX,      unsigned short aSizeY, unsigned short aBPP, double aFPS)
{
IAVIFile *lAVIFile = NULL;
IAVIStream *lAVIStream = NULL;
IAVIStream *lAVICompressedStream = NULL;
AVISTREAMINFO lAVISTREAMINFO;
AVICOMPRESSOPTIONS lAVICOMPRESSOPTIONS;

// Try to match the image format with the Video Compressor capabilities
BITMAPINFO lTempBI;
lTempBI.bmiHeader.biSize          = sizeof( BITMAPINFO );
lTempBI.bmiHeader.biWidth         = aSizeX;
lTempBI.bmiHeader.biHeight        = aSizeY;
lTempBI.bmiHeader.biPlanes        = 1;
lTempBI.bmiHeader.biBitCount      = aBPP * 8;
lTempBI.bmiHeader.biCompression   = BI_RGB;
lTempBI.bmiHeader.biSizeImage     = aSizeX * aSizeY * aBPP;
lTempBI.bmiHeader.biXPelsPerMeter = 128开发者_如何学JAVA0;
lTempBI.bmiHeader.biYPelsPerMeter = 720;
lTempBI.bmiHeader.biClrUsed       = 0;
lTempBI.bmiHeader.biClrImportant  = 0;
//lTempBI.bmiHeader.

if( ( mCOMPVARS.hic != NULL ) && // if not the "Full Frames (uncompressed)"
    ( ICCompressQuery( mCOMPVARS.hic, &lTempBI, NULL ) != ICERR_OK ) )
{
    mLastVideoError = "Image format not accepted by compressor!";
    CleanUp(lAVIFile, lAVIStream ,lAVICompressedStream);
    return PvResult::Code::GENERIC_ERROR;
}

// Try to open the stream for writing
if( mTempBuffer )
    delete [] mTempBuffer;

mTempBuffer = new unsigned char[ aSizeX * aSizeY * aBPP ];
if( mTempBuffer == NULL )
{
    mLastVideoError = "Cannot allocate memory for a temporary buffer!";
    CleanUp(lAVIFile, lAVIStream ,lAVICompressedStream);
    return PvResult::Code::GENERIC_ERROR;
}

if( AVIFileOpen( &lAVIFile, aFileName, OF_CREATE | OF_WRITE, NULL ) != 0 )
{
    mLastVideoError = "Cannot open movie file for writing!";
    CleanUp(lAVIFile, lAVIStream ,lAVICompressedStream);
    return PvResult::Code::GENERIC_ERROR;
}

// Fill out AVIStream information
memset( &lAVISTREAMINFO, 0, sizeof( AVISTREAMINFO ) );
lAVISTREAMINFO.fccType               = streamtypeVIDEO;
lAVISTREAMINFO.fccHandler            = mCOMPVARS.fccHandler;
lAVISTREAMINFO.dwFlags               = 0;
lAVISTREAMINFO.dwCaps                = 0;
lAVISTREAMINFO.wPriority             = 0;
lAVISTREAMINFO.wLanguage             = 0;
lAVISTREAMINFO.dwScale               = 100;
lAVISTREAMINFO.dwRate                = (unsigned long)( aFPS * 100.0 );
lAVISTREAMINFO.dwStart               = 0;
lAVISTREAMINFO.dwLength              = 0;
lAVISTREAMINFO.dwInitialFrames       = 0;
lAVISTREAMINFO.dwQuality             = mCOMPVARS.lQ;
lAVISTREAMINFO.dwSuggestedBufferSize = aSizeX * aSizeY * aBPP;
lAVISTREAMINFO.dwSampleSize          = aSizeX * aSizeY * aBPP;
SetRect(&lAVISTREAMINFO.rcFrame, 0, aSizeY, aSizeX, 0);
// Convert to a wchar_t*
char *orig = "Video Stream";
size_t origsize = strlen(orig) + 1;
const size_t newsize = 64;
size_t convertedChars = 0;

mbstowcs_s(&convertedChars, lAVISTREAMINFO.szName, origsize, orig, _TRUNCATE);

if( AVIFileCreateStream( lAVIFile, &lAVIStream, &lAVISTREAMINFO ) != 0 )
{
    mLastVideoError = "Cannot create video stream!";
    CleanUp(lAVIFile, lAVIStream ,lAVICompressedStream);
    return PvResult::Code::GENERIC_ERROR;
}

BITMAPINFOHEADER lBIH;
lBIH.biSize          = sizeof( BITMAPINFOHEADER );
lBIH.biWidth         = aSizeX;
lBIH.biHeight        = aSizeY;
lBIH.biPlanes        = 1;
lBIH.biBitCount      = aBPP * 8;
lBIH.biCompression   = BI_RGB;
lBIH.biSizeImage     = aSizeX * aSizeY * aBPP;
lBIH.biXPelsPerMeter = 1280;
lBIH.biYPelsPerMeter = 720;
lBIH.biClrUsed       = 0;
lBIH.biClrImportant  = 0;

memset( &lAVICOMPRESSOPTIONS, 0, sizeof( AVICOMPRESSOPTIONS ) );
lAVICOMPRESSOPTIONS.fccType           = streamtypeVIDEO;
lAVICOMPRESSOPTIONS.fccHandler        = mCOMPVARS.fccHandler;
lAVICOMPRESSOPTIONS.dwKeyFrameEvery   = 15;
lAVICOMPRESSOPTIONS.dwQuality         = mCOMPVARS.lQ;
lAVICOMPRESSOPTIONS.dwBytesPerSecond  = 0;
lAVICOMPRESSOPTIONS.dwFlags           = AVICOMPRESSF_KEYFRAMES; //|   AVICOMPRESSF_VALID;//|AVICOMPRESSF_DATARATE;
lAVICOMPRESSOPTIONS.lpFormat          = &lBIH;
lAVICOMPRESSOPTIONS.cbFormat          = sizeof( lBIH );
lAVICOMPRESSOPTIONS.lpParms           = 0;
lAVICOMPRESSOPTIONS.cbParms           = 0;
lAVICOMPRESSOPTIONS.dwInterleaveEvery = 0;

HRESULT lR = AVIMakeCompressedStream( &lAVICompressedStream, lAVIStream, &lAVICOMPRESSOPTIONS, NULL);
if( lR == AVIERR_NOCOMPRESSOR )
{
    mLastVideoError = "Cannot find a suitable compressor!";
    CleanUp(lAVIFile, lAVIStream ,lAVICompressedStream);
    return PvResult::Code::GENERIC_ERROR;
} 
else if( lR == AVIERR_MEMORY )
{
    mLastVideoError = "Not enough memory to start the compressor!";
    CleanUp(lAVIFile, lAVIStream ,lAVICompressedStream);
    return PvResult::Code::GENERIC_ERROR;
}
else if( lR == AVIERR_UNSUPPORTED )
{
    mLastVideoError = "Compression is not supported for this image buffer!";
    CleanUp(lAVIFile, lAVIStream ,lAVICompressedStream);
    return PvResult::Code::GENERIC_ERROR;
}

if( AVIStreamSetFormat( lAVICompressedStream, 0, &lBIH, sizeof( lBIH ) ) != 0 )
{
    mLastVideoError = "Cannot set stream format. It probably isn't supported by the Codec!";
    CleanUp(lAVIFile, lAVIStream ,lAVICompressedStream);
    return PvResult::Code::GENERIC_ERROR;
}

///////////////////

HRESULT hr;
//IBaseFilter mux = Null;
//IFileSinkFilter sink = null;

//    Guid x = new Guid( 0xe436eb88, 0x524f, 0x11ce, 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 );

//ICaptureGraphBuilder2::SetOutputFileName( 



//////////////////

// finishing up
mAVIFile             = lAVIFile;
mAVIStream           = lAVIStream;
mAVICompressedStream = lAVICompressedStream;

mSizeX     = aSizeX;
mSizeY     = aSizeY;
mBPP       = aBPP;
mImageSize = aSizeX * aSizeY * aBPP;

mLastSample = 0;

mCompressing = true;

return PvResult::Code::OK;
}

this compresses the stream

PvResult VideoCompressor::Compress(PvBuffer *aPvBuffer)
{
if (!mCompressing)
    return PvResult::Code::GENERIC_ERROR;

ASSERT( mTempBuffer != NULL );

long lSamplesWritten, lBytesWritten;

int numberOfLines = 0;

PvUInt8 * aBuffer = aPvBuffer->GetDataPointer();

for( unsigned short lLine = 0; lLine < mSizeY; lLine++ )
{
    numberOfLines = lLine;
    unsigned char *lCurLine    = (unsigned char *)aBuffer + (lLine             ) * mSizeX * mBPP;
    unsigned char *lCurLineInv = mTempBuffer              + (mSizeY - lLine - 1) * mSizeX * mBPP;
    ::memcpy( lCurLineInv, lCurLine, mSizeX * mBPP );
}

if( AVIStreamWrite( mAVICompressedStream, mLastSample, 1, mTempBuffer, mImageSize, 0, 
        &lSamplesWritten, &lBytesWritten ) != 0 ||
    lSamplesWritten < 1 ||
    lBytesWritten < 1 )
{
    mLastVideoError = "Cannot compress image!";
    return PvResult::Code::GENERIC_ERROR;

}

mLastSample ++;

return PvResult::Code::OK;
}

this is what it should look like: http://i13.photobucket.com/albums/a269/Masterg_/Untitled-16.png

this is what it saves as ( minus the guy): http://i13.photobucket.com/albums/a269/Masterg_/vlcsnap-2011-06-07-13h11m34s97.png


From MSDN we have:

Syntax

DWORD ICCompressQuery(
     hic,
     lpbiInput,
     lpbiOutput );

Parameters

hic : Handle to a compressor.

lpbiInput : Pointer to a BITMAPINFO structure containing the input format.

lpbiOutput : Pointer to a BITMAPINFO structure containing the output format. You can specify zero for this parameter to indicate any output format is acceptable.

I might be wrong, but it seems to me that you are trying to "force" this input format whitout taking into account the actual format you are passing as input. If your input format does not match the "forced" one, weird result must be expected. If your actual input format is not compatible with your compressor, you could try usign a ColorSpace converter filter before your compressor.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜