ビットマップを DirectShow DLL にリアルタイムで 25 フレーム/秒で送信する Delphi 6 アプリケーションがあります。DirectShow DLL も私のコードであり、DSPACK DirectShow コンポーネント スイートを使用して Delphi 6 で記述されています。特定のフラグが設定されている場合、ビットマップ内の各ピクセルを通過して画像の明るさとコントラストを変更する単純なコード ブロックがあります。それ以外の場合、ビットマップは変更されずに DirectShow DLL にプッシュされます (プッシュ ソース ビデオ フィルタ)。コードはメイン アプリケーションにありましたが、それを DirectShow DLL に移動しました。それがメインアプリケーションにあったとき、それはうまくいきました。期待どおりにビットマップの変更を確認できました。ただし、コードが DirectShow DLL に存在するため、次の問題があります。
以下のコード ブロックがアクティブな場合、DirectShow DLL は非常に遅くなります。私はクアッドコア i5 を持っていますが、とても遅いです。また、CPU 消費量に大きなスパイクが見られます。対照的に、メイン アプリケーションで実行されているまったく同じコードは、古いシングル コア P4 で正常に実行されました。その古いマシンでは CPU にかなりの負荷がかかりましたが、ビデオはスムーズで問題はありませんでした。画像のサイズはわずか 352 x 288 ピクセルです。
表示されているビットマップに期待される変更が見られません。DirectShow DLL のコードをトレースすると、各ピクセルの数値がコードによって適切に変更されていることがわかりますが、グラフ編集 ActiveMovie ウィンドウに表示される画像はまったく変更されていないように見えます。
コードを非アクティブ化すると (リアルタイムで実行できます)、ActiveMovie ウィンドウにはガラスのように滑らかなビデオが表示され、CPU にほとんど触れずに完全にレンダリングされます。コードを再アクティブ化すると、ビデオが途切れ途切れになり、おそらく最初のフレームが表示されるまでに長い遅延があり、1 秒に 1 ~ 2 フレームしか表示されず、CPU がスパイクします。完全ではありませんが、予想をはるかに超えています。
範囲チェック、オーバーフロー チェックなどを含むすべてを使用して DirectShow DLL をコンパイルしようとしましたが、実行時に警告やエラーは発生しませんでした。次に、最速でコンパイルしようとしましたが、上記とまったく同じ問題が発生しました。何かが本当に間違っていて、何が原因かわかりません。ビットマップを変更する前にキャンバスをロックし、完了後にロックを解除することに注意してください。上記の「すべてオン」のコンパイル実行がなければ、FPU 例外が発生し、すべてのピクセル計算で静かに飲み込まれたように感じたと思いますが、前述したように、エラーや例外は発生していません。
更新:Roman Rのコメントの1つに埋め込まれているソリューションがはっきりと見えるように、これをここに入れています。ScanLine プロパティにアクセスする前にPixelFormatプロパティをpf24Bitに設定していなかったという問題。ローマンが示唆したように、これを行わないと、TBitmap コードでビットマップの一時コピーを作成する必要があります。問題の下にコード行を追加するとすぐに、変更が表示されないこととソフトページフォールトの両方がなくなりました。影響を受ける唯一のオブジェクトは、ビットマップの一時コピーへのポインターが含まれているため (仮定)、ScanLine プロパティにアクセスするために使用するポインターであるため、これは潜行的な問題です。これが、ビットマップの元のコピーで機能したため、後続の TextOut() 呼び出しがまだ機能していた理由であるに違いありません。
clip.PixelFormat := pf24bit; // The missing code line that fixes the problem.
私が参照しているコードブロックは次のとおりです。
function IntToByte(i: Integer): Byte;
begin
if i > 255 then
Result := 255
else if i < 0 then
Result := 0
else
Result := i;
end;
// ---------------------------------------------------------------
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);
Inc(p0);
end;
end;
end;