我有一个用DSACK组件库编写的Delphi6 DirectShow过滤器(推送源视频过滤器)。在FillBuffer()调用中将修改后的位图输出到目标媒体样本之前,一些简单的代码会修改位图,这确实让我遇到了一个棘手的问题。代码如下所示。
正如您所看到的,它只是两个简单的循环,使用Byte指针遍历24位位图中的RGB值。此代码在非DirectShow测试应用程序中运行良好。但是,在我的DirectShow过滤器中,无论使用什么值,我都看不到渲染位图有任何更改。你甚至可以看到一条测试线,我只是简单地将每个字节设置为0。我仍然看到了未修改的图像。为了确保我没有幻影或损坏的位图对象,我添加了一行在位图上打印一个简单的句子。句子确实显示在渲染的位图上。
更令人困惑的是,当运行此代码时,我每秒会收到数千个软页面错误,正如任务管理器所报告的那样。如果我禁用此代码,软页面错误就会消失。是什么原因导致代码执行此操作?我追踪了整个循环,确实看到Byte值在每行之后都会改变值,但图像仍然不受影响。
最后,如果有人知道在不使用Scanline的情况下快速访问像素的方法,我想知道。我通过TBitmap进行追踪。扫描线,它打电话给FreeImage。如果可以的话,我想尽量减少内存分配。我不能使用GR32.TBitmap32,因为我使用的是Synapse的快速jpeg解码器,它不适用于TBitmap 32对象。
UPDATE:问题是在访问ScanLine属性之前,我没有将位图的PixelFormat属性设置为pf24Bit。查看此线程了解更多信息:像素修改代码在主应用程序中运行速度很快,在Delphi 6 DirectShow过滤器中运行速度真的很慢,还有其他问题
procedure brightnessTurboBoost(var clip: TBitmap; rangeExpansionPowerOf2: integer; shiftValue: Byte);
var
p0: PByte;
x,y: Integer;
begin
if (rangeExpansionPowerOf2 = 0) and (shiftValue = 0) then
exit; // These parameter settings will not change the pixel values.
for y := 0 to clip.Height-1 do
begin
p0 := clip.scanline[y];
// Can't just do the whole buffer as a big block of bytes since the
// individual scan lines may be padded for CPU alignment.
for x := 0 to (clip.Width - 1) * 3 do
begin
if rangeExpansionPowerOf2 >= 1 then
p0^ := IntToByte((p0^ shl rangeExpansionPowerOf2) + shiftValue)
else
p0^ := IntToByte(p0^ + shiftValue);
// Test wiping the image (didn't work, still see image).
// p0^ := 0;
Inc(p0);
end;
end;
clip.Canvas.TextOut(10, 10, 'HELLO THERE IS THERE ANYONE THERE?');
end;
那么,究竟是如何将IMediaSample
缓冲区数据复制到TBitmap
中,然后再向后复制呢?最有可能的事情,实际上比其他任何事情都更有可能,是您正在更改副本,并且永远不要将更改转回您向下游交付的缓冲区。此外,由于处理的副作用(例如,在来回转换图像数据时,内部内存分配过多),途中还会遇到页面错误。