Попытка записать 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;

// ---------------------------------------------------------------

0 ответов

Другие вопросы по тегам