Я неправильно настраиваю информацию avi для сохранения файла в C ++ vfw? - PullRequest
0 голосов
/ 08 июня 2011

Я использую специализированную сетевую потоковую камеру и пытаюсь сохранить видеопоток в файле. на данный момент код сохраняет видео, но в непристойном формате RGB, который портит цвет, а затем сохраняет его, используя VFW. Я делаю это правильно, и это должно создать avi с несоответствующими цветами, или я настроил что-то не так в областях BITMAPINFOHEADER?

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");
}

}

Я установил видеопоток и выбрал несжатый AVI для своего кодека. Я нажимаю кнопку «Сохранить», которая затем вызывает функцию ниже

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;
}

функция получает информацию о размере видео, а затем вызывает фактическое сжатие для запуска

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 = 1280;
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;
}

это сжимает поток

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;
}

вот как это должно выглядеть: http://i13.photobucket.com/albums/a269/Masterg_/Untitled-16.png

это то, что он сохраняет (минус парень): http://i13.photobucket.com/albums/a269/Masterg_/vlcsnap-2011-06-07-13h11m34s97.png

1 Ответ

0 голосов
/ 12 июня 2011

С MSDN у нас есть:

Синтаксис

DWORD ICCompressQuery(
     hic,
     lpbiInput,
     lpbiOutput );

Параметры

hic: дескриптор ккомпрессор

lpbiInput: указатель на структуру BITMAPINFO, содержащую формат ввода .

lpbiOutput: указатель на структуру BITMAPINFO, содержащую формат вывода.Вы можете указать ноль для этого параметра, чтобы указать, что любой выходной формат приемлемфактический формат, который вы передаете в качестве ввода.Если ваш входной формат не соответствует «принудительному», следует ожидать странного результата.Если ваш текущий формат ввода не совместим с вашим компрессором, вы можете попробовать использовать преобразователь ColorSpace перед вашим компрессором.

...