Juhara.com
Language : English Indonesia

DirectShow Tips: Memisahkan Data Audio - Video dari File Movie (MPEG)

Zamrony P Juhara
12 December 2006 18:05:00
 (4398 views)
Tutorial tentang cara memisahkan data audio - video dari file MPEG menggunakan DirectShow

Pendahuluan.

Kali ini kita akan membahas cara memisahkan data audio - video file MPEG. Artikel ini menyambung artikel sebelumnya, DirectShow Tips: Memisahkan Data Audio - Video dari File Movie (AVI). Jika anda belum membacanya, saya sarankan untuk membacanya dulu, karena kita akan menggunakan framework audio - video extractor yang sudah dibangun di artikel tersebut.

Apa yang anda butuhkan?

Anda membutuhkan software berikut ini:

  • Otak
  • Kompiler Delphi.
  • DirectX 8 atau yang lebih baru.
  • Header konversi DirectX. Download versi DirectX 9 atau DirectX 8.1. Saya sendiri menggunakan DirectX 8.1.
  • Indeo 5.10 video codec dan MPEG Layer 3 audio codec. Indeo 5.10 dan MPEG Layer 3 sudah terinstall dalam XP. Untuk Windows versi lain download codec ini dari situs-situs penyedia codec.
  • Filter WAV Dest bukan filter bawaan DirectShow. Filter ini adalah filter contoh yang disertakan dalam DirectX SDK. Filter ini harus diinstall (jika anda belum menginstallnya). Bersama download telah disediakan binary filter ini (wavdestfilter.zip). Ikuti petunjuk yang terdapat dalam file readme.txt untuk informasi proses instalasi.

Desain MPEG Extractor

Untuk memisahkan data audio dan video dari file MPEG, kita membutuhkan konstruksi filter graph seperti yang ditunjukkan gambar dibawah ini:

Filter graph MPEG audio video extractor

Gbr.1 Filter graph MPEG audio video extractor.

Kita masih akan menyimpan data audio sebagai file MP3 dan data video sebagai file AVI. Untuk memperkecil ukuran file AVI, kita kompress menggunakan Indeo 5.10 codec.

Implementasi MPEG Extractor

Kita akan membuat kelas baru bernama TMPEGAudioVideoExtractor yang akan kita turunkan dari TBasicAudioVideoExtractor. Metode BuildFilterGraph kita override dan kita isi dengan kode untuk mengkonstruksi filter graph seperti yang ditunjukkan gambar Gbr.1 di atas.

     TMPEGAudioVideoExtractor=class(TBasicAudioVideoExtractor)
     public
       procedure BuildFilterGraph;override;
     end;

Bagian implementasinya sebagai berikut:

procedure TMPEGAudioVideoExtractor.BuildFilterGraph;
var pMP3FileSink,pAVIFileSink:IFileSinkFilter;
    pFileSource:IFileSourceFilter;

    afileReader,aMPEGSplitter,aWaveDest,
    aMPEGLayer3,
    aMP3FileWriter,
    aAVIFileWriter,
    aAVIMux,
    aMPEGAudioDecompressor,
    aMPEGVideoDecompressor,
    aIndeoCompressor:IBaseFilter;

    aSrcFilename,aDestFilename:widestring;

    hr:HResult;
begin
  if (FFilterGraph<>nil) then
  begin
    //add file reader filter
    afileReader:=AddFilterByCLSID(CLSID_AsyncReader,'File Reader');
    //add AVI splitter filter
    aMPEGSplitter:=AddFilterByCLSID(CLSID_MPEG1Splitter,'MPEG-1 Splitter');

    //Add MPEG Layer 3 Encoder
    aMPEGLayer3:=FindFilterByFriendlyName(CLSID_AudioCompressorCategory,
                                         'MPEG Layer-3');
    FFilterGraph.AddFilter(aMPEGLayer3,'MPEG Layer-3');

    //add Wave Dest filter
    awaveDest:=AddFilterByCLSID(CLSID_WaveDest,'Wave Dest');
    //add MP3 file writer filter
    aMP3FileWriter:=AddFilterByCLSID(CLSID_FileWriter,'MP3 File Writer');
    //add AVI file writer filter
    aAVIFileWriter:=AddFilterByCLSID(CLSID_FileWriter,'AVI File Writer');
    //add AVI Mux filter
    aAVIMux:=AddFilterByCLSID(CLSID_AVIDest,'AVI Mux');

    //add MPEG-1 Video Decompressor filter
    aMPEGVideoDecompressor:=AddFilterByCLSID(CLSID_CMPEGVideoCodec,'MPEG-1 Video Decompressor');
    //add MPEG-1 Audio Decompressor filter
    aMPEGAudioDecompressor:=AddFilterByCLSID(CLSID_CMPEGAudioCodec,'MPEG-1 Audio Decompressor');

    //Add Indeo video 5.10 Encoder
    aIndeoCompressor:=FindFilterByFriendlyName(CLSID_VideoCompressorCategory,
                                         'Indeo® video 5.10');
    FFilterGraph.AddFilter(aIndeoCompressor,'Indeo video 5.10');

    if (afileReader<>nil) and
       (aMPEGSplitter<>nil) and
       (aMPEGAudioDecompressor<>nil) and
       (aMPEGVideoDecompressor<>nil) and
       (aMPEGLayer3<>nil) and
       (aWaveDest<>nil) and
       (aMP3FileWriter<>nil) and
       (aAVIFileWriter<>nil) and
       (aAVIMux<>nil)  and
       (aIndeoCompressor<>nil) then
    begin
      //ambil instance IFileSourceFilter
      afileReader.QueryInterface(IID_IFileSourceFilter,pFileSource);
      if pFileSource<>nil then
      begin
        aSrcFilename:=FSrcFilename;
        pFileSource.Load(PWideChar(aSrcFilename),nil);
      end;

      //connect output pin file reader ke
      //input pin AVI splitter
      hr:=ConnectFilter(aFileReader,aMPEGSplitter);
      if hr<>S_OK then
        RaiseDirectShowException(hr,'Koneksi File Reader ke MPEG-1 Splitter gagal. ');

      //connect output MPEG splitter ke
      //input pin MPEG Audio Decompressor
      hr:=ConnectFilter(aMPEGSplitter,aMPEGAudioDecompressor,0,0);
      if hr<>S_OK then
        RaiseDirectShowException(hr,'Koneksi MPEG Splitter ke MPEG Audio Decompressor. ');

      //connect output MPEG splitter ke
      //input pin MPEG Video Decompressor
      hr:=ConnectFilter(aMPEGSplitter,aMPEGVideoDecompressor,1,0);
      if hr<>S_OK then
        RaiseDirectShowException(hr,'Koneksi MPEG Splitter ke MPEG Video Decompressor. ');

      {--------begin video extractor----------}

      //connect output AVI Decompressor ke
      //input pin AVI Compressor
      hr:=ConnectFilter(aMPEGVideoDecompressor,aIndeoCompressor);
      if hr<>S_OK then
        RaiseDirectShowException(hr,'Koneksi MPEG Video Decompressor ke Indeo compressor gagal. ');

      //connect output Indeo Compressor ke
      //input pin AVI AVI Mux
      hr:=ConnectFilter(aIndeoCompressor,aAVIMux);
      if hr<>S_OK then
        RaiseDirectShowException(hr,'Koneksi Indeo compressor ke AVI Mux gagal. ');

      //ambil instance IFileSinkFilter
      aAVIFileWriter.QueryInterface(IID_IFileSinkFilter,pAVIFileSink);
      if pAVIFileSink<>nil then
      begin
        aDestFilename:=FVideoFilename;
        pAVIFileSink.SetFileName(PWideChar(aDestFilename),nil);
      end;

      //connect output AVI Mux ke
      //input pin AVI File Writer
      hr:=ConnectFilter(aAVIMux,aAVIFileWriter);
      if hr<>S_OK then
        RaiseDirectShowException(hr,'Koneksi AVI Mux ke AVI FileWriter gagal. ');

      {--------end video extractor----------}
      {--------begin audio extractor----------}

      //connect output MPEG Audio Decompressor ke
      //input pin MPEG Layer 3
      hr:=ConnectFilter(aMPEGAudioDecompressor,aMPEGLayer3);
      if hr<>S_OK then
        RaiseDirectShowException(hr,'Koneksi MPEG Audio Decompressor ke MPEG Layer 3. ');


      //connect output MPEG Layer 3 ke
      //input pin Wave Dest
      hr:=ConnectFilter(aMPEGLayer3,aWaveDest);
      if hr<>S_OK then
        RaiseDirectShowException(hr,'Koneksi MPEG Layer 3 ke Wave Dest gagal. ');

      //ambil instance IFileSinkFilter
      aMP3fileWriter.QueryInterface(IID_IFileSinkFilter,pMP3FileSink);
      if pMP3FileSink<>nil then
      begin
        aDestFilename:=FAudioFilename;
        pMP3FileSink.SetFileName(PWideChar(aDestFilename),nil);
      end;

      //connect output wave Dest ke
      //input pin FileWriter
      hr:=ConnectFilter(aWaveDest,aMP3FileWriter);
      if hr<>S_OK then
        RaiseDirectShowException(hr,'Koneksi Wave Dest ke File Writer gagal. ');

      {--------end audio extractor----------}
    end;
  end;
end;

Implementasi Aplikasi Utama.

Aplikasi utama hampir sama dengan aplikasi yang kita buat sebelumnya di artikel DirectShow Tips: Memisahkan Data Audio - Video dari File Movie (AVI). Berikut ini adalah screenshot desain UI.

User interface MPEG audio - video splitter

Gbr.2 User interface MPEG audio - video extractor.

Kita akan menambahkan item baru pada property Filter milik OpenDialog1. Di sini, kita tambahkan entry untuk MPEG file yakni MPEG files (*.mpg) | *.mpg.

Kita juga akan memodifikasi isi kode program utama. Kita menambahkan dua variabel baru dalam TfrmMain yakni AVIExtractor bertipe TAVIAudioVideoExtractor dan MPEGExtractor bertipe TMPEGAudioVideoExctractor. Variabel Extractor yang semula bertipe TAVIAudioVideoExtractor kita ubah menjadi TBasicAudioVideoExtractor.

Pada saat OpenDialog1 dieksekusi, kita cek apakah file yang sedang dibaca adalah file AVI atau MPEG (dengan mengecek properti FilterIndex OpenDialog1). Jika file adalah file AVI, Extractor kita set sebagai AVIExtractor, jika MPEG, kita set sebagai MPEGExtractor.

Berikut ini adalah implementasi lengkap aplikasi utama.

unit ufrmMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls,DirectShow,uDirectShowPlayer, ComCtrls, ExtCtrls;

type
  TfrmMain = class(TForm)
    grpbxSource: TGroupBox;
    lblFilename: TLabel;
    edSourceFilename: TEdit;
    grpbxDestination: TGroupBox;
    edAudioFile: TEdit;
    edVideoFile: TEdit;
    lblAudioFile: TLabel;
    lblVideoFile: TLabel;
    btnBrowse: TButton;
    btnBrowseAudio: TButton;
    btnBrowseVideo: TButton;
    btnExtract: TButton;
    btnClose: TButton;
    OpenDialog1: TOpenDialog;
    SaveVideoDialog: TSaveDialog;
    SaveAudioDialog: TSaveDialog;
    ProgressBar1: TProgressBar;
    progressTime: TTimer;
    procedure btnExtractClick(Sender: TObject);
    procedure btnBrowseClick(Sender: TObject);
    procedure btnBrowseAudioClick(Sender: TObject);
    procedure btnBrowseVideoClick(Sender: TObject);
    procedure btnCloseClick(Sender: TObject);
    procedure progressTimeTimer(Sender: TObject);
  private
    AVIExtractor:TAVIAudioVideoExtractor;
    MPEGExtractor:TMPEGAudioVideoExtractor;
    extractor:TBasicAudioVideoExtractor;
    { Private declarations }
    procedure WM_MMNotify(var msg: TMessage);message WM_MMNOTIFY;
  public
    constructor Create(AOwner:TComponent);override;
    destructor Destroy;override;
    { Public declarations }
  end;

var
  frmMain: TfrmMain;

implementation


{$R *.dfm}

{ TForm1 }

constructor TfrmMain.Create(AOwner: TComponent);
begin
  inherited;
  AVIExtractor:=TAVIAudioVideoExtractor.Create;
  AVIExtractor.Handle:=Handle;

  MPEGExtractor:=TMPEGAudioVideoExtractor.Create;
  MPEGExtractor.Handle:=Handle;

  extractor:=AVIExtractor;
end;

destructor TfrmMain.Destroy;
begin
  AVIExtractor.Free;
  MPEGExtractor.Free;
  inherited;
end;

procedure TfrmMain.WM_MMNotify(var msg: TMessage);
var aplayer:TBasicPlayer;
    evCode,param1,param2:integer;
begin
  aplayer:=TBasicPlayer(msg.LParam);
  aplayer.EventObj.GetEvent(evCode,param1,param2,0);
  case evCode of
    EC_COMPLETE:begin
                  aplayer.RemoveAllFilters;
                  btnExtract.Enabled:=true;
                  progressbar1.Position:=0;
                  progressTime.Enabled:=false;
                end;
  end;
  aplayer.EventObj.FreeEventParams(evCode,param1,param2);
end;

procedure TfrmMain.btnExtractClick(Sender: TObject);
begin
  btnExtract.Enabled:=false;

  Extractor.SrcFilename:=edSourceFilename.Text;
  Extractor.AudioFilename:=edAudioFile.Text;
  Extractor.VideoFilename:=edVideoFile.Text;

  extractor.Extract;

  progressbar1.Max:=extractor.Duration;
  progressbar1.Min:=0;
  progressbar1.Position:=0;
  progressTime.Enabled:=true;
end;

procedure TfrmMain.btnBrowseClick(Sender: TObject);
begin
  if OpenDialog1.Execute then
  begin
    edSourceFilename.Text:=OpenDialog1.FileName;
    case OpenDialog1.FilterIndex of
      1:Extractor:=AVIExtractor;
      2:Extractor:=MPEGExtractor;
    end;
  end;
end;

procedure TfrmMain.btnBrowseAudioClick(Sender: TObject);
begin
  if SaveAudioDialog.Execute then
    edAudioFile.Text:=SaveAudioDialog.FileName;
end;

procedure TfrmMain.btnBrowseVideoClick(Sender: TObject);
begin
  if SaveVideoDialog.Execute then
    edVideoFile.Text:=SaveVideoDialog.FileName;
end;

procedure TfrmMain.btnCloseClick(Sender: TObject);
begin
  Close;
end;

procedure TfrmMain.progressTimeTimer(Sender: TObject);
begin
  progressbar1.Position:=extractor.Position.Current;
end;

end.

Source code bisa di download di sini.

Ringkasan

Di artikel ini, kita telah mendiskusikan bagaimana memisahkan data audio - video file MPEG kedalam file audio MP3 dan file video AVI menggunakan filter-filter yang disediakan oleh DirectShow. Telah ditunjukkan pula cara mengintegrasikan framework pemisah audio video kedalam kode aplikasi yang sudah ada.

Artikel Terkait

Anda suka artikel ini? Bantu website ini berkembang dengan menyumbang. Berapapun jumlahnya akan sangat dihargai.

Atau Anda dapat membantu dengan membuat bookmark. Delicious Bookmark this on Delicious