Skip to content

Commit

Permalink
Merge pull request #79 from savonet/fdkaac-dynlink
Browse files Browse the repository at this point in the history
Added dynamically loaded fdkaac encoder.
  • Loading branch information
toots committed May 18, 2013
2 parents 946d1de + dfbb7bb commit a6e676e
Show file tree
Hide file tree
Showing 8 changed files with 325 additions and 86 deletions.
1 change: 1 addition & 0 deletions Makefile.defs.in
Original file line number Diff line number Diff line change
Expand Up @@ -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@
Expand Down
9 changes: 9 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 4 additions & 1 deletion src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -156,17 +156,19 @@ analyze = analyze/analyze_rms.ml
encoders = \
encoder/wav_encoder.ml \
encoder/lame_encoder.ml \
encoder/fdkaac_encoder.ml \
encoder/aacplus_encoder.ml \
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)
$(call conditional_compilation,encoders,$(W_LAME),encoder/lame_encoder_builtin.ml)
$(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 \
Expand All @@ -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 \
Expand Down
220 changes: 135 additions & 85 deletions src/encoder/fdkaac_encoder.ml
Original file line number Diff line number Diff line change
@@ -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
28 changes: 28 additions & 0 deletions src/encoder/fdkaac_encoder_builtin.ml
Original file line number Diff line number Diff line change
@@ -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"
50 changes: 50 additions & 0 deletions src/encoder/fdkaac_encoder_dynlink.ml
Original file line number Diff line number Diff line change
@@ -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 }
Loading

0 comments on commit a6e676e

Please sign in to comment.