Changeset 7122
- Timestamp:
- 01/29/10 06:44:55 (6 weeks ago)
- Location:
- trunk/liquidsoap/src
- Files:
-
- 11 modified
-
decoder/decoder.ml (modified) (1 diff)
-
decoder/decoder.mli (modified) (1 diff)
-
decoder/mp3.ml (modified) (4 diffs)
-
decoder/ogg_decoder.ml (modified) (6 diffs)
-
formats/wavformat.ml (modified) (5 diffs)
-
sources/external_input.ml (modified) (2 diffs)
-
sources/generated.ml (modified) (7 diffs)
-
sources/harbor_input.ml (modified) (5 diffs)
-
sources/http_source.ml (modified) (6 diffs)
-
stream/generator.ml (modified) (5 diffs)
-
stream/generator.mli (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/liquidsoap/src/decoder/decoder.ml
r7114 r7122 77 77 * of things that should be explicitly managed, not just garbage collected). 78 78 * Hence it does not need a close function. *) 79 type stream_decoder = input -> Generator.From_audio_video .t decoder79 type stream_decoder = input -> Generator.From_audio_video_plus.t decoder 80 80 81 81 (** A decoder is a filling function and a closing function, -
trunk/liquidsoap/src/decoder/decoder.mli
r7114 r7122 29 29 30 30 type 'a decoder = Decoder of ('a -> unit) 31 type stream_decoder = input -> Generator.From_audio_video .t decoder31 type stream_decoder = input -> Generator.From_audio_video_plus.t decoder 32 32 type file_decoder = { fill : Frame.t -> int; close : unit -> unit; } 33 33 -
trunk/liquidsoap/src/decoder/mp3.ml
r7114 r7122 25 25 open Dtools 26 26 27 module Generator = Generator.From_audio_video 28 module Buffered = Decoder.Buffered(Generator) 27 let log = Log.make ["decoder";"mp3"] 29 28 30 let log = Log.make ["decoder";"mp3"] 29 module Make (Generator:Generator.S_Asio) = 30 struct 31 31 32 32 let create_decoder input = … … 39 39 resampler ~audio_src_rate:(float sample_freq) data 40 40 in 41 Generator.set_mode gen `Audio ; 41 42 Generator.put_audio gen content 0 (Array.length content.(0))) 42 43 44 end 45 46 module G = Generator.From_audio_video 47 module Buffered = Decoder.Buffered(G) 48 module D = Make(G) 49 43 50 let create_file_decoder filename kind = 44 let generator = G enerator.create Generator.Audio in45 Buffered.file_decoder filename kind create_decoder generator51 let generator = G.create `Audio in 52 Buffered.file_decoder filename kind D.create_decoder generator 46 53 47 54 let conf_mad = … … 100 107 None) 101 108 109 module D_stream = Make(Generator.From_audio_video_plus) 110 102 111 let () = 103 112 Decoder.stream_decoders#register … … 117 126 * if there was possibly another plugin for decoding 118 127 * correctly the stream (e.g. by performing conversions). *) 119 Some create_decoder128 Some D_stream.create_decoder 120 129 else 121 130 None) -
trunk/liquidsoap/src/decoder/ogg_decoder.ml
r7114 r7122 22 22 23 23 (** Decode and read ogg files. *) 24 25 module Generator = Generator.From_audio_video26 module Buffered = Decoder.Buffered(Generator)27 24 28 25 let log = Dtools.Log.make ["decoder";"ogg"] … … 112 109 end 113 110 111 module Make (Generator:Generator.S_Asio) = 112 struct 113 114 114 (* TODO this mimicks the old code, but in the near future decoding should 115 115 * take into account the target content kind, e.g. for dropping channels *) 116 let create_decoder input =116 let create_decoder mode input = 117 117 let decoder = 118 118 let sync = Ogg.Sync.create input in … … 123 123 let video_resample = video_resample () in 124 124 Decoder.Decoder (fun buffer -> 125 Generator.set_mode buffer mode ; 125 126 if Ogg_demuxer.eos decoder then 126 127 raise Ogg_demuxer.End_of_stream; … … 159 160 Ogg_demuxer.feed decoder) 160 161 161 (** Stream decoder *) 162 end 163 164 (** File decoder *) 165 166 module G = Generator.From_audio_video 167 module Buffered = Decoder.Buffered(G) 168 module D = Make(G) 162 169 163 170 let create_file_decoder filename content_type kind = 164 171 let mode = 165 172 match content_type.Frame.video, content_type.Frame.audio with 166 | 0, _ -> Generator.Audio167 | _, 0 -> Generator.Video168 | _, _ -> Generator.Both169 in 170 let generator = G enerator.create mode in171 Buffered.file_decoder filename kind create_decodergenerator173 | 0, _ -> `Audio 174 | _, 0 -> `Video 175 | _, _ -> `Both 176 in 177 let generator = G.create mode in 178 Buffered.file_decoder filename kind (D.create_decoder mode) generator 172 179 173 180 let get_type filename = … … 227 234 This settings has been DEPRECATED." 228 235 236 module D_stream = Make(Generator.From_audio_video_plus) 237 229 238 let () = 230 239 Decoder.stream_decoders#register … … 233 242 (fun mime kind -> 234 243 if List.mem mime mime_types#get then 235 Some create_decoder 244 (* TODO We must find a way here... *) 245 Some (D_stream.create_decoder `Audio) 236 246 else 237 247 None) -
trunk/liquidsoap/src/formats/wavformat.ml
r7114 r7122 24 24 25 25 let log = Dtools.Log.make ["decoder";"wav"] 26 27 module Generator = Generator.From_audio_video28 module Buffered = Decoder.Buffered(Generator)29 26 30 27 (** {1 Generic decoder} *) … … 56 53 let read_short ic = read_int_num_bytes ic 2 57 54 55 module Make (Generator:Generator.S_Asio) = 56 struct 57 58 58 (* TODO It might be more efficient to write our code for an input 59 59 * channel and use directly the one we have when decoding files 60 60 * or external processes, if we could wrap the input function used 61 61 * for decoding stream (in http and harbor) as an in_channel. *) 62 let create _decoderinput =62 let create input = 63 63 let decoder = ref (fun gen -> assert false) in 64 64 … … 69 69 log#f 4 "Read %d bytes of PCM" bytes ; 70 70 let content,length = converter (String.sub data 0 bytes) in 71 Generator.set_mode gen `Audio ; 71 72 Generator.put_audio gen content 0 length ; 72 73 log#f 4 "Done (%d)" length … … 119 120 Decoder.Decoder (fun gen -> !decoder gen) 120 121 122 end 123 124 module Generator = Generator.From_audio_video 125 module Buffered = Decoder.Buffered(Generator) 126 121 127 (* File decoding *) 128 129 module D = Make(Generator) 122 130 123 131 let get_type filename = … … 128 136 129 137 let create_file_decoder filename kind = 130 let generator = Generator.create Generator.Audio in131 Buffered.file_decoder filename kind create_decodergenerator138 let generator = Generator.create `Audio in 139 Buffered.file_decoder filename kind D.create generator 132 140 133 141 let () = -
trunk/liquidsoap/src/sources/external_input.ml
r7031 r7122 21 21 *****************************************************************************) 22 22 23 module Generator = Generator.From_audio_video 24 module Generated = Generated.From_audio_video 23 module Generator = Generator.From_audio_video_plus 24 module Generated = Generated.From_audio_video_plus 25 25 26 26 (* {1 External Input handling} *) … … 38 38 () ~audio_src_rate:in_freq 39 39 in 40 let abg = Generator.create Generator.Audio in40 let abg = Generator.create `Audio in 41 41 let priority = Tutils.Non_blocking in 42 42 object (self) -
trunk/liquidsoap/src/sources/generated.ml
r7110 r7122 24 24 struct 25 25 26 (* Reads data from an audio buffer generator. The generator can be feeded27 * in parallel, using [lock] if not in the main thread.26 (* Reads data from an audio buffer generator. 27 * A thread safe generator should be used if it has to be fed concurrently. 28 28 * Store [bufferize] seconds before declaring itself as ready. *) 29 29 class virtual source ~bufferize ~empty_on_abort gen = … … 35 35 36 36 val mutable buffering = true 37 val lock = Mutex.create ()38 37 39 38 val mutable should_fail = false … … 43 42 method abort_track = should_fail <- true 44 43 45 method private length = 46 Mutex.lock lock ; 47 let r = Generator.length generator in 48 Mutex.unlock lock ; 49 r 44 method private length = Generator.length generator 50 45 51 46 method is_ready = … … 69 64 if should_fail then 0 else 70 65 let r = self#length in 71 Mutex.lock lock ;72 66 let l = Generator.remaining generator in 73 Mutex.unlock lock ; 74 if buffering && r <= bufferize then 0 else l 67 if buffering && r <= bufferize then 0 else l 75 68 76 69 method private get_frame ab = … … 79 72 self#log#f 4 "Performing skip." ; 80 73 should_fail <- false ; 81 if empty_on_abort then Generator.clear generator ; (* TODO lock *)74 if empty_on_abort then Generator.clear generator ; 82 75 Frame.add_break ab (Frame.position ab) 83 76 end else begin 84 Mutex.lock lock ;85 77 Generator.fill generator ab ; 86 78 (* Currently, we don't enter the buffering phase between tracks … … 96 88 self#log#f 4 "Buffer emptied, starting buffering." ; 97 89 buffering <- true 98 end ; 99 Mutex.unlock lock 90 end 100 91 end 101 92 … … 113 104 end 114 105 115 module From_audio_video = 116 Make(struct 117 type t = Generator.From_audio_video.t 118 let length x = Generator.From_audio_video.length x 119 let remaining x = Generator.From_audio_video.remaining x 120 let clear = Generator.From_audio_video.clear 121 let add_metadata = Generator.From_audio_video.add_metadata 122 let fill = Generator.From_audio_video.fill 123 end) 106 module From_audio_video_plus = Make(Generator.From_audio_video_plus) -
trunk/liquidsoap/src/sources/harbor_input.ml
r7110 r7122 30 30 ~on_connect ~on_disconnect 31 31 ~login ~debug = 32 (* let abg_max_len = Frame.audio_of_seconds max in 33 TODO handle buffer overflow, cf. input.http *) 32 let max_ticks = Frame.master_of_seconds max in 34 33 object (self) 35 34 inherit Source.source kind 36 35 (* TODO: we want video also in the genrator *) 37 36 inherit Generated.source 38 (Generator.create Generator.Audio)37 (Generator.create ~overfull:(`Drop_old max_ticks) `Undefined) 39 38 ~empty_on_abort:false ~bufferize 40 39 … … 58 57 if not (Hashtbl.mem m "title") then 59 58 (try Hashtbl.add m "title" (Hashtbl.find m "song") with _ -> ()); 60 self#log#f 3 "New metadata chunk \"%s -- %s\""59 self#log#f 3 "New metadata chunk %S -- %S." 61 60 (try Hashtbl.find m "artist" with _ -> "?") 62 61 (try Hashtbl.find m "title" with _ -> "?") ; … … 116 115 with 117 116 | e -> 118 self#log#f 2 "Feeding stopped: %s " (Printexc.to_string e) ;117 self#log#f 2 "Feeding stopped: %s." (Printexc.to_string e) ; 119 118 if debug then raise e ; 120 119 self#disconnect ; … … 149 148 150 149 method register_decoder mime = 150 Generator.set_mode generator `Undefined ; 151 151 match 152 152 Decoder.get_stream_decoder mime kind … … 215 215 Some "Function to execute when a source is connected. \ 216 216 Its receives the list of headers, of the form: \ 217 ( \"label\",\"value\"). All labels are lowercase.";217 (<label>,<value>). All labels are lowercase."; 218 218 219 219 "on_disconnect",Lang.fun_t [] Lang.unit_t, -
trunk/liquidsoap/src/sources/http_source.ml
r7110 r7122 177 177 host,80,mount,auth 178 178 179 module Generator = Generator.From_audio_video 179 module Generator = Generator.From_audio_video_plus 180 180 module Generated = Generated.Make(Generator) 181 181 … … 188 188 ~debug ?(logfile=None) 189 189 ~user_agent url = 190 let _ = 191 (* TODO 192 * We used to deal with overfull generators in the [put] method, 193 * passed to the stream decoders in the [sink]. Now, the 194 * interface is simpler, but we need to put this back somewhere: 195 * add overfull management to Generators? This can be done 196 * for a specific kind of generator, that also needs to be 197 * thread safe: 198 * 199 * The old "sink" system was used to: 200 * - control concurrency on the generator 201 * - log 202 * - conversions (samplerate) 203 * - control (fail to stop feeding on source/output stop) 204 * Most of it was adapted by passing directly a generator to the 205 * decoder, but we still need to handle multi-threading, 206 * by ensuring that read/writing in the generator don't occur 207 * at the same time. *) 208 Frame.audio_of_seconds (Pervasives.max max bufferize) 209 in 190 let max_ticks = Frame.master_of_seconds (Pervasives.max max bufferize) in 210 191 object (self) 211 192 inherit Source.source kind 212 193 inherit 213 194 Generated.source 214 (Generator.create Generator.Audio)195 (Generator.create ~overfull:(`Drop_old max_ticks) `Undefined) 215 196 ~empty_on_abort:false ~bufferize 216 197 … … 234 215 (* Insert metadata *) 235 216 method insert_metadata m = 236 self#log#f 3 "New metadata chunk \"%s -- %s\""217 self#log#f 3 "New metadata chunk: %S -- %S." 237 218 (try Hashtbl.find m "artist" with _ -> "?") 238 219 (try Hashtbl.find m "title" with _ -> "?") ; … … 269 250 self#log#f 2 "Feeding stopped: %s." s 270 251 | e -> 271 self#log#f 2 "Feeding stopped: %s " (Printexc.to_string e)252 self#log#f 2 "Feeding stopped: %s." (Printexc.to_string e) 272 253 end ; 273 254 begin match logf with … … 398 379 | Not_found -> () 399 380 end else begin 400 self#log#f 4 "Content-type \"%s\"." content_type ;381 self#log#f 4 "Content-type %S." content_type ; 401 382 if chunked then 402 383 self#log#f 4 "Chunked HTTP/1.1 transfer" ; 384 Generator.set_mode generator `Undefined ; 403 385 let dec = 404 386 match … … 567 549 raise (Lang.Invalid_value 568 550 (List.assoc "max" p, 569 "Maximu nbuffering inferior to pre-buffered data"));551 "Maximum buffering inferior to pre-buffered data")); 570 552 let poll_delay = Lang.to_float (List.assoc "poll_delay" p) in 571 553 ((new http ~kind ~playlist_mode ~timeout ~autostart ~track_on_meta -
trunk/liquidsoap/src/stream/generator.ml
r7110 r7122 29 29 val fill : t -> Frame.t -> unit 30 30 val add_metadata : t -> Frame.metadata -> unit 31 end 32 33 module type S_Asio = 34 sig 35 type t 36 val length : t -> int (* ticks *) 37 val remaining : t -> int (* ticks *) 38 val clear : t -> unit 39 val fill : t -> Frame.t -> unit 40 val add_metadata : t -> Frame.metadata -> unit 41 val put_audio : t -> Frame.audio_t array -> int -> int -> unit 42 val put_video : t -> Frame.video_t array -> int -> int -> unit 43 val set_mode : t -> [ `Audio | `Video | `Both | `Undefined ] -> unit 31 44 end 32 45 … … 232 245 struct 233 246 234 type mode = Audio | Video | Both247 type mode = [ `Audio | `Video | `Both | `Undefined ] 235 248 type t = { 236 249 mutable mode : mode ; … … 299 312 Generator.put t.audio content o l ; 300 313 match t.mode with 301 | Audio ->314 | `Audio -> 302 315 Generator.put t.video [||] 0 l 303 | Both -> ()304 | Video-> assert false316 | `Both -> () 317 | `Video | `Undefined -> assert false 305 318 306 319 (** Add some video content. Offset and length are given in video samples. *) … … 311 324 Generator.put t.video content o l ; 312 325 match t.mode with 313 | Video ->326 | `Video -> 314 327 Generator.put t.audio [||] 0 l 315 | Both -> ()316 | Audio-> assert false328 | `Both -> () 329 | `Audio | `Undefined -> assert false 317 330 318 331 (* Advance metadata and breaks by [len] ticks. *) … … 404 417 405 418 end 419 420 module From_audio_video_plus = 421 struct 422 423 module Super = From_audio_video 424 425 type mode = [ `Audio | `Video | `Both | `Undefined ] 426 type overfull = [ `Drop_old of int ] 427 type t = { 428 lock : Mutex.t ; 429 overfull : overfull option ; 430 gen : Super.t 431 } 432 433 let create ?(lock=Mutex.create()) ?overfull mode = 434 { lock = lock ; overfull = overfull ; gen = Super.create mode } 435 436 let mode t = Tutils.mutexify t.lock Super.mode t.gen 437 let set_mode t mode = Tutils.mutexify t.lock (Super.set_mode t.gen) mode 438 439 let audio_length t = Tutils.mutexify t.lock Super.audio_length t.gen 440 let video_length t = Tutils.mutexify t.lock Super.video_length t.gen 441 let length t = Tutils.mutexify t.lock Super.length t.gen 442 let remaining t = Tutils.mutexify t.lock Super.remaining t.gen 443 444 let add_metadata t m = 445 Tutils.mutexify t.lock (Super.add_metadata t.gen) m 446 let add_break t = Tutils.mutexify t.lock Super.add_break t.gen 447 448 let clear t = Tutils.mutexify t.lock Super.clear t.gen 449 let fill t frame = Tutils.mutexify t.lock (Super.fill t.gen) frame 450 451 let remove t len = 452 Tutils.mutexify t.lock (Super.remove t.gen) len 453 454 let check_overfull t extra = 455 assert (Tutils.seems_locked t.lock) ; 456 match t.overfull with 457 | Some (`Drop_old len) when Super.length t.gen + extra > len -> 458 Super.remove t.gen (Super.length t.gen + extra - len) 459 | _ -> () 460 461 let put_audio t buf off len = 462 Tutils.mutexify t.lock 463 (fun () -> 464 check_overfull t (Frame.master_of_audio len) ; 465 Super.put_audio t.gen buf off len) () 466 467 let put_video t buf off len = 468 Tutils.mutexify t.lock 469 (fun () -> 470 check_overfull t (Frame.master_of_video len) ; 471 Super.put_video t.gen buf off len) () 472 473 end -
trunk/liquidsoap/src/stream/generator.mli
r7110 r7122 64 64 sig 65 65 type t 66 type mode = Audio | Video | Both 66 67 (** In [Audio] mode, only audio can be put in the buffer, and similarly 68 * for the [Video] mode. In [Both] mode, both types of content can 69 * be fed into the generator, asynchronously, and they exit the 70 * buffer synchronously. 71 * The [Undefined] forbids any feeding, it's useful to make sure 72 * a meaningful mode is assigned before any use. *) 73 type mode = [ `Audio | `Video | `Both | `Undefined ] 74 67 75 val create : mode -> t 68 76 … … 89 97 val clear : t -> unit 90 98 end 99 100 (** Generator not only with Output but also with ASynchronous Input. *) 101 module type S_Asio = 102 sig 103 type t 104 val length : t -> int (* ticks *) 105 val remaining : t -> int (* ticks *) 106 val clear : t -> unit 107 val fill : t -> Frame.t -> unit 108 val add_metadata : t -> Frame.metadata -> unit 109 val put_audio : t -> Frame.audio_t array -> int -> int -> unit 110 val put_video : t -> Frame.video_t array -> int -> int -> unit 111 val set_mode : t -> [ `Audio | `Video | `Both | `Undefined ] -> unit 112 end 113 114 (** Same as From_audio_video but with two extra features useful for 115 * streaming decoders: it is thread safe and supports overfull 116 * buffer management. *) 117 module From_audio_video_plus : 118 sig 119 type t 120 121 (** Same as [From_audio_video]. *) 122 type mode = [ `Audio | `Video | `Both | `Undefined ] 123 124 (** How to handle overfull buffers: 125 * drop old data, keeping at most [len] ticks. *) 126 type overfull = [ `Drop_old of int ] 127 128 val create : ?lock:Mutex.t -> ?overfull:overfull -> mode -> t 129 130 val mode : t -> From_audio_video.mode 131 val set_mode : t -> From_audio_video.mode -> unit 132 133 val audio_length : t -> int 134 val video_length : t -> int 135 val length : t -> int 136 val remaining : t -> int 137 138 val add_metadata : t -> Frame.metadata -> unit 139 val add_break : t -> unit 140 141 (* [put_audio buffer data offset length]: 142 * offset and length are in audio samples! *) 143 val put_audio : t -> Frame.audio_t array -> int -> int -> unit 144 (* [put_video buffer data offset length]: 145 * offset and length are in video samples! *) 146 val put_video : t -> Frame.video_t array -> int -> int -> unit 147 val fill : t -> Frame.t -> unit 148 149 val remove : t -> int -> unit 150 val clear : t -> unit 151 end
