aboutsummaryrefslogblamecommitdiffstats
path: root/Game/Code/Classes/UAudio_FFMpeg.pas
blob: 35822a3bc9d85fad37e50d877d209e4632447b25 (plain) (tree)
1
2
3
4
5
6
7
8
9
                   
 






                                                                                

                                                               

                                                                                

         





                


                   




                  
                                                  


                                             

            
 














                                                                                                                   
                                                                                                             



                                               








                                                                                                                    
 
              
 


                 
          
             
               



             



                                                 

                   

                               

    


                                                                                          
 


                                                                                                                      

 

                                                              
           


                                  
                                  
                                  












                                               
                                                                                                                                   
          

                           
                                
                                   











                                                              
                                 










                            


                                                                      










                                                                              
                                   
     
                                                 
                  
    
 
                                                                                                                                           
   

                 
     


                                
 

                                        
       
                                                             
                                
 


                                                   
                                        

                             
 


                                                     
                                        

                             
 

               
 


                                                                         
 
 


                                        

    
                                           
   


                  
 

                                                                                






                                                                                
 



                                                                    
 
                                                              
 

                                              
 

    
 
                                                   




                                              
 
                                                           
  


                                                  
  

    
                                                        









                         
                                                           
                                                       

    
                                                  



                  
                                                   



                          
                                                             
                                                                 


                    
                           




                   
                               
     

                


      
                                           


                    
                                                           

                                                   

    
                             
     
  



                                                           
                                                                                                                                    


                                                                         
  

    
                                          
     
  



                                                           
  

    
                             
     
                           

    
                              
     
                          

    
                                    



                    
  


                                                           
  

    
                                         




                    
  


                                                           
  

    
                                         


                  
  




                                                           
  

    
                                  
     
                                                           
                                      

    
                                 
     
                                                           
                                            

    
                                   
     
                                                           


                                       

    
                                   
     
                                                           
                                       

    
                                   
     
                                                           
                                       

    
                                  
     
                                                           
                                      

    
                                 
     
                                                           
                                     

    
                                  
     
                                                           
                                      

    
                                 
     
                                                           
                                     

    
                                    
     
                                                           
                                        

    
                                    
     
                                                           
                                  

    

                                             
 


                                                           

    
                                                                                                          
   




                                         
     







                                                       





                                   
                                      
                            













                                                                                                                                                                                                    





                                         

                                              






























                                                                 
 
 

                                        
                                                                   
      

    
                                                                            
   




                                                                         





                                                                                                                                                           
     
                                       
 



                                                
 




                                                       
                                                                                            




                                             





                                                                            




                                     
 
                                                      


                                             
 

                        
 









                                                                    

                                              

    
                                                                                      
   

                                   












                                  

                          
                                                                    













                                                                        
                                               


                           
                                                                   


















                                                     


                                         








                                                     
                                  



                              
                                

         
                                                   
       
                                          


                                                 
                                      





                                       
 














                                                          


            
                    
                             

                         
                                    

  
       

                                                                    
 







                                                                     

    


       







                                                                    




                                                     










                                                                                              
                                                

                                      
         
























                                                           
      

              

    



















































                                                                                                                
           
                                            
   
                 
     
                                        
                                                         

    
                                                                         




             
  














                                                     
  

    
                                                                
     

                                                         






                                                                              
                                                                                    







                                                           
                                                                                             





























                                                                        





                                                              


                                                                 
 
    
unit UAudio_FFMpeg;

(*******************************************************************************

This unit is primarily based upon -
    http://www.dranger.com/ffmpeg/ffmpegtutorial_all.html
    
    and tutorial03.c

    http://www.inb.uni-luebeck.de/~boehme/using_libavcodec.html

*******************************************************************************)

interface

{$IFDEF FPC}
  {$MODE Delphi}
{$ENDIF}


uses Classes,
     {$IFDEF win32}
     windows,
     {$ENDIF}
     Messages,
     SysUtils,
     {$IFNDEF FPC}
     Forms,
     {$ENDIF}
     SDL,       // Used for Audio output Interface
     avcodec,   // FFMpeg Audio file decoding
     avformat,
     avutil,
     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 ] of byte;
  PAudioBuff = ^Taudiobuff;

implementation

uses
     {$IFDEF FPC}
     lclintf,
     libc,
     {$ENDIF}
//     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);



const
  ModeStr:  array[TMPModes] of string = ('Not ready', 'Stopped', 'Playing', 'Recording', 'Seeking', 'Paused', 'Open');



type
    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;

      //Custom Sounds
      CustomSounds: array of TCustomSoundEntry;
      Loaded:   boolean;
      Loop:     boolean;
      fHWND:    THandle;

      function find_stream_ids( const aFormatCtx : PAVFormatContext; Out aFirstVideoStream, aFirstAudioStream : integer ): boolean;
    public
//      Bass: hStream;
      constructor create();
      function  GetName: String;
      procedure InitializePlayback;
      procedure SetVolume(Volume: integer);
      procedure SetMusicVolume(Volume: integer);
      procedure SetLoop(Enabled: boolean);
      function Open(Name: string): boolean; // true if succeed
      procedure Rewind;
      procedure MoveTo(Time: real);
      procedure Play;
      procedure Pause; //Pause Mod
      procedure Stop;
      procedure Close;
      function Finished: boolean;
      function Length: real;
      function getPosition: real;
      procedure PlayStart;
      procedure PlayBack;
      procedure PlaySwoosh;
      procedure PlayChange;
      procedure PlayOption;
      procedure PlayClick;
      procedure PlayDrum;
      procedure PlayHihat;
      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;

      //Equalizer
      function GetFFTData: TFFTData;

      //Custom Sounds
      function LoadCustomSound(const Filename: String): Cardinal;
      procedure PlayCustomSound(const Index: Cardinal );
end;

constructor TAudio_ffMpeg.create();
begin
//  writeln( 'UVideo_FFMpeg - av_register_all' );
  av_register_all;
end;

function TAudio_ffMpeg.find_stream_ids( const aFormatCtx : PAVFormatContext; Out aFirstVideoStream, aFirstAudioStream : integer ): boolean;
var
  i : integer;
  st : pAVStream;
begin
  // Find the first video stream
  aFirstAudioStream := -1;
  aFirstVideoStream := -1;

  i := 0;
  while ( i < aFormatCtx.nb_streams ) do
  begin
//    writeln( ' aFormatCtx.streams[i] : ' + inttostr( i ) );
    st := aFormatCtx.streams[i];

    if(st.codec.codec_type = CODEC_TYPE_VIDEO ) AND
      (aFirstVideoStream < 0) THEN
    begin
//      writeln( 'Found Video Stream' );
      aFirstVideoStream := i;
    end;

    if ( st.codec.codec_type = CODEC_TYPE_AUDIO ) AND
       ( aFirstAudioStream < 0) THEN
    begin
//      writeln( 'Found Audio Stream' );
      aFirstAudioStream := i;
    end;

    inc( i );
  end; // while

  result := (aFirstAudioStream > -1) OR
            (aFirstVideoStream > -1) ;  // Didn't find any streams stream
end;


function  TAudio_ffMpeg.GetName: String;
begin
  result := 'FFMpeg';
end;

procedure TAudio_ffMpeg.InitializePlayback;
var
//  Pet:  integer;
  S:    integer;
begin

//  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');
*)

//  LoadSoundFromFile(BassShuffle, SoundPath + 'Shuffle.mp3');

//  Log.BenchmarkEnd(4);
//  Log.LogBenchmark('--> Loading Sounds', 4);

end;


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);
  BASS_SetConfig(BASS_CONFIG_GVOL_MUSIC, Volume);
*)
end;

procedure TAudio_ffMpeg.SetMusicVolume(Volume: Integer);
begin
  //Max Volume Prevention
  if Volume > 100 then
    Volume := 100;

  if Volume < 0 then
    Volume := 0;


  //Set Volume
  // TODO : jb_linux replace with something other than bass
//  BASS_ChannelSetAttributes (Bass, -1, Volume, -101);
end;

procedure TAudio_ffMpeg.SetLoop(Enabled: boolean);
begin
  Loop := Enabled;
end;

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);
  end;

  Result := Loaded;
end;

procedure TAudio_ffMpeg.Rewind;
begin
  if Loaded then
  begin
  end;
end;

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;
begin
(*
  // TODO : jb_linux replace with something other than bass
  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
  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
//  Bass_ChannelStop(Bass);
end;

procedure TAudio_ffMpeg.Close;
begin
//  Bass_StreamFree(Bass);
end;

function TAudio_ffMpeg.Length: real;
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.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);
end;

procedure TAudio_ffMpeg.PlayBack;
begin
  // TODO : jb_linux replace with something other than bass
//  BASS_ChannelPlay(BassBack, True);// then
end;

procedure TAudio_ffMpeg.PlaySwoosh;
begin
  // TODO : jb_linux replace with something other than bass
//  BASS_ChannelPlay(BassSwoosh, True);


end;

procedure TAudio_ffMpeg.PlayChange;
begin
  // TODO : jb_linux replace with something other than bass
//  BASS_ChannelPlay(BassChange, True);
end;

procedure TAudio_ffMpeg.PlayOption;
begin
  // TODO : jb_linux replace with something other than bass
//  BASS_ChannelPlay(BassOption, True);
end;

procedure TAudio_ffMpeg.PlayClick;
begin
  // TODO : jb_linux replace with something other than bass
//  BASS_ChannelPlay(BassClick, True);
end;

procedure TAudio_ffMpeg.PlayDrum;
begin
  // TODO : jb_linux replace with something other than bass
//  BASS_ChannelPlay(BassDrum, True);
end;

procedure TAudio_ffMpeg.PlayHihat;
begin
  // TODO : jb_linux replace with something other than bass
//  BASS_ChannelPlay(BassHihat, True);
end;

procedure TAudio_ffMpeg.PlayClap;
begin
  // TODO : jb_linux replace with something other than bass
//  BASS_ChannelPlay(BassClap, True);
end;

procedure TAudio_ffMpeg.PlayShuffle;
begin
  // TODO : jb_linux replace with something other than bass
//  BASS_ChannelPlay(BassShuffle, True);
end;

procedure TAudio_ffMpeg.StopShuffle;
begin
  // TODO : jb_linux replace with something other than bass
//  BASS_ChannelStop(BassShuffle);
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;
var
  pkt             : TAVPacket;
  audio_pkt_data  : pchar;//PUInt8 = nil;
  audio_pkt_size  : integer;
  len1            ,
  data_size       : integer;
begin
  {$ifdef win32}
    FillChar(pkt, sizeof(pkt), #0);
  {$else}
    memset(@pkt, 0, sizeof(pkt));   // todo : jb memset
  {$endif}

  audio_pkt_data := nil;
  audio_pkt_size := 0;

  while true do
  begin
  
    while ( audio_pkt_size > 0 ) do
    begin
//      writeln( 'got audio packet' );
      data_size := buf_size;

      len1 := -1;

      if aAudio_buf <> nil  then
      begin
//        writeln( 'pre avcodec_decode_audio' );
        {$ifdef fpc}
          len1 := avcodec_decode_audio(@aCodecCtx, PWord( aAudio_buf ), data_size, audio_pkt_data, audio_pkt_size); // Todo.. should be avcodec_decode_audio2 but this wont link on my ubuntu box.
        {$else}
          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.
        {$endif}
//        writeln( 'post avcodec_decode_audio' );        

      end;

//      writeln('avcodec_decode_audio');

      if(len1 < 0) then
      begin
	      //* 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 */
     	  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;


    audio_pkt_data := pchar( pkt.data );
    audio_pkt_size := pkt.size;
//    writeln( 'Audio Packet Size - ' + inttostr(audio_pkt_size) );
  end;
end;

procedure audio_callback( userdata: Pointer; stream: PUInt8; len: Integer );
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                                     
begin
  laudio_buf      := @lAudio_buf_data ;

  aCodecCtx       := pAVCodecContext(userdata)^;
  audio_size      := -1;
  audio_buf_index := 0;
  audio_buf_size  := 0;

  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, pUInt8( laudio_buf ), sizeof(laudio_buf));

      if(audio_size < 0) then
      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}
      end
      else
      begin
      	audio_buf_size := audio_size;
      end;

      audio_buf_index := 0;  // Todo : jb - SegFault ?
    end;
    
    len1 := audio_buf_size - audio_buf_index;

    if (len1 > len) then
      len1 := len;


    {$ifdef win32}
      lSrc := PUInt8( integer( laudio_buf ) + audio_buf_index );
      CopyMemory(stream, lSrc , len1);
    {$else}
      memcpy(stream, PUInt8( laudio_buf ) + audio_buf_index , len1);
    {$endif}

    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;
  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
//    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
//      writeln( 'packet_queue_put' );
      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;

//  halt(0);

  // 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);

      //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
  begin
    writeln('Sound not found: "' + Name + '"', 'LoadSoundFromFile');
    exit;
  end;

end;

procedure packet_queue_init(var aPacketQueue : TPacketQueue );
begin
  {$ifdef win32}
    FillChar(aPacketQueue, sizeof(TPacketQueue), #0);
  {$else}
    memset(@aPacketQueue, 0, sizeof(TPacketQueue));
  {$endif}
  
  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);
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;
  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();

  writeln( 'UAudio_Bass - Register Playback' );
  AudioManager.add( IAudioPlayback( singleton_MusicFFMpeg ) );

finalization
  AudioManager.Remove( IAudioPlayback( singleton_MusicFFMpeg ) );


end.