juhara.com
Language : English Indonesia

DirectShow Tips: Splitting Audio - Video Data from Movie File (MPEG)

Zamrony P Juhara
12 December 2006 18:05:00
 (3845 views)
Tutorial about how to split audio - video data from MPEG file with DirectShow

Introduction.

This time, we will talk about spliting audio - video data from MPEG file. This article continues previous article, DirectShow Tips: Splitting Audio - Video Data from Movie File (AVI). If you haven't read it yet, I suggest you to read it first because we will use audio - video extractor framework we have built in that article.

What do you need?

You need following softwares:

  • Brain
  • Delphi compiler.
  • DirectX 8 or newer.
  • DirectX header conversion. Download DirectX 9 or DirectX 8.1. I use DirectX 8.1.
  • Indeo 5.10 video codec and MPEG Layer 3 audio codec. Indeo 5.10 and MPEG Layer 3 is already installed in XP. For other Windows version, download these codecs from codec provider websites.
  • WAV Dest filter is not DirectShoiw built-in filter. This filter is sample filter included in DirectX SDK. This filter must be installed (if you haven't install it). Filter binary is included in download (wavdestfilter.zip). Follow the instructions in readme.txt for installation information.

Design Of MPEG Extractor

To split audio and video data from MPEG file, we need filter graph construction as shown in image below:

Filter graph of MPEG audio video extractor

Fig.1 Filter graph of MPEG audio video extractor.

We will store audio data as MP3 file and video data as AVI file. To reduce size of AVI, we compress it with Indeo 5.10 codec.

MPEG Extractor Implementation

We will create new class called TMPEGAudioVideoExtractor that will be derived from TBasicAudioVideoExtractor. BuildFilterGraph methode is overriden and flesh out with code to construct filter graph as shown in image Fig.1 above.

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

Implementation part is as follow:

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;

Main application Implementation.

Main application is very similar with our previous application in DirectShow Tips: Splitting Audio - Video data from Movie File (AVI). Following image is screenshot of UI design.

User interface of MPEG audio - video splitter

Fig.2 User interface of MPEG audio - video extractor.

We are going to add new item in Filter property of OpenDialog1. Here we add entry for MPEG file, i.e, MPEG files (*.mpg) | *.mpg.

We also modify code of main application. We add two new variables in TfrmMain, i.e, AVIExtractor of type of TAVIAudioVideoExtractor and MPEGExtractor of type of TMPEGAudioVideoExctractor. We change Extractor type from type of TAVIAudioVideoExtractor to TBasicAudioVideoExtractor.

When OpenDialog1 is executed, we check whether file currenly open is AVI or MPEG (by checking FilterIndex property of OpenDialog1). If file is AVI, We set Extractor as AVIExtractor, if MPEG, we set it as MPEGExtractor.

Next is full implementation of main application.

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 is available to download here.

Conclusion

In this article, we have discussed how to split audio - video data from MPEG file into MP3 file and AVI file using filters provided by DirectShow. We have shown how to integrate framework audio video splitter into existing application code.

Related Article

Do you like this article? Help this website improve by donating. Any amounts is appreciated.

Or you can help by bookmarking this page. Delicious Bookmark this on Delicious