aboutsummaryrefslogtreecommitdiffstats
path: root/Game/Code/Classes/UAudioDecoder_FFMpeg.pas
diff options
context:
space:
mode:
authortobigun <tobigun@b956fd51-792f-4845-bead-9b4dfca2ff2c>2008-08-30 18:12:06 +0000
committertobigun <tobigun@b956fd51-792f-4845-bead-9b4dfca2ff2c>2008-08-30 18:12:06 +0000
commit5f11f9f3e328f6818a42f0a3405404612399c64e (patch)
tree66f4cfcde3c1d4b0564ba47aceeb2d04082a7dfb /Game/Code/Classes/UAudioDecoder_FFMpeg.pas
parentd4ec88adaa7a93d1970c116ae3d621ff05683681 (diff)
downloadusdx-5f11f9f3e328f6818a42f0a3405404612399c64e.tar.gz
usdx-5f11f9f3e328f6818a42f0a3405404612399c64e.tar.xz
usdx-5f11f9f3e328f6818a42f0a3405404612399c64e.zip
Removed outdated 1.1 branch contents
git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/branches/1.1@1331 b956fd51-792f-4845-bead-9b4dfca2ff2c
Diffstat (limited to 'Game/Code/Classes/UAudioDecoder_FFMpeg.pas')
-rw-r--r--Game/Code/Classes/UAudioDecoder_FFMpeg.pas771
1 files changed, 0 insertions, 771 deletions
diff --git a/Game/Code/Classes/UAudioDecoder_FFMpeg.pas b/Game/Code/Classes/UAudioDecoder_FFMpeg.pas
deleted file mode 100644
index 646e9eef..00000000
--- a/Game/Code/Classes/UAudioDecoder_FFMpeg.pas
+++ /dev/null
@@ -1,771 +0,0 @@
-unit UAudioDecoder_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}
-
-{$I ../switches.inc}
-
-
-uses
- Classes,
- {$IFDEF win32}
- windows,
- {$ENDIF}
- SysUtils,
- UMusic;
-
-implementation
-
-uses
- {$ifndef win32}
- libc,
- {$endif}
- UIni,
- UMain,
- avcodec, // FFMpeg Audio file decoding
- avformat,
- avutil,
- avio, // used for url_ferror
- mathematics, // used for av_rescale_q
- SDL,
- ULog,
- UConfig;
-
-
-type
- PPacketQueue = ^TPacketQueue;
- TPacketQueue = class
- private
- firstPkt,
- lastPkt : PAVPacketList;
- nbPackets : integer;
- size : integer;
- mutex : PSDL_Mutex;
- cond : PSDL_Cond;
- quit : boolean;
-
- public
- constructor Create();
- destructor Destroy(); override;
-
- function Put(pkt : PAVPacket): integer;
- function Get(var pkt: TAVPacket; block: boolean): integer;
- procedure Flush();
- end;
-
-const
- MAX_AUDIOQ_SIZE = (5 * 16 * 1024);
-
-var
- EOFPacket: TAVPacket;
- FlushPacket: TAVPacket;
-
-type
- PAudioBuffer = ^TAudioBuffer;
- TAudioBuffer = array[0 .. (AVCODEC_MAX_AUDIO_FRAME_SIZE * 3 div 2)-1] of byte;
-
-type
- TFFMpegDecodeStream = class(TAudioDecodeStream)
- private
- _EOF: boolean; // end-of-stream flag
- _EOF_lock : PSDL_Mutex;
-
- lock : PSDL_Mutex;
- resumeCond : PSDL_Cond;
-
- quitRequest : boolean;
-
- seekRequest: boolean;
- seekFlags : integer;
- seekPos : int64;
-
- parseThread: PSDL_Thread;
- packetQueue: TPacketQueue;
-
- // FFMpeg internal data
- pFormatCtx : PAVFormatContext;
- pCodecCtx : PAVCodecContext;
- pCodec : PAVCodec;
- ffmpegStreamIndex : Integer;
- ffmpegStream : PAVStream;
-
- // state-vars for DecodeFrame
- pkt : TAVPacket;
- audio_pkt_data : PChar;
- audio_pkt_size : integer;
-
- // state-vars for AudioCallback
- audio_buf_index : cardinal;
- audio_buf_size : cardinal;
- audio_buf : TAudioBuffer;
-
- function DecodeFrame(var buffer: TAudioBuffer; bufSize: integer): integer;
- procedure SetEOF(state: boolean);
- public
- constructor Create(pFormatCtx: PAVFormatContext;
- pCodecCtx: PAVCodecContext; pCodec: PAVCodec;
- ffmpegStreamID : Integer; ffmpegStream: PAVStream);
- destructor Destroy(); override;
-
- procedure Close(); override;
-
- function GetLength(): real; override;
- function GetAudioFormatInfo(): TAudioFormatInfo; override;
- function GetPosition: real; override;
- procedure SetPosition(Time: real); override;
- function IsEOF(): boolean; override;
-
- function ReadData(Buffer: PChar; BufSize: integer): integer; override;
- end;
-
-type
- TAudioDecoder_FFMpeg = class( TInterfacedObject, IAudioDecoder )
- private
- class function FindAudioStreamIndex(pFormatCtx : PAVFormatContext): integer;
- public
- function GetName: String;
-
- function InitializeDecoder(): boolean;
- function Open(const Filename: string): TAudioDecodeStream;
- end;
-
-function ParseAudio(streamPtr: Pointer): integer; cdecl; forward;
-
-var
- singleton_AudioDecoderFFMpeg : IAudioDecoder;
-
-
-{ TFFMpegDecodeStream }
-
-constructor TFFMpegDecodeStream.Create(pFormatCtx: PAVFormatContext;
- pCodecCtx: PAVCodecContext; pCodec: PAVCodec;
- ffmpegStreamID : Integer; ffmpegStream: PAVStream);
-begin
- inherited Create();
-
- packetQueue := TPacketQueue.Create();
-
- audio_pkt_data := nil;
- audio_pkt_size := 0;
-
- audio_buf_index := 0;
- audio_buf_size := 0;
-
- FillChar(pkt, sizeof(TAVPacket), 0);
-
- Self.pFormatCtx := pFormatCtx;
- Self.pCodecCtx := pCodecCtx;
- Self.pCodec := pCodec;
- Self.ffmpegStreamIndex := ffmpegStreamIndex;
- Self.ffmpegStream := ffmpegStream;
-
- _EOF := false;
- _EOF_lock := SDL_CreateMutex();
-
- lock := SDL_CreateMutex();
- resumeCond := SDL_CreateCond();
-
- parseThread := SDL_CreateThread(@ParseAudio, Self);
-end;
-
-destructor TFFMpegDecodeStream.Destroy();
-begin
- //Close();
- //packetQueue.Free();
- inherited;
-end;
-
-procedure TFFMpegDecodeStream.Close();
-begin
- // TODO: abort thread
- //quitRequest := true;
- //SDL_WaitThread(parseThread, nil);
-
- (*
- // Close the codec
- if (pCodecCtx <> nil) then
- begin
- avcodec_close(pCodecCtx);
- pCodecCtx := nil;
- end;
-
- // Close the video file
- if (pFormatCtx <> nil) then
- begin
- av_close_input_file(pFormatCtx);
- pFormatCtx := nil;
- end;
- *)
-end;
-
-function TFFMpegDecodeStream.GetLength(): real;
-begin
- result := pFormatCtx^.duration / AV_TIME_BASE;
-end;
-
-function TFFMpegDecodeStream.GetAudioFormatInfo(): TAudioFormatInfo;
-begin
- result.Channels := pCodecCtx^.channels;
- result.SampleRate := pCodecCtx^.sample_rate;
- //result.Format := pCodecCtx^.sample_fmt; // sample_fmt not yet used by FFMpeg
- result.Format := asfS16; // use FFMpeg's standard format
-end;
-
-function TFFMpegDecodeStream.IsEOF(): boolean;
-begin
- SDL_mutexP(_EOF_lock);
- result := _EOF;
- SDL_mutexV(_EOF_lock);
-end;
-
-procedure TFFMpegDecodeStream.SetEOF(state: boolean);
-begin
- SDL_mutexP(_EOF_lock);
- _EOF := state;
- SDL_mutexV(_EOF_lock);
-end;
-
-function TFFMpegDecodeStream.GetPosition(): real;
-var
- bytes: integer;
-begin
- // see: tutorial on synching (audio-clock)
- Result := 0;
-end;
-
-procedure TFFMpegDecodeStream.SetPosition(Time: real);
-var
- bytes: integer;
-begin
- SDL_mutexP(lock);
- seekPos := Trunc(Time * AV_TIME_BASE);
- // FIXME: seek_flags = rel < 0 ? AVSEEK_FLAG_BACKWARD : 0
- seekFlags := 0;//AVSEEK_FLAG_BACKWARD;
- seekRequest := true;
- SDL_CondSignal(resumeCond);
- SDL_mutexV(lock);
-end;
-
-function ParseAudio(streamPtr: Pointer): integer; cdecl;
-var
- packet: TAVPacket;
- stream: TFFMpegDecodeStream;
- seekTarget: int64;
- eofState: boolean;
- pbIOCtx: PByteIOContext;
-begin
- stream := TFFMpegDecodeStream(streamPtr);
- eofState := false;
-
- while (true) do
- begin
- //SafeWriteLn('Hallo');
-
- SDL_mutexP(stream.lock);
- // wait if end-of-file reached
- if (eofState) then
- begin
- if (not (stream.seekRequest or stream.quitRequest)) then
- begin
- // signal end-of-file
- stream.packetQueue.put(@EOFPacket);
- // wait for reuse or destruction of stream
- repeat
- SDL_CondWait(stream.resumeCond, stream.lock);
- until (stream.seekRequest or stream.quitRequest);
- end;
- eofState := false;
- stream.SetEOF(false);
- end;
-
- if (stream.quitRequest) then
- begin
- break;
- end;
-
- // handle seek-request
- if(stream.seekRequest) then
- begin
- // TODO: Do we need this?
- // The position is converted to AV_TIME_BASE and then to the stream-specific base.
- // Why not convert to the stream-specific one from the beginning.
- seekTarget := av_rescale_q(stream.seekPos, AV_TIME_BASE_Q, stream.ffmpegStream^.time_base);
- if(av_seek_frame(stream.pFormatCtx, stream.ffmpegStreamIndex,
- seekTarget, stream.seekFlags) < 0) then
- begin
- // this will crash in FPC due to a bug
- //Log.LogStatus({stream.pFormatCtx^.filename +} ': error while seeking', 'UAudioDecoder_FFMpeg');
- end
- else
- begin
- stream.packetQueue.Flush();
- stream.packetQueue.Put(@FlushPacket);
- end;
- stream.seekRequest := false;
- end;
-
- SDL_mutexV(stream.lock);
-
-
- if(stream.packetQueue.size > MAX_AUDIOQ_SIZE) then
- begin
- SDL_Delay(10);
- continue;
- end;
-
- if(av_read_frame(stream.pFormatCtx, packet) < 0) then
- begin
- // check for end-of-file (eof is not an error)
- {$IF (LIBAVFORMAT_VERSION_MAJOR >= 52)}
- pbIOCtx := stream.pFormatCtx^.pb;
- {$ELSE}
- pbIOCtx := @stream.pFormatCtx^.pb;
- {$IFEND}
-
- if(url_feof(pbIOCtx) <> 0) then
- begin
- SafeWriteLn('feof');
- eofState := true;
- continue;
- end;
-
- // check for errors
- if(url_ferror(pbIOCtx) = 0) then
- begin
- SafeWriteLn('Errorf');
- // no error -> wait for user input
- SDL_Delay(100);
- continue;
- end
- else
- begin
- // an error occured -> abort
- // TODO: eof or quit?
- eofState := true;
- continue;
- end;
- end;
-
- //SafeWriteLn( 'ffmpeg - av_read_frame' );
-
- if(packet.stream_index = stream.ffmpegStreamIndex) then
- begin
- //SafeWriteLn( 'packet_queue_put' );
- stream.packetQueue.put(@packet);
- end
- else
- begin
- av_free_packet(@packet);
- end;
- end;
-
- SafeWriteLn('Done: ' + inttostr(stream.packetQueue.nbPackets));
-
- result := 0;
-end;
-
-function TFFMpegDecodeStream.DecodeFrame(var buffer: TAudioBuffer; bufSize: integer): integer;
-var
- len1,
- data_size: integer;
-begin
- result := -1;
-
- if EOF then
- exit;
-
- while(true) do
- begin
- while (audio_pkt_size > 0) do
- begin
- //SafeWriteLn( 'got audio packet' );
- data_size := bufSize;
-
- {$IF LIBAVCODEC_VERSION >= 51030000} // 51.30.0
- len1 := avcodec_decode_audio2(pCodecCtx, @buffer,
- data_size, audio_pkt_data, audio_pkt_size);
- {$ELSE}
- // FIXME: with avcodec_decode_audio a package could contain several frames
- // this is not handled yet
- len1 := avcodec_decode_audio(pCodecCtx, @buffer,
- data_size, audio_pkt_data, audio_pkt_size);
- {$IFEND}
-
- //SafeWriteLn('avcodec_decode_audio : ' + inttostr( len1 ));
-
- if(len1 < 0) then
- begin
- // if error, skip frame
- SafeWriteLn( 'Skip audio frame' );
- audio_pkt_size := 0;
- break;
- end;
-
- Inc(audio_pkt_data, len1);
- Dec(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
- begin
- av_free_packet(@pkt);
- end;
-
- if (packetQueue.quit) then
- exit;
-
- if (packetQueue.Get(pkt, true) < 0) then
- exit;
-
- audio_pkt_data := PChar(pkt.data);
- audio_pkt_size := pkt.size;
-
- if (audio_pkt_data = PChar(FlushPacket.data)) then
- begin
- avcodec_flush_buffers(pCodecCtx);
- SafeWriteLn('Flush');
- continue;
- end;
-
- // check for end-of-file
- if (audio_pkt_data = PChar(EOFPacket.data)) then
- begin
- // end-of-file reached -> set EOF-flag
- SetEOF(true);
- SafeWriteLn('EOF');
- // note: buffer is not (even partially) filled -> no data to return
- exit;
- end;
-
- //SafeWriteLn( 'Audio Packet Size - ' + inttostr(audio_pkt_size) );
- end;
-end;
-
-function TFFMpegDecodeStream.ReadData(Buffer : PChar; BufSize: integer): integer;
-var
- outStream : TFFMpegDecodeStream;
- len1,
- audio_size : integer;
- pSrc : Pointer;
- len : integer;
-begin
- len := BufSize;
- result := -1;
-
- // end-of-file reached
- if EOF then
- exit;
-
- 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 := DecodeFrame(audio_buf, sizeof(TAudioBuffer));
- //SafeWriteLn('audio_decode_frame : '+ inttostr(audio_size));
-
- if(audio_size < 0) then
- begin
- // If error, output silence
- audio_buf_size := 1024;
- FillChar(audio_buf, audio_buf_size, #0);
- //SafeWriteLn( 'Silence' );
- end
- else
- begin
- audio_buf_size := audio_size;
- end;
- audio_buf_index := 0;
- end;
-
- len1 := audio_buf_size - audio_buf_index;
- if (len1 > len) then
- len1 := len;
-
- pSrc := PChar(@audio_buf) + audio_buf_index;
- {$ifdef WIN32}
- CopyMemory(Buffer, pSrc , len1);
- {$else}
- memcpy(Buffer, pSrc , len1);
- {$endif}
-
- Dec(len, len1);
- Inc(PChar(Buffer), len1);
- Inc(audio_buf_index, len1);
- end;
-
- result := BufSize;
-end;
-
-
-{ TAudioDecoder_FFMpeg }
-
-function TAudioDecoder_FFMpeg.GetName: String;
-begin
- result := 'FFMpeg_Decoder';
-end;
-
-function TAudioDecoder_FFMpeg.InitializeDecoder: boolean;
-begin
- //Log.LogStatus('InitializeDecoder', 'UAudioDecoder_FFMpeg');
-
- av_register_all();
-
- // init end-of-file package
- av_init_packet(EOFPacket);
- EOFPacket.data := Pointer(PChar('EOF'));
-
- // init flush package
- av_init_packet(FlushPacket);
- FlushPacket.data := Pointer(PChar('FLUSH'));
-
- result := true;
-end;
-
-class function TAudioDecoder_FFMpeg.FindAudioStreamIndex(pFormatCtx : PAVFormatContext): integer;
-var
- i : integer;
- streamIndex: integer;
- stream : PAVStream;
-begin
- // Find the first audio stream
- streamIndex := -1;
-
- for i := 0 to pFormatCtx^.nb_streams-1 do
- begin
- //Log.LogStatus('aFormatCtx.streams[i] : ' + inttostr(i), 'UAudio_FFMpeg');
- stream := pFormatCtx^.streams[i];
-
- if ( stream.codec^.codec_type = CODEC_TYPE_AUDIO ) then
- begin
- //Log.LogStatus('Found Audio Stream', 'UAudio_FFMpeg');
- streamIndex := i;
- break;
- end;
- end;
-
- result := streamIndex;
-end;
-
-function TAudioDecoder_FFMpeg.Open(const Filename: string): TAudioDecodeStream;
-var
- pFormatCtx : PAVFormatContext;
- pCodecCtx : PAVCodecContext;
- pCodec : PAVCodec;
- ffmpegStreamID : Integer;
- ffmpegStream : PAVStream;
- wanted_spec,
- csIndex : integer;
- stream : TFFMpegDecodeStream;
-begin
- result := nil;
-
- if (not FileExists(Filename)) then
- begin
- Log.LogStatus('LoadSoundFromFile: Sound not found "' + Filename + '"', 'UAudio_FFMpeg');
- exit;
- end;
-
- // Open audio file
- if (av_open_input_file(pFormatCtx, PChar(Filename), nil, 0, nil) > 0) then
- exit;
-
- // Retrieve stream information
- if (av_find_stream_info(pFormatCtx) < 0) then
- exit;
-
- dump_format(pFormatCtx, 0, pchar(Filename), 0);
-
- ffmpegStreamID := FindAudioStreamIndex(pFormatCtx);
- if (ffmpegStreamID < 0) then
- exit;
-
- //Log.LogStatus('AudioStreamIndex is: '+ inttostr(ffmpegStreamID), 'UAudio_FFMpeg');
-
- ffmpegStream := pFormatCtx.streams[ffmpegStreamID];
- pCodecCtx := ffmpegStream^.codec;
-
- pCodec := avcodec_find_decoder(pCodecCtx^.codec_id);
- if (pCodec = nil) then
- begin
- Log.LogStatus('Unsupported codec!', 'UAudio_FFMpeg');
- exit;
- end;
-
- avcodec_open(pCodecCtx, pCodec);
- //WriteLn( 'Opened the codec' );
-
- stream := TFFMpegDecodeStream.Create(pFormatCtx, pCodecCtx, pCodec,
- ffmpegStreamID, ffmpegStream);
-
- result := stream;
-end;
-
-
-{ TPacketQueue }
-
-constructor TPacketQueue.Create();
-begin
- inherited;
-
- firstPkt := nil;
- lastPkt := nil;
- nbPackets := 0;
- size := 0;
-
- mutex := SDL_CreateMutex();
- cond := SDL_CreateCond();
-end;
-
-destructor TPacketQueue.Destroy();
-begin
- SDL_DestroyMutex(mutex);
- SDL_DestroyCond(cond);
- inherited;
-end;
-
-function TPacketQueue.Put(pkt : PAVPacket): integer;
-var
- pkt1 : PAVPacketList;
-begin
- result := -1;
-
- if ((pkt <> @EOFPacket) and (pkt <> @FlushPacket)) then
- if (av_dup_packet(pkt) < 0) then
- exit;
-
- pkt1 := av_malloc(sizeof(TAVPacketList));
- if (pkt1 = nil) then
- exit;
-
- pkt1^.pkt := pkt^;
- pkt1^.next := nil;
-
-
- SDL_LockMutex(Self.mutex);
- try
-
- if (Self.lastPkt = nil) then
- Self.firstPkt := pkt1
- else
- Self.lastPkt^.next := pkt1;
-
- Self.lastPkt := pkt1;
- inc(Self.nbPackets);
-
- //SafeWriteLn('Put: ' + inttostr(nbPackets));
-
- Self.size := Self.size + pkt1^.pkt.size;
- SDL_CondSignal(Self.cond);
-
- finally
- SDL_UnlockMutex(Self.mutex);
- end;
-
- result := 0;
-end;
-
-function TPacketQueue.Get(var pkt: TAVPacket; block: boolean): integer;
-var
- pkt1 : PAVPacketList;
-begin
- result := -1;
-
- SDL_LockMutex(Self.mutex);
- try
- while true do
- begin
- if (quit) then
- exit;
-
- pkt1 := Self.firstPkt;
-
- if (pkt1 <> nil) then
- begin
- Self.firstPkt := pkt1.next;
- if (Self.firstPkt = nil) then
- Self.lastPkt := nil;
- dec(Self.nbPackets);
-
- //SafeWriteLn('Get: ' + inttostr(nbPackets));
-
- Self.size := Self.size - pkt1^.pkt.size;
- pkt := pkt1^.pkt;
- av_free(pkt1);
-
- result := 1;
- break;
- end
- else
- if (not block) then
- begin
- result := 0;
- break;
- end
- else
- begin
- SDL_CondWait(Self.cond, Self.mutex);
- end;
- end;
- finally
- SDL_UnlockMutex(Self.mutex);
- end;
-end;
-
-procedure TPacketQueue.Flush();
-var
- pkt, pkt1: PAVPacketList;
-begin
- SDL_LockMutex(Self.mutex);
-
- pkt := Self.firstPkt;
- while(pkt <> nil) do
- begin
- pkt1 := pkt^.next;
- av_free_packet(@pkt^.pkt);
- // Note: param must be a pointer to a pointer!
- av_freep(@pkt);
- pkt := pkt1;
- end;
- Self.lastPkt := nil;
- Self.firstPkt := nil;
- Self.nbPackets := 0;
- Self.size := 0;
-
- SDL_UnlockMutex(Self.mutex);
-end;
-
-
-initialization
- singleton_AudioDecoderFFMpeg := TAudioDecoder_FFMpeg.create();
-
- //writeln( 'UAudioDecoder_FFMpeg - Register Decoder' );
- AudioManager.add( singleton_AudioDecoderFFMpeg );
-
-finalization
- AudioManager.Remove( singleton_AudioDecoderFFMpeg );
-
-
-end.