티스토리 뷰

동영상이나 음원을 다른 코덱으로 변환하는 것을 트렌스 코딩이라고 한다. 이런 것을 해주는 대표적인 프로그램이 FFMPEG이다.
FFMPEG은 www.ffmpeg.org 에서 제작하고 배포하는 프리웨어이다. 이를 이용하면 간단하게 WMA, MP3, OGG를 비롯하여 MPEG 영상의 코덱을 변경할 수 있다. ffmpeg을 제대로 실행하기 위해서는 pthreadGC2.dll 파일이 필요하다.

윈도우용으로 컴파일된 ffmpeg.exe 파일을 이용하면 간단하게 WMA 파일을 MP3로 변환할 수 있다.

ffmpeg.exe -i sample.wma -ab 128k -y -f mp3 sample.mp3

-i 옵션은 소스 음원이다. 즉, wma 파일을 지정하면 된다.
-ab 옵션은 bitrate를 정하는 것으로 128k가 CD음질로 알고 있다.
-y 옵션은 같은 이름의 파일이 있으면 덮어쓰게 되는 옵션이다.
-f 옵션은 변환하고자 하는 포맷을 의미하며 mp3 라고 지정하였으니 mp3로 변환될 것이다.
그리고 마지막으로 결과 파일의 이름을 지정해주면 된다.

이를 이용하면 간단하게 변환을 할 수 있다.

블로깅을 하다보니 다음과 같은 컨텍스트 메뉴에 추가하여 변환하는 방법을 사용하는 예가 있어서 소개한다.
http://it.kimgisa.net/39

이제 델파이를 이용하여 ffmpeg.exe를 감추고 그 결과를 얻어내서 그럴듯한 변환기를 만들 수 있는 틀을 공개하겠다.
물론 여러가지 여유가 없는 관계로 최소한의 기능만 구현했으니 시간이 허락되는 사람이 있다면 이를 고쳐서 멋진 변환기를 만드는데 도전해 보길 권한다. 단, 광고같은거 나오게는 하지말자.

프로그램의 미완성 형태는 다음과 같다.



열기를 눌러서 파일을 선택하면 자동으로 변환한다. 변환되는 진행 상황이 프로그레스바로 나타나게 되는데
여기서 나타나는 값은 ffmpeg 프로그램의 콘솔에 출력되는 값을 가져와서 뿌려주는 것이다.
콘솔에서 출력되는 값을 가져오는 것은 AcroEdit의 개발 사이트인 www.acrosoft.pe.kr 에서 얻을 수 있었다.
http://www.acrosoft.pe.kr/board/?mid=cg_tips&search_target=title&document_srl=24088


unit converter;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ShellAPI, ComCtrls, XPMan;

type
  TForm1 = class(TForm)
    Button1: TButton;
    OpenDialog1: TOpenDialog;
    ProgressBar1: TProgressBar;
    XPManifest1: TXPManifest;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    procedure RunDosCommand(Command : string);
  end;

var
  Form1: TForm1;

implementation

uses StrUtils;

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  cmd : string;
  ffmpeg_name : string;
  wma_name : string;
  mp3_name : string;
begin
  if OpenDialog1.Execute = False then Exit;

  wma_name := OpenDialog1.FileName;
  mp3_name := StringReplace(wma_name, ExtractFileExt(wma_name), '.mp3', [rfReplaceAll]);
  ffmpeg_name := 'ffmpeg.exe';
  cmd := ffmpeg_name + ' -i "' + wma_name + '" -ab 128k -y -f mp3 "' + mp3_name + '"';
  RunDosCommand(cmd);

end;

procedure TForm1.RunDosCommand(Command : string);
var  
  hReadPipe : THandle;
  hWritePipe : THandle;
  SI : TStartUpInfo;
  PI : TProcessInformation;
  SA : TSecurityAttributes;
  SD : TSecurityDescriptor;
  BytesRead : DWORD;
  Dest : array[0..4095] of char;
  CmdLine : array[0..512] of char;
  S, Param : string;
  Avail, ExitCode, wrResult : DWORD;
  tmpStr : string;
  sIdx, eIdx : Integer;
  time : Integer;
  duration : Integer;
begin  
{ Dos Application }
    InitializeSecurityDescriptor(@SD, SECURITY_DESCRIPTOR_REVISION);
    SetSecurityDescriptorDacl(@SD, True, nil, False);
    SA.nLength := SizeOf(SA);
    SA.lpSecurityDescriptor := @SD;
    SA.bInheritHandle := True;
    CreatePipe(hReadPipe, hWritePipe, @SA, 1024);
    duration := 0;
    time := 0;
  try
    Screen.Cursor := crHourglass;
    { STARTUPINFO를 설정한다. }
    FillChar(SI, SizeOf(SI), 0);
    SI.cb := SizeOf(TStartUpInfo);
    SI.wShowWindow := SW_HIDE;
    SI.dwFlags := STARTF_USESHOWWINDOW;
    { STARTF_USESTDHANDLES 를 빼면 PIPE로 입출력이 Redirect 되지 않는다. }
    SI.dwFlags := SI.dwFlags or STARTF_USESTDHANDLES;
    SI.hStdOutput := hWritePipe;
    SI.hStdError := hWritePipe;
    StrPCopy(CmdLine, Command);

    { Process를 생성한다. }
    if CreateProcess(nil, CmdLine, nil, nil, True, NORMAL_PRIORITY_CLASS, nil, nil, SI, PI) then
    begin
      ExitCode := 0;
      while ExitCode = 0 do
      begin
        wrResult := WaitForSingleObject(PI.hProcess, 500);
        { Pipe에 출력된 내용이 있는 지 조사한다. }
        if PeekNamedPipe(hReadPipe, nil, 0, nil, @Avail, nil) then
        begin
          if Avail > 0 then
          begin
            { Redirect된 화면 내용을 출력 윈도에 내보낸다. }
              FillChar(Dest, SizeOf(Dest), 0);
              ReadFile(hReadPipe, Dest, Avail, BytesRead, nil);
              tmpStr := StrPas(Dest);
              {최종 시간 검색}
              if  duration = 0 then
              begin
                sIdx := Pos('Duration: ', tmpStr);
                if ( sIdx > 0) then
                begin
                   eIdx := PosEx(':', tmpStr, sIdx + 10);
                   time := StrToInt(Copy(tmpStr, sIdx + 10 , eIdx - sIdx - 10)) * 60 * 60;

                   sIdx := PosEx(':', tmpStr, eIdx + 1);
                   time := time + StrToInt(Copy(tmpStr, eIdx + 1, sIdx - eIdx - 1)) * 60;

                   eIdx := PosEx('.', tmpStr, sIdx + 1);
                   time := time + StrToInt(Copy(tmpStr, sIdx + 1 , eIdx - sIdx - 1));

                   duration := time;
                   ProgressBar1.Max := duration;

                end;
              end;

              {출력되는 시간값을 통해서 현재 진행 상황을 업데이트 한다.}
              sIdx := Pos('time=', tmpStr);
              eIdx := PosEx('.', tmpStr, sIdx + 5);
              time := StrToInt(Copy(tmpStr, sIdx + 5 , eIdx - sIdx - 5));
              ProgressBar1.Position := time;
              Application.ProcessMessages;
          end;
        end;
        { WAIT_TIMEOUT이 아니면 루프를 마친다. }
        if wrResult <> WAIT_TIMEOUT then
          ExitCode := 1;
      end;
      { 실행이 끝났다.. }
      GetExitCodeProcess(PI.hProcess, ExitCode);
      CloseHandle(PI.hProcess);
      CloseHandle(PI.hThread);
    end;
  finally
    CloseHandle(hReadPipe);
    CloseHandle(hWritePipe);
    Screen.Cursor := crDefault;
  end;
end;

end.

FFMPEG.zip

Comments
댓글쓰기 폼