aboutsummaryrefslogtreecommitdiffstats
path: root/Game
diff options
context:
space:
mode:
Diffstat (limited to 'Game')
-rw-r--r--Game/Code/Classes/UAudio_FFMpeg.pas998
1 files changed, 462 insertions, 536 deletions
diff --git a/Game/Code/Classes/UAudio_FFMpeg.pas b/Game/Code/Classes/UAudio_FFMpeg.pas
index b89fa00f..f050eaea 100644
--- a/Game/Code/Classes/UAudio_FFMpeg.pas
+++ b/Game/Code/Classes/UAudio_FFMpeg.pas
@@ -36,36 +36,6 @@ uses Classes,
ULog,
UMusic;
-type
- TPacketQueue = record
- first_pkt ,
- last_pkt : pAVPacketList;
- nb_packets : integer;
- size : integer;
- mutex : pSDL_mutex;
- cond : pSDL_cond;
- end;
- pPacketQueue = ^TPacketQueue;
-
- function packet_queue_put(var aPacketQueue : TPacketQueue; var AVPacket : TAVPacket): integer;
- function packet_queue_get(var aPacketQueue : TPacketQueue; var AVPacket : TAVPacket; block : integer ): integer;
- procedure packet_queue_init( var aPacketQueue : TPacketQueue );
- procedure audio_callback( userdata: Pointer; stream: PUInt8; len: Integer ); cdecl;
- function audio_decode_frame(aCodecCtx : TAVCodecContext; aAudio_buf : PUInt8; buf_size: integer): integer;
-
-var
- singleton_MusicFFMpeg : IAudioPlayback = nil;
-
-var
- audioq : TPacketQueue;
- quit : integer = 0;
-// faudio_buf : array[ 0 .. 0 ] of byte; //pUInt8{$ifndef fpc};{$else} = nil;{$endif}
-// audio_buf : array[ 0 .. AVCODEC_MAX_AUDIO_FRAME_SIZE ] of byte; //pUInt8{$ifndef fpc};{$else} = nil;{$endif}
-
-type
- Taudiobuff = array[ 0 .. AVCODEC_MAX_AUDIO_FRAME_SIZE-1 ] of byte;
- PAudioBuff = ^Taudiobuff;
-
implementation
uses
@@ -73,55 +43,104 @@ uses
lclintf,
libc,
{$ENDIF}
-// URecord,
UIni,
UMain,
UThemes;
-//var
-// singleton_MusicFFMpeg : IAudioPlayback = nil;
+type
+ PPacketQueue = ^TPacketQueue;
+ TPacketQueue = class
+ private
+ firstPkt,
+ lastPkt : PAVPacketList;
+ nbPackets : integer;
+ size : integer;
+ mutex : PSDL_Mutex;
+ cond : PSDL_Cond;
+ quit : boolean;
-const
- RecordSystem = 1;
- SDL_AUDIO_BUFFER_SIZE = 1024;
-
+ public
+ constructor Create();
+
+ function Put(pkt : PAVPacket): integer;
+ function Get(var pkt: TAVPacket; block: boolean): integer;
+ end;
type
- TMPModes = (mpNotReady, mpStopped, mpPlaying, mpRecording, mpSeeking, mpPaused, mpOpen);
+ TStreamStatus = (sNotReady, sStopped, sPlaying, sSeeking, sPaused, sOpen);
+const
+ StreamStatusStr: array[TStreamStatus] of string = ('Not ready', 'Stopped', 'Playing', 'Seeking', 'Paused', 'Open');
+type
+ PAudioBuffer = ^TAudioBuffer;
+ TAudioBuffer = array[0 .. (AVCODEC_MAX_AUDIO_FRAME_SIZE * 3 div 2)-1] of byte;
const
- ModeStr: array[TMPModes] of string = ('Not ready', 'Stopped', 'Playing', 'Recording', 'Seeking', 'Paused', 'Open');
+ SDL_AUDIO_BUFFER_SIZE = 1024;
+
+type
+ TFFMpegOutputStream = class(TAudioOutputStream)
+ private
+ parseThread: PSDL_Thread;
+ packetQueue: TPacketQueue;
+
+ status: TStreamStatus;
+
+ // FFMpeg internal data
+ pFormatCtx : PAVFormatContext;
+ pCodecCtx : PAVCodecContext;
+ pCodec : PAVCodec;
+ ffmpegStreamID : Integer;
+ ffmpegStream : PAVStream;
+
+ // static vars for AudioDecodeFrame
+ pkt : TAVPacket;
+ audio_pkt_data : PChar;
+ audio_pkt_size : integer;
+
+ // static vars for AudioCallback
+ audio_buf_index : cardinal;
+ audio_buf_size : cardinal;
+ audio_buf : TAudioBuffer;
+ public
+ constructor Create(); overload;
+ constructor Create(pFormatCtx: PAVFormatContext;
+ pCodecCtx: PAVCodecContext; pCodec: PAVCodec;
+ ffmpegStreamID : Integer; ffmpegStream: PAVStream); overload;
+ procedure Play();
+ procedure Pause();
+ procedure Stop();
+ procedure Close();
+ function AudioDecodeFrame(buffer : PUInt8; bufSize: integer): integer;
+ end;
type
- TAudio_ffMpeg = class( TInterfacedObject, IAudioPlayback )
+ TAudio_FFMpeg = class( TInterfacedObject, IAudioPlayback )
private
-
- BassStart: hStream;
- BassBack: hStream;
- BassSwoosh: hStream;
- BassChange: hStream;
- BassOption: hStream;
- BassClick: hStream;
- BassDrum: hStream;
- BassHihat: hStream;
- BassClap: hStream;
- BassShuffle: hStream;
+ MusicStream: TFFMpegOutputStream;
+
+ StartSoundStream: TFFMpegOutputStream;
+ BackSoundStream: TFFMpegOutputStream;
+ SwooshSoundStream: TFFMpegOutputStream;
+ ChangeSoundStream: TFFMpegOutputStream;
+ OptionSoundStream: TFFMpegOutputStream;
+ ClickSoundStream: TFFMpegOutputStream;
+ DrumSoundStream: TFFMpegOutputStream;
+ HihatSoundStream: TFFMpegOutputStream;
+ ClapSoundStream: TFFMpegOutputStream;
+ ShuffleSoundStream: TFFMpegOutputStream;
//Custom Sounds
CustomSounds: array of TCustomSoundEntry;
Loaded: boolean;
Loop: boolean;
- fHWND: THandle;
- function find_stream_ids( const aFormatCtx : PAVFormatContext; Out aFirstVideoStream, aFirstAudioStream : integer ): boolean;
+ function FindAudioStreamID(pFormatCtx : PAVFormatContext): integer;
public
-// Bass: hStream;
- constructor create();
function GetName: String;
procedure InitializePlayback;
procedure SetVolume(Volume: integer);
@@ -148,105 +167,120 @@ type
procedure PlayClap;
procedure PlayShuffle;
procedure StopShuffle;
-// procedure CaptureStart;
-// procedure CaptureStop;
-// procedure CaptureCard(RecordI, PlayerLeft, PlayerRight: byte);
- procedure StopCard(Card: byte);
- function LoadSoundFromFile(var hStream: hStream; Name: string): boolean;
+
+ function LoadSoundFromFile(Name: string): TFFMpegOutputStream;
//Equalizer
function GetFFTData: TFFTData;
+ // Interface for Visualizer
+ function GetPCMData(var data: TPCMData): Cardinal;
+
//Custom Sounds
function LoadCustomSound(const Filename: String): Cardinal;
procedure PlayCustomSound(const Index: Cardinal );
-end;
+ end;
-constructor TAudio_ffMpeg.create();
+var
+ singleton_MusicFFMpeg : IAudioPlayback = nil;
+
+
+function ParseAudio(data: Pointer): integer; cdecl; forward;
+procedure AudioCallback( userdata: Pointer; stream: PUInt8; len: Integer ); cdecl; forward;
+
+constructor TFFMpegOutputStream.Create();
begin
-// writeln( 'UVideo_FFMpeg - av_register_all' );
- av_register_all;
+ inherited;
+
+ packetQueue := TPacketQueue.Create();
+
+ FillChar(pkt, sizeof(TAVPacket), #0);
+
+ status := sStopped;
+
+ audio_pkt_data := nil;
+ audio_pkt_size := 0;
+
+ audio_buf_index := 0;
+ audio_buf_size := 0;
end;
-function TAudio_ffMpeg.find_stream_ids( const aFormatCtx : PAVFormatContext; Out aFirstVideoStream, aFirstAudioStream : integer ): boolean;
-var
- i : integer;
- st : pAVStream;
+constructor TFFMpegOutputStream.Create(pFormatCtx: PAVFormatContext;
+ pCodecCtx: PAVCodecContext; pCodec: PAVCodec;
+ ffmpegStreamID : Integer; ffmpegStream: PAVStream);
begin
- // Find the first video stream
- aFirstAudioStream := -1;
- aFirstVideoStream := -1;
+ Create();
+ Self.pFormatCtx := pFormatCtx;
+ Self.pCodecCtx := pCodecCtx;
+ Self.pCodec := pCodec;
+ Self.ffmpegStreamID := ffmpegStreamID;
+ Self.ffmpegStream := ffmpegStream;
+end;
- i := 0;
- while ( i < aFormatCtx.nb_streams ) do
+procedure TFFMpegOutputStream.Play();
+begin
+ writeln('Play request');
+ if(status = sStopped) then
begin
-// writeln( ' aFormatCtx.streams[i] : ' + inttostr( i ) );
- st := aFormatCtx.streams[i];
+ writeln('Play ok');
+ status := sPlaying;
+ Self.parseThread := SDL_CreateThread(@ParseAudio, Self);
+ SDL_PauseAudio(0);
+ end;
+end;
- if(st.codec.codec_type = CODEC_TYPE_VIDEO ) AND
- (aFirstVideoStream < 0) THEN
- begin
-// writeln( 'Found Video Stream' );
- aFirstVideoStream := i;
- end;
+procedure TFFMpegOutputStream.Pause();
+begin
+end;
- if ( st.codec.codec_type = CODEC_TYPE_AUDIO ) AND
- ( aFirstAudioStream < 0) THEN
- begin
-// writeln( 'Found Audio Stream' );
- aFirstAudioStream := i;
- end;
+procedure TFFMpegOutputStream.Stop();
+begin
+end;
- inc( i );
- end; // while
+procedure TFFMpegOutputStream.Close();
+begin
+ // Close the codec
+ avcodec_close(pCodecCtx);
- result := (aFirstAudioStream > -1) OR
- (aFirstVideoStream > -1) ; // Didn't find any streams stream
+ // Close the video file
+ av_close_input_file(pFormatCtx);
end;
-function TAudio_ffMpeg.GetName: String;
+function TAudio_FFMpeg.GetName: String;
begin
result := 'FFMpeg';
end;
-procedure TAudio_ffMpeg.InitializePlayback;
-var
-// Pet: integer;
- S: integer;
+procedure TAudio_FFMpeg.InitializePlayback;
begin
+ Log.LogStatus('InitializePlayback', 'UAudio_FFMpeg');
-// LoadSoundFromFile(BassStart, SoundPath + 'Green Day - American Idiot.mp3');
-
-(*
- LoadSoundFromFile(BassStart, SoundPath + 'Common start.mp3');
- LoadSoundFromFile(BassBack, SoundPath + 'Common back.mp3');
- LoadSoundFromFile(BassSwoosh, SoundPath + 'menu swoosh.mp3');
- LoadSoundFromFile(BassChange, SoundPath + 'select music change music 50.mp3');
- LoadSoundFromFile(BassOption, SoundPath + 'option change col.mp3');
- LoadSoundFromFile(BassClick, SoundPath + 'rimshot022b.mp3');
-
- LoadSoundFromFile(BassDrum, SoundPath + 'bassdrumhard076b.mp3');
- LoadSoundFromFile(BassHihat, SoundPath + 'hihatclosed068b.mp3');
- LoadSoundFromFile(BassClap, SoundPath + 'claps050b.mp3');
-*)
+ Loaded := false;
+ Loop := false;
-// LoadSoundFromFile(BassShuffle, SoundPath + 'Shuffle.mp3');
+ av_register_all();
+ SDL_Init(SDL_INIT_AUDIO);
-// Log.BenchmarkEnd(4);
-// Log.LogBenchmark('--> Loading Sounds', 4);
+ StartSoundStream := LoadSoundFromFile(SoundPath + 'Common Start.mp3');
+ {
+ BackSoundStream := LoadSoundFromFile(SoundPath + 'Common Back.mp3');
+ SwooshSoundStream := LoadSoundFromFile(SoundPath + 'menu swoosh.mp3');
+ ChangeSoundStream := LoadSoundFromFile(SoundPath + 'select music change music 50.mp3');
+ OptionSoundStream := LoadSoundFromFile(SoundPath + 'option change col.mp3');
+ ClickSoundStream := LoadSoundFromFile(SoundPath + 'rimshot022b.mp3');
+ }
+// DrumSoundStream := LoadSoundFromFile(SoundPath + 'bassdrumhard076b.mp3');
+// HihatSoundStream := LoadSoundFromFile(SoundPath + 'hihatclosed068b.mp3');
+// ClapSoundStream := LoadSoundFromFile(SoundPath + 'claps050b.mp3');
+// ShuffleSoundStream := LoadSoundFromFile(SoundPath + 'Shuffle.mp3');
end;
-procedure TAudio_ffMpeg.SetVolume(Volume: integer);
+procedure TAudio_FFMpeg.SetVolume(Volume: integer);
begin
- //Old Sets Wave Volume
- //BASS_SetVolume(Volume);
//New: Sets Volume only for this Application
-
-
- // TODO : jb_linux replace with something other than bass
(*
BASS_SetConfig(BASS_CONFIG_GVOL_SAMPLE, Volume);
BASS_SetConfig(BASS_CONFIG_GVOL_STREAM, Volume);
@@ -254,7 +288,7 @@ begin
*)
end;
-procedure TAudio_ffMpeg.SetMusicVolume(Volume: Integer);
+procedure TAudio_FFMpeg.SetMusicVolume(Volume: Integer);
begin
//Max Volume Prevention
if Volume > 100 then
@@ -265,112 +299,102 @@ begin
//Set Volume
- // TODO : jb_linux replace with something other than bass
// BASS_ChannelSetAttributes (Bass, -1, Volume, -101);
end;
-procedure TAudio_ffMpeg.SetLoop(Enabled: boolean);
+procedure TAudio_FFMpeg.SetLoop(Enabled: boolean);
begin
Loop := Enabled;
end;
-function TAudio_ffMpeg.Open(Name: string): boolean;
+function TAudio_FFMpeg.Open(Name: string): boolean;
begin
Loaded := false;
if FileExists(Name) then
begin
- // TODO : jb_linux replace with something other than bass
// Bass := Bass_StreamCreateFile(false, pchar(Name), 0, 0, 0);
-
+
Loaded := true;
//Set Max Volume
-// SetMusicVolume (100);
+ SetMusicVolume (100);
end;
Result := Loaded;
end;
-procedure TAudio_ffMpeg.Rewind;
+procedure TAudio_FFMpeg.Rewind;
begin
if Loaded then
begin
end;
end;
-procedure TAudio_ffMpeg.MoveTo(Time: real);
+procedure TAudio_FFMpeg.MoveTo(Time: real);
var
bytes: integer;
begin
- // TODO : jb_linux replace with something other than bass
// bytes := BASS_ChannelSeconds2Bytes(Bass, Time);
// BASS_ChannelSetPosition(Bass, bytes);
end;
-procedure TAudio_ffMpeg.Play;
+procedure TAudio_FFMpeg.Play;
begin
-(*
- // TODO : jb_linux replace with something other than bass
+ if MusicStream <> nil then
if Loaded then
begin
if Loop then
- BASS_ChannelPlay(Bass, True); // start from beginning... actually bass itself does not loop, nor does this TAudio_ffMpeg Class
-
- BASS_ChannelPlay(Bass, False); // for setting position before playing
+ begin
+ end;
+ // start from beginning...
+ // actually bass itself does not loop, nor does this TAudio_FFMpeg Class
+ MusicStream.Play();
end;
-*)
end;
-procedure TAudio_ffMpeg.Pause; //Pause Mod
+procedure TAudio_FFMpeg.Pause; //Pause Mod
begin
-(*
- // TODO : jb_linux replace with something other than bass
+ if MusicStream <> nil then
if Loaded then begin
- BASS_ChannelPause(Bass); // Pauses Song
+ MusicStream.Pause(); // Pauses Song
end;
-*)
end;
-procedure TAudio_ffMpeg.Stop;
+procedure TAudio_FFMpeg.Stop;
begin
-// Bass_ChannelStop(Bass);
+ if MusicStream <> nil then
+ MusicStream.Stop();
end;
-procedure TAudio_ffMpeg.Close;
+procedure TAudio_FFMpeg.Close;
begin
-// Bass_StreamFree(Bass);
+ if MusicStream <> nil then
+ MusicStream.Close();
end;
-function TAudio_ffMpeg.Length: real;
+function TAudio_FFMpeg.Length: real;
var
- bytes: integer;
+ bytes: integer;
begin
- Result := 60;
-(*
- // TODO : jb_linux replace with something other than bass
- bytes := BASS_ChannelGetLength(Bass);
- Result := BASS_ChannelBytes2Seconds(Bass, bytes);
-*)
+ Result := MusicStream.pFormatCtx^.duration / AV_TIME_BASE;
end;
-function TAudio_ffMpeg.getPosition: real;
+function TAudio_FFMpeg.getPosition: real;
var
- bytes: integer;
+ bytes: integer;
begin
Result := 0;
(*
- // TODO : jb_linux replace with something other than bass
bytes := BASS_ChannelGetPosition(BASS);
Result := BASS_ChannelBytes2Seconds(BASS, bytes);
*)
end;
-function TAudio_ffMpeg.Finished: boolean;
+function TAudio_FFMpeg.Finished: boolean;
begin
Result := false;
(*
- // TODO : jb_linux replace with something other than bass
if BASS_ChannelIsActive(BASS) = BASS_ACTIVE_STOPPED then
begin
Result := true;
@@ -378,215 +402,166 @@ begin
*)
end;
-procedure TAudio_ffMpeg.PlayStart;
+procedure TAudio_FFMpeg.PlayStart;
begin
- // LoadSoundFromFile(BassStart, SoundPath + 'foo fighters - best of you.mp3');
-
- // TODO : jb_linux replace with something other than bass
-// BASS_ChannelPlay(BassStart, True);
+ if StartSoundStream <> nil then
+ StartSoundStream.Play();
end;
-procedure TAudio_ffMpeg.PlayBack;
+procedure TAudio_FFMpeg.PlayBack;
begin
- // TODO : jb_linux replace with something other than bass
-// BASS_ChannelPlay(BassBack, True);// then
+ if BackSoundStream <> nil then
+ BackSoundStream.Play();
end;
-procedure TAudio_ffMpeg.PlaySwoosh;
+procedure TAudio_FFMpeg.PlaySwoosh;
begin
- // TODO : jb_linux replace with something other than bass
-// BASS_ChannelPlay(BassSwoosh, True);
-
-
+ if SwooshSoundStream <> nil then
+ SwooshSoundStream.Play();
end;
-procedure TAudio_ffMpeg.PlayChange;
+procedure TAudio_FFMpeg.PlayChange;
begin
- // TODO : jb_linux replace with something other than bass
-// BASS_ChannelPlay(BassChange, True);
+ if ChangeSoundStream <> nil then
+ ChangeSoundStream.Play();
end;
-procedure TAudio_ffMpeg.PlayOption;
+procedure TAudio_FFMpeg.PlayOption;
begin
- // TODO : jb_linux replace with something other than bass
-// BASS_ChannelPlay(BassOption, True);
+ if OptionSoundStream <> nil then
+ OptionSoundStream.Play();
end;
-procedure TAudio_ffMpeg.PlayClick;
+procedure TAudio_FFMpeg.PlayClick;
begin
- // TODO : jb_linux replace with something other than bass
-// BASS_ChannelPlay(BassClick, True);
+ if ClickSoundStream <> nil then
+ ClickSoundStream.Play();
end;
-procedure TAudio_ffMpeg.PlayDrum;
+procedure TAudio_FFMpeg.PlayDrum;
begin
- // TODO : jb_linux replace with something other than bass
-// BASS_ChannelPlay(BassDrum, True);
+ if DrumSoundStream <> nil then
+ DrumSoundStream.Play();
end;
-procedure TAudio_ffMpeg.PlayHihat;
+procedure TAudio_FFMpeg.PlayHihat;
begin
- // TODO : jb_linux replace with something other than bass
-// BASS_ChannelPlay(BassHihat, True);
+ if HihatSoundStream <> nil then
+ HihatSoundStream.Play();
end;
-procedure TAudio_ffMpeg.PlayClap;
+procedure TAudio_FFMpeg.PlayClap;
begin
- // TODO : jb_linux replace with something other than bass
-// BASS_ChannelPlay(BassClap, True);
+ if ClapSoundStream <> nil then
+ ClapSoundStream.Play();
end;
-procedure TAudio_ffMpeg.PlayShuffle;
+procedure TAudio_FFMpeg.PlayShuffle;
begin
- // TODO : jb_linux replace with something other than bass
-// BASS_ChannelPlay(BassShuffle, True);
+ if ShuffleSoundStream <> nil then
+ ShuffleSoundStream.Play();
end;
-procedure TAudio_ffMpeg.StopShuffle;
+procedure TAudio_FFMpeg.StopShuffle;
begin
- // TODO : jb_linux replace with something other than bass
-// BASS_ChannelStop(BassShuffle);
+ if ShuffleSoundStream <> nil then
+ ShuffleSoundStream.Stop();
end;
-procedure TAudio_ffMpeg.StopCard(Card: byte);
-begin
-
- // TODO : jb_linux replace with something other than bass
-// BASS_RecordSetDevice(Card);
-// BASS_RecordFree;
-end;
-
-function audio_decode_frame(aCodecCtx : TAVCodecContext; aAudio_buf : PUInt8; buf_size: integer): integer;
+function TFFMpegOutputStream.AudioDecodeFrame(buffer : PUInt8; bufSize: integer): integer;
var
- pkt : TAVPacket;
- audio_pkt_data : pchar;//PUInt8 = nil;
- audio_pkt_size : integer;
- len1 ,
- data_size : integer;
+ len1,
+ data_size: integer;
begin
result := -1;
-(*
- {$ifdef win32}
- FillChar(pkt, sizeof(TAVPacket), #0);
- {$else}
- memset(@pkt, 0, sizeof(TAVPacket)); // todo : jb memset
- {$endif}
-
- audio_pkt_data := nil;
- audio_pkt_size := 0;
+ if (buffer = nil) then
+ exit;
while true do
- begin
-
- while ( audio_pkt_size > 0 ) do
+ begin
+ while (audio_pkt_size > 0) do
begin
// writeln( 'got audio packet' );
- data_size := buf_size;
-
- len1 := -1;
+ data_size := bufSize;
- if aAudio_buf <> nil then
- begin
- len1 := avcodec_decode_audio(@aCodecCtx, Pointer( aAudio_buf ), data_size, audio_pkt_data, audio_pkt_size); // Todo.. should be avcodec_decode_audio2 but this wont link on my ubuntu box.
- end;
+ // TODO: should be avcodec_decode_audio2 but this wont link on my ubuntu box.
+ len1 := avcodec_decode_audio(pCodecCtx, Pointer(buffer),
+ data_size, audio_pkt_data, audio_pkt_size);
-// writeln('avcodec_decode_audio : ' + inttostr( len1 ));
+ writeln('avcodec_decode_audio : ' + inttostr( len1 ));
if(len1 < 0) then
begin
- //* if error, skip frame */
- writeln( 'Skip audio frame' );
+ // if error, skip frame
+// writeln( 'Skip audio frame' );
audio_pkt_size := 0;
break;
end;
-
+
audio_pkt_data := audio_pkt_data + len1;
audio_pkt_size := audio_pkt_size + len1;
-
+
if (data_size <= 0) then
begin
- //* No data yet, get more frames */
+ // No data yet, get more frames
continue;
end;
-
- //* We have data, return it and come back for more later */
+
+ // We have data, return it and come back for more later
result := data_size;
exit;
end;
- if ( pkt.data <> nil ) then
- av_free_packet( pkt );
+ if (pkt.data <> nil) then
+ av_free_packet(pkt);
- if ( quit <> 0 ) then
+ if (packetQueue.quit) then
begin
result := -1;
exit;
end;
- if (packet_queue_get(audioq, pkt, 1) < 0) then
+ if (packetQueue.Get(pkt, true) < 0) then
begin
result := -1;
exit;
end;
-
- audio_pkt_data := pchar( pkt.data );
+ audio_pkt_data := PChar(pkt.data);
audio_pkt_size := pkt.size;
// writeln( 'Audio Packet Size - ' + inttostr(audio_pkt_size) );
- end; *)
+ end;
end;
-procedure audio_callback( userdata: Pointer; stream: PUInt8; len: Integer );
+procedure AudioCallback(userdata: Pointer; stream: PUInt8; len: Integer); cdecl;
var
- audio_buf_index : cardinal; // static unsigned int audio_buf_index = 0;
- audio_buf_size : cardinal; // static unsigned int audio_buf_size = 0;
- audio_size ,
- len1 : integer;
- aCodecCtx : TAVCodecContext;
-
- lSrc : pointer;
-
- // this is used to emulate ...... static uint8_t audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
- lAudio_buf_data : Taudiobuff; // This created the memory we need
- laudio_buf : PAudioBuff; // this makes it easy to work with.. since its the pointer to that memeory everywhere
+ outStream : TFFMpegOutputStream;
+ len1,
+ audio_size : integer;
+ pSrc : Pointer;
begin
- laudio_buf := @lAudio_buf_data ;
-
- aCodecCtx := pAVCodecContext(userdata)^;
- audio_size := -1;
- audio_buf_index := 0;
- audio_buf_size := 0;
+ outStream := TFFMpegOutputStream(userdata);
while (len > 0) do
- begin
-
+ with outStream do begin
if (audio_buf_index >= audio_buf_size) then
begin
+ // We have already sent all our data; get more
+ audio_size := AudioDecodeFrame(@audio_buf, sizeof(TAudioBuffer));
+ writeln('audio_decode_frame : '+ inttostr(audio_size));
- // We have already sent all our data; get more */
- audio_size := audio_decode_frame(aCodecCtx, pUInt8( laudio_buf ), sizeof(Taudiobuff));
- writeln( 'audio_decode_frame : ' + inttostr( audio_size ) + ' / ' + inttostr( sizeof(Taudiobuff) ) );
-
- if(audio_size > 0) then
+ if(audio_size < 0) then
begin
- audio_buf_size := audio_size;
+ // If error, output silence
+ audio_buf_size := 1024;
+ FillChar(audio_buf, audio_buf_size, #0);
+ writeln( 'Silence' );
end
else
begin
- // If error, output silence */
-
-// audio_buf_size := 1024; // arbitrary?
-
-// {$ifdef win32}
-// FillChar(laudio_buf, audio_buf_size, #0);
-// {$else}
-// memset(laudio_buf, 0, audio_buf_size); // todo : jb memset
-// {$endif}
-
- writeln( 'Silence' );
+ audio_buf_size := audio_size;
end;
-
audio_buf_index := 0; // Todo : jb - SegFault ?
end;
@@ -594,354 +569,305 @@ begin
if (len1 > len) then
len1 := len;
- lSrc := PUInt8( integer( laudio_buf ) + audio_buf_index );
+ pSrc := PChar(@audio_buf) + audio_buf_index;
{$ifdef WIN32}
- CopyMemory(stream, lSrc , len1);
+ CopyMemory(stream, pSrc , len1);
{$else}
- memcpy(stream, lSrc , len1);
+ memcpy(stream, pSrc , len1);
{$endif}
- len := len - len1;
- stream^ := stream^ + len1;
- audio_buf_index := audio_buf_index + len1;
+ Dec(len, len1);
+ Inc(stream, len1);
+ Inc(audio_buf_index, len1);
end;
end;
-function TAudio_ffMpeg.LoadSoundFromFile(var hStream: hStream; Name: string): boolean;
+function TAudio_FFMpeg.FindAudioStreamID(pFormatCtx : PAVFormatContext): integer;
var
- L : Integer;
- pFormatCtx : PAVFormatContext;
- lVidStreamID ,
- lAudStreamID : Integer;
- aCodecCtx : pAVCodecContext;
- wanted_spec ,
- spec : TSDL_AudioSpec;
- lAudioStream : pAVStream;
- aCodec : pAVCodec;
- i : integer;
- packet : TAVPacket;
- event : TSDL_Event;
-begin
- result := false;
+ i : integer;
+ streamID: integer;
+ stream : PAVStream;
+begin
+ // Find the first audio stream
+ streamID := -1;
- if FileExists(Name) then
+ for i := 0 to pFormatCtx^.nb_streams-1 do
begin
- writeln('Loading Sound: "' + Name + '"', 'LoadSoundFromFile');
-
- // Open video file
- if (av_open_input_file(pFormatCtx, pchar(Name), nil, 0, nil) > 0) then
- exit;
+ //Log.LogStatus('aFormatCtx.streams[i] : ' + inttostr(i), 'UAudio_FFMpeg');
+ stream := pFormatCtx^.streams[i];
- // Retrieve stream information
- if (av_find_stream_info(pFormatCtx)<0) then
- exit;
-
- dump_format(pFormatCtx, 0, pchar(Name), 0);
-
- if not find_stream_ids( pFormatCtx, lVidStreamID, lAudStreamID ) then
- exit;
-
-// writeln( 'done searching for stream ids' );
-
- if lAudStreamID > -1 then
- begin
-// writeln( 'Audio Stream ID is : '+ inttostr( lAudStreamID ) );
-
- lAudioStream := pFormatCtx.streams[lAudStreamID];
- aCodecCtx := lAudioStream.codec;
-
- // Set audio settings from codec info
- wanted_spec.freq := aCodecCtx.sample_rate;
- wanted_spec.format := AUDIO_S16SYS;
- wanted_spec.channels := aCodecCtx.channels;
- wanted_spec.silence := 0;
- wanted_spec.samples := SDL_AUDIO_BUFFER_SIZE;
- wanted_spec.callback := audio_callback;
- wanted_spec.userdata := aCodecCtx;
- end;
-
- if (SDL_OpenAudio(@wanted_spec, @spec) < 0) then
- begin
- writeln('SDL_OpenAudio: '+SDL_GetError());
- exit
+ if ( stream.codec^.codec_type = CODEC_TYPE_AUDIO ) then
+ begin
+ Log.LogStatus('Found Audio Stream', 'UAudio_FFMpeg');
+ streamID := i;
+ break;
+ end;
end;
-// writeln( 'SDL opened audio device' );
-
- aCodec := avcodec_find_decoder(aCodecCtx.codec_id);
- if (aCodec = nil) then
- begin
- writeln('Unsupported codec!');
- exit;
- end;
+ result := streamID;
+end;
- avcodec_open(aCodecCtx, aCodec);
+function ParseAudio(data: Pointer): integer; cdecl;
+var
+ packet: TAVPacket;
+ stream: TFFMpegOutputStream;
+begin
+ stream := TFFMpegOutputStream(data);
-// writeln( 'Opened the codec' );
-
- packet_queue_init( audioq );
- SDL_PauseAudio(0);
-
-// writeln( 'SDL_PauseAudio' );
-
- i := 0;
- while (av_read_frame(pFormatCtx, packet) >= 0) do
+ while (av_read_frame(stream.pFormatCtx, packet) >= 0) do
begin
-// writeln( 'ffmpeg - av_read_frame' );
-
- if (packet.stream_index = lAudStreamID ) then
+ writeln( 'ffmpeg - av_read_frame' );
+
+ if (packet.stream_index = stream.ffmpegStreamID) then
begin
-// writeln( 'packet_queue_put' );
- packet_queue_put(audioq, packet);
+ //writeln( 'packet_queue_put' );
+ stream.packetQueue.put(@packet);
end
else
begin
av_free_packet(packet);
end;
+ end;
+ Writeln('Done: ' + inttostr(stream.packetQueue.nbPackets));
- // Free the packet that was allocated by av_read_frame
- SDL_PollEvent(@event);
+ result := 0;
+end;
-(*
- if event.type_ = SDL_QUIT the
- begin
- quit := 1;
- SDL_Quit();
- end
- else
- break;
-*)
+function TAudio_FFMpeg.LoadSoundFromFile(Name: string): TFFMpegOutputStream;
+var
+ pFormatCtx : PAVFormatContext;
+ pCodecCtx : PAVCodecContext;
+ pCodec : PAVCodec;
+ ffmpegStreamID : Integer;
+ ffmpegStream : PAVStream;
+ wanted_spec,
+ spec : TSDL_AudioSpec;
+ csIndex : integer;
+ stream : TFFMpegOutputStream;
+begin
+ result := nil;
+
+ if (not FileExists(Name)) then
+ begin
+ Log.LogStatus('LoadSoundFromFile: Sound not found "' + Name + '"', 'UAudio_FFMpeg');
+ exit;
end;
-
- writeln( 'Done filling buffer' );
-// halt(0);
+ // Open audio file
+ if (av_open_input_file(pFormatCtx, PChar(Name), nil, 0, nil) > 0) then
+ exit;
- // Close the codec
-// avcodec_close(aCodecCtx);
+ // Retrieve stream information
+ if (av_find_stream_info(pFormatCtx) < 0) then
+ exit;
- // Close the video file
-// av_close_input_file(pFormatCtx);
+ dump_format(pFormatCtx, 0, pchar(Name), 0);
-(*
- try
- // TODO : jb_linux replace with something other than bass
- hStream := BASS_StreamCreateFile(False, pchar(Name), 0, 0, 0);
-
- //Add CustomSound
- L := High(CustomSounds) + 1;
- SetLength (CustomSounds, L + 1);
- CustomSounds[L].Filename := Name;
- CustomSounds[L].Handle := hStream;
- except
- Log.LogError('Failed to open using BASS', 'LoadSoundFromFile');
- end;
-*)
-
- end
- else
+ ffmpegStreamID := FindAudioStreamID(pFormatCtx);
+ if (ffmpegStreamID < 0) then
+ exit;
+
+ //Log.LogStatus('Audio Stream ID is : '+ inttostr(ffmpegStreamID), 'UAudio_FFMpeg');
+
+ ffmpegStream := pFormatCtx.streams[ffmpegStreamID];
+ pCodecCtx := ffmpegStream^.codec;
+
+ pCodec := avcodec_find_decoder(pCodecCtx^.codec_id);
+ if (pCodec = nil) then
begin
- writeln('Sound not found: "' + Name + '"', 'LoadSoundFromFile');
+ Log.LogStatus('Unsupported codec!', 'UAudio_FFMpeg');
exit;
end;
+ avcodec_open(pCodecCtx, pCodec);
+ //writeln( 'Opened the codec' );
+
+ stream := TFFMpegOutputStream.Create(pFormatCtx, pCodecCtx, pCodec,
+ ffmpegStreamID, ffmpegStream);
+
+ // Set SDL audio settings from codec info
+ wanted_spec.freq := pCodecCtx^.sample_rate;
+ wanted_spec.format := AUDIO_S16SYS;
+ wanted_spec.channels := pCodecCtx^.channels;
+ wanted_spec.silence := 0;
+ wanted_spec.samples := SDL_AUDIO_BUFFER_SIZE;
+ wanted_spec.callback := AudioCallback;
+ wanted_spec.userdata := stream;
+
+ // TODO: this works only one time (?)
+ if (SDL_OpenAudio(@wanted_spec, @spec) < 0) then
+ begin
+ Log.LogStatus('SDL_OpenAudio: '+SDL_GetError(), 'UAudio_FFMpeg');
+ stream.Free();
+ exit
+ end;
+
+ Log.LogStatus('SDL opened audio device', 'UAudio_FFMpeg');
+
+ //Add CustomSound
+ csIndex := High(CustomSounds) + 1;
+ SetLength (CustomSounds, csIndex + 1);
+ CustomSounds[csIndex].Filename := Name;
+ CustomSounds[csIndex].Stream := stream;
+
+ result := stream;
end;
-procedure packet_queue_init(var aPacketQueue : TPacketQueue );
+//Equalizer
+function TAudio_FFMpeg.GetFFTData: TFFTData;
+var
+ data: TFFTData;
begin
- {$ifdef win32}
- FillChar(aPacketQueue, sizeof(TPacketQueue), #0);
- {$else}
- memset(@aPacketQueue, 0, sizeof(TPacketQueue));
- {$endif}
-
- aPacketQueue.mutex := SDL_CreateMutex();
- aPacketQueue.cond := SDL_CreateCond();
+ //Get Channel Data Mono and 256 Values
+// BASS_ChannelGetData(Bass, @Result, BASS_DATA_FFT512);
+ result := data;
+end;
+
+// Interface for Visualizer
+function TAudio_FFMpeg.GetPCMData(var data: TPCMData): Cardinal;
+begin
+ result := 0;
+end;
+
+function TAudio_FFMpeg.LoadCustomSound(const Filename: String): Cardinal;
+var
+ S: TFFMpegOutputStream;
+ I: Integer;
+ F: String;
+begin
+ //Search for Sound in already loaded Sounds
+ F := UpperCase(SoundPath + FileName);
+ For I := 0 to High(CustomSounds) do
+ begin
+ if (UpperCase(CustomSounds[I].Filename) = F) then
+ begin
+ Result := I;
+ Exit;
+ end;
+ end;
+
+ S := LoadSoundFromFile(SoundPath + Filename);
+ if (S <> nil) then
+ Result := High(CustomSounds)
+ else
+ Result := 0;
+end;
+
+procedure TAudio_FFMpeg.PlayCustomSound(const Index: Cardinal );
+begin
+ if Index <= High(CustomSounds) then
+ (CustomSounds[Index].Stream as TFFMpegOutputStream).Play();
end;
-function packet_queue_put(var aPacketQueue : TPacketQueue; var AVPacket : TAVPacket): integer;
+
+constructor TPacketQueue.Create();
+begin
+ inherited;
+
+ firstPkt := nil;
+ lastPkt := nil;
+ nbPackets := 0;
+ size := 0;
+
+ mutex := SDL_CreateMutex();
+ cond := SDL_CreateCond();
+end;
+
+function TPacketQueue.Put(pkt : PAVPacket): integer;
var
- pkt1 : pAVPacketList;
+ pkt1 : PAVPacketList;
begin
result := -1;
-
-// writeln( 'TAudio_ffMpeg.packet_queue_put' );
-
- if av_dup_packet(@AVPacket) < 0 then
+
+ if (av_dup_packet(pkt) < 0) then
exit;
pkt1 := av_malloc(sizeof(TAVPacketList));
if (pkt1 = nil) then
exit;
-
- pkt1.pkt := AVPacket;
- pkt1.next := nil;
+
+ pkt1^.pkt := pkt^;
+ pkt1^.next := nil;
- SDL_LockMutex( aPacketQueue.mutex );
+ SDL_LockMutex(Self.mutex);
try
- if (aPacketQueue.last_pkt = nil) then
- aPacketQueue.first_pkt := pkt1
+ if (Self.lastPkt = nil) then
+ Self.firstPkt := pkt1
else
- aPacketQueue.last_pkt.next := pkt1;
+ Self.lastPkt^.next := pkt1;
- aPacketQueue.last_pkt := pkt1;
- inc( aPacketQueue.nb_packets );
-
- aPacketQueue.size := aPacketQueue.size + pkt1.pkt.size;
- SDL_CondSignal(aPacketQueue.cond);
+ Self.lastPkt := pkt1;
+ inc(Self.nbPackets);
+
+ Writeln('Put: ' + inttostr(nbPackets));
+
+ Self.size := Self.size + pkt1^.pkt.size;
+ SDL_CondSignal(Self.cond);
finally
- SDL_UnlockMutex( aPacketQueue.mutex );
+ SDL_UnlockMutex(Self.mutex);
end;
result := 0;
end;
-function packet_queue_get(var aPacketQueue : TPacketQueue; var AVPacket : TAVPacket; block : integer ): integer;
+function TPacketQueue.Get(var pkt: TAVPacket; block: boolean): integer;
var
- pkt1 : pAVPacketList;
+ pkt1 : PAVPacketList;
begin
result := -1;
-// writeln( 'packet_queue_get' );
-
- SDL_LockMutex(aPacketQueue.mutex);
+
+ SDL_LockMutex(Self.mutex);
try
while true do
begin
-
- if (quit <> 0) then
+ if (quit) then
exit;
- pkt1 := aPacketQueue.first_pkt;
-
- if ( pkt1 <> nil ) then
+ pkt1 := Self.firstPkt;
+
+ if (pkt1 <> nil) then
begin
- aPacketQueue.first_pkt := pkt1.next;
-
- if (aPacketQueue.first_pkt = nil ) then
- aPacketQueue.last_pkt := nil;
-
- dec(aPacketQueue.nb_packets);
-
- aPacketQueue.size := aPacketQueue.size - pkt1.pkt.size;
-
- AVPacket := pkt1.pkt;
+ Self.firstPkt := pkt1.next;
+ if (Self.firstPkt = nil) then
+ Self.lastPkt := nil;
+ dec(Self.nbPackets);
+
+ Writeln('Get: ' + inttostr(nbPackets));
+ Self.size := Self.size - pkt1^.pkt.size;
+ pkt := pkt1^.pkt;
av_free(pkt1);
result := 1;
break;
end
else
- if (block = 0) then
+ if (not block) then
begin
result := 0;
break;
end
else
begin
- SDL_CondWait(aPacketQueue.cond, aPacketQueue.mutex);
+ SDL_CondWait(Self.cond, Self.mutex);
end;
end;
finally
- SDL_UnlockMutex(aPacketQueue.mutex);
- end;
-end;
-
-
-//Equalizer
-function TAudio_ffMpeg.GetFFTData: TFFTData;
-var
- Data: TFFTData;
-begin
- //Get Channel Data Mono and 256 Values
-// BASS_ChannelGetData(Bass, @Result, BASS_DATA_FFT512);
-end;
-
-function TAudio_ffMpeg.LoadCustomSound(const Filename: String): Cardinal;
-var
- S: hStream;
- I: Integer;
- F: String;
-begin
-(*
- //Search for Sound in already loaded Sounds
- F := UpperCase(SoundPath + FileName);
- For I := 0 to High(CustomSounds) do
- begin
- if (UpperCase(CustomSounds[I].Filename) = F) then
- begin
- Result := I;
- Exit;
- end;
+ SDL_UnlockMutex(Self.mutex);
end;
-
- if LoadSoundFromFile(S, SoundPath + Filename) then
- Result := High(CustomSounds)
- else
- Result := 0;
-*)
end;
-procedure TAudio_ffMpeg.PlayCustomSound(const Index: Cardinal );
-begin
-// if Index <= High(CustomSounds) then
-// BASS_ChannelPlay(CustomSounds[Index].Handle, True);
-end;
-
-
-{*
-
-Sorry guys... this is my mess :(
-Im going to try and get ffmpeg to handle audio playback ( at least for linux )
-and Im going to implement it nicly along side BASS, in TAudio_ffMpeg ( where I can )
-
-http://www.dranger.com/ffmpeg/ffmpeg.html
-http://www.dranger.com/ffmpeg/ffmpegtutorial_all.html
-
-http://www.inb.uni-luebeck.de/~boehme/using_libavcodec.html
-
-*}
-{*
-function TAudio_ffMpeg.FFMPeg_StreamCreateFile(abool : boolean; aFileName : pchar ): THandle;
-var
- lFormatCtx : PAVFormatContext;
-begin
-
-(*
- if(SDL_OpenAudio(&wanted_spec, &spec) < 0)
- begin
- fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError());
- writeln( 'SDL_OpenAudio' );
- exit;
- end;
-*)
-
-(*
- if ( av_open_input_file( lFormatCtx, aFileName, NULL, 0, NULL ) <> 0 )
- begin
- writeln( 'Unable to open file '+ aFileName );
- exit;
- end;
-
- // Retrieve stream information
- if ( av_find_stream_info(pFormatCtx) < 0 )
- begin
- writeln( 'Unable to Retrieve stream information' );
- exit;
- end;
-*)
-end; *}
initialization
- singleton_MusicFFMpeg := TAudio_ffMpeg.create();
+ singleton_MusicFFMpeg := TAudio_FFMpeg.create();
- writeln( 'UAudio_Bass - Register Playback' );
+ writeln( 'UAudio_FFMpeg - Register Playback' );
AudioManager.add( IAudioPlayback( singleton_MusicFFMpeg ) );
finalization