2

ビデオとオーディオを取得し、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

4

1 に答える 1

1

次のページに「TAVIWriter」というコンポーネントがあります。

http://www.efg2.com/Lab/Library/Delphi/Graphics/FileFormatsAndConversion.htm

これには、コンポーネントの完全なソースコードと、その使用方法のデモが含まれています。

于 2012-05-06T13:36:56.617 に答える