Попытка записать TBitmaps в файл AVI и получить только черные кадры (все нулевые данные)
У меня есть приложение Delphi, которое читает кадры JPEG из файла и записывает их в файл AVI. Каждый кадр JPEG декодируется в объект TBitmap, а затем записывается в выходной файл AVI с использованием служб, предоставляемых DLL-библиотекой Windows API для операций AVI (AVIFIL32.DLL), через модуль Delphi 6 VFW.PAS.
Проблема в том, что я получаю все черные рамки в выходном файле. Я знаю, что TBitmaps, которые я использую в качестве источника перед вызовом AVIStreamWrite(), содержит действительные данные, потому что я записал их на диск с помощью метода TBitmap.SaveToFile(), а исходное изображение выглядит нормально. Но я все равно получаю черные рамки. Что-то не так с тем, как я получаю биты из TBitmap, потому что указатель, возвращаемый GetDIBBits(), показывает все нулевые значения, если я проверяю область памяти, на которую он указывает.
Ниже мой код. Что я делаю неправильно? Кроме того, если я пытаюсь освободить первые pBits, возвращенные CreateDIBSection(), я получаю нарушение прав доступа. Это нормально или есть какой-то правильный способ освободить его?
// aryBytes contains a JPEG frame as a Byte array.
/*
Gets the next JPEG frame from a video input file and writes it to
the output AVI file (stream).
If the HRESULT from the desired operation is a failure code a
formatted Exception will be raised.
*/
procedure makeAviCallWithJPEGFrame(
fullVideoInFilename: string;
const aryBytes: TDynamicByteArray;
theAviMaker: TAviWriterWithCompression);
var
hr: HRESULT;
bmi: TBitmapInfo;
pImg: PJpegDecode;
jpegDecodeErr: TJpegDecodeError;
hbm: HBITMAP;
pBits, pBits2: Pointer;
theBitmap: Graphics.TBitmap;
iNumScanLinesCopied: integer;
numBytesInBitmap: Integer;
begin
if not Assigned(theAviMaker) then
raise Exception.Create('(makeAviCallWithJPEGFrame) The AVI maker is unassigned.');
pImg := nil;
pBits := nil;
pBits2 := nil;
hbm := 0;
theBitmap := nil;
try
jpegDecodeErr := JpegDecode(@aryBytes[0], Length(aryBytes), pImg);
if jpegDecodeErr <> JPEG_SUCCESS then
raise Exception.Create('(makeAviCallWithJPEGFrame) The bitmap failed to decode with error code: ' + IntToStr(Ord(jpegDecodeErr)));
// Get the DIB bits.
// theBitmap.SaveToFile('c:\temp\robomoviemaker.bmp');
if not Assigned(pImg) then
raise Exception.Create('(makeAviCallWithJPEGFrame) The bitmap decoded from the first JPEG frame in the video file is unassigned: ' + fullVideoInFilename);
pImg^.ToBMI(bmi);
theBitmap := pImg.ToBitmap;
// This always shows a valid image so I know the bitmap contains image data.
// theBitmap.SaveToFile('c:\temp\test-bitmap.bmp');
// Now create a DIB section.
hbm := CreateDIBSection(theBitmap.Handle, bmi, DIB_RGB_COLORS, pBits, 0, 0);
if hbm = ERROR_INVALID_PARAMETER then
raise Exception.Create('(makeAviCallWithJPEGFrame) One of the parameters passed to CreateDIBSection is invalid.');
if hbm = 0 then
raise Exception.Create('(makeAviCallWithJPEGFrame) The call to CreateDIBSection failed.');
// Height may be negative to indicate orientation so we
// take the absolute value of it.
// Allocate memory to receive the bits.
numBytesInBitmap :=
Abs(bmi.bmiHeader.biHeight)
* Abs(bmi.bmiHeader.biWidth)
* bmi.bmiHeader.biBitCount;
numBytesInBitmap := numBytesInBitmap div 8;
pBits2 := AllocMem(numBytesInBitmap);
if not Assigned(pBits2) then
hr := LongInt(AVIERR_MEMORY)
else
begin
// Get the DIB bits first.
iNumScanLinesCopied :=
// hr :=
GetDIBits(
theBitmap.Canvas.Handle,
theBitmap.Handle,
0,
Abs(bmi.bmiHeader.biHeight),
pBits2,
bmi, // @pVidInfoHdr.bmiHeader^,
DIB_RGB_COLORS);
if iNumScanLinesCopied <= 0 then
// Flag it as internal error.
hr := LongInt(AVIERR_INTERNAL)
else
// Add the bitmap to the output AVI file.
hr := theAviMaker.addVideoFrame(hbm);
end; // if not Assigned(pBits2) then
checkAviResult('TfrmMain_moviemaker_.cmdTestClick', hr, 'Error during add video frame call');
finally
if Assigned(pBits2) then
FreeMem(pBits2);
if Assigned(pImg) then
begin
pImg^.Free;
pImg := nil;
end;
if Assigned(theBitmap) then
FreeAndNil(theBitmap);
if hbm > 0 then
DeleteObject(hbm);
end; // try (2)
end;
// ---------------------------------------------------------------