{This unit is part of United Openlibraries of Sound (uos)} {This is the Dynamic loading version of FAAD2 Pascal Wrapper. mcwNeAACDec.pas, mcwMP4FF.pas, mcwAAC.pas By Franklyn A. Harlow Feb 2016 License : modified LGPL. mcw* merged into uos_aac by Fred van Stappen / fiens@hotmail.com } unit uos_aac; {$mode objfpc}{$H+} {$PACKRECORDS C} interface uses Classes, SysUtils, ctypes, math, dynlibs; const {$IFDEF unix} {$IFDEF darwin} libaa= 'libfaad.2.dylib'; libm4= 'libmp4ff.0.dylib'; {$ELSE} libaa= 'libfaad.so.2'; libm4= 'libmp4ff.so.0.0.0'; {$ENDIF} {$ELSE} libaa= 'Faad2.dll'; libm4= 'mp4ff.dll'; {$ENDIF} //////////// from mcwMP4FF.pas By Franklyn A. Harlow type ArSingle = array of Single; PArSingle = ^ArSingle; read_callback_t = function(user_data : Pointer; buffer : pcfloat; length : LongWord) : LongWord; cdecl; write_callback_t = function(user_data : Pointer; buffer : pcfloat; length : LongWord) : LongWord; cdecl; seek_callback_t = function(user_data : Pointer; Position : cInt64) : LongWord; cdecl; truncate_callback_t = function(user_data : Pointer) : LongWord; cdecl; mp4ff_callback_t = record read : read_callback_t; write : write_callback_t; seek : seek_callback_t; truncate : truncate_callback_t; user_data : Pointer; end; p_mp4ff_callback_t = ^mp4ff_callback_t; mp4ff_t = pointer; int32_t = LongInt; int64_t = cInt64; uint32_t = LongWord; var mp4ff_open_read : function(f : p_mp4ff_callback_t) : mp4ff_t; cdecl; mp4ff_open_read_metaonly : function(f : p_mp4ff_callback_t) : mp4ff_t; cdecl; mp4ff_close : procedure(f : mp4ff_t); cdecl; mp4ff_get_sample_duration : function(f : mp4ff_t; track, sample : int32_t) : int32_t; cdecl; mp4ff_get_sample_duration_use_offsets : function(f : mp4ff_t; track, sample : int32_t) : int32_t; cdecl; mp4ff_get_sample_position : function(f : mp4ff_t; track, sample : int32_t) : int64_t; cdecl; mp4ff_get_sample_offset : function(f : mp4ff_t; track, sample : int32_t) : int32_t; cdecl; mp4ff_find_sample : function(f : mp4ff_t; track : int32_t; offset : int64_t; var toskip : int32_t) : int32_t; cdecl; mp4ff_find_sample_use_offsets : function(f : mp4ff_t; track : int32_t; offset : int64_t; var toskip : int32_t) : int32_t; cdecl; mp4ff_set_sample_position : function(f : mp4ff_t; track : int32_t; sample : int64_t) : int32_t; cdecl; mp4ff_read_sample : function(f : mp4ff_t; track, sample : int32_t; var audio_buffer : pcfloat; var bytes : LongWord) : int32_t; cdecl; mp4ff_read_sample_v2 : function(f : mp4ff_t; track, sample : int32_t; buffer : pcfloat): int32_t; cdecl; //returns 0 on error, number of bytes read on success, use mp4ff_read_sample_getsize_t = function() to check buffer size needed mp4ff_read_sample_getsize : function(f : mp4ff_t; track, sample : Integer) : int32_t; cdecl; //returns 0 on error, buffer size needed for mp4ff_read_sample_v2_t = function() on success mp4ff_get_decoder_config : function(f : mp4ff_t; track : Integer; var ppBuf : pcfloat; var pBufSize : LongWord) : int32_t; cdecl; mp4ff_free_decoder_config : procedure(Buf : pcfloat); cdecl; mp4ff_get_track_type : function(f : mp4ff_t; const track : Integer) : int32_t; cdecl; mp4ff_total_tracks : function(f : mp4ff_t) : int32_t; cdecl; mp4ff_num_samples : function(f : mp4ff_t; track : Integer) : int32_t; cdecl; mp4ff_time_scale : function(f : mp4ff_t; track : Integer) : int32_t; cdecl; mp4ff_get_avg_bitrate : function(f : mp4ff_t; track : int32_t) : uint32_t; cdecl; mp4ff_get_max_bitrate : function(f : mp4ff_t; track : int32_t) : uint32_t; cdecl; mp4ff_get_track_duration : function(f : mp4ff_t; track : int32_t) : int64_t; cdecl; //returns _t = function(-1) if unknown mp4ff_get_track_duration_use_offsets : function(f : mp4ff_t; track : int32_t) : Integer; cdecl; //returns _t = function(-1) if unknown mp4ff_get_sample_rate : function(f : mp4ff_t; track : int32_t) : uint32_t; cdecl; mp4ff_get_channel_count : function(f : mp4ff_t; track : int32_t) : uint32_t; cdecl; mp4ff_get_audio_type : function(f : mp4ff_t; track : int32_t) : uint32_t; cdecl; mp4ff_meta_get_num_items : function(f : mp4ff_t) : Integer; cdecl; mp4ff_meta_get_by_index : function(f : mp4ff_t; index : LongWord; var item, value : PChar) : Integer; cdecl; mp4ff_meta_get_title : function(f : mp4ff_t; var value : PChar) : Integer; cdecl; mp4ff_meta_get_artist : function(f : mp4ff_t; var value : PChar) : Integer; cdecl; mp4ff_meta_get_writer : function(f : mp4ff_t; var value : PChar) : Integer; cdecl; mp4ff_meta_get_album : function(f : mp4ff_t; var value : PChar) : Integer; cdecl; mp4ff_meta_get_date : function(f : mp4ff_t; var value : PChar) : Integer; cdecl; mp4ff_meta_get_tool : function(f : mp4ff_t; var value : PChar) : Integer; cdecl; mp4ff_meta_get_comment : function(f : mp4ff_t; var value : PChar) : Integer; cdecl; mp4ff_meta_get_genre : function(f : mp4ff_t; var value : PChar) : Integer; cdecl; mp4ff_meta_get_track : function(f : mp4ff_t; var value : PChar) : Integer; cdecl; mp4ff_meta_get_disc : function(f : mp4ff_t; var value : PChar) : Integer; cdecl; mp4ff_meta_get_totaltracks : function(f : mp4ff_t; var value : PChar) : Integer; cdecl; mp4ff_meta_get_totaldiscs : function(f : mp4ff_t; var value : PChar) : Integer; cdecl; mp4ff_meta_get_compilation : function(f : mp4ff_t; var value : PChar) : Integer; cdecl; mp4ff_meta_get_tempo : function(f : mp4ff_t; var value : PChar) : Integer; cdecl; mp4ff_meta_get_coverart : function(f : mp4ff_t; var value : PChar) : Integer; cdecl; function GetAACTrack(infile : mp4ff_t) : Integer; procedure Loadmp4ff(mp4ff : AnsiString); procedure UnLoadMp4ff; Function isMp4ffLoaded : Boolean; //////////// from mcwNeAACDec.pas by Franklyn A. Harlow Const { object types for AAC } MAIN = 1; LC = 2; SSR = 3; LTP = 4; HE_AAC = 5; ER_LC = 17; ER_LTP = 19; LD = 23; { special object type for DRM } DRM_ER_LC = 27; { header types } RAW = 0; ADIF = 1; ADTS = 2; LATM = 3; { SBR signalling } NO_SBR = 0; SBR_UPSAMPLED = 1; SBR_DOWNSAMPLED = 2; NO_SBR_UPSAMPLED = 3; { library output formats } FAAD_FMT_16BIT = 1; FAAD_FMT_24BIT = 2; FAAD_FMT_32BIT = 3; FAAD_FMT_FLOAT = 4; FAAD_FMT_FIXED = FAAD_FMT_FLOAT; FAAD_FMT_DOUBLE = 5; { Capabilities } { Can decode LC } LC_DEC_CAP = 1 shl 0; { Can decode MAIN } MAIN_DEC_CAP = 1 shl 1; { Can decode LTP } LTP_DEC_CAP = 1 shl 2; { Can decode LD } LD_DEC_CAP = 1 shl 3; { Can decode ER } ERROR_RESILIENCE_CAP = 1 shl 4; { Fixed point } FIXED_POINT_CAP = 1 shl 5; { Channel definitions } FRONT_CHANNEL_CENTER = 1; FRONT_CHANNEL_LEFT = 2; FRONT_CHANNEL_RIGHT = 3; SIDE_CHANNEL_LEFT = 4; SIDE_CHANNEL_RIGHT = 5; BACK_CHANNEL_LEFT = 6; BACK_CHANNEL_RIGHT = 7; BACK_CHANNEL_CENTER = 8; LFE_CHANNEL = 9; UNKNOWN_CHANNEL = 0; { DRM channel definitions } DRMCH_MONO = 1; DRMCH_STEREO = 2; DRMCH_SBR_MONO = 3; DRMCH_SBR_STEREO = 4; DRMCH_SBR_PS_STEREO = 5; { A decode call can eat up to FAAD_MIN_STREAMSIZE bytes per decoded channel, so at least so much bytes per channel should be available in this stream } { 6144 bits/channel } FAAD_MIN_STREAMSIZE = 768; Type PNeAACDec = Pointer; NeAAC_byte = {$IFDEF FPC}{$IFDEF CPU64}cuint32 {$ELSE}Byte {$ENDIF}{$ELSE}Byte {$ENDIF}; NeAAC_word = {$IFDEF FPC}{$IFDEF CPU64}cuint64{$ELSE}Word {$ENDIF}{$ELSE}Word {$ENDIF}; NeAAC_longword = {$IFDEF FPC}{$IFDEF CPU64}culong {$ELSE}LongWord{$ENDIF}{$ELSE}LongWord{$ENDIF}; NeAACDecConfiguration = record defObjectType : NeAAC_byte; defSampleRate : NeAAC_longword; outputFormat : NeAAC_byte; downMatrix : NeAAC_byte; useOldADTSFormat : NeAAC_byte; dontUpSampleImplicitSBR : NeAAC_byte; end; TNeAACDecConfiguration = NeAACDecConfiguration; PNeAACDecConfiguration = ^NeAACDecConfiguration; NeAACDecFrameInfo = record bytesconsumed : NeAAC_longword; samples : NeAAC_longword; channels : NeAAC_byte; error : NeAAC_byte; samplerate : NeAAC_longword; sbr : NeAAC_byte; //* SBR: 0: off, 1: on; upsample, 2: on; downsampled, 3: off; upsampled */ object_type : NeAAC_byte; //* MPEG-4 ObjectType */ header_type : NeAAC_byte; //* AAC header type; MP4 will be signalled as RAW also */ num_front_channels : NeAAC_byte; //* multichannel configuration */ num_side_channels : NeAAC_byte; num_back_channels : NeAAC_byte; num_lfe_channels : NeAAC_byte; channel_position : array[0..63] of NeAAC_byte; ps : NeAAC_byte; //* PS: 0: off, 1: on */ end; TNeAACDecFrameInfo = NeAACDecFrameInfo; PNeAACDecFrameInfo = ^NeAACDecFrameInfo; mp4AudioSpecificConfig = record objectTypeIndex : NeAAC_byte; samplingFrequencyIndex : NeAAC_byte; samplingFrequency : NeAAC_longword; channelsConfiguration : NeAAC_byte; frameLengthFlag : NeAAC_byte; //* GA Specific Info */ dependsOnCoreCoder : NeAAC_byte; coreCoderDelay : NeAAC_word; extensionFlag : NeAAC_byte; aacSectionDataResilienceFlag : NeAAC_byte; aacScalefactorDataResilienceFlag : NeAAC_byte; aacSpectralDataResilienceFlag : NeAAC_byte; epConfig : NeAAC_byte; sbr_present_flag : NeAAC_byte; forceUpSampling : NeAAC_byte; downSampledSBR : NeAAC_byte; end; Tmp4AudioSpecificConfig = mp4AudioSpecificConfig; Pmp4AudioSpecificConfig = ^mp4AudioSpecificConfig; var NeAACDecGetErrorMessage : function(ErrorCode : Byte) : PChar; cdecl; NeAACDecGetCapabilities : function : LongWord; cdecl; NeAACDecOpen : function : PNeAACDec; cdecl; NeAACDecGetCurrentConfiguration : function( hDecoder : PNeAACDec) : PNeAACDecConfiguration; cdecl; NeAACDecSetConfiguration : function( hDecoder : PNeAACDec; pConfig : PNeAACDecConfiguration) : Byte; cdecl; NeAACDecInit : function( hDecoder : PNeAACDec; pBuffer : pcfloat; lwBufferLength : LongWord; var lwSampleRate : LongWord; var Channels : Byte) : LongInt; cdecl; NeAACDecInit2 : function( hDecoder : PNeAACDec; pBuffer : pcfloat; SizeOfDecoderSpecificInfo : LongWord; var lwSampleRate : LongWord; var Channels : Byte) : Byte; cdecl; NeAACDecPostSeekReset : procedure(hDecoder : PNeAACDec; Frame : LongInt); cdecl; NeAACDecClose : procedure(hDecoder : PNeAACDec); cdecl; NeAACDecDecode : function( hDecoder : PNeAACDec; hInfo : PNeAACDecFrameInfo; pBuffer : pcfloat; lwBufferLength : LongWord) : Pointer; cdecl; NeAACDecDecode2 : function( hDecoder : PNeAACDec; hInfo : PNeAACDecFrameInfo; pBuffer : pcfloat; lwBufferLength : LongWord; var pSampleBuf : Pointer; lwSampleBufSize : LongWord) : Pointer; cdecl; NeAACDecAudioSpecificConfig : function( pBuffer : pcfloat; lwBufferLength : LongWord; var mp4ASC : mp4AudioSpecificConfig) : Byte; cdecl; procedure LoadNeAAC(NeAAC : AnsiString); Procedure UnLoadNeAAC; Function Is_NeAAC_Loaded : Boolean; ////////////////// // from mcwAAC.pas from Franklyn A. Harlow Const kNeAAC_OK = 1; kNeAAC_FAIL = 0; Type TAACIdata = array[0..2024*1024-1] of byte; TAACInfo = class(TObject) public // libfaad control interface... fsStream : TFileStream; pDecoder : PNeAACDec; hMP4 : mp4ff_t; // output interface setup... Channels : longword; // stereo = 2 BitsPerSample : longword; // ie short/smallint = 16 SampleRate : longword; // Frequency = 44100 outputFormat : byte; // See FAAD_FMT_16BIT etc... Bitrate : longword; // 256000 = 256 TotalTime : double; // Length in Seconds {$if not defined(fs32bit)} TotalSamples : cint64; Size : cint64; // in frames Position : cint64; // in frames {$else} TotalSamples : cint; Size : cint; // in frames Position : cint; // in frames {$endif} // UoS interface pData : pcfloat; lwDataLen : longword; // tag info... Artist : AnsiString; AlbumArtist : AnsiString; Album : AnsiString; Title : AnsiString; Date : AnsiString; Genre : AnsiString; Track : AnsiString; Comment : AnsiString; // internal data... cbs : mp4ff_callback_t; _Buf : TAACIdata; BufTmp : TAACIdata; fTrack : longint; fTimescale : longword; // Not actually used fBufStart : longword; fBufEnd : longword; End; Function aa_load(mp4ff, NeAAC: AnsiString): Boolean; Procedure aa_Unload; Function isLibAACLoaded : Boolean; Function MP4OpenFile(fName : String; OutputFormat : Byte) : TAACInfo; Procedure MP4CloseFile(var AACI: TAACInfo); procedure MP4GetData(var AACI: TAACInfo; var Buffer: pcfloat; var Bytes: longword); function MP4Seek(var AACI: TAACInfo; var SampleNum: longint) : Boolean; implementation var // hNeAAC: {$IFDEF MSWINDOWS}longword{$ELSE}{$IFDEF CPU32}longword{$ELSE}PtrInt{$ENDIF}{$ENDIF}; hNeAAC:TLibHandle=dynlibs.NilHandle; NeAACLoaded : Boolean; Mp4ffLoaded : Boolean = False; hMp4ff:TLibHandle=dynlibs.NilHandle; //////////// from mcwNeAACDec.pas By Franklyn A. Harlow function CBMP4Read(user_data : Pointer; buffer : pcfloat; length : LongWord) : LongWord; cdecl; begin try Result := LongWord(TAACInfo(user_data).fsStream.Read(buffer^, Integer(length))); except Result := 0; end; end; function CBMP4Write(user_data : Pointer; buffer : pcfloat; length : LongWord) : LongWord; cdecl; begin try Result := LongWord(TAACInfo(user_data).fsStream.Write(buffer^, Integer(length))); TAACInfo(user_data).fsStream.Position:=0; except Result := 0; end; end; function CBMP4Seek(user_data : Pointer; Position : Int64) : LongWord; cdecl; begin try Result := LongWord(TAACInfo(user_data).fsStream.Seek(Position, soBeginning)); except Result := 0; end; end; function CBMP4Truncate(user_data : Pointer) : LongWord; cdecl; begin Result := 0; end; //////////// from mcwAAC.pas By Franklyn A. Harlow Function aa_load(mp4ff, NeAAC: AnsiString): Boolean; Begin // Safe To Call Multiple times, actual load of Lib checks to see if it is already loaded & // returns true if it is... LoadNeAAC(NeAAC); Loadmp4ff(mp4ff); Result:= Is_NeAAC_Loaded And isMp4ffLoaded; End; Procedure aa_Unload; Begin UnLoadNeAAC(); UnLoadMp4ff(); End; Function isLibAACLoaded : Boolean; Begin Result:= Is_NeAAC_Loaded And isMp4ffLoaded; end; Function isFileAAC(fName : AnsiString): Boolean; Begin Result:= LowerCase(ExtractFileExt(fName)) = '.m4a'; end; Function MP4OpenFile(fName : String; OutputFormat : Byte) : TAACInfo; Var pConfig : PNeAACDecConfiguration; mp4ASC : mp4AudioSpecificConfig; pBuf : pcfloat; lwBufSize : longword; lwBufSize2 : longword; lwSampleRate : longword; bChannels : byte; bRet : Byte; iRet : LongInt; pID3 : PAnsiChar; f : Double; Begin Result:= nil; if not FileExists(fName) then Exit; if Not isFileAAC(fName) then Exit; // writeln('MP4OpenFileBegin'); Result:= TAACInfo.Create; // writeln('MP4OpenFile3'); Result.fsStream:= TFileStream.Create(fName, fmOpenRead or fmShareDenyWrite); sleep(1); // writeln('MP4OpenFile4'); Result.cbs.read := @CBMP4Read; Result.cbs.write := @CBMP4Write; Result.cbs.seek := @CBMP4Seek; Result.cbs.truncate := @CBMP4Truncate; Result.cbs.user_data := Pointer(Result); // writeln('MP4OpenFile5'); Result.pDecoder := NeAACDecOpen(); // writeln('MP4OpenFile6'); pConfig := NeAACDecGetCurrentConfiguration(Result.pDecoder); // writeln('MP4OpenFile7'); pConfig^.defObjectType := LC; pConfig^.defSampleRate := 44100; pConfig^.outputFormat := OutputFormat; // FAAD_FMT_FLOAT FAAD_FMT_16BIT FAAD_FMT_32BIT pConfig^.downMatrix := 1; pConfig^.dontUpSampleImplicitSBR := 0; NeAACDecSetConfiguration(Result.pDecoder, pConfig) ; pConfig := NeAACDecGetCurrentConfiguration(Result.pDecoder); // writeln('MP4OpenFile9'); case pConfig^.outputFormat of FAAD_FMT_16BIT : Result.BitsPerSample := 16; FAAD_FMT_24BIT : Result.BitsPerSample := 24; FAAD_FMT_32BIT : Result.BitsPerSample := 32; FAAD_FMT_FLOAT : Result.BitsPerSample := 32; FAAD_FMT_DOUBLE: Result.BitsPerSample := 64; end; // writeln('MP4OpenFile10'); Result.outputFormat:= pConfig^.outputFormat; Result.hMP4 := mp4ff_open_read(@Result.cbs); // writeln('MP4OpenFile11'); Result.fTrack := GetAACTrack(Result.hMP4); // writeln('MP4OpenFile12'); pBuf:= nil; iRet:= mp4ff_get_decoder_config(Result.hMP4, Result.fTrack, pBuf, lwBufSize); // writeln('MP4OpenFile13'); lwBufSize2:= lwBufSize; // writeln('MP4OpenFile14'); bRet:= NeAACDecInit2(Result.pDecoder, pBuf, lwBufSize, lwSampleRate, bChannels); // writeln('MP4OpenFile15'); Result.SampleRate := mp4ff_get_sample_rate(Result.hMP4, Result.fTrack); Result.Channels := mp4ff_get_channel_count(Result.hMP4, Result.fTrack); Result.fTimescale := mp4ff_time_scale(Result.hMP4, Result.fTrack); Result.Bitrate := mp4ff_get_avg_bitrate(Result.hMP4, Result.fTrack); Result.Size := mp4ff_num_samples(Result.hMP4, Result.fTrack); // writeln('MP4OpenFile16'); if pBuf <> nil then begin bRet:= NeAACDecAudioSpecificConfig(pBuf, lwBufSize2, mp4ASC); // writeln('MP4OpenFile17'); if bRet <> 0 then Begin // unix x64, NeAACDecAudioSpecificConfig Fails correct read, // But if both previous SampleRates match, we'll use them... {$IFDEF unix}{$IFDEF CPU64} if Result.SampleRate = lwSampleRate then Begin mp4ASC.sbr_present_flag := 0; mp4ASC.samplingFrequency := lwSampleRate; End; {$ENDIF}{$ENDIF} End; // writeln('MP4OpenFile18'); mp4ff_free_decoder_config(pBuf); // writeln('MP4OpenFile19'); end; f := 1024.0; if mp4ASC.sbr_present_flag = 1 then f := f * 2.0; Result.TotalTime := Result.Size * (f-1.0) / mp4ASC.samplingFrequency; { ...End} Result.TotalSamples := Trunc(Result.TotalTime * mp4ASC.samplingFrequency); // writeln('MP4OpenFile20'); if mp4ASC.samplingFrequency > Result.SampleRate then Result.SampleRate:= mp4ASC.samplingFrequency; Result.Artist:= ''; iRet:= mp4ff_meta_get_writer(Result.hMP4, pID3); if iRet = 1 then Result.Artist:= pID3; Result.AlbumArtist:= ''; iRet:= mp4ff_meta_get_artist(Result.hMP4, pID3); if iRet = 1 then Result.AlbumArtist:= pID3; Result.Album:= ''; iRet:= mp4ff_meta_get_album(Result.hMP4, pID3); if iRet = 1 then Result.Album:= pID3; Result.Title:= ''; iRet:= mp4ff_meta_get_title(Result.hMP4, pID3); if iRet = 1 then Result.Title:= pID3; Result.Date:= ''; iRet:= mp4ff_meta_get_date(Result.hMP4, pID3); if iRet = 1 then Result.Date:= pID3; Result.Genre:= ''; iRet:= mp4ff_meta_get_genre(Result.hMP4, pID3); if iRet = 1 then Result.Genre:= pID3; Result.Track:= ''; iRet:= mp4ff_meta_get_track(Result.hMP4, pID3); if iRet = 1 then Result.Track:= pID3; Result.Comment:= ''; iRet:= mp4ff_meta_get_comment(Result.hMP4, pID3); if iRet = 1 then Result.Comment:= pID3; Result.Position := 0; Result.fBufStart := 0; Result.fBufEnd := 0; // writeln('MP4OpenFile End'); end; Procedure MP4CloseFile(var AACI: TAACInfo); Begin // writeln('MP4CloseFile1'); NeAACDecClose(AACI.pDecoder); sleep(50); // writeln('MP4CloseFile2'); mp4ff_close(AACI.hMP4); // writeln('MP4CloseFile3'); sleep(50); end; procedure MP4GetData(var AACI: TAACInfo; var Buffer: pcfloat; var Bytes: longword); var ReqBytes : longword; CurBufSize : longword; NewSampleBuf : Pointer; NewBytesRead : longword; NewBytesDecoded : longword; Function readNextSample(var audioBuf : pcfloat; var audioSize : longword): longword; Begin audioSize := 0; Result:= 0; audioBuf := nil; // writeln('readNextSample'); if AACI.Position > AACI.Size then Begin Result:= 0; Exit; end; Result := mp4ff_read_sample(AACI.hMP4, AACI.fTrack, AACI.Position, audioBuf, audioSize); Inc(AACI.Position); end; Function getNextChunk(var SampBuf : Pointer; var NBR : longword) : longword; Var pAB : pcfloat; iAB : longword; frameInfo: NeAACDecFrameInfo; Begin NBR:= 0; // writeln('getNextChunk'); Result:= 0; Result:= readNextSample(pAB, iAB); if Result = 0 then Exit; SampBuf := NeAACDecDecode(AACI.pDecoder, @frameInfo, pAB, iAB); if pAB <> nil then mp4ff_free_decoder_config(pAB); NBR:= frameInfo.samples * (AACI.BitsPerSample div 8); end; begin // writeln('MP4GetData1'); ReqBytes:= Bytes; // writeln('MP4GetDataBegin1-2'); CurBufSize:= AACI.fBufEnd - AACI.fBufStart; While ReqBytes > CurBufSize do Begin // writeln('MP4GetData31'); // We need to put more data into Buffer... // If We Have Left Over Data... if CurBufSize > 0 then Begin // Save Existing Left over data.. Move(AACI._Buf[AACI.fBufStart], AACI.BufTmp[0], CurBufSize); // Put Existing Data to Start of buffer... Move(AACI.BufTmp[0], AACI._Buf[0], CurBufSize); end; // writeln('MP4GetData32'); // because we reshuffled buffers, AACI.fBufStart is now 0 AACI.fBufStart:= 0; NewSampleBuf := nil; // Read next block of data NewBytesRead:= getNextChunk(NewSampleBuf, NewBytesDecoded); // writeln('MP4GetData322'); if NewBytesRead = 0 then begin Buffer := nil; Bytes := 0; Exit; end; // writeln('MP4GetData33'); // Append new data to buffer Move(NewSampleBuf^, AACI._Buf[CurBufSize], NewBytesDecoded); // Update current unprocessed data count CurBufSize:= CurBufSize + NewBytesDecoded; // writeln('MP4GetData34'); end; // writeln('MP4GetData4'); // set AACI.fBufEnd to last valid data byte in buffer AACI.fBufEnd:= CurBufSize; // writeln('MP4GetData5'); // If requested Byte count is more tha what we have, reduce requested count.. if Bytes > AACI.fBufEnd - AACI.fBufStart then Bytes := AACI.fBufEnd - AACI.fBufStart; // writeln('MP4GetData6'); // pass data back to calling function/procedure Buffer := @AACI._Buf[AACI.fBufStart]; // writeln('MP4GetData7'); Inc(AACI.fBufStart, Bytes); // writeln('MP4GetData8'); end; function MP4Seek(var AACI: TAACInfo; var SampleNum: longint) : Boolean; begin Result := False; if (AACI.Size = 0) or (AACI.TotalSamples = 0) then Exit; if SampleNum > AACI.TotalSamples then SampleNum := AACI.TotalSamples; AACI.Position:= Trunc(SampleNum / AACI.TotalSamples * AACI.Size); Result := True; end; procedure LoadNeAAC(NeAAC : AnsiString); var thelib: string; Begin if Length(NeAAC) = 0 then thelib := libaa else thelib := NeAAC; hNeAAC:= DynLibs.SafeLoadLibrary(PChar(thelib)); NeAACLoaded:= hNeAAC <> dynlibs.NilHandle; Pointer(NeAACDecGetErrorMessage) := GetProcAddress(hNeAAC, PChar('NeAACDecGetErrorMessage')); Pointer(NeAACDecGetCapabilities) := GetProcAddress(hNeAAC, PChar('NeAACDecGetCapabilities')); Pointer(NeAACDecOpen) := GetProcAddress(hNeAAC, PChar('NeAACDecOpen')); Pointer(NeAACDecGetCurrentConfiguration) := GetProcAddress(hNeAAC, PChar('NeAACDecGetCurrentConfiguration')); Pointer(NeAACDecSetConfiguration) := GetProcAddress(hNeAAC, PChar('NeAACDecSetConfiguration')); Pointer(NeAACDecInit) := GetProcAddress(hNeAAC, PChar('NeAACDecInit')); Pointer(NeAACDecInit2) := GetProcAddress(hNeAAC, PChar('NeAACDecInit2')); Pointer(NeAACDecPostSeekReset) := GetProcAddress(hNeAAC, PChar('NeAACDecPostSeekReset')); Pointer(NeAACDecClose) := GetProcAddress(hNeAAC, PChar('NeAACDecClose')); Pointer(NeAACDecDecode) := GetProcAddress(hNeAAC, PChar('NeAACDecDecode')); Pointer(NeAACDecDecode2) := GetProcAddress(hNeAAC, PChar('NeAACDecDecode2')); Pointer(NeAACDecPostSeekReset) := GetProcAddress(hNeAAC, PChar('NeAACDecPostSeekReset')); Pointer(NeAACDecAudioSpecificConfig) := GetProcAddress(hNeAAC, PChar('NeAACDecAudioSpecificConfig')); end; Procedure UnLoadNeAAC; Begin if NeAACLoaded then DynLibs.UnloadLibrary(hNeAAC); NeAACLoaded:= False; end; Function Is_NeAAC_Loaded : Boolean; Begin Result:= NeAACLoaded; end; ////////////////////////////// from mcwMP4FF.pas by Franklyn A. Harlow function GetAACTrack(infile : mp4ff_t) : Integer; var i, rc, numTracks : Integer; buff : pcfloat; buff_size : LongWord; mp4ASC : mp4AudioSpecificConfig; begin numTracks := mp4ff_total_tracks(infile); for i := 0 to numTracks - 1 do begin buff := nil; buff_size:=0; mp4ff_get_decoder_config(infile, i, buff, buff_size); if buff <> nil then begin rc := NeAACDecAudioSpecificConfig(buff, buff_size, mp4ASC); mp4ff_free_decoder_config(buff); if rc < 0 then continue; Result := i; Exit; end; end; Result := -1; end; procedure UnLoadMp4ff; begin if Mp4ffLoaded then DynLibs.UnloadLibrary(hMp4ff); Mp4ffLoaded := False; end; Function isMp4ffLoaded : Boolean; Begin Result:= Mp4ffLoaded; end; procedure Loadmp4ff(mp4ff : AnsiString); var thelib: string; begin if Mp4ffLoaded then Exit; if Length(mp4ff) = 0 then thelib := libm4 else thelib := mp4ff; hMp4ff := DynLibs.SafeLoadLibrary(PChar(thelib)); Mp4ffLoaded := hMp4ff <> dynlibs.NilHandle; // writeln('hMp4ff' + inttostr(hMp4ff)); Pointer(mp4ff_open_read) := GetProcAddress(hMp4ff, pchar('mp4ff_open_read')); // if Pointer(mp4ff_open_read) <> nil then // writeln('mp4ff_open_read OK') else // writeln('mp4ff_open_read NOT OK'); Pointer(mp4ff_open_read_metaonly) := GetProcAddress(hMp4ff, PChar('mp4ff_open_read_metaonly')); Pointer(mp4ff_close) := GetProcAddress(hMp4ff, PChar('mp4ff_close')); Pointer(mp4ff_get_sample_duration) := GetProcAddress(hMp4ff, PChar('mp4ff_get_sample_duration')); Pointer(mp4ff_get_sample_duration_use_offsets) := GetProcAddress(hMp4ff, PChar('mp4ff_get_sample_duration_use_offsets')); Pointer(mp4ff_get_sample_position) := GetProcAddress(hMp4ff, PChar('mp4ff_get_sample_position')); Pointer(mp4ff_get_sample_offset) := GetProcAddress(hMp4ff, PChar('mp4ff_get_sample_offset')); Pointer(mp4ff_find_sample) := GetProcAddress(hMp4ff, PChar('mp4ff_find_sample')); Pointer(mp4ff_find_sample_use_offsets) := GetProcAddress(hMp4ff, PChar('mp4ff_find_sample_use_offsets')); Pointer(mp4ff_set_sample_position) := GetProcAddress(hMp4ff, PChar('mp4ff_set_sample_position')); Pointer(mp4ff_read_sample) := GetProcAddress(hMp4ff, PChar('mp4ff_read_sample')); Pointer(mp4ff_read_sample_v2) := GetProcAddress(hMp4ff, PChar('mp4ff_read_sample_v2')); Pointer(mp4ff_read_sample_getsize) := GetProcAddress(hMp4ff, PChar('mp4ff_read_sample_getsize')); Pointer(mp4ff_get_sample_position) := GetProcAddress(hMp4ff, PChar('mp4ff_get_sample_position')); Pointer(mp4ff_get_sample_offset) := GetProcAddress(hMp4ff, PChar('mp4ff_get_sample_offset')); Pointer(mp4ff_find_sample) := GetProcAddress(hMp4ff, PChar('mp4ff_find_sample')); Pointer(mp4ff_get_decoder_config) := GetProcAddress(hMp4ff, PChar('mp4ff_get_decoder_config')); Pointer(mp4ff_get_track_type) := GetProcAddress(hMp4ff, PChar('mp4ff_get_track_type')); Pointer(mp4ff_total_tracks) := GetProcAddress(hMp4ff, PChar('mp4ff_total_tracks')); Pointer(mp4ff_num_samples) := GetProcAddress(hMp4ff, PChar('mp4ff_num_samples')); Pointer(mp4ff_time_scale) := GetProcAddress(hMp4ff, PChar('mp4ff_time_scale')); Pointer(mp4ff_get_avg_bitrate) := GetProcAddress(hMp4ff, PChar('mp4ff_get_avg_bitrate')); Pointer(mp4ff_get_max_bitrate) := GetProcAddress(hMp4ff, PChar('mp4ff_get_max_bitrate')); Pointer(mp4ff_get_track_duration) := GetProcAddress(hMp4ff, PChar('mp4ff_get_track_duration')); Pointer(mp4ff_get_track_duration_use_offsets) := GetProcAddress(hMp4ff, PChar('mp4ff_get_track_duration_use_offsets')); Pointer(mp4ff_get_sample_rate) := GetProcAddress(hMp4ff, PChar('mp4ff_get_sample_rate')); Pointer(mp4ff_get_channel_count) := GetProcAddress(hMp4ff, PChar('mp4ff_get_channel_count')); Pointer(mp4ff_get_audio_type) := GetProcAddress(hMp4ff, PChar('mp4ff_get_audio_type')); Pointer(mp4ff_free_decoder_config) := GetProcAddress(hMp4ff, PChar('mp4ff_free_decoder_config')); Pointer(mp4ff_meta_get_num_items) := GetProcAddress(hMp4ff, PChar('mp4ff_meta_get_num_items')); Pointer(mp4ff_meta_get_by_index) := GetProcAddress(hMp4ff, PChar('mp4ff_meta_get_by_index')); Pointer(mp4ff_meta_get_title) := GetProcAddress(hMp4ff, PChar('mp4ff_meta_get_title')); Pointer(mp4ff_meta_get_artist) := GetProcAddress(hMp4ff, PChar('mp4ff_meta_get_artist')); Pointer(mp4ff_meta_get_writer) := GetProcAddress(hMp4ff, PChar('mp4ff_meta_get_writer')); Pointer(mp4ff_meta_get_album) := GetProcAddress(hMp4ff, PChar('mp4ff_meta_get_album')); Pointer(mp4ff_meta_get_date) := GetProcAddress(hMp4ff, PChar('mp4ff_meta_get_date')); Pointer(mp4ff_meta_get_tool) := GetProcAddress(hMp4ff, PChar('mp4ff_meta_get_tool')); Pointer(mp4ff_meta_get_comment) := GetProcAddress(hMp4ff, PChar('mp4ff_meta_get_comment')); Pointer(mp4ff_meta_get_genre) := GetProcAddress(hMp4ff, PChar('mp4ff_meta_get_genre')); Pointer(mp4ff_meta_get_track) := GetProcAddress(hMp4ff, PChar('mp4ff_meta_get_track')); Pointer(mp4ff_meta_get_disc) := GetProcAddress(hMp4ff, PChar('mp4ff_meta_get_disc')); Pointer(mp4ff_meta_get_totaltracks) := GetProcAddress(hMp4ff, PChar('mp4ff_meta_get_totaltracks')); Pointer(mp4ff_meta_get_totaldiscs) := GetProcAddress(hMp4ff, PChar('mp4ff_meta_get_totaldiscs')); Pointer(mp4ff_meta_get_compilation) := GetProcAddress(hMp4ff, PChar('mp4ff_meta_get_compilation')); Pointer(mp4ff_meta_get_tempo) := GetProcAddress(hMp4ff, PChar('mp4ff_meta_get_tempo')); Pointer(mp4ff_meta_get_coverart) := GetProcAddress(hMp4ff, PChar('mp4ff_meta_get_coverart')); end; initialization NeAACLoaded:= False; SetExceptionMask(GetExceptionMask + [exZeroDivide] + [exInvalidOp] + [exDenormalized] + [exOverflow] + [exPrecision]); finalization end.