MP3Convert.pas
上传用户:wanyu_2000
上传日期:2021-02-21
资源大小:527k
文件大小:13k
源码类别:

DVD

开发平台:

Delphi

  1. {-----------------------------------------------------------------------------
  2.  Unit Name: MP3Convert
  3.  Author:    paul fisher
  4.  Purpose:  convert from redbook pcm to mp3 and back !
  5.  History:  first release
  6. -----------------------------------------------------------------------------}
  7. unit MP3Convert;
  8. interface
  9. uses
  10.    Classes, Messages,dialogs, Windows, Forms, SysUtils, Controls, MSACM, MMSystem;
  11. const
  12. // addons for extra codecs
  13.    WAVE_FORMAT_MSG723 = 66;
  14.    WAVE_FORMAT_MPEGLAYER3 = 85;
  15.    MPEGLAYER3_WFX_EXTRA_BYTES = 12;
  16.    MP3_BLOCK_SIZE = 522;
  17.    MPEGLAYER3_ID_UNKNOWN = 0;
  18.    MPEGLAYER3_ID_MPEG = 1;
  19.    MPEGLAYER3_ID_CONSTANTFRAMESIZE = 2;
  20.    MPEGLAYER3_FLAG_PADDING_ISO = $00000000;
  21.    MPEGLAYER3_FLAG_PADDING_ON = $00000001;
  22.    MPEGLAYER3_FLAG_PADDING_OFF = $00000002;
  23. type
  24.    TMpegLayer3WaveFormat = record
  25.       wfx: TWaveFormatEx;
  26.       wID: WORD;
  27.       fdwFlags: DWORD;
  28.       nBlockSize: WORD;
  29.       nFramesPerBlock: WORD;
  30.       nCodecDelay: WORD;
  31.    end;
  32. type
  33.    TMP3Convertor = class
  34.    private
  35.       FStreamHandle: HACMStream;
  36.       FDriverName : String;
  37.    protected
  38.       procedure FindACMDriver(SourceFormat, DestFormat: PWaveFormatEx);
  39.    public
  40.       PCMFormat: TWaveFormatEx;
  41.       MP3Format: TMpegLayer3WaveFormat;
  42.       LastError: string;
  43.       constructor Create(AOwner: TComponent);
  44.       destructor Destroy; override;
  45.       procedure InitialisePCM;
  46.       procedure InitialiseMP3;
  47.       function ConvertToMP3Format(srcData: Pointer; srcDataSize: DWORD;
  48.          out dstData: Pointer; out dstDataSize: DWORD): Boolean;
  49.       function ConvertFromMP3Format(srcData: Pointer; srcDataSize: DWORD;
  50.          out dstData: Pointer; out dstDataSize: DWORD): Boolean;
  51.    published
  52.       Property ACMDriverName : String read FDriverName;
  53.    end;
  54. implementation
  55. var
  56.    TargetWaveFormat : PWaveFormatEx;
  57.    ACMDrvDet : TACMDriverDetails;
  58.    ACMFmtDet : PACMFormatDetails;
  59.    WaveFormatEx : PWaveFormatEx;
  60.    MP3DriversFound : Integer;
  61.    ACMDriver : HACMDRIVERID;
  62.    DriverName : String;
  63.    MaxSize: Word;
  64. constructor TMP3Convertor.Create(AOwner: TComponent);
  65. begin
  66.    FStreamHandle := nil;
  67.    MP3DriversFound := 0;
  68.  // red book audio in
  69.    PCMFormat.wFormatTag := WAVE_FORMAT_PCM;
  70.    PCMFormat.nChannels := 2;
  71.    PCMFormat.nSamplesPerSec := 44100;
  72.    PCMFormat.nBlockAlign := 4;
  73.    PCMFormat.wbitspersample := 16;
  74.    // PCMFormat.nAvgBytesPerSec:= PCMFormat.nSamplesPerSec * PCMFormat.nBlockAlign;
  75.    PCMFormat.nAvgBytesPerSec := (((PCMFormat.nSamplesPerSec * PCMFormat.wbitspersample) * PCMFormat.nChannels) div 8);
  76.    PCMFormat.wbitspersample := 16;
  77.    PCMFormat.cbSize := 0;
  78.  // MP3 audio out
  79.    MP3Format.wfx.wFormatTag := WAVE_FORMAT_MPEGLAYER3;
  80.    MP3Format.wfx.nChannels := PCMFormat.nChannels;
  81.    MP3Format.wfx.nSamplesPerSec := PCMFormat.nSamplesPerSec;
  82.    MP3Format.wfx.nAvgBytesPerSec := PCMFormat.nAvgBytesPerSec;
  83.    MP3Format.wfx.cbSize := 0;
  84.    MP3Format.wfx.wBitsPerSample := 0;
  85.    MP3Format.wfx.nBlockAlign := 1;
  86.    MP3Format.nCodecDelay := 1393;
  87.    MP3Format.nBlockSize := MP3_BLOCK_SIZE;
  88.    MP3Format.fdwFlags := MPEGLAYER3_FLAG_PADDING_OFF;
  89.    MP3Format.wID := MPEGLAYER3_ID_MPEG;
  90. end;
  91. destructor TMP3Convertor.Destroy;
  92. begin
  93.    FStreamHandle := nil;
  94. end;
  95. function FormatEnumProc(hACMDrvId: HACMDRIVERID;
  96.    NewACMFmtDet: PAcmFormatDetails;
  97.    dwInstance: DWord; fdwSupport: DWord): longbool; stdcall;
  98. begin
  99.  Result := True;
  100.  try
  101.    if NewACMFmtDet^.pwfx^.wFormatTag = TargetWaveFormat.wFormatTag then
  102.    begin
  103.       if NewACMFmtDet^.pwfx^.nSamplesPerSec = TargetWaveFormat.nSamplesPerSec then
  104.          if NewACMFmtDet^.pwfx^.nChannels = TargetWaveFormat.nChannels then
  105.          If NewACMFmtDet^.pwfx^.nAvgBytesPerSec = TargetWaveFormat.nAvgBytesPerSec Then 
  106.           // store driver handle and format structure
  107.             begin
  108.                ACMDriver := hACMDrvId;
  109.                TargetWaveFormat := NewACMFmtDet^.pwfx;
  110.                Inc(MP3DriversFound);
  111.                Result := False;
  112.             end;
  113.    end;
  114.    except
  115.       Result := False;
  116.    end;
  117. end;
  118. function DriverEnumProc(hACMDrvId: HACMDRIVERID;
  119.    dwInstance: DWord; fdwSupport: DWord): bool; stdcall;
  120. var
  121.    hACMDrv: HACMDriver;
  122. begin
  123.    Result := True;
  124.    if (fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC) then
  125.    begin
  126.       FillChar(WaveFormatEx^, SizeOf(TWaveFormatEx), #0);
  127.       FillChar(ACMFmtDet^, SizeOf(TACMFormatDetails), #0);
  128.       {get the driver and enumerate the formats}
  129.       hACMDrv := nil;
  130.       {get driver details}
  131.       ACMDrvDet.cbStruct := SizeOf(ACMDrvDet);
  132.       if acmDriverDetails(hACMDrvId, ACMDrvDet, 0) = 0 then
  133.         DriverName := ACMDrvDet.szLongName;
  134.       if acmDriverOpen(hACMDrv, hACMDrvId, 0) = 0 then
  135.       begin
  136.          MaxSize := 0;
  137.          if acmMetrics(HACMOBJ(hACMDrv), ACM_METRIC_MAX_SIZE_FORMAT, MaxSize) = 0 then
  138.          begin
  139.             if MaxSize < SizeOf(TWaveFormatEx) then MaxSize := SizeOf(TWaveFormatEx);
  140.             WaveFormatEx^.cbSize := LoWord(MaxSize) - SizeOf(TWaveFormatEx);
  141.             WaveFormatEx^.wFormatTag := 0;
  142.             ACMFmtDet^.cbStruct := SizeOf(TACMFormatDetails); //set up format details to receive enumerations
  143.             ACMFmtDet^.pwfx := WaveFormatEx;
  144.             ACMFmtDet^.cbwfx := MaxSize;
  145.             ACMFmtDet^.dwFormatTag := 0;
  146.             acmFormatEnum(hACMDrv, ACMFmtDet^, @FormatEnumProc, integer(hACMDrvId), 0); //start enumerating formats
  147.          end;
  148.        {close the driver}
  149.          acmDriverClose(hACMDrv, 0);
  150.       end
  151.        else
  152.           Exit;
  153.    end;
  154. end;
  155. procedure TMP3Convertor.FindACMDriver(SourceFormat, DestFormat: PWaveFormatEx);
  156. begin
  157.    TargetWaveFormat := DestFormat;
  158.    new(WaveFormatEx);
  159.    new(ACMFmtDet);
  160.    acmDriverEnum(@DriverEnumProc, 0, 0);
  161.    FDriverName := DriverName;
  162.    DestFormat := TargetWaveFormat;
  163.   // dispose(WaveFormatEx);
  164.  //  dispose(ACMFmtDet);
  165. end;
  166. procedure TMP3Convertor.InitialiseMP3;
  167. begin
  168.    FindACMDriver(@PCMFormat, @MP3Format.wfx);
  169. end;
  170. procedure TMP3Convertor.InitialisePCM;
  171. begin
  172.    FindACMDriver(@MP3Format.wfx, @PCMFormat);
  173. end;
  174. // Converts the wave data to the specified format. The caller is responsible to
  175. // release the memory allocated for the converted wave data buffer.
  176. function TMP3Convertor.ConvertToMP3Format(srcData: Pointer; srcDataSize: DWORD;
  177.    out dstData: Pointer; out dstDataSize: DWORD): Boolean;
  178. var
  179.    hStream: HACMSTREAM;
  180.    Header: TACMSTREAMHEADER;
  181.    Converted: Integer;
  182.    hACMDrv: HACMDriver;
  183. begin
  184.    Result := False;
  185.    LastError := '';
  186.  try
  187.   InitialiseMP3;
  188.   if MP3DriversFound = 0 then
  189.      showmessage('MP3 Codec Not Found');
  190.   if acmDriverOpen(hACMDrv, ACMDriver, 0) = 0 then
  191.   begin
  192.   try
  193.    if acmStreamOpen(hStream, hACMDrv, PCMFormat, MP3Format.wfx, nil, 0, 0, ACM_STREAMOPENF_NONREALTIME) = 0 then
  194.    begin
  195.       try
  196.          if acmStreamSize(hStream, srcDataSize, dstDataSize, ACM_STREAMSIZEF_SOURCE) = 0 then
  197.          begin
  198.             dstData := nil;
  199.             FillChar(Header, SizeOf(Header), 0);
  200.             dstDataSize := dstDataSize + (dstDataSize div 2);  // add a bit for good measure
  201.             ReallocMem(dstData, dstDataSize);
  202.             try
  203.                Header.cbStruct := SizeOf(Header);
  204.                Header.pbSrc := srcData;
  205.                Header.cbSrcLength := srcDataSize;
  206.                Header.pbDst := dstData;
  207.                Header.cbDstLength := dstDataSize;
  208.                if acmStreamPrepareHeader(hStream, Header, 0) = 0 then
  209.                try
  210.                   Converted := acmStreamConvert(hStream, Header, ACM_STREAMCONVERTF_START or ACM_STREAMCONVERTF_END);
  211.                   case Converted of
  212.                      ACMERR_NotPossible: LastError := 'The requested operation cannot be performed.';
  213.                      ACMERR_BUSY: LastError := 'The stream header specified in pash is currently in use and cannot be reused.';
  214.                      ACMERR_UNPREPARED: LastError := 'The stream header specified in pash is currently not prepared by the acmStreamPrepareHeader function.';
  215.                      MMSYSERR_INVALFLAG: LastError := 'At least one flag is invalid.';
  216.                      MMSYSERR_INVALHANDLE: LastError := 'The specified handle is invalid.';
  217.                      MMSYSERR_INVALPARAM: LastError := 'At least one parameter is invalid.';
  218.                      MMSYSERR_NoMem: LastError := 'The system is unable to allocate resources.';
  219.                      MMSYSERR_NoDriver: LastError := 'A suitable driver is not available to provide valid format selections.';
  220.                      MMSYSERR_ALLOCATED: LastError := 'The specified resource is already in use.';
  221.                      MMSYSERR_BADDEVICEID: LastError := 'The specified resource does not exist.';
  222.                      WAVERR_BADFORMAT: LastError := 'Unsupported audio format.';
  223.                      WAVERR_SYNC: LastError := 'The specified device does not support asynchronous operation.';
  224.                   end;
  225.                   Result := (Converted = 0);
  226.                finally
  227.                   acmStreamUnprepareHeader(hStream, Header, 0);
  228.                end;
  229.             finally
  230.                ReallocMem(dstData, Header.cbDstLengthUsed);
  231.                dstDataSize := Header.cbDstLengthUsed;
  232.             end;
  233.          end;
  234.       finally
  235.          acmStreamClose(hStream, 0);
  236.       end;
  237.    end;
  238.    finally
  239.       acmDriverClose(hACMDrv, 0);
  240.    end;
  241.   end;
  242.   except
  243.       On E:Exception do
  244.             showmessage('error : ' + e.Message);
  245.   end;
  246. end;
  247. // Converts the wave data to the specified format. The caller is responsible to
  248. // release the memory allocated for the converted wave data buffer.
  249. function TMP3Convertor.ConvertFromMP3Format(srcData: Pointer; srcDataSize: DWORD;
  250.    out dstData: Pointer; out dstDataSize: DWORD): Boolean;
  251. var
  252.    hStream: HACMSTREAM;
  253.    Header: TACMSTREAMHEADER;
  254.    Converted: Integer;
  255.    hACMDrv: HACMDriver;   
  256. begin
  257.    Result := False;
  258.    LastError := '';
  259.   InitialisePCM;
  260.   if MP3DriversFound = 0 then
  261.      showmessage('MP3 Codec Not Found');
  262.   if acmDriverOpen(hACMDrv, ACMDriver, 0) = 0 then
  263.   begin
  264.   try
  265.    if acmStreamOpen(hStream, nil, MP3Format.wfx, PCMFormat, nil, 0, 0, ACM_STREAMOPENF_NONREALTIME) = 0 then
  266.    begin
  267.       try
  268.          if acmStreamSize(hStream, srcDataSize, dstDataSize, ACM_STREAMSIZEF_SOURCE) = 0 then
  269.          begin
  270.             dstData := nil;
  271.             FillChar(Header, SizeOf(Header), 0);
  272.             ReallocMem(dstData, dstDataSize);
  273.             try
  274.                Header.cbStruct := SizeOf(Header);
  275.                Header.pbSrc := srcData;
  276.                Header.cbSrcLength := srcDataSize;
  277.                Header.pbDst := dstData;
  278.                Header.cbDstLength := dstDataSize;
  279.                if acmStreamPrepareHeader(hStream, Header, 0) = 0 then
  280.                try
  281.                   Converted := acmStreamConvert(hStream, Header, ACM_STREAMCONVERTF_START or ACM_STREAMCONVERTF_END);
  282.                   case Converted of
  283.                      ACMERR_NotPossible: LastError := 'The requested operation cannot be performed.';
  284.                      ACMERR_BUSY: LastError := 'The stream header specified in pash is currently in use and cannot be reused.';
  285.                      ACMERR_UNPREPARED: LastError := 'The stream header specified in pash is currently not prepared by the acmStreamPrepareHeader function.';
  286.                      MMSYSERR_INVALFLAG: LastError := 'At least one flag is invalid.';
  287.                      MMSYSERR_INVALHANDLE: LastError := 'The specified handle is invalid.';
  288.                      MMSYSERR_INVALPARAM: LastError := 'At least one parameter is invalid.';
  289.                      MMSYSERR_NoMem: LastError := 'The system is unable to allocate resources.';
  290.                      MMSYSERR_NoDriver: LastError := 'A suitable driver is not available to provide valid format selections.';
  291.                      MMSYSERR_ALLOCATED: LastError := 'The specified resource is already in use.';
  292.                      MMSYSERR_BADDEVICEID: LastError := 'The specified resource does not exist.';
  293.                      WAVERR_BADFORMAT: LastError := 'Unsupported audio format.';
  294.                      WAVERR_SYNC: LastError := 'The specified device does not support asynchronous operation.';
  295.                   end;
  296.                   Result := (Converted = 0);
  297.                finally
  298.                   acmStreamUnprepareHeader(hStream, Header, 0);
  299.                end;
  300.             finally
  301.                ReallocMem(dstData, Header.cbDstLengthUsed);
  302.                dstDataSize := Header.cbDstLengthUsed;
  303.             end;
  304.          end;
  305.       finally
  306.          acmStreamClose(hStream, 0);
  307.       end;
  308.       end;
  309.    finally
  310.       acmDriverClose(hACMDrv, 0);
  311.    end;
  312.   end;      
  313. end;
  314. end.