From dfbb7bb3556e8d615cc5692001778878e0fbf454 Mon Sep 17 00:00:00 2001 From: Romain Beauxis Date: Sat, 18 May 2013 10:59:51 -0500 Subject: [PATCH] Added dynamically loaded fdkaac encoder. --- Makefile.defs.in | 1 + configure.ac | 9 ++ src/Makefile | 5 +- src/encoder/fdkaac_encoder.ml | 220 ++++++++++++++++---------- src/encoder/fdkaac_encoder_builtin.ml | 28 ++++ src/encoder/fdkaac_encoder_dynlink.ml | 50 ++++++ src/tools/fdkaac_dynlink.ml | 50 ++++++ src/tools/fdkaac_dynlink.mli | 48 ++++++ 8 files changed, 325 insertions(+), 86 deletions(-) create mode 100644 src/encoder/fdkaac_encoder_builtin.ml create mode 100644 src/encoder/fdkaac_encoder_dynlink.ml create mode 100644 src/tools/fdkaac_dynlink.ml create mode 100644 src/tools/fdkaac_dynlink.mli diff --git a/Makefile.defs.in b/Makefile.defs.in index 9135d41e91..f221ad05bc 100644 --- a/Makefile.defs.in +++ b/Makefile.defs.in @@ -79,6 +79,7 @@ W_AACPLUS=@W_AACPLUS@ W_AACPLUS_DYN=@W_AACPLUS_DYN@ W_VOAACENC=@W_VOAACENC@ W_FDKAAC=@W_FDKAAC@ +W_FDKAAC_DYN=@W_FDKAAC_DYN@ W_ALSA=@W_ALSA@ W_BJACK=@W_BJACK@ W_AO=@W_AO@ diff --git a/configure.ac b/configure.ac index 9a2ba66ac7..09e6cc6758 100644 --- a/configure.ac +++ b/configure.ac @@ -484,6 +484,15 @@ AC_CHECK_OCAML_BINDING([voaacenc],[0.1.0]) # AC_CHECK_OCAML_BINDING([fdkaac],[0.1.0]) +if test -z "${W_FDKAAC}"; then + if test -n "${W_DYNLINK}"; then + if test -n "${OCAML_HAS_FIRST_CLASS_MODULES}"; then + W_FDKAAC_DYN=yes + w_FDKAAC="detected at runtime" + fi + fi +fi +AC_SUBST(W_FDKAAC_DYN) # # Theora diff --git a/src/Makefile b/src/Makefile index b6851fb905..e9af43dc7e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -156,9 +156,11 @@ analyze = analyze/analyze_rms.ml encoders = \ encoder/wav_encoder.ml \ encoder/lame_encoder.ml \ + encoder/fdkaac_encoder.ml \ encoder/aacplus_encoder.ml \ $(if ($(OS_TYPE):Win32=),encoder/external_encoder.ml) \ $(if $(W_LAME_DYN),encoder/lame_encoder_dynlink.ml) \ + $(if $(W_FDKAAC_DYN),encoder/fdkaac_encoder_dynlink.ml) \ $(if $(W_AACPLUS_DYN),encoder/aacplus_encoder_dynlink.ml) $(call conditional_compilation,encoders,$(W_SHINE),encoder/shine_encoder.ml) @@ -166,7 +168,7 @@ $(call conditional_compilation,encoders,$(W_LAME),encoder/lame_encoder_builtin.m $(call conditional_compilation,encoders,$(W_FLAC),encoder/flac_encoder.ml) $(call conditional_compilation,encoders,$(W_AACPLUS),encoder/aacplus_encoder_builtin.ml) $(call conditional_compilation,encoders,$(W_VOAACENC),encoder/voaacenc_encoder.ml) -$(call conditional_compilation,encoders,$(W_FDKAAC),encoder/fdkaac_encoder.ml) +$(call conditional_compilation,encoders,$(W_FDKAAC),encoder/fdkaac_encoder_builtin.ml) $(call conditional_compilation,encoders,$(W_TAGLIB),encoder/taglib_id3v2.ml) outputs = outputs/output.ml \ @@ -188,6 +190,7 @@ tools = tools/stdlib.ml tools/doc.ml tools/plug.ml tools/utils.ml \ $(if $(W_DYNLINK),tools/dyntools.ml) \ tools/rqueue.ml \ $(if $(W_LAME_DYN),tools/lame_dynlink.ml) \ + $(if $(W_FDKAAC_DYN),tools/fdkaac_dynlink.ml) \ $(if $(W_AACPLUS_DYN),tools/aacplus_dynlink.ml) \ tools/wav.ml tools/tutils.ml \ tools/file_watcher.ml tools/file_watcher_mtime.ml \ diff --git a/src/encoder/fdkaac_encoder.ml b/src/encoder/fdkaac_encoder.ml index 11b6363080..858090656e 100644 --- a/src/encoder/fdkaac_encoder.ml +++ b/src/encoder/fdkaac_encoder.ml @@ -1,106 +1,156 @@ (***************************************************************************** - + Liquidsoap, a programmable audio stream generator. Copyright 2003-2013 Savonet team - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details, fully stated in the COPYING file at the root of the liquidsoap distribution. - + You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - + *****************************************************************************) - + (** FDK-AAC encoder *) -module G = Generator.Generator - -let create_encoder params = - let encoder = - Fdkaac.Encoder.create params.Encoder.FdkAacEnc.channels - in - let params = [ - `Aot params.Encoder.FdkAacEnc.aot; - `Bitrate (params.Encoder.FdkAacEnc.bitrate*1000); - `Samplerate params.Encoder.FdkAacEnc.samplerate; - `Transmux params.Encoder.FdkAacEnc.transmux ] @ ( - if params.Encoder.FdkAacEnc.aot = `Mpeg_4 `AAC_ELD then - [`Sbr_mode params.Encoder.FdkAacEnc.sbr_mode] - else []) - in - List.iter (Fdkaac.Encoder.set encoder) params; - encoder - -let encoder aac = - let enc = create_encoder aac in - let channels = aac.Encoder.FdkAacEnc.channels in - let samplerate = aac.Encoder.FdkAacEnc.samplerate in - let samplerate_converter = - Audio_converter.Samplerate.create channels - in - let src_freq = float (Frame.audio_of_seconds 1.) in - let dst_freq = float samplerate in - let n = 1024 in - let buf = Buffer.create n in - let encode frame start len = - let start = Frame.audio_of_master start in - let b = AFrame.content_of_type ~channels frame start in - let len = Frame.audio_of_master len in - let b,start,len = - if src_freq <> dst_freq then - let b = Audio_converter.Samplerate.resample - samplerate_converter (dst_freq /. src_freq) - b start len - in - b,0,Array.length b.(0) - else - b,start,len - in - let encoded = Buffer.create n in - Buffer.add_string buf (Audio.S16LE.make b start len); - let len = Buffer.length buf in - let rec f start = - if start+n > len then - begin - Utils.buffer_drop buf start; - Buffer.contents encoded - end - else - begin - let data = Buffer.sub buf start n in - Buffer.add_string encoded - (Fdkaac.Encoder.encode enc data 0 n); - f (start+n) +module type Fdkaac_t = + sig + module Encoder : + sig + exception Invalid_handle + exception Unsupported_parameter + exception Invalid_config + exception Error of int + exception End_of_file + exception Unknown of int + val string_of_exception : exn -> string option + type t + type mpeg2_aac = [ `AAC_LC | `HE_AAC | `HE_AAC_v2 ] + type mpeg4_aac = + [ `AAC_ELD | `AAC_LC | `AAC_LD | `HE_AAC | `HE_AAC_v2 ] + type aot = [ `Mpeg_2 of mpeg2_aac | `Mpeg_4 of mpeg4_aac ] + type bitrate_mode = [ `Constant | `Full_bitreservoir ] + type transmux = + [ `Adif | `Adts | `Latm | `Latm_out_of_band | `Loas | `Raw ] + type param_name = + [ `Afterburner + | `Aot + | `Bandwidth + | `Bitrate + | `Bitrate_mode + | `Granule_length + | `Samplerate + | `Sbr_mode + | `Transmux ] + type param = + [ `Afterburner of bool + | `Aot of aot + | `Bandwidth of bool + | `Bitrate of int + | `Bitrate_mode of bitrate_mode + | `Granule_length of int + | `Samplerate of int + | `Sbr_mode of bool + | `Transmux of transmux ] + val create : int -> t + val set : t -> param -> unit + val get : t -> param_name -> param + val encode : t -> string -> int -> int -> string + val flush : t -> string end + end + +module Register(Fdkaac : Fdkaac_t) = +struct + module G = Generator.Generator + + let create_encoder params = + let encoder = + Fdkaac.Encoder.create params.Encoder.FdkAacEnc.channels in - f 0 - in - let stop () = - let rem = Buffer.contents buf in - let s = - Fdkaac.Encoder.encode enc rem 0 (String.length rem) + let params = [ + `Aot params.Encoder.FdkAacEnc.aot; + `Bitrate (params.Encoder.FdkAacEnc.bitrate*1000); + `Samplerate params.Encoder.FdkAacEnc.samplerate; + `Transmux params.Encoder.FdkAacEnc.transmux ] @ ( + if params.Encoder.FdkAacEnc.aot = `Mpeg_4 `AAC_ELD then + [`Sbr_mode params.Encoder.FdkAacEnc.sbr_mode] + else []) in - s ^ (Fdkaac.Encoder.flush enc) - in - { - Encoder. - insert_metadata = (fun m -> ()) ; - header = None ; - encode = encode ; - stop = stop - } - -let () = - Encoder.plug#register "AAC" - (function - | Encoder.FdkAacEnc m -> Some (fun _ _ -> encoder m) - | _ -> None) + List.iter (Fdkaac.Encoder.set encoder) params; + encoder + + let encoder aac = + let enc = create_encoder aac in + let channels = aac.Encoder.FdkAacEnc.channels in + let samplerate = aac.Encoder.FdkAacEnc.samplerate in + let samplerate_converter = + Audio_converter.Samplerate.create channels + in + let src_freq = float (Frame.audio_of_seconds 1.) in + let dst_freq = float samplerate in + let n = 1024 in + let buf = Buffer.create n in + let encode frame start len = + let start = Frame.audio_of_master start in + let b = AFrame.content_of_type ~channels frame start in + let len = Frame.audio_of_master len in + let b,start,len = + if src_freq <> dst_freq then + let b = Audio_converter.Samplerate.resample + samplerate_converter (dst_freq /. src_freq) + b start len + in + b,0,Array.length b.(0) + else + b,start,len + in + let encoded = Buffer.create n in + Buffer.add_string buf (Audio.S16LE.make b start len); + let len = Buffer.length buf in + let rec f start = + if start+n > len then + begin + Utils.buffer_drop buf start; + Buffer.contents encoded + end + else + begin + let data = Buffer.sub buf start n in + Buffer.add_string encoded + (Fdkaac.Encoder.encode enc data 0 n); + f (start+n) + end + in + f 0 + in + let stop () = + let rem = Buffer.contents buf in + let s = + Fdkaac.Encoder.encode enc rem 0 (String.length rem) + in + s ^ (Fdkaac.Encoder.flush enc) + in + { + Encoder. + insert_metadata = (fun m -> ()) ; + header = None ; + encode = encode ; + stop = stop + } + + let register_encoder name = + Encoder.plug#register name + (function + | Encoder.FdkAacEnc m -> Some (fun _ _ -> encoder m) + | _ -> None) +end diff --git a/src/encoder/fdkaac_encoder_builtin.ml b/src/encoder/fdkaac_encoder_builtin.ml new file mode 100644 index 0000000000..62fa3191d0 --- /dev/null +++ b/src/encoder/fdkaac_encoder_builtin.ml @@ -0,0 +1,28 @@ +(***************************************************************************** + + Liquidsoap, a programmable audio stream generator. + Copyright 2003-2013 Savonet team + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details, fully stated in the COPYING + file at the root of the liquidsoap distribution. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + *****************************************************************************) + +(** Builtin Fdkaac encoder *) + +module Register = Fdkaac_encoder.Register(Fdkaac) + +let () = + Register.register_encoder "AAC/fdkaac/builtin" diff --git a/src/encoder/fdkaac_encoder_dynlink.ml b/src/encoder/fdkaac_encoder_dynlink.ml new file mode 100644 index 0000000000..f979afd345 --- /dev/null +++ b/src/encoder/fdkaac_encoder_dynlink.ml @@ -0,0 +1,50 @@ +(***************************************************************************** + + Liquidsoap, a programmable audio stream generator. + Copyright 2003-2013 Savonet team + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details, fully stated in the COPYING + file at the root of the liquidsoap distribution. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + *****************************************************************************) + +(** Dynamic Fdkaac encoder *) + +let path = + try + [Sys.getenv "FDKAAC_DYN_PATH"] + with + | Not_found -> + List.fold_left + (fun l x -> (x ^ "/fdkaac") :: l) + Configure.findlib_path Configure.findlib_path + +open Fdkaac_dynlink + +let () = + let load () = + match handler.fdkaac_module with + | Some m -> + let module Fdkaac = (val m : Fdkaac_dynlink.Fdkaac_t) in + let module Register = Fdkaac_encoder.Register(Fdkaac) in + Register.register_encoder "AAC/fdkaac/dynlink" + | None -> assert false + in + Hashtbl.add Dyntools.dynlink_list + "fdkaac encoder" + { Dyntools. + path = path; + files = ["fdkaac";"fdkaac_loader"]; + load = load } diff --git a/src/tools/fdkaac_dynlink.ml b/src/tools/fdkaac_dynlink.ml new file mode 100644 index 0000000000..d1b9078753 --- /dev/null +++ b/src/tools/fdkaac_dynlink.ml @@ -0,0 +1,50 @@ +module type Fdkaac_t = +sig + module Encoder : + sig + exception Invalid_handle + exception Unsupported_parameter + exception Invalid_config + exception Error of int + exception End_of_file + exception Unknown of int + val string_of_exception : exn -> string option + type t + type mpeg2_aac = [ `AAC_LC | `HE_AAC | `HE_AAC_v2 ] + type mpeg4_aac = + [ `AAC_ELD | `AAC_LC | `AAC_LD | `HE_AAC | `HE_AAC_v2 ] + type aot = [ `Mpeg_2 of mpeg2_aac | `Mpeg_4 of mpeg4_aac ] + type bitrate_mode = [ `Constant | `Full_bitreservoir ] + type transmux = + [ `Adif | `Adts | `Latm | `Latm_out_of_band | `Loas | `Raw ] + type param_name = + [ `Afterburner + | `Aot + | `Bandwidth + | `Bitrate + | `Bitrate_mode + | `Granule_length + | `Samplerate + | `Sbr_mode + | `Transmux ] + type param = + [ `Afterburner of bool + | `Aot of aot + | `Bandwidth of bool + | `Bitrate of int + | `Bitrate_mode of bitrate_mode + | `Granule_length of int + | `Samplerate of int + | `Sbr_mode of bool + | `Transmux of transmux ] + val create : int -> t + val set : t -> param -> unit + val get : t -> param_name -> param + val encode : t -> string -> int -> int -> string + val flush : t -> string + end +end + +type handler = { mutable fdkaac_module : (module Fdkaac_t) option } + +let handler = {fdkaac_module = None } diff --git a/src/tools/fdkaac_dynlink.mli b/src/tools/fdkaac_dynlink.mli new file mode 100644 index 0000000000..a4aa46df98 --- /dev/null +++ b/src/tools/fdkaac_dynlink.mli @@ -0,0 +1,48 @@ +module type Fdkaac_t = + sig + module Encoder : + sig + exception Invalid_handle + exception Unsupported_parameter + exception Invalid_config + exception Error of int + exception End_of_file + exception Unknown of int + val string_of_exception : exn -> string option + type t + type mpeg2_aac = [ `AAC_LC | `HE_AAC | `HE_AAC_v2 ] + type mpeg4_aac = + [ `AAC_ELD | `AAC_LC | `AAC_LD | `HE_AAC | `HE_AAC_v2 ] + type aot = [ `Mpeg_2 of mpeg2_aac | `Mpeg_4 of mpeg4_aac ] + type bitrate_mode = [ `Constant | `Full_bitreservoir ] + type transmux = + [ `Adif | `Adts | `Latm | `Latm_out_of_band | `Loas | `Raw ] + type param_name = + [ `Afterburner + | `Aot + | `Bandwidth + | `Bitrate + | `Bitrate_mode + | `Granule_length + | `Samplerate + | `Sbr_mode + | `Transmux ] + type param = + [ `Afterburner of bool + | `Aot of aot + | `Bandwidth of bool + | `Bitrate of int + | `Bitrate_mode of bitrate_mode + | `Granule_length of int + | `Samplerate of int + | `Sbr_mode of bool + | `Transmux of transmux ] + val create : int -> t + val set : t -> param -> unit + val get : t -> param_name -> param + val encode : t -> string -> int -> int -> string + val flush : t -> string + end + end +type handler = { mutable fdkaac_module : (module Fdkaac_t) option; } +val handler : handler