aboutsummaryrefslogtreecommitdiffstats
path: root/mediaplugin/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--mediaplugin/src/media/UAudioConverter.pas82
-rw-r--r--mediaplugin/src/media/UAudioDecoder_FFmpeg.pas15
-rw-r--r--mediaplugin/src/media/UMediaCore_FFmpeg.pas302
-rw-r--r--mediaplugin/src/media/UMediaPlugin.pas40
4 files changed, 57 insertions, 382 deletions
diff --git a/mediaplugin/src/media/UAudioConverter.pas b/mediaplugin/src/media/UAudioConverter.pas
index 657b80dd..aa3e343e 100644
--- a/mediaplugin/src/media/UAudioConverter.pas
+++ b/mediaplugin/src/media/UAudioConverter.pas
@@ -40,9 +40,7 @@ uses
{$IFDEF UseSRCResample}
samplerate,
{$ENDIF}
- {$IFDEF UseFFmpegResample}
- avcodec,
- {$ENDIF}
+ UMediaPlugin,
UMediaCore_SDL,
sdl,
SysUtils,
@@ -76,13 +74,11 @@ type
end;
{$IFDEF UseFFmpegResample}
- // Note: FFmpeg seems to be using "kaiser windowed sinc" for resampling, so
- // the quality should be good.
TAudioConverter_FFmpeg = class(TAudioConverter)
private
- // TODO: use SDL for multi-channel->stereo and format conversion
- ResampleContext: PReSampleContext;
- Ratio: double;
+ fPluginInfo: PMediaPluginInfo;
+ fAudioConverter: PAudioConverterInfo;
+ fStream: PAudioConvertStream;
public
function Init(SrcFormatInfo: TAudioFormatInfo; DstFormatInfo: TAudioFormatInfo): boolean; override;
destructor Destroy(); override;
@@ -199,84 +195,50 @@ end;
{$IFDEF UseFFmpegResample}
function TAudioConverter_FFmpeg.Init(SrcFormatInfo: TAudioFormatInfo; DstFormatInfo: TAudioFormatInfo): boolean;
+var
+ CSrcFormatInfo: TCAudioFormatInfo;
+ CDstFormatInfo: TCAudioFormatInfo;
begin
inherited Init(SrcFormatInfo, DstFormatInfo);
Result := false;
-
- // Note: ffmpeg does not support resampling for more than 2 input channels
-
- if (srcFormatInfo.Format <> asfS16) then
- begin
- Log.LogError('Unsupported format', 'TAudioConverter_FFmpeg.Init');
- Exit;
- end;
-
- // TODO: use SDL here
- if (srcFormatInfo.Format <> dstFormatInfo.Format) then
+ fPluginInfo := Plugin_register(MediaPluginCore);
+ fPluginInfo.initialize();
+ fAudioConverter := fPluginInfo.audioConverter;
+
+ AudioFormatInfoToCStruct(SrcFormatInfo, CSrcFormatInfo);
+ AudioFormatInfoToCStruct(DstFormatInfo, CDstFormatInfo);
+ fStream := fAudioConverter.open(@CSrcFormatInfo, @CDstFormatInfo);
+ if (fStream = nil) then
begin
- Log.LogError('Incompatible formats', 'TAudioConverter_FFmpeg.Init');
+ Log.LogError('fAudioConverter.open() failed', 'TAudioConverter_FFmpeg.Init');
Exit;
end;
- ResampleContext := audio_resample_init(
- dstFormatInfo.Channels, srcFormatInfo.Channels,
- Round(dstFormatInfo.SampleRate), Round(srcFormatInfo.SampleRate));
- if (ResampleContext = nil) then
- begin
- Log.LogError('audio_resample_init() failed', 'TAudioConverter_FFmpeg.Init');
- Exit;
- end;
-
- // calculate ratio
- Ratio := (dstFormatInfo.Channels / srcFormatInfo.Channels) *
- (dstFormatInfo.SampleRate / srcFormatInfo.SampleRate);
-
Result := true;
end;
destructor TAudioConverter_FFmpeg.Destroy();
begin
- if (ResampleContext <> nil) then
- audio_resample_close(ResampleContext);
+ if (fStream <> nil) then
+ fAudioConverter.close(fStream);
inherited;
end;
function TAudioConverter_FFmpeg.Convert(InputBuffer: PByteArray; OutputBuffer: PByteArray; var InputSize: integer): integer;
-var
- InputSampleCount: integer;
- OutputSampleCount: integer;
begin
- Result := -1;
-
- if (InputSize <= 0) then
- begin
- // avoid div-by-zero in audio_resample()
- if (InputSize = 0) then
- Result := 0;
- Exit;
- end;
-
- InputSampleCount := InputSize div SrcFormatInfo.FrameSize;
- OutputSampleCount := audio_resample(
- ResampleContext, PSmallInt(OutputBuffer), PSmallInt(InputBuffer),
- InputSampleCount);
- if (OutputSampleCount = -1) then
- begin
- Log.LogError('audio_resample() failed', 'TAudioConverter_FFmpeg.Convert');
- Exit;
- end;
- Result := OutputSampleCount * DstFormatInfo.FrameSize;
+ Result := fAudioConverter.convert(fStream,
+ PCuint8(InputBuffer), PCuint8(OutputBuffer), @InputSize);
end;
function TAudioConverter_FFmpeg.GetOutputBufferSize(InputSize: integer): integer;
begin
- Result := Ceil(InputSize * GetRatio());
+ Result := fAudioConverter.getOutputBufferSize(fStream, InputSize);
end;
function TAudioConverter_FFmpeg.GetRatio(): double;
begin
- Result := Ratio;
+ Result := fAudioConverter.getRatio(fStream);
end;
{$ENDIF}
diff --git a/mediaplugin/src/media/UAudioDecoder_FFmpeg.pas b/mediaplugin/src/media/UAudioDecoder_FFmpeg.pas
index 3031b46a..bef162bd 100644
--- a/mediaplugin/src/media/UAudioDecoder_FFmpeg.pas
+++ b/mediaplugin/src/media/UAudioDecoder_FFmpeg.pas
@@ -199,21 +199,6 @@ end;
{ TAudioDecoder_FFmpeg }
-const
-{$IFDEF MSWINDOWS}
- ffmpegPlugin = 'ffmpeg_playback.dll';
-{$ENDIF}
-{$IFDEF LINUX}
- ffmpegPlugin = 'ffmpeg_playback';
-{$ENDIF}
-{$IFDEF DARWIN}
- ffmpegPlugin = 'ffmpeg_playback.dylib';
- {$linklib ffmpegPlugin}
-{$ENDIF}
-
-function Plugin_register(core: PMediaPluginCore): PMediaPluginInfo;
- cdecl; external ffmpegPlugin;
-
constructor TAudioDecoder_FFmpeg.Create();
begin
inherited Create();
diff --git a/mediaplugin/src/media/UMediaCore_FFmpeg.pas b/mediaplugin/src/media/UMediaCore_FFmpeg.pas
index eb136995..2f589442 100644
--- a/mediaplugin/src/media/UMediaCore_FFmpeg.pas
+++ b/mediaplugin/src/media/UMediaCore_FFmpeg.pas
@@ -46,32 +46,6 @@ uses
ULog,
UPath;
-type
- PPacketQueue = ^TPacketQueue;
- TPacketQueue = class
- private
- FirstListEntry: PAVPacketList;
- LastListEntry: PAVPacketList;
- PacketCount: integer;
- Mutex: PSDL_Mutex;
- Condition: PSDL_Cond;
- Size: integer;
- AbortRequest: boolean;
- public
- constructor Create();
- destructor Destroy(); override;
-
- function Put(Packet : PAVPacket): integer;
- function PutStatus(StatusFlag: integer; StatusInfo: Pointer): integer;
- procedure FreeStatusInfo(var Packet: TAVPacket);
- function GetStatusInfo(var Packet: TAVPacket): Pointer;
- function Get(var Packet: TAVPacket; Blocking: boolean): integer;
- function GetSize(): integer;
- procedure Flush();
- procedure Abort();
- function IsAborted(): boolean;
- end;
-
const
STATUS_PACKET: PChar = 'STATUS_PACKET';
const
@@ -122,76 +96,8 @@ const
var
Instance: TMediaCore_FFmpeg;
-function AV_VERSION_INT(a, b, c: cardinal): cuint;
-begin
- Result := (a shl 16) or (b shl 8) or c;
-end;
-
procedure CheckVersions();
-var
- libVersion: cuint;
- headerVersion: cuint;
-
- function hexVerToStr(Version: cuint): string;
- var
- Major, Minor, Release: cardinal;
- begin
- Major := (Version shr 16) and $FF;;
- Minor := (Version shr 8) and $FF;
- Release := Version and $FF;
- Result := Format('%d.%d.%d', [Major, Minor, Release]);
- end;
-
begin
- libVersion := avcodec_version();
- headerVersion := AV_VERSION_INT(
- LIBAVCODEC_VERSION_MAJOR,
- LIBAVCODEC_VERSION_MINOR,
- LIBAVCODEC_VERSION_RELEASE);
- if (libVersion <> headerVersion) then
- begin
- Log.LogError(Format('%s header (%s) and DLL (%s) versions do not match.',
- ['libavcodec', hexVerToStr(headerVersion), hexVerToStr(libVersion)]));
- end;
-
- {$IF LIBAVFORMAT_VERSION >= 52020000} // 52.20.0
- libVersion := avformat_version();
- headerVersion := AV_VERSION_INT(
- LIBAVFORMAT_VERSION_MAJOR,
- LIBAVFORMAT_VERSION_MINOR,
- LIBAVFORMAT_VERSION_RELEASE);
- if (libVersion <> headerVersion) then
- begin
- Log.LogError(Format('%s header (%s) and DLL (%s) versions do not match.',
- ['libavformat', hexVerToStr(headerVersion), hexVerToStr(libVersion)]));
- end;
- {$IFEND}
-
- {$IF LIBAVUTIL_VERSION >= 49008000} // 49.8.0
- libVersion := avutil_version();
- headerVersion := AV_VERSION_INT(
- LIBAVUTIL_VERSION_MAJOR,
- LIBAVUTIL_VERSION_MINOR,
- LIBAVUTIL_VERSION_RELEASE);
- if (libVersion <> headerVersion) then
- begin
- Log.LogError(Format('%s header (%s) and DLL (%s) versions do not match.',
- ['libavutil', hexVerToStr(headerVersion), hexVerToStr(libVersion)]));
- end;
- {$IFEND}
-
- {$IF LIBSWSCALE_VERSION >= 000006001} // 0.6.1
- libVersion := swscale_version();
- headerVersion := AV_VERSION_INT(
- LIBSWSCALE_VERSION_MAJOR,
- LIBSWSCALE_VERSION_MINOR,
- LIBSWSCALE_VERSION_RELEASE);
- if (libVersion <> headerVersion) then
- begin
- Log.LogError(Format('%s header (%s) and DLL (%s) versions do not match.',
- ['libswscale', hexVerToStr(headerVersion), hexVerToStr(libVersion)]));
- end;
- {$IFEND}
end;
constructor TMediaCore_FFmpeg.Create();
@@ -434,212 +340,4 @@ begin
Result := 0;
end;
-
-{ TPacketQueue }
-
-constructor TPacketQueue.Create();
-begin
- inherited;
-
- FirstListEntry := nil;
- LastListEntry := nil;
- PacketCount := 0;
- Size := 0;
-
- Mutex := SDL_CreateMutex();
- Condition := SDL_CreateCond();
-end;
-
-destructor TPacketQueue.Destroy();
-begin
- Flush();
- SDL_DestroyMutex(Mutex);
- SDL_DestroyCond(Condition);
- inherited;
-end;
-
-procedure TPacketQueue.Abort();
-begin
- SDL_LockMutex(Mutex);
-
- AbortRequest := true;
-
- SDL_CondBroadcast(Condition);
- SDL_UnlockMutex(Mutex);
-end;
-
-function TPacketQueue.IsAborted(): boolean;
-begin
- SDL_LockMutex(Mutex);
- Result := AbortRequest;
- SDL_UnlockMutex(Mutex);
-end;
-
-function TPacketQueue.Put(Packet : PAVPacket): integer;
-var
- CurrentListEntry : PAVPacketList;
-begin
- Result := -1;
-
- if (Packet = nil) then
- Exit;
-
- if (PChar(Packet^.data) <> STATUS_PACKET) then
- begin
- if (av_dup_packet(Packet) < 0) then
- Exit;
- end;
-
- CurrentListEntry := av_malloc(SizeOf(TAVPacketList));
- if (CurrentListEntry = nil) then
- Exit;
-
- CurrentListEntry^.pkt := Packet^;
- CurrentListEntry^.next := nil;
-
- SDL_LockMutex(Mutex);
- try
- if (LastListEntry = nil) then
- FirstListEntry := CurrentListEntry
- else
- LastListEntry^.next := CurrentListEntry;
-
- LastListEntry := CurrentListEntry;
- Inc(PacketCount);
-
- Size := Size + CurrentListEntry^.pkt.size;
- SDL_CondSignal(Condition);
- finally
- SDL_UnlockMutex(Mutex);
- end;
-
- Result := 0;
-end;
-
-(**
- * Adds a status packet (EOF, Flush, etc.) to the end of the queue.
- * StatusInfo can be used to pass additional information to the decoder.
- * Only assign nil or a valid pointer to data allocated with Getmem() to
- * StatusInfo because the pointer will be disposed with Freemem() on a call
- * to Flush(). If the packet is removed from the queue it is the decoder's
- * responsibility to free the StatusInfo data with FreeStatusInfo().
- *)
-function TPacketQueue.PutStatus(StatusFlag: integer; StatusInfo: Pointer): integer;
-var
- TempPacket: PAVPacket;
-begin
- // create temp. package
- TempPacket := av_malloc(SizeOf(TAVPacket));
- if (TempPacket = nil) then
- begin
- Result := -1;
- Exit;
- end;
- // init package
- av_init_packet(TempPacket^);
- TempPacket^.data := Pointer(STATUS_PACKET);
- TempPacket^.flags := StatusFlag;
- TempPacket^.priv := StatusInfo;
- // put a copy of the package into the queue
- Result := Put(TempPacket);
- // data has been copied -> delete temp. package
- av_free(TempPacket);
-end;
-
-procedure TPacketQueue.FreeStatusInfo(var Packet: TAVPacket);
-begin
- if (Packet.priv <> nil) then
- FreeMem(Packet.priv);
-end;
-
-function TPacketQueue.GetStatusInfo(var Packet: TAVPacket): Pointer;
-begin
- Result := Packet.priv;
-end;
-
-function TPacketQueue.Get(var Packet: TAVPacket; Blocking: boolean): integer;
-var
- CurrentListEntry: PAVPacketList;
-const
- WAIT_TIMEOUT = 10; // timeout in ms
-begin
- Result := -1;
-
- SDL_LockMutex(Mutex);
- try
- while (true) do
- begin
- if (AbortRequest) then
- Exit;
-
- CurrentListEntry := FirstListEntry;
- if (CurrentListEntry <> nil) then
- begin
- FirstListEntry := CurrentListEntry^.next;
- if (FirstListEntry = nil) then
- LastListEntry := nil;
- Dec(PacketCount);
-
- Size := Size - CurrentListEntry^.pkt.size;
- Packet := CurrentListEntry^.pkt;
- av_free(CurrentListEntry);
-
- Result := 1;
- Break;
- end
- else if (not Blocking) then
- begin
- Result := 0;
- Break;
- end
- else
- begin
- // block until a new package arrives,
- // but do not wait till infinity to avoid deadlocks
- if (SDL_CondWaitTimeout(Condition, Mutex, WAIT_TIMEOUT) = SDL_MUTEX_TIMEDOUT) then
- begin
- Result := 0;
- Break;
- end;
- end;
- end;
- finally
- SDL_UnlockMutex(Mutex);
- end;
-end;
-
-function TPacketQueue.GetSize(): integer;
-begin
- SDL_LockMutex(Mutex);
- Result := Size;
- SDL_UnlockMutex(Mutex);
-end;
-
-procedure TPacketQueue.Flush();
-var
- CurrentListEntry, TempListEntry: PAVPacketList;
-begin
- SDL_LockMutex(Mutex);
-
- CurrentListEntry := FirstListEntry;
- while(CurrentListEntry <> nil) do
- begin
- TempListEntry := CurrentListEntry^.next;
- // free status data
- if (PChar(CurrentListEntry^.pkt.data) = STATUS_PACKET) then
- FreeStatusInfo(CurrentListEntry^.pkt);
- // free packet data
- av_free_packet(@CurrentListEntry^.pkt);
- // Note: param must be a pointer to a pointer!
- av_freep(@CurrentListEntry);
- CurrentListEntry := TempListEntry;
- end;
- LastListEntry := nil;
- FirstListEntry := nil;
- PacketCount := 0;
- Size := 0;
-
- SDL_UnlockMutex(Mutex);
-end;
-
end.
diff --git a/mediaplugin/src/media/UMediaPlugin.pas b/mediaplugin/src/media/UMediaPlugin.pas
index 8e2708bf..c676619c 100644
--- a/mediaplugin/src/media/UMediaPlugin.pas
+++ b/mediaplugin/src/media/UMediaPlugin.pas
@@ -36,6 +36,7 @@ interface
{$ENDIF}
uses
+ UMusic,
ctypes;
type
@@ -78,7 +79,7 @@ type
end;
PAudioDecodeStream = Pointer;
- PAudioResampleStream = Pointer;
+ PAudioConvertStream = Pointer;
PCAudioFormatInfo = ^TCAudioFormatInfo;
TCAudioFormatInfo = record
@@ -104,9 +105,11 @@ type
PAudioConverterInfo = ^TAudioConverterInfo;
TAudioConverterInfo = record
- open: function(inputFormat: PCAudioFormatInfo; outputFormat: PCAudioFormatInfo): PAudioResampleStream; cdecl;
- close: procedure(stream: PAudioResampleStream); cdecl;
- convert: function(stream: PAudioResampleStream; input, output: PCuint8; numSamples: cint): cint; cdecl;
+ open: function(inputFormat: PCAudioFormatInfo; outputFormat: PCAudioFormatInfo): PAudioConvertStream; cdecl;
+ close: procedure(stream: PAudioConvertStream); cdecl;
+ convert: function(stream: PAudioConvertStream; input, output: PCuint8; numSamples: PCint): cint; cdecl;
+ getOutputBufferSize: function(stream: PAudioConvertStream; inputSize: cint): cint; cdecl;
+ getRatio: function(stream: PAudioConvertStream): double; cdecl;
end;
PMediaPluginInfo = ^TMediaPluginInfo;
@@ -119,10 +122,29 @@ type
audioConverter: PAudioConverterInfo;
end;
- Plugin_register = function(core: PMediaPluginCore): PMediaPluginInfo; cdecl;
+ Plugin_registerFunc = function(core: PMediaPluginCore): PMediaPluginInfo; cdecl;
+
+const
+{$IFDEF MSWINDOWS}
+ ffmpegPlugin = 'ffmpeg_playback.dll';
+{$ENDIF}
+{$IFDEF LINUX}
+ ffmpegPlugin = 'ffmpeg_playback';
+{$ENDIF}
+{$IFDEF DARWIN}
+ ffmpegPlugin = 'ffmpeg_playback.dylib';
+ {$linklib ffmpegPlugin}
+{$ENDIF}
+
+function Plugin_register(core: PMediaPluginCore): PMediaPluginInfo;
+ cdecl; external ffmpegPlugin;
+
function MediaPluginCore: PMediaPluginCore;
+procedure AudioFormatInfoToCStruct(
+ const Info: TAudioFormatInfo; var CInfo: TCAudioFormatInfo);
+
implementation
uses
@@ -147,6 +169,14 @@ begin
Result := @MediaPluginCore_Instance;
end;
+procedure AudioFormatInfoToCStruct(
+ const Info: TAudioFormatInfo; var CInfo: TCAudioFormatInfo);
+begin
+ CInfo.sampleRate := Info.SampleRate;
+ CInfo.channels := Info.Channels;
+ CInfo.format := Ord(Info.Format);
+end;
+
{* Misc *}
procedure Core_log(level: cint; msg: PChar; context: PChar); cdecl;