File: metadata_decoder.ml

package info (click to toggle)
liquidsoap 1.3.3-2
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 4,504 kB
  • sloc: ml: 37,149; python: 956; makefile: 624; sh: 458; perl: 322; lisp: 124; ansic: 53; ruby: 8
file content (101 lines) | stat: -rw-r--r-- 3,424 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
(*****************************************************************************

  Liquidsoap, a programmable audio stream generator.
  Copyright 2003-2017 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

 *****************************************************************************)

let log = Dtools.Log.make ["decoder";"puremeta"]

exception Error

(** Parse next item:
  *   [[Int:]Int:]Int String String
  * Int can be Float, and there can be more than hours. *)
let parse_item stream =
  let rec ts_of_list d = function
    | hd::tl -> hd*.d +. ts_of_list (d*.60.) tl
    | [] -> 0.
  in
  let rec read_meta timestamp =
    match Stream.next stream with
      | Genlex.Kwd ":" -> read_meta timestamp
      | Genlex.Int i -> read_meta (float i :: timestamp)
      | Genlex.Float f -> read_meta (f :: timestamp)
      | Genlex.String key ->
         begin match Stream.next stream with
           | Genlex.String value -> ts_of_list 1. timestamp, key, value
           | _ -> raise Error
         end
      | _ -> raise Error
  in
    read_meta []

let parse_file filename =
  let input = open_in filename in
  let lexer = Genlex.make_lexer [":"] (Stream.of_channel input) in
  let rec parse acc =
    match try Some (parse_item lexer) with Stream.Failure -> None with
      | Some i -> parse (i::acc)
      | None -> List.rev acc
  in
  let data = parse [] in
    close_in input ;
    data

let empty = {Frame.audio=0;video=0;midi=0}

let file_deco filename =
  let events = ref (parse_file filename) in
  let t = ref 0. in
  let size = Lazy.force Frame.size in
  let fill frame =
    let pos = Frame.position frame in
    let duration = Frame.seconds_of_master (size-pos) in
    let rec aux () =
      match !events with
        | (ts,k,v)::tl ->
            if ts < !t+.duration then
              let pos = Frame.master_of_seconds (ts -. !t) in
              let meta = Hashtbl.create 1 in
                Hashtbl.add meta k v ;
                Frame.set_metadata frame pos meta ;
                events := tl ;
                aux ()
            else
              Frame.add_break frame size
        | [] -> Frame.add_break frame pos
    in
      ignore (Frame.content_of_type frame pos empty) ;
      aux () ;
      t := !t +. Frame.seconds_of_master (Frame.position frame - pos) ;
      -1 (* TODO remaining time *)
  in
    { Decoder.
        fill = fill ; 
        fseek = (fun _ -> 0);
        close = ignore }

let () =
  Decoder.file_decoders#register "META"
    (fun ~metadata:_ filename kind ->
       if Frame.type_has_kind empty kind then begin
         ignore (parse_file filename) ;
         Some (fun () -> file_deco filename)
       end else
         None)