From 17d2f56fb988150dafcb6fab9dff45cc484e5b0a Mon Sep 17 00:00:00 2001 From: jaybinks Date: Fri, 26 Oct 2007 07:04:58 +0000 Subject: did some major work towards ffmpeg audio playback. still not working 100% needs code to be re-compared to original C Source because I Suspect there are some translation errors. git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@529 b956fd51-792f-4845-bead-9b4dfca2ff2c --- Game/Code/Classes/UAudio_FFMpeg.pas | 690 +++++++++++++++++++++++++----------- Game/Code/UltraStar.lpr | 14 +- 2 files changed, 487 insertions(+), 217 deletions(-) (limited to 'Game') diff --git a/Game/Code/Classes/UAudio_FFMpeg.pas b/Game/Code/Classes/UAudio_FFMpeg.pas index 959d904a..548fb343 100644 --- a/Game/Code/Classes/UAudio_FFMpeg.pas +++ b/Game/Code/Classes/UAudio_FFMpeg.pas @@ -1,5 +1,14 @@ unit UAudio_FFMpeg; +(******************************************************************************* + +This unit is primarily based upon - + http://www.dranger.com/ffmpeg/ffmpegtutorial_all.html + + and tutorial03.c + +*******************************************************************************) + interface {$IFDEF FPC} @@ -16,37 +25,76 @@ uses Classes, {$IFNDEF FPC} Forms, {$ENDIF} + avcodec, // FFMpeg Audio file decoding + avformat, + avutil, + SDL, // Used for Audio output Interface 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; audio_buf : PUInt8; buf_size: integer): integer; + +var + singleton_MusicFFMpeg : IAudioPlayback = nil; + + implementation uses {$IFDEF FPC} lclintf, {$ENDIF} - URecord, + libc, +// URecord, UIni, UMain, UThemes; +//var +// singleton_MusicFFMpeg : IAudioPlayback = nil; + + const RecordSystem = 1; + SDL_AUDIO_BUFFER_SIZE = 1024; + type - TMPModes = (mpNotReady, mpStopped, mpPlaying, mpRecording, mpSeeking, - mpPaused, mpOpen); + TMPModes = (mpNotReady, mpStopped, mpPlaying, mpRecording, mpSeeking, mpPaused, mpOpen); + + const ModeStr: array[TMPModes] of string = ('Not ready', 'Stopped', 'Playing', 'Recording', 'Seeking', 'Paused', 'Open'); +var + audioq : TPacketQueue; + quit : integer = 0; + + type TAudio_ffMpeg = class( TInterfacedObject, IAudioPlayback ) private - BassStart: hStream; // Wait, I've replaced this with BASS - BassBack: hStream; // It has almost all features we need + + BassStart: hStream; + BassBack: hStream; BassSwoosh: hStream; - BassChange: hStream; // Almost? It aleady has them all :) + BassChange: hStream; BassOption: hStream; BassClick: hStream; BassDrum: hStream; @@ -60,11 +108,12 @@ type Loop: boolean; fHWND: THandle; + function find_stream_ids( const aFormatCtx : PAVFormatContext; Out aFirstVideoStream, aFirstAudioStream : integer ): boolean; public - Bass: hStream; +// Bass: hStream; + constructor create(); function GetName: String; procedure InitializePlayback; - procedure InitializeRecord; procedure SetVolume(Volume: integer); procedure SetMusicVolume(Volume: integer); procedure SetLoop(Enabled: boolean); @@ -77,7 +126,7 @@ type procedure Close; function Finished: boolean; function Length: real; - function Position: real; + function getPosition: real; procedure PlayStart; procedure PlayBack; procedure PlaySwoosh; @@ -89,9 +138,9 @@ type procedure PlayClap; procedure PlayShuffle; procedure StopShuffle; - procedure CaptureStart; - procedure CaptureStop; - procedure CaptureCard(RecordI, PlayerLeft, PlayerRight: byte); +// procedure CaptureStart; +// procedure CaptureStop; +// procedure CaptureCard(RecordI, PlayerLeft, PlayerRight: byte); procedure StopCard(Card: byte); function LoadSoundFromFile(var hStream: hStream; Name: string): boolean; @@ -103,141 +152,83 @@ type procedure PlayCustomSound(const Index: Cardinal ); end; -var - singleton_MusicFFMpeg : IAudioPlayback; - -function TAudio_ffMpeg.GetName: String; +constructor TAudio_ffMpeg.create(); begin - result := 'FFMpeg'; + writeln( 'UVideo_FFMpeg - av_register_all' ); + av_register_all; end; -procedure TAudio_ffMpeg.InitializePlayback; +function TAudio_ffMpeg.find_stream_ids( const aFormatCtx : PAVFormatContext; Out aFirstVideoStream, aFirstAudioStream : integer ): boolean; var - Pet: integer; - S: integer; + i : integer; + st : pAVStream; begin - Log.BenchmarkStart(4); - Log.LogStatus('Initializing Playback Subsystem', 'Music Initialize'); - - Loaded := false; - Loop := false; + // Find the first video stream + aFirstAudioStream := -1; + aFirstVideoStream := -1; - {$ifdef win32} - // TODO : JB_Linux ... is this needed ? :) - fHWND := AllocateHWND( nil); // TODO : JB_lazarus - can we do something different here ?? lazarus didnt like this function - {$ENDIF} - - // TODO : jb_linux replace with something other than bass - if not BASS_Init(1, 44100, 0, fHWND, nil) then + i := 0; + while ( i < aFormatCtx.nb_streams ) do begin - {$IFNDEF FPC} - // TODO : JB_linux find a way to do this nice.. - Application.MessageBox ('Could not initialize BASS', 'Error'); - {$ENDIF} - Exit; - end; + writeln( ' aFormatCtx.streams[i] : ' + inttostr( i ) ); + st := aFormatCtx.streams[i]; - Log.BenchmarkEnd(4); Log.LogBenchmark('--> Bass Init', 4); + if(st.codec.codec_type = CODEC_TYPE_VIDEO ) AND + (aFirstVideoStream < 0) THEN + begin + writeln( 'Found Video Stream' ); + aFirstVideoStream := i; + end; - // config playing buffer -// BASS_SetConfig(BASS_CONFIG_UPDATEPERIOD, 10); -// BASS_SetConfig(BASS_CONFIG_BUFFER, 100); + if ( st.codec.codec_type = CODEC_TYPE_AUDIO ) AND + ( aFirstAudioStream < 0) THEN + begin + writeln( 'Found Audio Stream' ); + aFirstAudioStream := i; + end; - Log.LogStatus('Loading Sounds', 'Music Initialize'); + inc( i ); + end; // while - Log.BenchmarkStart(4); - 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'); + result := (aFirstAudioStream > -1) OR + (aFirstVideoStream > -1) ; // Didn't find any streams stream +end; -// LoadSoundFromFile(BassShuffle, SoundPath + 'Shuffle.mp3'); - Log.BenchmarkEnd(4); - Log.LogBenchmark('--> Loading Sounds', 4); +function TAudio_ffMpeg.GetName: String; +begin + result := 'FFMpeg'; end; -procedure TAudio_ffMpeg.InitializeRecord; +procedure TAudio_ffMpeg.InitializePlayback; var - S: integer; - device: integer; - descr: string; - input: integer; - input2: integer; - flags: integer; - mic: array[0..15] of integer; - SC: integer; // soundcard - SCI: integer; // soundcard input -begin - if RecordSystem = 1 then begin - SetLength(Sound, 6 {max players});//Ini.Players+1); - for S := 0 to High(Sound) do begin //Ini.Players do begin - Sound[S] := TSound.Create; - Sound[S].Num := S; - Sound[S].BufferNew := TMemoryStream.Create; - SetLength(Sound[S].BufferLong, 1); - Sound[S].BufferLong[0] := TMemoryStream.Create; - Sound[S].n := 4*1024; - end; - - - // check for recording devices; - {device := 0; - descr := BASS_RecordGetDeviceDescription(device); - - SetLength(SoundCard, 0); - while (descr <> '') do begin - SC := High(SoundCard) + 1; - SetLength(SoundCard, SC+1); - - Log.LogAnalyze('Device #'+IntToStr(device)+': '+ descr); - SoundCard[SC].Description := Descr; - - // check for recording inputs - mic[device] := -1; // default to no change - input := 0; - BASS_RecordInit(device); - Log.LogAnalyze('Input #' + IntToStr(Input) + ': ' + BASS_RecordGetInputName(input)); - flags := BASS_RecordGetInput(input); - - SetLength(SoundCard[SC].Input, 0); - while (flags <> -1) do begin - SCI := High(SoundCard[SC].Input) + 1; - SetLength(SoundCard[SC].Input, SCI+1); +// Pet: integer; + S: integer; +begin - Log.LogAnalyze('Input #' + IntToStr(Input) + ': ' + BASS_RecordGetInputName(input)); - SoundCard[SC].Input[SCI].Name := BASS_RecordGetInputName(Input); + LoadSoundFromFile(BassStart, SoundPath + 'foo fighters - best of you.mp3'); - if (flags and BASS_INPUT_TYPE_MASK) = BASS_INPUT_TYPE_MIC then begin - mic[device] := input; // auto set microphone - end; - Inc(Input); - flags := BASS_RecordGetInput(input); - end; +(* + 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'); - if mic[device] <> -1 then begin - Log.LogAnalyze('Found the mic at input ' + IntToStr(Mic[device])) - end else begin - Log.LogAnalyze('Mic not found'); - mic[device] := 0; // setting to the first one (for kxproject) - end; - SoundCard[SC].InputSeleceted := Mic[Device]; + LoadSoundFromFile(BassDrum, SoundPath + 'bassdrumhard076b.mp3'); + LoadSoundFromFile(BassHihat, SoundPath + 'hihatclosed068b.mp3'); + LoadSoundFromFile(BassClap, SoundPath + 'claps050b.mp3'); +*) +// LoadSoundFromFile(BassShuffle, SoundPath + 'Shuffle.mp3'); - BASS_RecordFree; +// Log.BenchmarkEnd(4); +// Log.LogBenchmark('--> Loading Sounds', 4); - inc(Device); - descr := BASS_RecordGetDeviceDescription(Device); - end; // while} - end; // if end; + procedure TAudio_ffMpeg.SetVolume(Volume: integer); begin //Old Sets Wave Volume @@ -246,9 +237,11 @@ begin // TODO : jb_linux replace with something other than bass +(* BASS_SetConfig(BASS_CONFIG_GVOL_SAMPLE, Volume); BASS_SetConfig(BASS_CONFIG_GVOL_STREAM, Volume); BASS_SetConfig(BASS_CONFIG_GVOL_MUSIC, Volume); +*) end; procedure TAudio_ffMpeg.SetMusicVolume(Volume: Integer); @@ -263,7 +256,7 @@ begin //Set Volume // TODO : jb_linux replace with something other than bass - BASS_ChannelSetAttributes (Bass, -1, Volume, -101); +// BASS_ChannelSetAttributes (Bass, -1, Volume, -101); end; procedure TAudio_ffMpeg.SetLoop(Enabled: boolean); @@ -277,11 +270,11 @@ begin if FileExists(Name) then begin // TODO : jb_linux replace with something other than bass - Bass := Bass_StreamCreateFile(false, pchar(Name), 0, 0, 0); +// Bass := Bass_StreamCreateFile(false, pchar(Name), 0, 0, 0); Loaded := true; //Set Max Volume - SetMusicVolume (100); +// SetMusicVolume (100); end; Result := Loaded; @@ -289,7 +282,8 @@ end; procedure TAudio_ffMpeg.Rewind; begin - if Loaded then begin + if Loaded then + begin end; end; @@ -298,12 +292,13 @@ var bytes: integer; begin // TODO : jb_linux replace with something other than bass - bytes := BASS_ChannelSeconds2Bytes(Bass, Time); - BASS_ChannelSetPosition(Bass, bytes); +// bytes := BASS_ChannelSeconds2Bytes(Bass, Time); +// BASS_ChannelSetPosition(Bass, bytes); end; procedure TAudio_ffMpeg.Play; begin +(* // TODO : jb_linux replace with something other than bass if Loaded then begin @@ -312,26 +307,27 @@ begin BASS_ChannelPlay(Bass, False); // for setting position before playing end; +*) end; procedure TAudio_ffMpeg.Pause; //Pause Mod begin +(* // TODO : jb_linux replace with something other than bass if Loaded then begin BASS_ChannelPause(Bass); // Pauses Song end; +*) end; procedure TAudio_ffMpeg.Stop; begin - // TODO : jb_linux replace with something other than bass - Bass_ChannelStop(Bass); +// Bass_ChannelStop(Bass); end; procedure TAudio_ffMpeg.Close; begin - // TODO : jb_linux replace with something other than bass - Bass_StreamFree(Bass); +// Bass_StreamFree(Bass); end; function TAudio_ffMpeg.Length: real; @@ -339,183 +335,344 @@ var bytes: integer; begin Result := 60; - +(* // TODO : jb_linux replace with something other than bass bytes := BASS_ChannelGetLength(Bass); Result := BASS_ChannelBytes2Seconds(Bass, bytes); +*) end; -function TAudio_ffMpeg.Position: real; +function TAudio_ffMpeg.getPosition: real; var 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; begin Result := false; +(* // TODO : jb_linux replace with something other than bass if BASS_ChannelIsActive(BASS) = BASS_ACTIVE_STOPPED then begin Result := true; end; +*) end; procedure TAudio_ffMpeg.PlayStart; begin // TODO : jb_linux replace with something other than bass - BASS_ChannelPlay(BassStart, True); +// BASS_ChannelPlay(BassStart, True); end; procedure TAudio_ffMpeg.PlayBack; begin // TODO : jb_linux replace with something other than bass - BASS_ChannelPlay(BassBack, True);// then +// BASS_ChannelPlay(BassBack, True);// then end; procedure TAudio_ffMpeg.PlaySwoosh; begin // TODO : jb_linux replace with something other than bass - BASS_ChannelPlay(BassSwoosh, True); +// BASS_ChannelPlay(BassSwoosh, True); + + end; procedure TAudio_ffMpeg.PlayChange; begin // TODO : jb_linux replace with something other than bass - BASS_ChannelPlay(BassChange, True); +// BASS_ChannelPlay(BassChange, True); end; procedure TAudio_ffMpeg.PlayOption; begin // TODO : jb_linux replace with something other than bass - BASS_ChannelPlay(BassOption, True); +// BASS_ChannelPlay(BassOption, True); end; procedure TAudio_ffMpeg.PlayClick; begin // TODO : jb_linux replace with something other than bass - BASS_ChannelPlay(BassClick, True); +// BASS_ChannelPlay(BassClick, True); end; procedure TAudio_ffMpeg.PlayDrum; begin // TODO : jb_linux replace with something other than bass - BASS_ChannelPlay(BassDrum, True); +// BASS_ChannelPlay(BassDrum, True); end; procedure TAudio_ffMpeg.PlayHihat; begin // TODO : jb_linux replace with something other than bass - BASS_ChannelPlay(BassHihat, True); +// BASS_ChannelPlay(BassHihat, True); end; procedure TAudio_ffMpeg.PlayClap; begin // TODO : jb_linux replace with something other than bass - BASS_ChannelPlay(BassClap, True); +// BASS_ChannelPlay(BassClap, True); end; procedure TAudio_ffMpeg.PlayShuffle; begin // TODO : jb_linux replace with something other than bass - BASS_ChannelPlay(BassShuffle, True); +// BASS_ChannelPlay(BassShuffle, True); end; procedure TAudio_ffMpeg.StopShuffle; begin // TODO : jb_linux replace with something other than bass - BASS_ChannelStop(BassShuffle); +// BASS_ChannelStop(BassShuffle); end; -procedure TAudio_ffMpeg.CaptureStart; -var - S: integer; - SC: integer; - P1: integer; - P2: integer; -begin - for S := 0 to High(Sound) do - Sound[S].BufferLong[0].Clear; - - for SC := 0 to High(Ini.CardList) do begin - P1 := Ini.CardList[SC].ChannelL; - P2 := Ini.CardList[SC].ChannelR; - if P1 > PlayersPlay then P1 := 0; - if P2 > PlayersPlay then P2 := 0; - if (P1 > 0) or (P2 > 0) then - CaptureCard(SC, P1, P2); - end; +procedure TAudio_ffMpeg.StopCard(Card: byte); +begin + // TODO : jb_linux replace with something other than bass +// BASS_RecordSetDevice(Card); +// BASS_RecordFree; end; -procedure TAudio_ffMpeg.CaptureStop; +function audio_decode_frame(aCodecCtx : TAVCodecContext; audio_buf : PUInt8; buf_size: integer): integer; var - SC: integer; - P1: integer; - P2: integer; + pkt : TAVPacket; + audio_pkt_data : pchar;//PUInt8 = nil; + audio_pkt_size : integer; + len1 , + data_size : integer; begin +// result := 1; +// exit; + + while true do + begin + + while ( audio_pkt_size > 0 ) do + begin + writeln( 'got audio packet' ); + data_size := buf_size; + +// len1 := avcodec_decode_audio2(aCodecCtx, (int16_t )audio_buf, &data_size, audio_pkt_data, audio_pkt_size); + len1 := avcodec_decode_audio(@aCodecCtx, PWord( audio_buf ), data_size, audio_pkt_data, audio_pkt_size); // Todo.. should be avcodec_decode_audio2 but this wont link on my ubuntu box. + +// writeln('avcodec_decode_audio'); + + if(len1 < 0) then + begin + //* if error, skip 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 */ + continue; + end; + + //* 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 ( quit <> 0 ) then + begin + result := -1; + exit; + end; + + if (packet_queue_get(audioq, pkt, 1) < 0) then + begin + result := -1; + exit; + end; - for SC := 0 to High(Ini.CardList) do begin - P1 := Ini.CardList[SC].ChannelL; - P2 := Ini.CardList[SC].ChannelR; - if P1 > PlayersPlay then P1 := 0; - if P2 > PlayersPlay then P2 := 0; - if (P1 > 0) or (P2 > 0) then StopCard(SC); - end; + audio_pkt_data := pchar( pkt.data ); + audio_pkt_size := pkt.size; + writeln( 'Audio Packet Size - ' + inttostr(audio_pkt_size) ); + end; end; -//procedure TAudio_ffMpeg.CaptureCard(RecordI, SoundNum, PlayerLeft, PlayerRight: byte); -procedure TAudio_ffMpeg.CaptureCard(RecordI, PlayerLeft, PlayerRight: byte); +procedure audio_callback( userdata: Pointer; stream: PUInt8; len: Integer ); var - Error: integer; - ErrorMsg: string; + 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; + audio_buf : pUInt8 = nil; begin - if not BASS_RecordInit(RecordI) then - begin - Error := BASS_ErrorGetCode; + aCodecCtx := pAVCodecContext(userdata)^; + audio_buf := UInt8( (AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) div 2); // todo : JB + audio_size := -1; - ErrorMsg := IntToStr(Error); - if Error = BASS_ERROR_DX then ErrorMsg := 'No DX5'; - if Error = BASS_ERROR_ALREADY then ErrorMsg := 'The device has already been initialized'; - if Error = BASS_ERROR_DEVICE then ErrorMsg := 'The device number specified is invalid'; - if Error = BASS_ERROR_DRIVER then ErrorMsg := 'There is no available device driver'; +// writeln('----------- audio callback' ); - {Log.LogAnalyze('Error initializing record [' + IntToStr(RecordI) + ', ' - + IntToStr(PlayerLeft) + ', '+ IntToStr(PlayerRight) + ']: ' - + ErrorMsg);} - Log.LogError('Error initializing record [' + IntToStr(RecordI) + ', ' - + IntToStr(PlayerLeft) + ', '+ IntToStr(PlayerRight) + ']: ' - + ErrorMsg); - Log.LogError('Music -> CaptureCard: Error initializing record: ' + ErrorMsg); + while (len > 0) do + begin + if(audio_buf_index >= audio_buf_size) then + begin + // We have already sent all our data; get more */ + audio_size := audio_decode_frame(aCodecCtx, audio_buf, sizeof(audio_buf)); + + if(audio_size < 0) then + begin + // If error, output silence */ + audio_buf_size := 1024; // arbitrary? + memset(audio_buf, 0, audio_buf_size); // todo : jb memset + end + else + begin + audio_buf_size := audio_size; + end; +// audio_buf_index := 0; // Todo : jb - SegFault ? + end; + + len1 := audio_buf_size - audio_buf_index; - end - else - begin - Recording.SoundCard[RecordI].BassRecordStream := BASS_RecordStart(44100, 2, MakeLong(0, 20) , @GetMicrophone, PlayerLeft + PlayerRight*256); - end; -end; + if (len1 > len) then + len1 := len; + + memcpy(stream, PUInt8( audio_buf ) + audio_buf_index , len1); -procedure TAudio_ffMpeg.StopCard(Card: byte); -begin - // TODO : jb_linux replace with something other than bass - BASS_RecordSetDevice(Card); - BASS_RecordFree; + len := len - len1; + stream := stream + len1; + audio_buf_index := audio_buf_index + len1; + end; end; function TAudio_ffMpeg.LoadSoundFromFile(var hStream: hStream; Name: string): boolean; var L: Integer; -begin + 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; + if FileExists(Name) then begin - Log.LogStatus('Loading Sound: "' + Name + '"', 'LoadSoundFromFile'); + writeln('Loading Sound: "' + Name + '"', 'LoadSoundFromFile'); + + // Open video file + if (av_open_input_file(pFormatCtx, pchar(Name), nil, 0, nil) > 0) then + exit; + + // 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 + end; + + writeln( 'SDL opened audio device' ); + + aCodec := avcodec_find_decoder(aCodecCtx.codec_id); + if (aCodec = nil) then + begin + writeln('Unsupported codec!'); + exit; + end; + + avcodec_open(aCodecCtx, aCodec); + + writeln( 'Opened the codec' ); + + packet_queue_init( audioq ); + SDL_PauseAudio(0); + + writeln( 'SDL_PauseAudio' ); + + i := 0; + while (av_read_frame(pFormatCtx, packet)>=0) do + begin + writeln( 'ffmpeg - av_read_frame' ); + + if (packet.stream_index = lAudStreamID ) then + begin + packet_queue_put(audioq, packet); + end + else + begin + av_free_packet(packet); + end; + + + // Free the packet that was allocated by av_read_frame + SDL_PollEvent(@event); + +(* + if event.type_ = SDL_QUIT the + begin + quit := 1; + SDL_Quit(); + end + else + break; +*) + + end; + + // Close the codec + avcodec_close(aCodecCtx); + + // Close the video file + av_close_input_file(pFormatCtx); + +(* try // TODO : jb_linux replace with something other than bass hStream := BASS_StreamCreateFile(False, pchar(Name), 0, 0, 0); @@ -528,21 +685,124 @@ begin except Log.LogError('Failed to open using BASS', 'LoadSoundFromFile'); end; +*) + end else begin - Log.LogError('Sound not found: "' + Name + '"', 'LoadSoundFromFile'); + writeln('Sound not found: "' + Name + '"', 'LoadSoundFromFile'); + exit; + end; + +end; + +procedure packet_queue_init(var aPacketQueue : TPacketQueue ); +begin + memset(@aPacketQueue, 0, sizeof(TPacketQueue)); + + aPacketQueue.mutex := SDL_CreateMutex(); + aPacketQueue.cond := SDL_CreateCond(); +end; + +function packet_queue_put(var aPacketQueue : TPacketQueue; var AVPacket : TAVPacket): integer; +var + pkt1 : pAVPacketList; +begin + result := -1; + + writeln( 'TAudio_ffMpeg.packet_queue_put' ); + + if av_dup_packet(@AVPacket) < 0 then exit; + + pkt1 := av_malloc(sizeof(TAVPacketList)); + if (pkt1 = nil) then + exit; + + pkt1.pkt := AVPacket; + pkt1.next := nil; + + + SDL_LockMutex( aPacketQueue.mutex ); + try + + if (aPacketQueue.last_pkt = nil) then + aPacketQueue.first_pkt := pkt1 + else + aPacketQueue.last_pkt.next := pkt1; + + aPacketQueue.last_pkt := pkt1; + inc( aPacketQueue.nb_packets ); + + aPacketQueue.size := aPacketQueue.size + pkt1.pkt.size; + SDL_CondSignal(aPacketQueue.cond); + + finally + SDL_UnlockMutex( aPacketQueue.mutex ); end; + + result := 0; end; +function packet_queue_get(var aPacketQueue : TPacketQueue; var AVPacket : TAVPacket; block : integer ): integer; +var + pkt1 : pAVPacketList; +begin + result := -1; +// writeln( 'packet_queue_get' ); + + SDL_LockMutex(aPacketQueue.mutex); + try + while true do + begin + + if (quit <> 0) then + exit; + + pkt1 := aPacketQueue.first_pkt; + + 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; + + av_free(pkt1); + + result := 1; + break; + end + else + if (block = 0) then + begin + result := 0; + break; + end + else + begin + SDL_CondWait(aPacketQueue.cond, aPacketQueue.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); +// BASS_ChannelGetData(Bass, @Result, BASS_DATA_FFT512); end; function TAudio_ffMpeg.LoadCustomSound(const Filename: String): Cardinal; @@ -551,6 +811,7 @@ var I: Integer; F: String; begin +(* //Search for Sound in already loaded Sounds F := UpperCase(SoundPath + FileName); For I := 0 to High(CustomSounds) do @@ -566,12 +827,13 @@ begin 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); +// if Index <= High(CustomSounds) then +// BASS_ChannelPlay(CustomSounds[Index].Handle, True); end; @@ -625,8 +887,8 @@ initialization writeln( 'UAudio_Bass - Register Playback' ); AudioManager.add( IAudioPlayback( singleton_MusicFFMpeg ) ); -finalization - AudioManager.Remove( IAudioPlayback( singleton_MusicFFMpeg ) ); - +finalization + AudioManager.Remove( IAudioPlayback( singleton_MusicFFMpeg ) ); + end. diff --git a/Game/Code/UltraStar.lpr b/Game/Code/UltraStar.lpr index 31115dde..1026c04b 100644 --- a/Game/Code/UltraStar.lpr +++ b/Game/Code/UltraStar.lpr @@ -123,15 +123,15 @@ uses UMusic in 'Classes\UMusic.pas', + UMedia_dummy in 'Classes\UMedia_dummy.pas', -// UAudio_FFMpeg in 'Classes\UAudio_FFMpeg.pas', UVideo in 'Classes\UVideo.pas', - +// UAudio_FFMpeg in 'Classes\UAudio_FFMpeg.pas', {$ifdef win32} UAudio_bass in 'Classes\UAudio_bass.pas', {$endif} -// UAudio_fmod in 'Classes\UAudio_fmod.pas', // Not ready yet +// UAudio_fmod in 'Classes\UAudio_fmod.pas', // this has not yet been developed.. :( UParty in 'Classes\UParty.pas', UPlaylist in 'Classes\UPlaylist.pas', @@ -417,6 +417,14 @@ exit; Log.LogStatus('Initialize Sound', 'Initialization'); InitializeSound(); Log.BenchmarkEnd(1); Log.LogBenchmark('Initializing Sound', 1); + + +(* + // This is jays debugging for FFMpeg audio output.. + singleton_MusicFFMpeg.PlaySwoosh(); + writeln( 'did you hear the sound ?? ' ); + halt(0); +*) // Graphics Log.BenchmarkStart(1); -- cgit v1.2.3