aboutsummaryrefslogtreecommitdiffstats
path: root/src/media
diff options
context:
space:
mode:
Diffstat (limited to 'src/media')
-rw-r--r--src/media/UAudioCore_Bass.pas12
-rw-r--r--src/media/UAudioDecoder_Bass.pas21
-rw-r--r--src/media/UAudioDecoder_FFmpeg.pas39
-rw-r--r--src/media/UAudioInput_Bass.pas5
-rw-r--r--src/media/UAudioPlaybackBase.pas23
-rw-r--r--src/media/UAudioPlayback_Bass.pas6
-rw-r--r--src/media/UMediaCore_FFmpeg.pas124
-rw-r--r--src/media/UMedia_dummy.pas15
-rw-r--r--src/media/UVideo.pas22
-rw-r--r--src/media/UVisualizer.pas5
10 files changed, 214 insertions, 58 deletions
diff --git a/src/media/UAudioCore_Bass.pas b/src/media/UAudioCore_Bass.pas
index 12623dc1..197f9760 100644
--- a/src/media/UAudioCore_Bass.pas
+++ b/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/src/media/UAudioDecoder_Bass.pas b/src/media/UAudioDecoder_Bass.pas
index 6bbdaeaa..d6d2425a 100644
--- a/src/media/UAudioDecoder_Bass.pas
+++ b/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)
@@ -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
@@ -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, PAnsiChar(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/src/media/UAudioDecoder_FFmpeg.pas b/src/media/UAudioDecoder_FFmpeg.pas
index 97d8a8df..d079afdc 100644
--- a/src/media/UAudioDecoder_FFmpeg.pas
+++ b/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,
Math,
- UMusic,
- UIni,
- UMain,
+ SysUtils,
avcodec,
avformat,
avutil,
avio,
mathematics, // used for av_rescale_q
rational,
- SDL,
- SysUtils,
+ UMusic,
+ UIni,
+ UMain,
UMediaCore_FFmpeg,
ULog,
UCommon,
- UConfig;
+ UConfig,
+ UPath;
const
MAX_AUDIOQ_SIZE = (5 * 16 * 1024);
@@ -138,7 +139,7 @@ type
AudioBufferSize: integer;
AudioBuffer: PByteArray;
- Filename: string;
+ Filename: IPath;
procedure SetPositionIntern(Time: real; Flush: boolean; Blocking: boolean);
procedure SetEOF(State: boolean); {$IFDEF HasInline}inline;{$ENDIF}
@@ -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;
@@ -183,7 +184,7 @@ type
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, PAnsiChar(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, PAnsiChar(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;
@@ -1117,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/src/media/UAudioInput_Bass.pas b/src/media/UAudioInput_Bass.pas
index ad6c3818..9d4417f1 100644
--- a/src/media/UAudioInput_Bass.pas
+++ b/src/media/UAudioInput_Bass.pas
@@ -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/src/media/UAudioPlaybackBase.pas b/src/media/UAudioPlaybackBase.pas
index 7d143fdc..de2d5563 100644
--- a/src/media/UAudioPlaybackBase.pas
+++ b/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/src/media/UAudioPlayback_Bass.pas b/src/media/UAudioPlayback_Bass.pas
index 923c1d7b..1d7a44dc 100644
--- a/src/media/UAudioPlayback_Bass.pas
+++ b/src/media/UAudioPlayback_Bass.pas
@@ -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/src/media/UMediaCore_FFmpeg.pas b/src/media/UMediaCore_FFmpeg.pas
index 9ad19a5b..b4951fe1 100644
--- a/src/media/UMediaCore_FFmpeg.pas
+++ b/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/src/media/UMedia_dummy.pas b/src/media/UMedia_dummy.pas
index 7558dd0b..25e94724 100644
--- a/src/media/UMedia_dummy.pas
+++ b/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/src/media/UVideo.pas b/src/media/UVideo.pas
index f55690b2..8d441e6c 100644
--- a/src/media/UVideo.pas
+++ b/src/media/UVideo.pas
@@ -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}
@@ -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;
@@ -252,7 +253,7 @@ begin
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.ToUTF8), 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
diff --git a/src/media/UVisualizer.pas b/src/media/UVisualizer.pas
index 37e0268a..b25d68a9 100644
--- a/src/media/UVisualizer.pas
+++ b/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;