我使用FastJpeg库(jpegdec.pas)将JPEG帧解码为Graphics.TBitmap对象。解码工作正常,我使用TBitmap.SaveToFile()方法将位图打印到文件进行目视检查,看起来很棒。然后我使用TBitmap句柄调用GetObject()来获取TDibSection对象。返回的TDibSection对象确实显示了顶级字段(bmWidth,bmHeight等)的正确值,尽管bmBit是NIL,我发现看起来令人惊讶,因为SaveToFile()调用确实正确地将图像写入磁盘。我遇到的问题是TBitmapHeaderInfo字段(dsBmih)全为零。此外,如果重要的话,dsBitFields,dshSection和dsOffset字段也都是零。就像它填充了主要字段,之后的所有内容都被遗漏了。这是返回的TDibSection对象的转储:
dsBm: (0, 320, 240, 1280, 1, 32, nil)
dsBmih: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
dsBitfields: (0, 0, 0)
dshSection: 0
dsOffset: 0
下面的代码基本上显示了我在做什么。为什么我要回到一个空白的TBitmapHeaderInfo字段?这导致我对AVI dll的调用出现问题,所以我需要解决这个问题。
这是代码段
var
theBitmap: Graphics.TBitmap;
aryBytes: TDynamicByteArray;
dibs: TDibSection;
begin
aryBytes := nil;
// The following function loads JPEG frame #0 from a collection of JPEG frames.
aryBytes := LoadJpegFrame(0);
// Decode the first JPEG frame so we can pass it to the compressor
// selector call.
theBitmap := JpegDecode(@aryBytes[0], Length(aryBytes));
if GetObject(theBitmap.Handle, sizeof(dibs), @dibs) = 0 then
raise Exception.Create('Get Object failed getting the TDibSection information for the bitmap.');
// ... The TBitmapHeaderInfo field in dibs is empty as described in the post.
end;
更新:在回复TLama的评论时,我已经更新了代码,如下所示。它现在有效。我有一些问题:
1)代码可以简化吗?它显然比上面的原始代码复杂得多,也许我执行的步骤太多了。
2)我是否释放所有内存并释放所有GDI句柄&我需要的物品?我不希望任何内存泄漏。
以下是更新后的代码:
var
hr: HRESULT;
bmi: TBitmapInfo;
pImg: PJpegDecode;
jpegDecodeErr: TJpegDecodeError;
hbm: HBITMAP;
pBits: Pointer;
begin
hr := 0; pImg := nil; hbm := 0; pBits := nil;
try
jpegDecodeErr := JpegDecode(@aryBytes[0], Length(aryBytes), pImg);
if jpegDecodeErr <> JPEG_SUCCESS then
raise Exception.Create('(TfrmMain_moviemaker_.cmdTestClick) The bitmap failed to decode with error code: ' + IntToStr(Ord(jpegDecodeErr)));
if not Assigned(pImg) then
raise Exception.Create('(TfrmMain_moviemaker_.cmdTestClick) The bitmap decoded from the first JPEG frame in the video file is unassigned: ' + fullVideoInFilename);
pImg^.ToBMI(bmi);
theBitmap := pImg.ToBitmap;
// 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('(TfrmMain_moviemaker_.cmdTestClick) One of the parameters passed to CreateDIBSection is invalid.');
if hbm = 0 then
raise Exception.Create('(TfrmMain_moviemaker_.cmdTestClick) The call to CreateDIBSection failed.');
// Select the compressor. This call USED to fail before TLama's
// suggestion. Now it works.
hr := aviMaker.compression(hbm, nil, true, Self.Handle);
if hr <> S_OK then
raise Exception.Create('(TfrmMain_moviemaker_.cmdTestClick) Error during compressor selector call: ' + FormatAviMessage(hr));
finally
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 :(得分:3)
由于您只需要一个句柄来处理从JPEG文件解码的第一帧的DIB部分,我认为应该足够使用CreateDIBSection
并复制到函数调用分配的内存块中TJpegDecode.pRGB
指向的内容,它应该是DIB部分值。
procedure ProbeGetObject(ACanvas: TCanvas; AGDIObject: HGDIOBJ);
var
Width, Height: Integer;
DIBSection: TDIBSection;
BitmapInfo: TBitmapInfo;
begin
if GetObject(AGDIObject, SizeOf(DIBSection), @DIBSection) <> 0 then
begin
FillChar(BitmapInfo, SizeOf(BitmapInfo), 0);
BitmapInfo.bmiHeader := DIBSection.dsBmih;
// if you comment the following line, the image will be rendered flipped
BitmapInfo.bmiHeader.biHeight := - BitmapInfo.bmiHeader.biHeight;
Width := DIBSection.dsBm.bmWidth;
Height := Abs(DIBSection.dsBm.bmHeight);
StretchDIBits(ACanvas.Handle, 0, 0, Width, Height, 0, 0, Width, Height,
DIBSection.dsBm.bmBits, BitmapInfo, DIB_RGB_COLORS, SRCCOPY);
end;
end;
procedure InitializeCompressor(Buffer: Pointer; BufferLen: Integer);
var
ScreenDC: HDC;
DIBHandle: HBITMAP;
DIBValues: Pointer;
BufferSize: DWORD;
BufferHandle: THandle;
BufferPointer: Pointer;
JPEGImage: PJpegDecode;
BitmapInfo: TBitmapInfo;
begin
if JpegDecode(Buffer, BufferLen, JPEGImage) = JPEG_SUCCESS then
try
JPEGImage^.ToBMI(BitmapInfo);
BufferSize := Abs(BitmapInfo.bmiHeader.biWidth *
BitmapInfo.bmiHeader.biHeight * 4);
BufferHandle := CreateFileMapping(INVALID_HANDLE_VALUE, nil,
PAGE_READWRITE, 0, BufferSize, nil);
if BufferHandle <> 0 then
try
BufferPointer := MapViewOfFile(BufferHandle, FILE_MAP_WRITE, 0, 0, 0);
if Assigned(BufferPointer) then
begin
CopyMemory(BufferPointer, JPEGImage^.pRGB, BufferSize);
ScreenDC := GetDC(0);
if ScreenDC <> 0 then
try
DIBHandle := CreateDIBSection(ScreenDC, BitmapInfo, DIB_RGB_COLORS,
DIBValues, BufferHandle, 0);
if (DIBHandle <> 0) and Assigned(DIBValues) then
try
ProbeGetObject(Form1.Canvas, DIBHandle);
// here try to initialize the compressor, the DIB section should
// contain values obtained from the JPEG decoder; in the DIBHandle
// variable is the handle to the DIB section
finally
DeleteObject(DIBHandle);
end;
finally
ReleaseDC(0, ScreenDC);
end;
end;
finally
CloseHandle(BufferHandle);
end;
finally
JPEGImage^.Free;
end;
end;