ビデオとオーディオを取得し、VFW サービスを使用して AVI に書き込む Delphi 6 アプリを作成しようとしています。ビデオストリームを正常に動作させることができました。VLC または Windows Media Player で正常に再生されます。しかし、オーディオ ストリームを追加して出力 AVI を再生しようとすると、VLC プレーヤーは AVI ファイルが壊れていると文句を言います。ファイルを再生し、ビデオは問題ないように見えますが、音声はありません。ビデオストリームを書き込む前に、オーディオストリームを追加してから追加しようとしました。どちらも機能しませんでした。
また、オーディオ ストリームを追加しない場合は、Windows エクスプローラーで出力 AVI ファイルを右クリックすると、概要タブにストリーム内のビデオ データの適切な情報が表示されます。ストリームを追加した後、右クリックすると、AVI プロパティを読み取れなかったというステータス メッセージが表示されます。
更新:私は本当に基本的に間違ったことをしています。私がやっていることは、ファイルの最上位ヘッダーを吹き飛ばしていることです。オーディオ ストリームを作成しない場合、ファイルは問題なく、ファイルの先頭に通常のヘッダー情報が表示されます。 オーディオ ストリームを作成するための呼び出しを行った瞬間、作成した 2 番目のストリームでは、出力 AVI ファイルの最初のヘッダーは完全に空白 (ゼロ) です。 AVIStreamSetFormat() を呼び出したり、データを書き込んだりしなくても (たとえ書き込んだとしても)、その 2 回目の AVICreateStream() 呼び出しを行うだけで、16 進エディターでファイルを調べるときに、ファイルの先頭が消去されます。出力ファイルに「損傷」がある場合、この量を引き起こしている可能性があります。
私の質問は次のとおりです。
1) 私は何を間違っていますか? 2) オーディオとビデオがインターリーブされた AVI を作成する方法を示す良いサンプル、特に圧縮されたオーディオ ストリームを書き込む方法を示すサンプルを知っていますか?
ビデオストリームを完全に書き出した後、オーディオストリームを書き込むために使用しているコードを次に示します。ユニット レベル変数 FAvi には、TWaveFormatEx フィールド (wfx) が既に入力されています。内容を調べたところ、フィールドはすべて 8000 Khz のサンプル レート、1 チャンネル、1 チャンネルあたり 16 ビット、フォーマット タグ 1 (WAVE_FORMAT_PCM) の有効な値に設定されています。ブロックアライン、データレートなどもすべて適切に入力されています。
function TAviWriterWithCompression.addAudioFrame(dat: Pointer; numbytes: Cardinal): HRESULT;
var
bRetErr: boolean;
numsamps: LongInt;
ahdr: TAVISTREAMINFO;
hr: HRESULT;
lSampWritten, lBytesWritten: LONG;
begin
Result := S_OK;
bRetErr := true;
if Assigned(FAvi_) then
begin
if Assigned(dat) and (numbytes <> 0) then
begin
if not FAvi_.iserr then
begin
if FAvi_.wfx.nChannels <> 0 then
bRetErr := false
else
Result := LongInt(AVIERR_BADFORMAT);
end
else
Result := LongInt(AVIERR_ERROR);
end
else
Result := LongInt(AVIERR_BADPARAM);
end
else
Result := LongInt(AVIERR_BADHANDLE);
if bRetErr then
// =========================== EXIT POINT ==============
exit;
if FAvi_.wfx.wBitsPerSample <= 0 then
begin
Result := LongInt(AVIERR_BADFORMAT);
// =========================== EXIT POINT ==============
exit;
end; // if FAvi_.wfx.wBitsPerSample <= 0 then
numsamps := Trunc((numbytes * 8) / FAvi_.wfx.wBitsPerSample);
if ((numsamps * FAvi_.wfx.wBitsPerSample / 8) <> numbytes) then
begin
Result := LongInt(AVIERR_BADPARAM);
// =========================== EXIT POINT ==============
exit;
end; // if ((numsamps * FAvi_.wfx.wBitsPerSample/8) <> numbytes) then
if not Assigned(FAvi_.theAs) then
begin
ZeroMemory(@ahdr, sizeof(ahdr));
ahdr.fccType := streamtypeAUDIO;
ahdr.dwScale := FAvi_.wfx.nBlockAlign;
ahdr.dwRate := FAvi_.wfx.nSamplesPerSec*FAvi_.wfx.nBlockAlign;
ahdr.dwSampleSize := FAvi_.wfx.nBlockAlign;
ahdr.dwQuality := DWORD(-1);
hr := AVIFileCreateStream(FAvi_.pfile, FAvi_.theAs, ahdr);
if hr <> AVIERR_OK then
begin
Result := hr;
// Set the error flag.
FAvi_.iserr := true;
// =========================== EXIT POINT ==============
exit;
end; // if hr <> AVIERR_OK then
hr := AVIStreamSetFormat(FAvi_.theAs, 0, @FAvi_.wfx, sizeof(FAvi_.wfx));
if hr <> AVIERR_OK then
begin
Result := hr;
// Set the error flag.
FAvi_.iserr := true;
// =========================== EXIT POINT ==============
exit;
end; // if hr <> AVIERR_OK then
end; // if not Assigned(FAvi_.theAs) then
// now we can write the data
hr := AVIStreamWrite(FAvi_.theAs, FAvi_.nsamp, numsamps, dat, numbytes, AVIIF_KEYFRAME, @lSampWritten, @lBytesWritten);
if hr <> AVIERR_OK then
begin
Result := hr;
// Set the error flag in our utility object.
FAvi_.iserr := true;
// =========================== EXIT POINT ==============
exit;
end; // if hr <> AVIERR_OK then
Inc(FAvi_.nsamp, numsamps);
// Set the flag that tells it is no longer a virgin file and that
// attempting to set the compression is not allowed.
FIsVirginFile := false;
end;
終了時にオーディオ ストリームとビデオ ストリームの両方をクリーンアップするコードを次に示します。
destructor TAviWriterWithCompression.Destroy;
begin
// Code goes here.
if Assigned(FAvi_) then
begin
// Release the streams.
if Assigned(FAvi_.theAs) then
begin
AVIStreamRelease(FAvi_.theAs);
FAvi_.theAs := nil;
end;
if Assigned(FAvi_.thePsCompressed) then
begin
AVIStreamRelease(FAvi_.thePsCompressed);
// FAvi_.thePsCompressed := nil;
end;
if Assigned(FAvi_.thePs) then
begin
AVIStreamRelease(FAvi_.thePs);
// FAvi_.thePs := nil;
end;
if Assigned(FAvi_.pfile) then
begin
AVIFileRelease(FAvi_.pfile);
// FAvi_.pfile := nil;
end;
AVIFileExit();
// FreeAndNil(FAvi_);
end; // if Assigned(FAvi_) then
inherited Destroy;
end;
通知: @RemyLebau