Я использую специализированную сетевую потоковую камеру и пытаюсь сохранить видеопоток в файле. на данный момент код сохраняет видео, но в непристойном формате 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