From 1ab628e8ad6c85c8f1b562f10480253ee3e622b7 Mon Sep 17 00:00:00 2001 From: whiteshark0 Date: Fri, 11 Dec 2009 17:34:54 +0000 Subject: merged trunk into lua branch plugin loading is disabled atm because of a bug reading the files (lua may be the reason). Reading the files in usdx and passing the contents to lua may solve this git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/branches/experimental@2019 b956fd51-792f-4845-bead-9b4dfca2ff2c --- Lua/src/media/UAudioConverter.pas | 14 ++-- Lua/src/media/UAudioCore_Bass.pas | 12 +++ Lua/src/media/UAudioDecoder_Bass.pas | 25 ++++-- Lua/src/media/UAudioDecoder_FFmpeg.pas | 68 ++++++++-------- Lua/src/media/UAudioInput_Bass.pas | 7 +- Lua/src/media/UAudioInput_Portaudio.pas | 3 - Lua/src/media/UAudioPlaybackBase.pas | 23 +++--- Lua/src/media/UAudioPlayback_Bass.pas | 24 +++--- Lua/src/media/UAudioPlayback_SDL.pas | 14 ++-- Lua/src/media/UAudioPlayback_SoftMixer.pas | 44 +++++----- Lua/src/media/UMediaCore_FFmpeg.pas | 124 ++++++++++++++++++++++++++++- Lua/src/media/UMedia_dummy.pas | 15 ++-- Lua/src/media/UVideo.pas | 79 ++++++++++++------ Lua/src/media/UVisualizer.pas | 20 +++-- 14 files changed, 328 insertions(+), 144 deletions(-) (limited to 'Lua/src/media') diff --git a/Lua/src/media/UAudioConverter.pas b/Lua/src/media/UAudioConverter.pas index 24131b16..657b80dd 100644 --- a/Lua/src/media/UAudioConverter.pas +++ b/Lua/src/media/UAudioConverter.pas @@ -70,7 +70,7 @@ type function Init(SrcFormatInfo: TAudioFormatInfo; DstFormatInfo: TAudioFormatInfo): boolean; override; destructor Destroy(); override; - function Convert(InputBuffer: PChar; OutputBuffer: PChar; var InputSize: integer): integer; override; + function Convert(InputBuffer: PByteArray; OutputBuffer: PByteArray; var InputSize: integer): integer; override; function GetOutputBufferSize(InputSize: integer): integer; override; function GetRatio(): double; override; end; @@ -87,7 +87,7 @@ type function Init(SrcFormatInfo: TAudioFormatInfo; DstFormatInfo: TAudioFormatInfo): boolean; override; destructor Destroy(); override; - function Convert(InputBuffer: PChar; OutputBuffer: PChar; var InputSize: integer): integer; override; + function Convert(InputBuffer: PByteArray; OutputBuffer: PByteArray; var InputSize: integer): integer; override; function GetOutputBufferSize(InputSize: integer): integer; override; function GetRatio(): double; override; end; @@ -103,7 +103,7 @@ type function Init(SrcFormatInfo: TAudioFormatInfo; DstFormatInfo: TAudioFormatInfo): boolean; override; destructor Destroy(); override; - function Convert(InputBuffer: PChar; OutputBuffer: PChar; var InputSize: integer): integer; override; + function Convert(InputBuffer: PByteArray; OutputBuffer: PByteArray; var InputSize: integer): integer; override; function GetOutputBufferSize(InputSize: integer): integer; override; function GetRatio(): double; override; end; @@ -173,7 +173,7 @@ begin Result := cvt.len_ratio; end; -function TAudioConverter_SDL.Convert(InputBuffer: PChar; OutputBuffer: PChar; var InputSize: integer): integer; +function TAudioConverter_SDL.Convert(InputBuffer: PByteArray; OutputBuffer: PByteArray; var InputSize: integer): integer; begin Result := -1; @@ -242,7 +242,7 @@ begin inherited; end; -function TAudioConverter_FFmpeg.Convert(InputBuffer: PChar; OutputBuffer: PChar; var InputSize: integer): integer; +function TAudioConverter_FFmpeg.Convert(InputBuffer: PByteArray; OutputBuffer: PByteArray; var InputSize: integer): integer; var InputSampleCount: integer; OutputSampleCount: integer; @@ -360,11 +360,11 @@ begin inherited; end; -function TAudioConverter_SRC.Convert(InputBuffer: PChar; OutputBuffer: PChar; var InputSize: integer): integer; +function TAudioConverter_SRC.Convert(InputBuffer: PByteArray; OutputBuffer: PByteArray; var InputSize: integer): integer; var FloatInputBuffer: PSingle; FloatOutputBuffer: PSingle; - TempBuffer: PChar; + TempBuffer: PByteArray; TempSize: integer; NumSamples: integer; OutputSize: integer; diff --git a/Lua/src/media/UAudioCore_Bass.pas b/Lua/src/media/UAudioCore_Bass.pas index 12623dc1..197f9760 100644 --- a/Lua/src/media/UAudioCore_Bass.pas +++ b/Lua/src/media/UAudioCore_Bass.pas @@ -44,6 +44,7 @@ type public constructor Create(); class function GetInstance(): TAudioCore_Bass; + function CheckVersion(): boolean; function ErrorGetString(): string; overload; function ErrorGetString(errCode: integer): string; overload; function ConvertAudioFormatToBASSFlags(Format: TAudioSampleFormat; out Flags: DWORD): boolean; @@ -56,6 +57,12 @@ uses UMain, ULog; +const + // TODO: 2.4.2 is not ABI compatible with older versions + // as (BASS_RECORDINFO.driver was removed) + //BASS_MIN_REQUIRED_VERSION = $02040201; + BASS_MIN_REQUIRED_VERSION = $02000000; + var Instance: TAudioCore_Bass; @@ -71,6 +78,11 @@ begin Result := Instance; end; +function TAudioCore_Bass.CheckVersion(): boolean; +begin + Result := BASS_GetVersion() >= BASS_MIN_REQUIRED_VERSION; +end; + function TAudioCore_Bass.ErrorGetString(): string; begin Result := ErrorGetString(BASS_ErrorGetCode()); diff --git a/Lua/src/media/UAudioDecoder_Bass.pas b/Lua/src/media/UAudioDecoder_Bass.pas index 3c31175d..d6d2425a 100644 --- a/Lua/src/media/UAudioDecoder_Bass.pas +++ b/Lua/src/media/UAudioDecoder_Bass.pas @@ -38,11 +38,12 @@ implementation uses Classes, SysUtils, + bass, UMain, UMusic, UAudioCore_Bass, ULog, - bass; + UPath; type TBassDecodeStream = class(TAudioDecodeStream) @@ -65,7 +66,7 @@ type function IsEOF(): boolean; override; function IsError(): boolean; override; - function ReadData(Buffer: PChar; BufSize: integer): integer; override; + function ReadData(Buffer: PByteArray; BufSize: integer): integer; override; end; type @@ -75,7 +76,7 @@ type function InitializeDecoder(): boolean; function FinalizeDecoder(): boolean; - function Open(const Filename: string): TAudioDecodeStream; + function Open(const Filename: IPath): TAudioDecodeStream; end; var @@ -193,7 +194,7 @@ begin Result := Error; end; -function TBassDecodeStream.ReadData(Buffer: PChar; BufSize: integer): integer; +function TBassDecodeStream.ReadData(Buffer: PByteArray; BufSize: integer): integer; begin Result := BASS_ChannelGetData(Handle, Buffer, BufSize); // check error state (do not handle EOF as error) @@ -213,7 +214,10 @@ end; function TAudioDecoder_Bass.InitializeDecoder(): boolean; begin + Result := false; BassCore := TAudioCore_Bass.GetInstance(); + if not BassCore.CheckVersion then + Exit; Result := true; end; @@ -222,7 +226,7 @@ begin Result := true; end; -function TAudioDecoder_Bass.Open(const Filename: string): TAudioDecodeStream; +function TAudioDecoder_Bass.Open(const Filename: IPath): TAudioDecodeStream; var Stream: HSTREAM; ChannelInfo: BASS_CHANNELINFO; @@ -237,7 +241,14 @@ begin // TODO: use BASS_STREAM_PRESCAN for accurate seeking in VBR-files? // disadvantage: seeking will slow down. - Stream := BASS_StreamCreateFile(False, PChar(Filename), 0, 0, BASS_STREAM_DECODE); + + {$IFDEF MSWINDOWS} + // Windows: Use UTF-16 version + Stream := BASS_StreamCreateFile(False, PWideChar(Filename.ToWide), 0, 0, BASS_STREAM_DECODE or BASS_UNICODE); + {$ELSE} + // Mac OS X: Use UTF8/ANSI version + Stream := BASS_StreamCreateFile(False, PAnsiChar(Filename.ToNative), 0, 0, BASS_STREAM_DECODE); + {$ENDIF} if (Stream = 0) then begin //Log.LogError(BassCore.ErrorGetString(), 'TAudioDecoder_Bass.Open'); @@ -247,7 +258,7 @@ begin // check if BASS opened some erroneously recognized file-formats if BASS_ChannelGetInfo(Stream, channelInfo) then begin - fileExt := ExtractFileExt(Filename); + fileExt := Filename.GetExtension.ToUTF8; // BASS opens FLV-files (maybe others too) although it cannot handle them. // Setting BASS_CONFIG_VERIFY to the max. value (100000) does not help. if ((fileExt = '.flv') and (channelInfo.ctype = BASS_CTYPE_STREAM_MP1)) then diff --git a/Lua/src/media/UAudioDecoder_FFmpeg.pas b/Lua/src/media/UAudioDecoder_FFmpeg.pas index 399c2f52..d079afdc 100644 --- a/Lua/src/media/UAudioDecoder_FFmpeg.pas +++ b/Lua/src/media/UAudioDecoder_FFmpeg.pas @@ -56,23 +56,24 @@ interface implementation uses + SDL, // SDL redefines some base types -> include before SysUtils to ignore them Classes, - SysUtils, Math, - UMusic, - UIni, - UMain, + SysUtils, avcodec, avformat, avutil, avio, mathematics, // used for av_rescale_q rational, + UMusic, + UIni, + UMain, UMediaCore_FFmpeg, - SDL, ULog, UCommon, - UConfig; + UConfig, + UPath; const MAX_AUDIOQ_SIZE = (5 * 16 * 1024); @@ -129,16 +130,16 @@ type // state-vars for DecodeFrame (locked by DecoderLock) AudioPaket: TAVPacket; - AudioPaketData: PChar; + AudioPaketData: PByteArray; AudioPaketSize: integer; AudioPaketSilence: integer; // number of bytes of silence to return // state-vars for AudioCallback (locked by DecoderLock) AudioBufferPos: integer; AudioBufferSize: integer; - AudioBuffer: PChar; + AudioBuffer: PByteArray; - Filename: string; + Filename: IPath; procedure SetPositionIntern(Time: real; Flush: boolean; Blocking: boolean); procedure SetEOF(State: boolean); {$IFDEF HasInline}inline;{$ENDIF} @@ -153,7 +154,7 @@ type procedure PauseParser(); procedure ResumeParser(); - function DecodeFrame(Buffer: PChar; BufferSize: integer): integer; + function DecodeFrame(Buffer: PByteArray; BufferSize: integer): integer; procedure FlushCodecBuffers(); procedure PauseDecoder(); procedure ResumeDecoder(); @@ -161,7 +162,7 @@ type constructor Create(); destructor Destroy(); override; - function Open(const Filename: string): boolean; + function Open(const Filename: IPath): boolean; procedure Close(); override; function GetLength(): real; override; @@ -173,17 +174,17 @@ type function IsEOF(): boolean; override; function IsError(): boolean; override; - function ReadData(Buffer: PChar; BufferSize: integer): integer; override; + function ReadData(Buffer: PByteArray; BufferSize: integer): integer; override; end; type - TAudioDecoder_FFmpeg = class( TInterfacedObject, IAudioDecoder ) + TAudioDecoder_FFmpeg = class(TInterfacedObject, IAudioDecoder) public function GetName: string; function InitializeDecoder(): boolean; function FinalizeDecoder(): boolean; - function Open(const Filename: string): TAudioDecodeStream; + function Open(const Filename: IPath): TAudioDecodeStream; end; var @@ -270,7 +271,7 @@ begin inherited; end; -function TFFmpegDecodeStream.Open(const Filename: string): boolean; +function TFFmpegDecodeStream.Open(const Filename: IPath): boolean; var SampleFormat: TAudioSampleFormat; AVResult: integer; @@ -280,18 +281,18 @@ begin Close(); Reset(); - if (not FileExists(Filename)) then + if (not Filename.IsFile) then begin - Log.LogError('Audio-file does not exist: "' + Filename + '"', 'UAudio_FFmpeg'); + Log.LogError('Audio-file does not exist: "' + Filename.ToNative + '"', 'UAudio_FFmpeg'); Exit; end; Self.Filename := Filename; - // open audio file - if (av_open_input_file(FormatCtx, PChar(Filename), nil, 0, nil) <> 0) then + // use custom 'ufile' protocol for UTF-8 support + if (av_open_input_file(FormatCtx, PAnsiChar('ufile:'+FileName.ToUTF8), nil, 0, nil) <> 0) then begin - Log.LogError('av_open_input_file failed: "' + Filename + '"', 'UAudio_FFmpeg'); + Log.LogError('av_open_input_file failed: "' + Filename.ToNative + '"', 'UAudio_FFmpeg'); Exit; end; @@ -301,7 +302,7 @@ begin // retrieve stream information if (av_find_stream_info(FormatCtx) < 0) then begin - Log.LogError('av_find_stream_info failed: "' + Filename + '"', 'UAudio_FFmpeg'); + Log.LogError('av_find_stream_info failed: "' + Filename.ToNative + '"', 'UAudio_FFmpeg'); Close(); Exit; end; @@ -310,13 +311,13 @@ begin FormatCtx^.pb.eof_reached := 0; {$IFDEF DebugFFmpegDecode} - dump_format(FormatCtx, 0, pchar(Filename), 0); + dump_format(FormatCtx, 0, PAnsiChar(Filename.ToNative), 0); {$ENDIF} AudioStreamIndex := FFmpegCore.FindAudioStreamIndex(FormatCtx); if (AudioStreamIndex < 0) then begin - Log.LogError('FindAudioStreamIndex: No Audio-stream found "' + Filename + '"', 'UAudio_FFmpeg'); + Log.LogError('FindAudioStreamIndex: No Audio-stream found "' + Filename.ToNative + '"', 'UAudio_FFmpeg'); Close(); Exit; end; @@ -378,14 +379,14 @@ begin // try standard format SampleFormat := asfS16; end; - + if CodecCtx^.channels > 255 then + Log.LogStatus('Error: CodecCtx^.channels > 255', 'TFFmpegDecodeStream.Open'); FormatInfo := TAudioFormatInfo.Create( - CodecCtx^.channels, + byte(CodecCtx^.channels), CodecCtx^.sample_rate, SampleFormat ); - PacketQueue := TPacketQueue.Create(); // finally start the decode thread @@ -446,7 +447,9 @@ end; function TFFmpegDecodeStream.GetLength(): real; begin - // do not forget to consider the start_time value here + // do not forget to consider the start_time value here + // there is a type size mismatch warnign because start_time and duration are cint64. + // So, in principle there could be an overflow when doing the sum. Result := (FormatCtx^.start_time + FormatCtx^.duration) / AV_TIME_BASE; end; @@ -643,7 +646,6 @@ end; function TFFmpegDecodeStream.ParseLoop(): boolean; var Packet: TAVPacket; - StatusPacket: PAVPacket; SeekTarget: int64; ByteIOCtx: PByteIOContext; ErrorCode: integer; @@ -862,7 +864,7 @@ begin end; end; -function TFFmpegDecodeStream.DecodeFrame(Buffer: PChar; BufferSize: integer): integer; +function TFFmpegDecodeStream.DecodeFrame(Buffer: PByteArray; BufferSize: integer): integer; var PaketDecodedSize: integer; // size of packet data used for decoding DataSize: integer; // size of output data decoded by FFmpeg @@ -945,7 +947,7 @@ begin Exit; // handle Status-packet - if (PChar(AudioPaket.data) = STATUS_PACKET) then + if (PAnsiChar(AudioPaket.data) = STATUS_PACKET) then begin AudioPaket.data := nil; AudioPaketData := nil; @@ -986,7 +988,7 @@ begin Continue; end; - AudioPaketData := PChar(AudioPaket.data); + AudioPaketData := AudioPaket.data; AudioPaketSize := AudioPaket.size; // if available, update the stream position to the presentation time of this package @@ -1005,7 +1007,7 @@ begin end; end; -function TFFmpegDecodeStream.ReadData(Buffer: PChar; BufferSize: integer): integer; +function TFFmpegDecodeStream.ReadData(Buffer: PByteArray; BufferSize: integer): integer; var CopyByteCount: integer; // number of bytes to copy RemainByteCount: integer; // number of bytes left (remain) to read @@ -1116,7 +1118,7 @@ begin Result := true; end; -function TAudioDecoder_FFmpeg.Open(const Filename: string): TAudioDecodeStream; +function TAudioDecoder_FFmpeg.Open(const Filename: IPath): TAudioDecodeStream; var Stream: TFFmpegDecodeStream; begin diff --git a/Lua/src/media/UAudioInput_Bass.pas b/Lua/src/media/UAudioInput_Bass.pas index cf292c45..9d4417f1 100644 --- a/Lua/src/media/UAudioInput_Bass.pas +++ b/Lua/src/media/UAudioInput_Bass.pas @@ -95,7 +95,7 @@ var * user - players associated with left/right channels *} function MicrophoneCallback(stream: HSTREAM; buffer: Pointer; - len: Cardinal; inputDevice: Pointer): boolean; {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} + len: integer; inputDevice: Pointer): boolean; {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} begin AudioInputProcessor.HandleMicrophoneData(buffer, len, inputDevice); Result := true; @@ -489,6 +489,11 @@ end; function TAudioInput_Bass.InitializeRecord(): boolean; begin BassCore := TAudioCore_Bass.GetInstance(); + if not BassCore.CheckVersion then + begin + Result := false; + Exit; + end; Result := EnumDevices(); end; diff --git a/Lua/src/media/UAudioInput_Portaudio.pas b/Lua/src/media/UAudioInput_Portaudio.pas index 53080a03..31d2882b 100644 --- a/Lua/src/media/UAudioInput_Portaudio.pas +++ b/Lua/src/media/UAudioInput_Portaudio.pas @@ -95,7 +95,6 @@ var Error: TPaError; inputParams: TPaStreamParameters; deviceInfo: PPaDeviceInfo; - SourceIndex: integer; begin Result := false; @@ -291,8 +290,6 @@ var sourceIndex: integer; sourceName: string; {$ENDIF} - cbPolls: integer; - cbWorks: boolean; begin Result := false; diff --git a/Lua/src/media/UAudioPlaybackBase.pas b/Lua/src/media/UAudioPlaybackBase.pas index 7d143fdc..de2d5563 100644 --- a/Lua/src/media/UAudioPlaybackBase.pas +++ b/Lua/src/media/UAudioPlaybackBase.pas @@ -34,7 +34,8 @@ interface {$I switches.inc} uses - UMusic; + UMusic, + UPath; type TAudioPlaybackBase = class(TInterfacedObject, IAudioPlayback) @@ -46,12 +47,12 @@ type function GetLatency(): double; virtual; abstract; // open sound or music stream (used by Open() and OpenSound()) - function OpenStream(const Filename: string): TAudioPlaybackStream; - function OpenDecodeStream(const Filename: string): TAudioDecodeStream; + function OpenStream(const Filename: IPath): TAudioPlaybackStream; + function OpenDecodeStream(const Filename: IPath): TAudioDecodeStream; public function GetName: string; virtual; abstract; - function Open(const Filename: string): boolean; // true if succeed + function Open(const Filename: IPath): boolean; // true if succeed procedure Close; procedure Play; @@ -79,7 +80,7 @@ type function Length: real; // Sounds - function OpenSound(const Filename: string): TAudioPlaybackStream; + function OpenSound(const Filename: IPath): TAudioPlaybackStream; procedure PlaySound(Stream: TAudioPlaybackStream); procedure StopSound(Stream: TAudioPlaybackStream); @@ -108,7 +109,7 @@ begin Result := true; end; -function TAudioPlaybackBase.Open(const Filename: string): boolean; +function TAudioPlaybackBase.Open(const Filename: IPath): boolean; begin // free old MusicStream MusicStream.Free; @@ -130,7 +131,7 @@ begin FreeAndNil(MusicStream); end; -function TAudioPlaybackBase.OpenDecodeStream(const Filename: String): TAudioDecodeStream; +function TAudioPlaybackBase.OpenDecodeStream(const Filename: IPath): TAudioDecodeStream; var i: integer; begin @@ -140,7 +141,7 @@ begin if (assigned(Result)) then begin Log.LogInfo('Using decoder ' + IAudioDecoder(AudioDecoders[i]).GetName() + - ' for "' + Filename + '"', 'TAudioPlaybackBase.OpenDecodeStream'); + ' for "' + Filename.ToNative + '"', 'TAudioPlaybackBase.OpenDecodeStream'); Exit; end; end; @@ -157,7 +158,7 @@ begin SourceStream.Free; end; -function TAudioPlaybackBase.OpenStream(const Filename: string): TAudioPlaybackStream; +function TAudioPlaybackBase.OpenStream(const Filename: IPath): TAudioPlaybackStream; var PlaybackStream: TAudioPlaybackStream; DecodeStream: TAudioDecodeStream; @@ -169,7 +170,7 @@ begin DecodeStream := OpenDecodeStream(Filename); if (not assigned(DecodeStream)) then begin - Log.LogStatus('Could not open "' + Filename + '"', 'TAudioPlayback_Bass.OpenStream'); + Log.LogStatus('Could not open "' + Filename.ToNative + '"', 'TAudioPlayback_Bass.OpenStream'); Exit; end; @@ -283,7 +284,7 @@ begin Result := 0; end; -function TAudioPlaybackBase.OpenSound(const Filename: string): TAudioPlaybackStream; +function TAudioPlaybackBase.OpenSound(const Filename: IPath): TAudioPlaybackStream; begin Result := OpenStream(Filename); end; diff --git a/Lua/src/media/UAudioPlayback_Bass.pas b/Lua/src/media/UAudioPlayback_Bass.pas index d68ac1d4..1d7a44dc 100644 --- a/Lua/src/media/UAudioPlayback_Bass.pas +++ b/Lua/src/media/UAudioPlayback_Bass.pas @@ -37,7 +37,6 @@ implementation uses Classes, - SysUtils, Math, UIni, UMain, @@ -46,7 +45,8 @@ uses UAudioCore_Bass, ULog, sdl, - bass; + bass, + SysUtils; type PHDSP = ^HDSP; @@ -90,7 +90,7 @@ type function GetAudioFormatInfo(): TAudioFormatInfo; override; - function ReadData(Buffer: PChar; BufferSize: integer): integer; + function ReadData(Buffer: PByteArray; BufferSize: integer): integer; property EOF: boolean READ IsEOF; end; @@ -106,8 +106,8 @@ type function Open(ChannelMap: integer; FormatInfo: TAudioFormatInfo): boolean; override; procedure Close(); override; - procedure WriteData(Buffer: PChar; BufferSize: integer); override; - function ReadData(Buffer: PChar; BufferSize: integer): integer; override; + procedure WriteData(Buffer: PByteArray; BufferSize: integer); override; + function ReadData(Buffer: PByteArray; BufferSize: integer): integer; override; function IsEOF(): boolean; override; function IsError(): boolean; override; end; @@ -163,14 +163,14 @@ begin Result := BytesRead; end; -function TBassPlaybackStream.ReadData(Buffer: PChar; BufferSize: integer): integer; +function TBassPlaybackStream.ReadData(Buffer: PByteArray; BufferSize: integer): integer; var AdjustedSize: integer; RequestedSourceSize, SourceSize: integer; SkipCount: integer; SourceFormatInfo: TAudioFormatInfo; FrameSize: integer; - PadFrame: PChar; + PadFrame: PByteArray; //Info: BASS_INFO; //Latency: double; begin @@ -610,7 +610,7 @@ begin inherited Close(); end; -procedure TBassVoiceStream.WriteData(Buffer: PChar; BufferSize: integer); +procedure TBassVoiceStream.WriteData(Buffer: PByteArray; BufferSize: integer); var QueueSize: DWORD; begin if ((Handle <> 0) and (BufferSize > 0)) then @@ -626,7 +626,7 @@ begin end; // Note: we do not need the read-function for the BASS implementation -function TBassVoiceStream.ReadData(Buffer: PChar; BufferSize: integer): integer; +function TBassVoiceStream.ReadData(Buffer: PByteArray; BufferSize: integer): integer; begin Result := -1; end; @@ -684,9 +684,11 @@ end; function TAudioPlayback_Bass.InitializePlayback(): boolean; begin - result := false; + Result := false; BassCore := TAudioCore_Bass.GetInstance(); + if not BassCore.CheckVersion then + Exit; EnumDevices(); @@ -706,7 +708,7 @@ begin //BASS_SetConfig(BASS_CONFIG_UPDATEPERIOD, 10); //BASS_SetConfig(BASS_CONFIG_BUFFER, 100); - result := true; + Result := true; end; function TAudioPlayback_Bass.FinalizePlayback(): boolean; diff --git a/Lua/src/media/UAudioPlayback_SDL.pas b/Lua/src/media/UAudioPlayback_SDL.pas index b0887676..8403ef03 100644 --- a/Lua/src/media/UAudioPlayback_SDL.pas +++ b/Lua/src/media/UAudioPlayback_SDL.pas @@ -33,16 +33,14 @@ interface {$I switches.inc} -uses - Classes, - SysUtils, - UMusic; - implementation uses + Classes, sdl, + SysUtils, UAudioPlayback_SoftMixer, + UMusic, ULog, UIni, UMain; @@ -60,13 +58,13 @@ type function GetLatency(): double; override; public function GetName: String; override; - procedure MixBuffers(dst, src: PChar; size: Cardinal; volume: Single); override; + procedure MixBuffers(dst, src: PByteArray; size: Cardinal; volume: Single); override; end; { TAudioPlayback_SDL } -procedure SDLAudioCallback(userdata: Pointer; stream: PChar; len: integer); cdecl; +procedure SDLAudioCallback(userdata: Pointer; stream: PByteArray; len: integer); cdecl; var Engine: TAudioPlayback_SDL; begin @@ -172,7 +170,7 @@ begin Result := Latency; end; -procedure TAudioPlayback_SDL.MixBuffers(dst, src: PChar; size: Cardinal; volume: Single); +procedure TAudioPlayback_SDL.MixBuffers(dst, src: PByteArray; size: Cardinal; volume: Single); begin SDL_MixAudio(PUInt8(dst), PUInt8(src), size, Round(volume * SDL_MIX_MAXVOLUME)); end; diff --git a/Lua/src/media/UAudioPlayback_SoftMixer.pas b/Lua/src/media/UAudioPlayback_SoftMixer.pas index f3797dd6..c87e461d 100644 --- a/Lua/src/media/UAudioPlayback_SoftMixer.pas +++ b/Lua/src/media/UAudioPlayback_SoftMixer.pas @@ -35,8 +35,8 @@ interface uses Classes, - SysUtils, sdl, + SysUtils, URingBuffer, UMusic, UAudioPlaybackBase; @@ -48,12 +48,12 @@ type private Engine: TAudioPlayback_SoftMixer; - SampleBuffer: PChar; + SampleBuffer: PByteArray; SampleBufferSize: integer; SampleBufferCount: integer; // number of available bytes in SampleBuffer - SampleBufferPos: cardinal; + SampleBufferPos: integer; - SourceBuffer: PChar; + SourceBuffer: PByteArray; SourceBufferSize: integer; SourceBufferCount: integer; // number of available bytes in SourceBuffer @@ -70,7 +70,7 @@ type procedure Reset(); - procedure ApplySoundEffects(Buffer: PChar; BufferSize: integer); + procedure ApplySoundEffects(Buffer: PByteArray; BufferSize: integer); function InitFormatConversion(): boolean; procedure FlushBuffers(); @@ -100,7 +100,7 @@ type function GetAudioFormatInfo(): TAudioFormatInfo; override; - function ReadData(Buffer: PChar; BufferSize: integer): integer; + function ReadData(Buffer: PByteArray; BufferSize: integer): integer; function GetPCMData(var Data: TPCMData): Cardinal; override; procedure GetFFTData(var Data: TFFTData); override; @@ -114,7 +114,7 @@ type Engine: TAudioPlayback_SoftMixer; ActiveStreams: TList; - MixerBuffer: PChar; + MixerBuffer: PByteArray; InternalLock: PSDL_Mutex; AppVolume: single; @@ -129,7 +129,7 @@ type destructor Destroy(); override; procedure AddStream(Stream: TAudioPlaybackStream); procedure RemoveStream(Stream: TAudioPlaybackStream); - function ReadData(Buffer: PChar; BufferSize: integer): integer; + function ReadData(Buffer: PByteArray; BufferSize: integer): integer; property Volume: single read GetVolume write SetVolume; end; @@ -144,7 +144,7 @@ type function StartAudioPlaybackEngine(): boolean; virtual; abstract; procedure StopAudioPlaybackEngine(); virtual; abstract; function FinalizeAudioPlaybackEngine(): boolean; virtual; abstract; - procedure AudioCallback(Buffer: PChar; Size: integer); {$IFDEF HasInline}inline;{$ENDIF} + procedure AudioCallback(Buffer: PByteArray; Size: integer); {$IFDEF HasInline}inline;{$ENDIF} function CreatePlaybackStream(): TAudioPlaybackStream; override; public @@ -159,7 +159,7 @@ type function GetMixer(): TAudioMixerStream; {$IFDEF HasInline}inline;{$ENDIF} function GetAudioFormatInfo(): TAudioFormatInfo; - procedure MixBuffers(DstBuffer, SrcBuffer: PChar; Size: Cardinal; Volume: Single); virtual; + procedure MixBuffers(DstBuffer, SrcBuffer: PByteArray; Size: Cardinal; Volume: Single); virtual; end; type @@ -174,8 +174,8 @@ type function Open(ChannelMap: integer; FormatInfo: TAudioFormatInfo): boolean; override; procedure Close(); override; - procedure WriteData(Buffer: PChar; BufferSize: integer); override; - function ReadData(Buffer: PChar; BufferSize: integer): integer; override; + procedure WriteData(Buffer: PByteArray; BufferSize: integer); override; + function ReadData(Buffer: PByteArray; BufferSize: integer): integer; override; function IsEOF(): boolean; override; function IsError(): boolean; override; end; @@ -276,7 +276,7 @@ begin Unlock(); end; -function TAudioMixerStream.ReadData(Buffer: PChar; BufferSize: integer): integer; +function TAudioMixerStream.ReadData(Buffer: PByteArray; BufferSize: integer): integer; var i: integer; Size: integer; @@ -545,7 +545,7 @@ begin SourceBufferCount := 0; end; -procedure TGenericPlaybackStream.ApplySoundEffects(Buffer: PChar; BufferSize: integer); +procedure TGenericPlaybackStream.ApplySoundEffects(Buffer: PByteArray; BufferSize: integer); var i: integer; begin @@ -558,23 +558,21 @@ begin end; end; -function TGenericPlaybackStream.ReadData(Buffer: PChar; BufferSize: integer): integer; +function TGenericPlaybackStream.ReadData(Buffer: PByteArray; BufferSize: integer): integer; var ConversionInputCount: integer; ConversionOutputSize: integer; // max. number of converted data (= buffer size) ConversionOutputCount: integer; // actual number of converted data SourceSize: integer; - RequestedSourceSize: integer; NeededSampleBufferSize: integer; - BytesNeeded, BytesAvail: integer; + BytesNeeded: integer; SourceFormatInfo, OutputFormatInfo: TAudioFormatInfo; SourceFrameSize, OutputFrameSize: integer; SkipOutputCount: integer; // number of output-data bytes to skip SkipSourceCount: integer; // number of source-data bytes to skip FillCount: integer; // number of bytes to fill with padding data CopyCount: integer; - PadFrame: PChar; - i: integer; + PadFrame: PByteArray; begin Result := -1; @@ -986,7 +984,7 @@ begin inherited Close(); end; -procedure TGenericVoiceStream.WriteData(Buffer: PChar; BufferSize: integer); +procedure TGenericVoiceStream.WriteData(Buffer: PByteArray; BufferSize: integer); begin // lock access to buffer SDL_mutexP(BufferLock); @@ -999,7 +997,7 @@ begin end; end; -function TGenericVoiceStream.ReadData(Buffer: PChar; BufferSize: integer): integer; +function TGenericVoiceStream.ReadData(Buffer: PByteArray; BufferSize: integer): integer; begin Result := -1; @@ -1059,7 +1057,7 @@ begin Result := true; end; -procedure TAudioPlayback_SoftMixer.AudioCallback(Buffer: PChar; Size: integer); +procedure TAudioPlayback_SoftMixer.AudioCallback(Buffer: PByteArray; Size: integer); begin MixerStream.ReadData(Buffer, Size); end; @@ -1102,7 +1100,7 @@ begin MixerStream.Volume := Volume; end; -procedure TAudioPlayback_SoftMixer.MixBuffers(DstBuffer, SrcBuffer: PChar; Size: Cardinal; Volume: Single); +procedure TAudioPlayback_SoftMixer.MixBuffers(DstBuffer, SrcBuffer: PByteArray; Size: Cardinal; Volume: Single); var SampleIndex: Cardinal; SampleInt: Integer; diff --git a/Lua/src/media/UMediaCore_FFmpeg.pas b/Lua/src/media/UMediaCore_FFmpeg.pas index 9ad19a5b..b4951fe1 100644 --- a/Lua/src/media/UMediaCore_FFmpeg.pas +++ b/Lua/src/media/UMediaCore_FFmpeg.pas @@ -34,12 +34,16 @@ interface {$I switches.inc} uses - UMusic, + Classes, + ctypes, + sdl, avcodec, avformat, avutil, + avio, + UMusic, ULog, - sdl; + UPath; type PPacketQueue = ^TPacketQueue; @@ -97,12 +101,29 @@ implementation uses SysUtils; +function FFmpegStreamOpen(h: PURLContext; filename: PChar; flags: cint): cint; cdecl; forward; +function FFmpegStreamRead(h: PURLContext; buf: PByteArray; size: cint): cint; cdecl; forward; +function FFmpegStreamWrite(h: PURLContext; buf: PByteArray; size: cint): cint; cdecl; forward; +function FFmpegStreamSeek(h: PURLContext; pos: int64; whence: cint): int64; cdecl; forward; +function FFmpegStreamClose(h: PURLContext): cint; cdecl; forward; + +const + UTF8FileProtocol: TURLProtocol = ( + name: 'ufile'; + url_open: FFmpegStreamOpen; + url_read: FFmpegStreamRead; + url_write: FFmpegStreamWrite; + url_seek: FFmpegStreamSeek; + url_close: FFmpegStreamClose; + ); + var Instance: TMediaCore_FFmpeg; constructor TMediaCore_FFmpeg.Create(); begin inherited; + av_register_protocol(@UTF8FileProtocol); AVCodecLock := SDL_CreateMutex(); end; @@ -220,6 +241,105 @@ begin Result := true; end; + +{** + * UTF-8 Filename wrapper based on: + * http://www.mail-archive.com/libav-user@mplayerhq.hu/msg02460.html + *} + +function FFmpegStreamOpen(h: PURLContext; filename: PChar; flags: cint): cint; cdecl; +var + Stream: TStream; + Mode: word; + ProtPrefix: string; + FilePath: IPath; +begin + // check for protocol prefix ('ufile:') and strip it + ProtPrefix := Format('%s:', [UTF8FileProtocol.name]); + if (StrLComp(filename, PChar(ProtPrefix), Length(ProtPrefix)) = 0) then + begin + Inc(filename, Length(ProtPrefix)); + end; + + FilePath := Path(filename); + + if ((flags and URL_RDWR) <> 0) then + Mode := fmCreate + else if ((flags and URL_WRONLY) <> 0) then + Mode := fmCreate // TODO: fmCreate is Read+Write -> reopen with fmOpenWrite + else + Mode := fmOpenRead; + + Result := 0; + + try + Stream := TBinaryFileStream.Create(FilePath, Mode); + h.priv_data := Stream; + except + Result := AVERROR_NOENT; + end; +end; + +function FFmpegStreamRead(h: PURLContext; buf: PByteArray; size: cint): cint; cdecl; +var + Stream: TStream; +begin + Stream := TStream(h.priv_data); + if (Stream = nil) then + raise EInvalidContainer.Create('FFmpegStreamRead on nil'); + try + Result := Stream.Read(buf[0], size); + except + Result := -1; + end; +end; + +function FFmpegStreamWrite(h: PURLContext; buf: PByteArray; size: cint): cint; cdecl; +var + Stream: TStream; +begin + Stream := TStream(h.priv_data); + if (Stream = nil) then + raise EInvalidContainer.Create('FFmpegStreamWrite on nil'); + try + Result := Stream.Write(buf[0], size); + except + Result := -1; + end; +end; + +function FFmpegStreamSeek(h: PURLContext; pos: int64; whence: cint): int64; cdecl; +var + Stream : TStream; + Origin : TSeekOrigin; +begin + Stream := TStream(h.priv_data); + if (Stream = nil) then + raise EInvalidContainer.Create('FFmpegStreamSeek on nil'); + case whence of + 0 {SEEK_SET}: Origin := soBeginning; + 1 {SEEK_CUR}: Origin := soCurrent; + 2 {SEEK_END}: Origin := soEnd; + AVSEEK_SIZE: begin + Result := Stream.Size; + Exit; + end + else + Origin := soBeginning; + end; + Result := Stream.Seek(pos, Origin); +end; + +function FFmpegStreamClose(h: PURLContext): cint; cdecl; +var + Stream : TStream; +begin + Stream := TStream(h.priv_data); + Stream.Free; + Result := 0; +end; + + { TPacketQueue } constructor TPacketQueue.Create(); diff --git a/Lua/src/media/UMedia_dummy.pas b/Lua/src/media/UMedia_dummy.pas index 7558dd0b..25e94724 100644 --- a/Lua/src/media/UMedia_dummy.pas +++ b/Lua/src/media/UMedia_dummy.pas @@ -36,9 +36,10 @@ interface implementation uses - SysUtils, - math, - UMusic; + SysUtils, + math, + UMusic, + UPath; type TMedia_dummy = class( TInterfacedObject, IVideoPlayback, IVideoVisualization, IAudioPlayback, IAudioInput ) @@ -51,7 +52,7 @@ type function Init(): boolean; function Finalize(): boolean; - function Open(const aFileName : string): boolean; // true if succeed + function Open(const aFileName: IPath): boolean; // true if succeed procedure Close; procedure Play; @@ -88,7 +89,7 @@ type function Finished: boolean; function Length: real; - function OpenSound(const Filename: string): TAudioPlaybackStream; + function OpenSound(const Filename: IPath): TAudioPlaybackStream; procedure CloseSound(var PlaybackStream: TAudioPlaybackStream); procedure PlaySound(stream: TAudioPlaybackStream); procedure StopSound(stream: TAudioPlaybackStream); @@ -125,7 +126,7 @@ begin Result := true; end; -function TMedia_dummy.Open(const aFileName : string): boolean; // true if succeed +function TMedia_dummy.Open(const aFileName : IPath): boolean; // true if succeed begin Result := false; end; @@ -236,7 +237,7 @@ begin Result := 60; end; -function TMedia_dummy.OpenSound(const Filename: string): TAudioPlaybackStream; +function TMedia_dummy.OpenSound(const Filename: IPath): TAudioPlaybackStream; begin Result := nil; end; diff --git a/Lua/src/media/UVideo.pas b/Lua/src/media/UVideo.pas index 197fc572..6db9cd20 100644 --- a/Lua/src/media/UVideo.pas +++ b/Lua/src/media/UVideo.pas @@ -22,7 +22,7 @@ * $URL$ * $Id$ *} - + unit UVideo; {* @@ -69,8 +69,9 @@ type implementation uses + SysUtils, + Math, SDL, - textgl, avcodec, avformat, avutil, @@ -79,17 +80,17 @@ uses {$IFDEF UseSWScale} swscale, {$ENDIF} - UMediaCore_FFmpeg, - math, gl, glext, - SysUtils, + textgl, + UMediaCore_FFmpeg, UCommon, UConfig, ULog, UMusic, UGraphicClasses, - UGraphic; + UGraphic, + UPath; const {$IFDEF PIXEL_FMT_BGR} @@ -135,7 +136,7 @@ type fAspect: real; //**< width/height ratio fAspectCorrection: TAspectCorrection; - + fTimeBase: extended; //**< FFmpeg time base per time unit fTime: extended; //**< video time position (absolute) fLoopTime: extended; //**< start time of the current loop @@ -145,7 +146,7 @@ type procedure SynchronizeTime(Frame: PAVFrame; var pts: double); procedure GetVideoRect(var ScreenRect, TexRect: TRectCoords); - + procedure ShowDebugInfo(); public @@ -154,7 +155,7 @@ type function Init(): boolean; function Finalize: boolean; - function Open(const aFileName : string): boolean; // true if succeed + function Open(const FileName : IPath): boolean; // true if succeed procedure Close; procedure Play; @@ -171,7 +172,7 @@ type var FFmpegCore: TMediaCore_FFmpeg; - + // These are called whenever we allocate a frame buffer. // We use this to store the global_pts in a frame at the time it is allocated. function PtsGetBuffer(CodecCtx: PAVCodecContext; Frame: PAVFrame): integer; cdecl; @@ -248,11 +249,11 @@ begin // TODO: do we really want this by default? fLoop := true; fLoopTime := 0; - + fAspectCorrection := acoCrop; end; -function TVideoPlayback_FFmpeg.Open(const aFileName : string): boolean; // true if succeed +function TVideoPlayback_FFmpeg.Open(const FileName : IPath): boolean; // true if succeed var errnum: Integer; AudioStreamIndex: integer; @@ -261,10 +262,11 @@ begin Reset(); - errnum := av_open_input_file(fFormatContext, PChar(aFileName), nil, 0, nil); + // use custom 'ufile' protocol for UTF-8 support + errnum := av_open_input_file(fFormatContext, PAnsiChar('ufile:'+FileName.ToNative), nil, 0, nil); if (errnum <> 0) then begin - Log.LogError('Failed to open file "'+aFileName+'" ('+FFmpegCore.GetErrorString(errnum)+')'); + Log.LogError('Failed to open file "'+ FileName.ToNative +'" ('+FFmpegCore.GetErrorString(errnum)+')'); Exit; end; @@ -434,7 +436,7 @@ begin fAVFrame := nil; fAVFrameRGB := nil; fFrameBuffer := nil; - + if (fCodecContext <> nil) then begin // avcodec_close() is not thread-safe @@ -479,7 +481,7 @@ end; * Decode a new frame from the video stream. * The decoded frame is stored in fAVFrame. fTime is updated to the new frame's * time. - * @param pts will be updated to the presentation time of the decoded frame. + * @param pts will be updated to the presentation time of the decoded frame. * returns true if a frame could be decoded. False if an error or EOF occured. *} function TVideoPlayback_FFmpeg.DecodeFrame(): boolean; @@ -532,8 +534,17 @@ begin end; // no error -> wait for user input - SDL_Delay(100); +{ + SDL_Delay(100); // initial version, left for documentation continue; +} + + // Patch by Hawkear: + // Why should this function loop in an endless loop if there is an error? + // This runs in the main thread, so it halts the whole program + // Therefore, it is better to exit when an error occurs + Exit; + end; // if we got a packet from the video stream, then decode it @@ -564,6 +575,10 @@ begin begin pts := 0; end; + + if fStream^.start_time <> AV_NOPTS_VALUE then + pts := pts - fStream^.start_time; + pts := pts * av_q2d(fStream^.time_base); // synchronize time on each complete frame @@ -611,7 +626,7 @@ begin 'TimeDiff: '+inttostr(floor(TimeDifference*1000))); {$endif} - // check if last time is more than one frame in the past + // check if last time is more than one frame in the past if (TimeDifference < fTimeBase) then begin {$ifdef DebugFrames} @@ -635,7 +650,7 @@ begin {$IFDEF VideoBenchmark} Log.BenchmarkStart(15); {$ENDIF} - + // fetch new frame (updates fTime) Success := DecodeFrame(); TimeDifference := NewTime - fTime; @@ -662,7 +677,7 @@ begin Success := DecodeFrame(); end; - // check if we got an EOF or error + // check if we got an EOF or error if (not Success) then begin if fLoop then @@ -688,11 +703,17 @@ begin 0, fCodecContext^.Height, @(fAVFrameRGB.data), @(fAVFrameRGB.linesize)); {$ELSE} + // img_convert from lib/ffmpeg/avcodec.pas is actually deprecated. + // If ./configure does not find SWScale then this gives the error + // that the identifier img_convert is not known or similar. + // I think this should be removed, but am not sure whether there should + // be some other replacement or a warning, Therefore, I leave it for now. + // April 2009, mischi errnum := img_convert(PAVPicture(fAVFrameRGB), PIXEL_FMT_FFMPEG, PAVPicture(fAVFrame), fCodecContext^.pix_fmt, fCodecContext^.width, fCodecContext^.height); {$ENDIF} - + if (errnum < 0) then begin Log.LogError('Image conversion failed', 'TVideoPlayback_ffmpeg.GetFrame'); @@ -785,8 +806,18 @@ var begin // have a nice black background to draw on // (even if there were errors opening the vid) - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); + // TODO: Philipp: IMO TVideoPlayback should not clear the screen at + // all, because clearing is already done by the background class + // at this moment. + if (Screen = 1) then + begin + // It is important that we just clear once before we start + // drawing the first screen otherwise the first screen + // would be cleared by the drawgl called when the second + // screen is drawn + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); + end; // exit if there's nothing to draw if (not fOpened) then @@ -913,7 +944,7 @@ begin fTime := Time; fEOF := false; - fFrameTexValid := false; + fFrameTexValid := false; if (av_seek_frame(fFormatContext, fStreamIndex, Floor(Time/fTimeBase), SeekFlags) < 0) then begin diff --git a/Lua/src/media/UVisualizer.pas b/Lua/src/media/UVisualizer.pas index 9af6d8c2..b25d68a9 100644 --- a/Lua/src/media/UVisualizer.pas +++ b/Lua/src/media/UVisualizer.pas @@ -77,6 +77,7 @@ uses UGraphic, UMain, UConfig, + UPath, ULog; {$IF PROJECTM_VERSION < 1000000} // < 1.0 @@ -130,7 +131,7 @@ type function Init(): boolean; function Finalize(): boolean; - function Open(const aFileName : string): boolean; // true if succeed + function Open(const aFileName: IPath): boolean; // true if succeed procedure Close; procedure Play; @@ -183,7 +184,7 @@ begin Result := true; end; -function TVideoPlayback_ProjectM.Open(const aFileName : string): boolean; // true if succeed +function TVideoPlayback_ProjectM.Open(const aFileName: IPath): boolean; // true if succeed begin Result := false; end; @@ -484,7 +485,11 @@ begin glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); - gluOrtho2D(0, 1, 0, 1); + // Use count of screens instead of 1 for the right corner + // otherwise we would draw the visualization streched over both screens + // another point is that we draw over the at this time drawn first + // screen, if Screen = 2 + gluOrtho2D(0, Screens, 0, 1); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); @@ -496,11 +501,12 @@ begin glColor4f(1, 1, 1, 1); // draw projectM frame + // Screen is 1 to 2. So current screen is from (Screen - 1) to (Screen) glBegin(GL_QUADS); - glTexCoord2f(0, 0); glVertex2f(0, 0); - glTexCoord2f(1, 0); glVertex2f(1, 0); - glTexCoord2f(1, 1); glVertex2f(1, 1); - glTexCoord2f(0, 1); glVertex2f(0, 1); + glTexCoord2f(0, 0); glVertex2f((Screen - 1), 0); + glTexCoord2f(1, 0); glVertex2f(Screen, 0); + glTexCoord2f(1, 1); glVertex2f(Screen, 1); + glTexCoord2f(0, 1); glVertex2f((Screen - 1), 1); glEnd(); glDisable(GL_TEXTURE_2D); -- cgit v1.2.3