2012-05-06 43 views
2

我正在嘗試編寫一個Delphi 6應用程序,該應用程序需要使用VFW服務將視頻和音頻寫入AVI。我設法讓視頻流正常工作。它在VLC或Windows Media Player中運行良好。但是當我添加一個音頻流並嘗試播放輸出AVI時,VLC播放器抱怨AVI文件被破壞。它會播放文件和視頻看起來不錯,但沒有音頻。我試圖在寫入視頻流之前添加音頻流,然後再添加音頻流。都沒有工作。在Delphi 6應用程序中無法使用視頻和音頻(VFW)創建AVI文件

此外,如果我不添加音頻流,我可以在Windows資源管理器中右鍵單擊輸出AVI文件,並在摘要選項卡中查看流中視頻數據的正確信息。添加流右鍵單擊後,顯示狀態消息說AVI屬性無法讀取。

UPDATE:我正在做一些真正基本錯誤的事情。事實證明,我正在做的是吹的文件的頂級標題。如果我沒有創建音頻流,那麼文件就沒有問題,我會在文件的開頭看到通常的標題信息。 我打電話創建音頻流,即創建的第二個流,輸出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

你在問一個例子;那麼['VirtualDub'](http://sourceforge.net/projects/virtualdub/files/)應該能夠向您展示如何處理音頻流並正確設置所有結構(請參閱* AudioSource .cpp *,* InputFileMP3.cpp *和* InputFileWAV.cpp *)。幾年前,當我使用它時,我感到很滿意。 – TLama

+0

是的,我一直在使用它。這就是我發現創建音頻流的方法是用Hex File Editor和Riff Chunk協助來改變AVI文件頭。 –

回答

相關問題