在Delphi 6应用程序中无法使用视频和音频(VFW)创建AVI文件

时间:2012-05-06 01:11:01

标签: delphi wav avi vfw

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

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

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

我的问题是:

1)我做错了什么? 2)你知道一个很好的样本,它展示了如何创建一个带有音频和视频交错的AVI,尤其是一个展示如何编写压缩音频流的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

1 个答案:

答案 0 :(得分:1)

下页有一个名为“TAVIWriter”的组件:

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

包括组件的完整源代码以及如何使用它的演示。