我正在尝试编写一个带有视频和音频的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
答案 0 :(得分:1)
下页有一个名为“TAVIWriter”的组件:
http://www.efg2.com/Lab/Library/Delphi/Graphics/FileFormatsAndConversion.htm
包括组件的完整源代码以及如何使用它的演示。