Changeset 7142
- Timestamp:
- 02/05/10 23:11:40 (5 weeks ago)
- Location:
- trunk
- Files:
-
- 1 added
- 8 modified
-
liquidsoap/doc/content/encoding_formats.txt (modified) (1 diff)
-
liquidsoap/doc/content/external_encoders.txt (modified) (4 diffs)
-
liquidsoap/doc/content/video.txt (modified) (4 diffs)
-
liquidsoap/src/Makefile (modified) (1 diff)
-
liquidsoap/src/lang/lang_cry.ml (added)
-
liquidsoap/src/outputs/icecast2.ml (modified) (7 diffs)
-
ocaml-cry/CHANGES (modified) (1 diff)
-
ocaml-cry/src/cry.ml (modified) (7 diffs)
-
ocaml-cry/src/cry.mli (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/liquidsoap/doc/content/encoding_formats.txt
r7067 r7142 79 79 h4. External encoders 80 80 81 For a detailed presentation of external encoders, see "this page":external_encoders.html. 82 81 83 %% 82 84 %external(channels=2,samplerate=44100,header=true, -
trunk/liquidsoap/doc/content/external_encoders.txt
r7137 r7142 1 1 title: External encoders 2 3 **External encoders are currently unavailable in the SVN trunk. This page will be updated when they are available again.**4 2 5 3 h3. Introduction … … 10 8 When using an external encoding process, uncompressed PCM data will be sent to the process through its standard input (@stdin@), and encoded data will be read through its standard output (@stdout@). When using a process that does only file input or output, @/dev/stdin@ and @/dev/stdout@ can be used, though this may generate issues if the encoding process expects to be able to go backward/forward in the file. 11 9 12 h3. Main operators 13 14 The main operators are: 15 16 * @output.file.external@ 17 * @output.pipe.external@ 18 * @output.icecast.external@ 19 20 The available options are the same as the usual @output.file@ and @output.icecast@ operators, 21 with the following additions: 10 h3. External encoders 11 12 For a general presentation on encoding formats, see "this page":encoding_formats.html 13 14 The main operators that can be used with external encoders are: 15 16 * @output.file@ 17 * @output.icecast@ 18 19 In order to use external encoders with these operators, you have to use the @%external@ encoding format. 20 Its syntax is: 21 22 %% 23 %external(channels=2,samplerate=44100,header=true, 24 restart_on_crash=false, 25 restart_on_new_track, 26 restart_after_delay=<int>, 27 process="") 28 %% 29 30 The available options are: 22 31 * @process@: this parameter is a function that takes the current metadata and return the process to start. 23 32 * @header@: if set to @false@ then no WAV header will be added to the data fed to the encoding process, thus the encoding process shall operate on RAW data. … … 26 35 * @restart_encoder_delay@: Restart the encoder after some delay. This can be useful for encoders that cannot operate on infinite streams, or are buggy after some time, like the @lame@ binary. The default for @lame@ and @accplusenc@-based encoders is to restart the encoder every hour. 27 36 37 Only one of @restart_encoder_delay@ or @restart_on_new_track@ should be used. 38 28 39 The restart mechanism strongly relies on the good behaviour of the encoding process. The restart operation will 29 40 close the standard input of the encoding process. The encoding process is then expected to finish its own operations and … … 33 44 process yourself. 34 45 35 Some specific options are available for @output.icecast.external@: 46 If you use an external encoder with the @output.icecast@ operator, you should also use the following options 47 of @output.icecast@ 36 48 * @icy_metadata@: send new metadata as ICY update. This is the case for headerless formats, such as MP3 or AAC, and it appears to work also for ogg/vorbis streams. 37 * @ shout_raw@: ask shout not to do any synchronization. Useful when sending formats that shout does not recognize, like AAC. Since liquidsoap is real-time, data is sent at real-rate anyway.38 * @format@: shout format. Must be one of "ogg" or "mp3". Use "mp3" for sending other headerless audio data, such as AAC.49 * @format@: Content-type (mime) of the data sent to icecast. For instance, for ogg data, it is one of 50 "application/ogg", "audio/ogg" or "video/ogg" and for mp3 data it is "audio/mpeg". 39 51 40 52 h3. Wrappers -
trunk/liquidsoap/doc/content/video.txt
r7141 r7142 1 1 title: Video in Liquidsoap 2 3 **This page needs to be updated !**4 2 5 3 h3. Video … … 9 7 In order to stream video, you should first inform your script that you are going to use video by doing 10 8 %% 11 set("frame.video.channels", 1)9 set("frame.video.channels",0) 12 10 %% 13 11 Optionnaly, you can also set the width, the height and the number of frames per seconds of the streamed video with … … 19 17 And that's almost it! You can use usual operators such as <code>single</code> or <code>playlist</code> to read video files. For now, only file in the ogg/theora format are supported (you can use the "ffmpeg2theora":http://v2v.cc/~j/ffmpeg2theora/ program to convert your videos to this format). For instance, a playlist of ogg videos can be streamed using 20 18 %% 21 output.icecast .theora(playlist("my_playlist"))19 output.icecast(%ogg(%theora,%vorbis), playlist("my_playlist")) 22 20 %% 23 21 where <code>my_playlist</code> is a list of video files. 24 22 23 For more details about the encoding settings, you can see the "encoding formats":encoding_formats.html page. 24 25 25 If you have SDL support in Liquidsoap, the video part of the stream can be previewed locally using the <code>output.sdl</code> operator. For example, the script 26 26 %% 27 output.sdl( single("file.ogv"))27 output.sdl(drop_audio(single("file.ogv"))) 28 28 %% 29 29 will display the video file <code>file.ogv</code>. 30 31 We use the @drop_audio@ operator because the @output.sdl@ operator only supports pure video stream. 32 Hence, @drop_audio@ returns a source where only the video track is present. 30 33 31 34 h4. Video effects … … 33 36 A lot of video effects are available in Liquidsoap. The corresponding operators are named <code>video.*</code>. In particular, the <code>video.fade.in</code> and <code>video.fade.out</code> should be used to program transitions, similarly to the <code>fade.in</code> and <code>fade.out</code> operators for audio. 34 37 35 h4. Known issues and limitations.36 37 Current support for video is not complete. There are several limitations. In particular, liquidsoap cannot do any video38 framerate conversion. This means that all video files must have the same number of frames per second as the global setting.39 40 Additionally, in order to maintain audio and video synchronisation, you have to make sure that the duration of41 a liquidsoap frame is a multiple of the duration of a video frame and the duration of an audio frame.42 43 For instance, if you want to read videos with 10 frames per seconds, and audio is sampled at 44.100 Hz, then44 if @x@ is the length of a liquidsoap frame -- set with @set("frame.size",x)@:45 46 * For now liquidsoap frame duration is exactly the audio duration, then the liquidsoap frame duration is: @x*44.100@.47 * For this duration, there are exactly: @y = floor(x*44.100/10)@ video frames.48 * The duration of the @y@ frames is: @y*10@.49 50 Hence, the equation is: @y*10 = x*44.100@ for @x@ and @y@ integers. We can for instance take @y = 1@, such that there51 will be a single video frame per liquidsoap frame, and then @x = 4.410@, and you have to add the following at the begining of your script:52 53 %%54 set("frame.video.channels",1)55 set("frame.size",4410)56 set("frame.video.fps",10)57 %%58 59 60 This limitation will be removed with the next major release.61 -
trunk/liquidsoap/src/Makefile
r7133 r7142 166 166 $(if $(W_MAGIC),lang/lang_magic.ml) \ 167 167 $(if $(W_LAST),lang/lang_lastfm.ml) \ 168 $(if $(W_CRY),lang/lang_cry.ml) \ 168 169 main.ml 169 170 -
trunk/liquidsoap/src/outputs/icecast2.ml
r7109 r7142 33 33 } 34 34 35 type icy_metadata = Guess | True | False 36 35 37 let no_mount = "Use [name] with .ogg extension if relevant" 36 38 let no_name = "Use [mount]" 39 40 let user_agent = 41 Printf.sprintf "liquidsoap %s" Configure.version 42 let user_agent = Lang.product (Lang.string "User-Agent") 43 (Lang.string user_agent) 37 44 38 45 let proto kind = … … 61 68 "public", Lang.bool_t, Some (Lang.bool true), None ; 62 69 ("headers", Lang.metadata_t, 63 Some (Lang.list (Lang.product_t Lang.string_t Lang.string_t) [ ]),70 Some (Lang.list (Lang.product_t Lang.string_t Lang.string_t) [user_agent]), 64 71 Some "Additional headers.") ; 72 "icy_metadata", Lang.string_t, Some (Lang.string "guess"), 73 Some "Send new metadata using the ICY protocol. One of: \"guess\", \"true\", \"false\""; 65 74 ("format", Lang.string_t, Some (Lang.string ""), 66 75 Some "Format, e.g. \"audio/ogg\". When empty, the encoder is used to guess.") ; … … 86 95 (v, "Valid values are 'http' (icecast) \ 87 96 and 'icy' (shoutcast)")) 97 in 98 99 let icy_metadata = 100 let v = List.assoc "icy_metadata" p in 101 match Lang.to_string v with 102 | "guess" -> Guess 103 | "true" -> True 104 | "false" -> False 105 | _ -> 106 raise (Lang.Invalid_value 107 (v, "Valid values are 'guess', \ 108 'true' or 'false'")) 88 109 in 89 110 … … 172 193 please specify one.")) 173 194 in 195 196 let icy_metadata = 197 let f = Cry.string_of_content_type in 198 match format, icy_metadata with 199 | _, True -> true 200 | _, False -> false 201 | x, _ when f x = f Cry.mpeg -> true 202 | x, _ when f x = f Cry.ogg_application || 203 f x = f Cry.ogg_audio || 204 f x = f Cry.ogg_video -> false 205 | _, Guess -> 206 raise (Lang.Invalid_value (List.assoc "icy_metadata" p, 207 "Could not guess icy_metadata \ 208 for this format, please specify \ 209 either 'true' or 'false'.")) 210 in 211 174 212 175 213 let ogg = … … 266 304 267 305 method reset_encoder m = 268 if ogg then269 (Utils.get_some encoder).Encoder.reset m270 else306 (* Update metadata using ICY if told to.. *) 307 if icy_metadata then 308 begin 271 309 let get h k l = 272 310 try … … 311 349 match Cry.get_status connection with 312 350 | Cry.Connected _ -> 313 (try Cry.update_metadata connection m ; "" with _ -> "")351 (try Cry.update_metadata connection m with _ -> ()) 314 352 | Cry.Disconnected -> 315 353 (* Do nothing if shout connection isn't available *) 316 "" 354 () 355 end ; 356 (* Now send the remaining data.. *) 357 if ogg then 358 (Utils.get_some encoder).Encoder.reset m 359 else "" 360 317 361 method send b = 318 362 match Cry.get_status connection with … … 376 420 f icecast_info.channels "channels" string_of_int; 377 421 let user_agent = 378 Printf.sprintf "liquidsoap %s" Configure.version 422 try 423 List.assoc "User-Agent" headers 424 with 425 | Not_found -> Printf.sprintf "liquidsoap %s" Configure.version 379 426 in 380 427 let source = -
trunk/ocaml-cry/CHANGES
r6863 r7142 1 0.2.0 () 2 ===== 3 * Changed send function to 4 use Unix.write instead of Pervasives. 5 This has been reported to generate much less load. 6 * Added manual_update_metadata to 7 update metadata on any source with being 8 previously connected/streaming on it. 9 1 10 0.1.1 (2009-10-26) 2 11 ===== -
trunk/ocaml-cry/src/cry.ml
r6838 r7142 309 309 Printf.sprintf "SOURCE %s HTTP/1.1\r\n%s\r\n\r\n" 310 310 311 let get_auth source=312 Printf.sprintf "Basic %s" (encode64 ( source.user ^ ":" ^ source.password))311 let get_auth user password = 312 Printf.sprintf "Basic %s" (encode64 (user ^ ":" ^ password)) 313 313 314 314 let write_data socket request = … … 387 387 388 388 let connect_http c socket source = 389 let auth = get_auth source in389 let auth = get_auth source.user source.password in 390 390 try 391 391 Hashtbl.add source.headers "Authorization" auth; … … 501 501 "GET /admin.cgi?mode=updinfo&pass=%s%s HTTP/1.0\r\n%s\r\n" 502 502 503 let update_metadata c m = 504 let source = 505 match c.status with 506 | PrivConnected (x,_) -> x 507 | _ -> raise (Error Not_connected) 508 in 509 if not c.icy_cap then 510 raise (Error Invalid_usage); 511 let socket = create_socket ~ipv6:c.ipv6 ?bind:c.bind () in 503 let manual_update_metadata 504 ~host ~port ~protocol ~user ~password 505 ~mount ?headers ?(ipv6=false) 506 ?bind m = 507 let mount = 508 if mount.[0] <> '/' then 509 "/" ^ mount 510 else 511 mount 512 in 513 let headers = 514 match headers with 515 | Some x -> x 516 | None -> Hashtbl.create 0 517 in 518 let socket = create_socket ~ipv6 ?bind () in 512 519 let close () = 513 520 try … … 517 524 in 518 525 try 519 connect_socket socket source.host source.port ;526 connect_socket socket host port ; 520 527 let user_agent = 521 528 try 522 Hashtbl.find source.headers "User-Agent"529 Hashtbl.find headers "User-Agent" 523 530 with 524 531 | Not_found -> "ocaml-cry" … … 526 533 (** This seems to be needed for shoutcast *) 527 534 let agent_complement = 528 if source.protocol = Icy then535 if protocol = Icy then 529 536 " (Mozilla compatible)" 530 537 else … … 544 551 in 545 552 let request = 546 match source.protocol with553 match protocol with 547 554 | Http -> 548 555 let headers = 549 Printf.sprintf "Authorization: %s\r\n%s" (get_auth source) user_agent556 Printf.sprintf "Authorization: %s\r\n%s" (get_auth user password) user_agent 550 557 in 551 http_meta_request source.mount meta headers552 | Icy -> icy_meta_request source.password meta user_agent558 http_meta_request mount meta headers 559 | Icy -> icy_meta_request password meta user_agent 553 560 in 554 561 write_data socket request; … … 569 576 raise e 570 577 578 let update_metadata c m = 579 let source = 580 match c.status with 581 | PrivConnected (x,_) -> x 582 | _ -> raise (Error Not_connected) 583 in 584 if not c.icy_cap then 585 raise (Error Invalid_usage); 586 let user = source.user in 587 let port = source.port in 588 let password = source.password in 589 let headers = Some source.headers in 590 let protocol = source.protocol in 591 let mount = source.mount in 592 let host = source.host in 593 let ipv6 = c.ipv6 in 594 let bind = c.bind in 595 manual_update_metadata 596 ~host ~port ~protocol 597 ~user ~password 598 ~mount ?headers 599 ~ipv6 ?bind m 600 571 601 let send c x = 572 602 try 573 let socket = get_socket c in 574 let out_e = Unix.out_channel_of_descr socket in 575 output_string out_e x; 576 flush out_e 603 let socket = get_socket c in 604 let len = String.length x in 605 let rec write ofs = 606 let rem = len - ofs in 607 let ret = Unix.write socket x ofs rem in 608 if ret < rem then 609 write (ofs+ret) 610 in 611 write 0 577 612 with 578 613 | _ -> raise (Error Write) -
trunk/ocaml-cry/src/cry.mli
r6838 r7142 196 196 val update_metadata : t -> metadata -> unit 197 197 198 (** Manually update metadata on any source with 199 * being connected or streaming. 200 * 201 * Use it only if you know what you are doing ! *) 202 val manual_update_metadata : 203 host:string -> 204 port:int -> 205 protocol:protocol -> 206 user:string -> 207 password:string -> 208 mount:string -> 209 ?headers:(string, string) Hashtbl.t -> 210 ?ipv6:bool -> ?bind:string -> metadata -> unit 211 198 212 (** Send data to a source connection. 199 213 *
