2

我正在尝试编写一个 Delphi 6 应用程序,该应用程序获取视频和音频并使用 VFW 服务将其写入 AVI。我设法让视频流正常工作。它在 VLC 或 Windows Media Player 中播放良好。但是当我添加一个音频流并尝试播放输出 AVI 时,VLC 播放器抱怨 AVI 文件被破坏。它将播放文件,视频看起来不错,但没有音频。我尝试在写入视频流之前添加音频流,然后在它之后添加。都没有奏效。

此外,如果我不添加音频流,我可以在 Windows 资源管理器中右键单击输出 AVI 文件,在摘要选项卡中,我可以看到流中视频数据的正确信息。添加流后,右键单击会显示一条状态消息,说明无法读取 AVI 属性。

更新:我做的事情基本上是错误的。事实证明,我正在做的事情是破坏文件的顶级标题。如果我不创建音频流,则文件很好,我会在文件的开头看到通常的标题信息。 在我调用创建音频流的那一刻,我创建的第二个流,输出 AVI 文件开头的标题是完全空白的(零)。 即使我没有调用 AVIStreamSetFormat() 或写入任何数据(即使我这样做了),在使用十六进制编辑器检查文件时,只需进行第二次 AVICreateStream() 调用就会擦除文件的开头。如果对输出文件“损坏”,我能做什么会导致这个数量。

我的问题是:

1)我做错了什么?2) 你知道一个很好的示例,它展示了如何创建一个音频和视频交错的 AVI,尤其是一个展示如何编写压缩音频流的示例?

在我完全写出视频流之后,这是我用来编写音频流的代码。单元级变量 FAvi 已经填充了 TWaveFormatEx 字段 (wfx)。我检查了内容,所有字段都设置为 8000 Khz 采样率、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 回答