Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prioritize, use file decoders file extensions when computing request
duration.
  • Loading branch information
toots committed Sep 14, 2024
commit 07e78cc5c541ef3194f38a948b18ea9b10681c1b
18 changes: 14 additions & 4 deletions src/core/decoder/external_decoder.ml
Original file line number Diff line number Diff line change
Expand Up @@ -120,13 +120,18 @@ let register_stdin ~name ~doc ~priority ~mimes ~file_extensions ~test process =
stream_decoder = Some (fun ~ctype:_ _ -> create_stream process);
};

let duration ~metadata:_ filename =
let dresolver ~metadata:_ filename =
let process =
Printf.sprintf "cat %s | %s" (Filename.quote filename) process
in
duration process
in
Plug.register Request.dresolvers name ~doc duration
Plug.register Request.dresolvers name ~doc
{
dpriority = (fun () -> priority);
file_extensions = (fun () -> Option.value ~default:[] file_extensions);
dresolver;
}

(** Now an external decoder that directly operates
* on the file. The remaining time in this case
Expand Down Expand Up @@ -196,5 +201,10 @@ let register_oblivious ~name ~doc ~priority ~mimes ~file_extensions ~test
stream_decoder = None;
};

let duration ~metadata:_ filename = duration (process filename) in
Plug.register Request.dresolvers name ~doc duration
let dresolver ~metadata:_ filename = duration (process filename) in
Plug.register Request.dresolvers name ~doc
{
dpriority = (fun () -> priority);
file_extensions = (fun () -> Option.value ~default:[] file_extensions);
dresolver;
}
18 changes: 12 additions & 6 deletions src/core/decoder/ffmpeg_decoder.ml
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,7 @@ let parse_file_decoder_args metadata =
| Some args -> parse_input_args args
| None -> ([], None)

let duration ~metadata file =
let dresolver ~metadata file =
let args, format = parse_file_decoder_args metadata in
let opts = Hashtbl.create 10 in
List.iter (fun (k, v) -> Hashtbl.replace opts k v) args;
Expand All @@ -558,10 +558,16 @@ let duration ~metadata file =
Option.map (fun d -> Int64.to_float d /. 1000.) duration)

let () =
Plug.register Request.dresolvers "ffmepg" ~doc:"" (fun ~metadata fname ->
match duration ~metadata fname with
| None -> raise Not_found
| Some d -> d)
Plug.register Request.dresolvers "ffmepg" ~doc:""
{
dpriority = (fun () -> priority#get);
file_extensions = (fun () -> file_extensions#get);
dresolver =
(fun ~metadata fname ->
match dresolver ~metadata fname with
| None -> raise Not_found
| Some d -> d);
}

let tags_substitutions = [("track", "tracknumber")]

Expand Down Expand Up @@ -1087,7 +1093,7 @@ let mk_streams ~ctype ~decode_first_metadata container =

let create_decoder ~ctype ~metadata fname =
let args, format = parse_file_decoder_args metadata in
let file_duration = duration ~metadata fname in
let file_duration = dresolver ~metadata fname in
let remaining = Atomic.make file_duration in
let set_remaining ~pts ~duration stream =
let pts =
Expand Down
8 changes: 6 additions & 2 deletions src/core/decoder/liq_flac_decoder.ml
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ let check filename =
true
with _ -> false

let duration ~metadata:_ file =
let dresolver ~metadata:_ file =
if not (check file) then raise Not_found;
let fd = Decoder.openfile file in
Fun.protect
Expand All @@ -199,4 +199,8 @@ let duration ~metadata:_ file =

let () =
Plug.register Request.dresolvers "flac" ~doc:"Compute duration of flac files."
duration
{
dpriority = (fun () -> priority#get);
file_extensions = (fun () -> file_extensions#get);
dresolver;
}
9 changes: 7 additions & 2 deletions src/core/decoder/mad_decoder.ml
Original file line number Diff line number Diff line change
Expand Up @@ -189,11 +189,16 @@ let check filename =
true
with _ -> false

let duration ~metadata:_ file =
let dresolver ~metadata:_ file =
if not (check file) then raise Not_found;
let ans = Mad.duration file in
match ans with 0. -> raise Not_found | _ -> ans

let () =
Plug.register Request.dresolvers "mad"
~doc:"Compute duration of mp3 files using MAD library." duration
~doc:"Compute duration of mp3 files using MAD library."
{
dpriority = (fun () -> priority#get);
file_extensions = (fun () -> file_extensions#get);
dresolver;
}
10 changes: 8 additions & 2 deletions src/core/decoder/ogg_flac_duration.ml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

(** Read duration of ogg/flac files. *)

let duration ~metadata:_ file =
let dresolver ~metadata:_ file =
let sync, fd = Ogg.Sync.create_from_file file in
Fun.protect
~finally:(fun () -> Unix.close fd)
Expand Down Expand Up @@ -63,4 +63,10 @@ let duration ~metadata:_ file =
if samples <= 0. then raise Not_found;
samples /. float info.Flac.Decoder.sample_rate)

let () = Plug.register Request.dresolvers "ogg/flac" ~doc:"" duration
let () =
Plug.register Request.dresolvers "ogg/flac" ~doc:""
{
dpriority = (fun () -> Liq_ogg_decoder.priority#get);
file_extensions = (fun () -> Liq_ogg_decoder.file_extensions#get);
dresolver;
}
10 changes: 8 additions & 2 deletions src/core/decoder/vorbisduration.ml
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,16 @@

(** Read duration of ogg/vorbis files. *)

let duration ~metadata:_ file =
let dresolver ~metadata:_ file =
let dec, fd = Vorbis.File.Decoder.openfile file in
Fun.protect
~finally:(fun () -> Unix.close fd)
(fun _ -> Vorbis.File.Decoder.duration dec (-1))

let () = Plug.register Request.dresolvers "vorbis" ~doc:"" duration
let () =
Plug.register Request.dresolvers "vorbis" ~doc:""
{
dpriority = (fun () -> Liq_ogg_decoder.priority#get);
file_extensions = (fun () -> Liq_ogg_decoder.file_extensions#get);
dresolver;
}
9 changes: 7 additions & 2 deletions src/core/decoder/wav_aiff_decoder.ml
Original file line number Diff line number Diff line change
Expand Up @@ -219,14 +219,19 @@ let () =
}

let () =
let duration ~metadata:_ file =
let dresolver ~metadata:_ file =
let w = Wav_aiff.fopen file in
let ret = Wav_aiff.duration w in
Wav_aiff.close w;
ret
in
Plug.register Request.dresolvers "wav/aiff"
~doc:"Native computation of wav and aiff files duration." duration
~doc:"Native computation of wav and aiff files duration."
{
dpriority = (fun () -> aiff_priorities#get);
file_extensions = (fun () -> aiff_file_extensions#get);
dresolver;
}

let basic_mime_types =
Dtools.Conf.list
Expand Down
49 changes: 44 additions & 5 deletions src/core/request.ml
Original file line number Diff line number Diff line change
Expand Up @@ -121,20 +121,59 @@ let status { status } = Atomic.get status
let indicator ?(metadata = Frame.Metadata.empty) ?temporary s =
{ uri = home_unrelate s; temporary = temporary = Some true; metadata }

(** Length *)
type dresolver = {
dpriority : unit -> int;
file_extensions : unit -> string list;
dresolver : metadata:Frame.metadata -> string -> float;
}

let dresolvers_doc = "Methods to extract duration from a file."

let dresolvers = Plug.create ~doc:dresolvers_doc "audio file formats (duration)"
let conf_dresolvers =
Dtools.Conf.list ~p:(conf#plug "dresolvers") ~d:[]
"Methods to extract file duration."

let f c v =
match c#get_d with
| None -> c#set_d (Some [v])
| Some d -> c#set_d (Some (d @ [v]))

let dresolvers =
Plug.create ~doc:dresolvers_doc
~register_hook:(fun name _ -> f conf_dresolvers name)
"audio file formats (duration)"

let get_dresolvers ~file () =
let extension = try Utils.get_ext file with _ -> "" in
let f cur name =
match Plug.get dresolvers name with
| Some ({ file_extensions } as p)
when List.mem extension (file_extensions ()) ->
(name, p) :: cur
| Some _ -> cur
| None ->
log#severe "Cannot find duration resolver %s" name;
cur
in
let resolvers = List.fold_left f [] conf_dresolvers#get in
List.sort
(fun (_, a) (_, b) -> compare (b.dpriority ()) (a.dpriority ()))
resolvers

let compute_duration ~metadata file =
try
Plug.iter dresolvers (fun _ resolver ->
List.iter
(fun (name, { dpriority; dresolver }) ->
try
let ans = resolver ~metadata file in
log#info "Trying duration resolver %s (priority: %d) for file %s.."
name (dpriority ())
(Lang_string.quote_string file);
let ans = dresolver ~metadata file in
raise (Duration ans)
with
| Duration e -> raise (Duration e)
| _ -> ());
| _ -> ())
(get_dresolvers ~file ());
raise Not_found
with Duration d -> d

Expand Down
11 changes: 10 additions & 1 deletion src/core/request.mli
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ type resolve_flag = [ `Resolved | `Failed | `Timeout ]
(** Metadata resolvers priorities. *)
val conf_metadata_decoder_priorities : Dtools.Conf.ut

(** Read the request's metadata. *)
val read_metadata : t -> unit

(** [resolve request timeout] tries to resolve the request within
[timeout] seconds. *)
val resolve : t -> float -> resolve_flag
Expand Down Expand Up @@ -165,8 +168,14 @@ val done_playing : source:Source.source -> t -> unit

(** {1 Plugs} *)

type dresolver = {
dpriority : unit -> int;
file_extensions : unit -> string list;
dresolver : metadata:Frame.metadata -> string -> float;
}

(** Functions for computing duration. *)
val dresolvers : (metadata:Frame.metadata -> string -> float) Plug.t
val dresolvers : dresolver Plug.t

(** Type for a metadata resolver. Resolvers are executed in priority
order and the first returned metadata take precedence over any other
Expand Down