workaround bug in ocaml 3.10.x
[mldonkey.git] / tools / subconv.ml
blob4ae1f12799eada6249b9cbf4f6686f5b074ea2a1
1 (* Copyright 2001, 2002 b8_bavard, b8_fee_carabine, INRIA *)
2 (*
3 This file is part of mldonkey.
5 mldonkey is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 mldonkey is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with mldonkey; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 open Gettext
21 open Md4
22 open LittleEndian
23 open Unix
24 open Printf2
26 let _s x = _s "Subconv" x
27 let _b x = _b "Subconv" x
29 type position =
30 FrameInterval of float * float
32 let argument = ref []
33 let framerate = ref 24.
34 let split_frame = ref None
35 let delay_frame = ref 0.
36 let concat_frame = ref None
38 let input_line ic =
39 let s = input_line ic in
40 let len = String.length s in
41 if len > 0 && s.[len-1] = '\r' then
42 String.sub s 0 (len-1)
43 else s
45 let int_of_string s =
46 try
47 int_of_string s
48 with e ->
49 lprintf "Error in int_of_string: [%s]\n" s;
50 raise e
52 (*************************************************************************)
53 (* *)
54 (* SRT functions *)
55 (* *)
56 (*************************************************************************)
58 let srt_time_of_frame frame =
59 let time = frame /. !framerate in
60 Printf.sprintf "%02d:%02d:%02d,%03d"
61 (int_of_float (time /. 3600.))
62 (int_of_float (time /. 60.) mod 60)
63 (int_of_float time mod 60)
64 (int_of_float (time *. 1000.) mod 1000)
66 let frame_of_srt_time time =
67 try
68 match String2.split_simplify time ':' with
69 hours :: mins :: secs :: [] ->
70 let hours = int_of_string hours in
71 let mins = int_of_string mins in
72 let secs, msecs =
73 match String2.split_simplify secs ',' with
74 [secs; msecs] ->
75 int_of_string secs, int_of_string msecs
76 | _ -> raise Not_found
78 ((float_of_int hours *. 3600. +.
79 float_of_int mins *. 60. +.
80 float_of_int secs +.
81 float_of_int msecs /. 1000.) *. !framerate)
82 | _ -> raise Not_found
84 with e ->
85 failwith (Printf.sprintf "Bad time format [%s]" time)
87 (*************************************************************************)
88 (* *)
89 (* output_frames *)
90 (* *)
91 (*************************************************************************)
93 let fprintf_sub oc (pos, lines) frame_offset =
95 let frame1, frame2 =
96 match pos with
97 FrameInterval (frame1, frame2) ->
98 frame1, frame2
101 let frame1 = frame1 +. !delay_frame in
102 let frame2 = frame2 +. !delay_frame in
104 let line = String2.unsplit lines '|' in
106 Printf.fprintf oc "{%d}{%d}%s\n"
107 (int_of_float (frame1 -. frame_offset))
108 (int_of_float (frame2 -. frame_offset)) line
110 let fprintf_srt oc i (pos, lines) frame_offset =
112 let frame1, frame2 =
113 match pos with
114 FrameInterval (frame1, frame2) ->
115 frame1, frame2
118 let frame1 = frame1 +. !delay_frame in
119 let frame2 = frame2 +. !delay_frame in
121 Printf.fprintf oc "%d\n" i;
122 Printf.fprintf oc "%s --> %s\n"
123 (srt_time_of_frame
124 (frame1 -. frame_offset))
125 (srt_time_of_frame
126 (frame2 -. frame_offset));
127 List.iter (fun line ->
128 Printf.fprintf oc "%s\n" line) lines;
129 Printf.fprintf oc "\n"
131 let output_frames file frame_begin frame_end frame_offset =
132 if file <> "" then
133 match Filename2.last_extension file with
134 ".sub" ->
136 let oc = open_out file in
138 List.iter (fun (pos, lines) ->
139 let frame1, frame2 =
140 match pos with
141 FrameInterval (frame1, frame2) ->
142 frame1, frame2
145 let frame1 = frame1 +. !delay_frame in
146 let frame2 = frame2 +. !delay_frame in
148 if frame1 < frame_end && frame2 > frame_begin then
150 fprintf_sub oc (pos,lines) frame_offset
151 ) !argument;
153 close_out oc
155 | ".srt" ->
157 let oc = open_out file in
159 let rec iter i list =
160 match list with
161 [] -> ()
162 | (pos, lines) :: tail ->
164 let frame1, frame2 =
165 match pos with
166 FrameInterval (frame1, frame2) ->
167 frame1, frame2
170 let frame1 = frame1 +. !delay_frame in
171 let frame2 = frame2 +. !delay_frame in
173 if frame1 < frame_end && frame2 > frame_begin then begin
175 fprintf_srt oc i (pos,lines) frame_offset;
176 iter (i+1) tail
177 end else iter i tail
180 iter 1 !argument;
182 close_out oc
184 | e -> lprintf "Unknown extension [%s]\n" e; exit 2
186 (*************************************************************************)
187 (* *)
188 (* read_frames *)
189 (* *)
190 (*************************************************************************)
192 let read_frames file concat_frame =
194 match Filename2.last_extension file with
195 ".sub" ->
197 let subtitles = ref [] in
198 let ic = open_in file in
199 (try
200 while true do
201 let line = input_line ic in
203 let pos1 = String.index line '}' in
204 let pos2 = String.index_from line (pos1+1) '}' in
206 let frame1 = int_of_string (String.sub line 1 (pos1 - 1)) in
207 let frame2 = int_of_string (String.sub line
208 (pos1+2) (pos2 - pos1 - 2)) in
210 let sub = String.sub line (pos2+1) (String.length line - pos2 - 1) in
211 let lines = String2.split sub '|' in
213 subtitles := (FrameInterval (
214 concat_frame +. float_of_int frame1,
215 concat_frame +. float_of_int frame2), lines) ::
216 !subtitles
217 done
218 with End_of_file ->
219 close_in ic
220 | e -> close_in ic; raise e
222 List.rev !subtitles
225 | ".srt" ->
227 let subtitles = ref [] in
228 let ic = open_in file in
229 (try
230 while true do
232 let line = input_line ic in
233 let i = int_of_string line in
235 let line = input_line ic in
236 let frame1, frame2 =
237 match String2.split line ' ' with
238 time1 :: _ :: time2 :: [] ->
240 concat_frame +. frame_of_srt_time time1,
241 concat_frame +. frame_of_srt_time time2
243 | _ ->
244 failwith (Printf.sprintf "Bad line [%s]\n" line)
247 let rec iter list =
248 let line = input_line ic in
249 if line = "" then List.rev list else
250 iter (line :: list)
252 let lines = iter [] in
254 subtitles := (FrameInterval (frame1, frame2), lines) ::
255 !subtitles
256 done
257 with End_of_file ->
258 close_in ic
259 | e -> close_in ic; raise e
261 List.rev !subtitles
263 | e -> lprintf "Unknown extension [%s]\n" e; exit 2
265 (*************************************************************************)
266 (* *)
267 (* MAIN *)
268 (* *)
269 (*************************************************************************)
271 let _ =
272 Arg2.parse [
274 "-from", Arg2.String (fun file ->
275 argument := read_frames file 0.;
276 ), " <filename>: read <filename> subtitle file (.sub or .srt file)";
278 "-framerate", Arg2.Float (fun f -> framerate := f),
279 " <framerate>: set the framerate (nb frames/second)";
281 "-delay_frame", Arg2.Float (fun i -> delay_frame := i),
282 " <frame>: introduce this delay in the subtitles";
284 "-delay_time", Arg2.Float (fun f ->
285 delay_frame := (f *. !framerate)),
286 " <time>: introduce this delay in the subtitles";
289 "-remove_delay_frame", Arg2.Float (fun i -> delay_frame := -. i),
290 " <frame>: introduce this delay in the subtitles";
292 "-remove_delay_time", Arg2.Float (fun f ->
293 delay_frame := -. (f *. !framerate)),
294 " <time>: introduce this delay in the subtitles";
297 "-rescale", Arg2.Float (fun newframerate ->
299 let rescale = !framerate /. newframerate in
301 let rescale frame = frame *. rescale in
303 argument := List2.tail_map (fun
304 (FrameInterval (frame1, frame2),lines) ->
305 FrameInterval (rescale frame1, rescale frame2), lines
306 ) !argument
308 ) , " <framerate> : rescale the frames on a different frame rate";
310 "-to", Arg2.String (fun file ->
311 output_frames file min_float max_float 0.
312 ), " <filename>: write <filename> subtitle file (.sub or .srt)";
314 "-split_frame", Arg2.Float (fun i -> split_frame := Some i),
315 " <frame>: where to cut the subtitle file";
317 "-split_time", Arg2.Float (fun f ->
318 split_frame := Some (f *. !framerate)),
319 " <time>: where to cut the subtitle file";
321 "-split", Arg2.Array (2, fun array ->
322 match !split_frame with
323 None -> lprintf "No split frame set. You must set one.\n"; exit 2
324 | Some split_frame ->
326 output_frames array.(0) min_float split_frame 0.;
327 output_frames array.(1) split_frame max_float split_frame;
329 ), " <filename1> <filename2>: cut subtitles in <filename1> and <filename2>";
331 "-concat_frame", Arg2.Float (fun i -> concat_frame := Some i),
332 " <frame>: where to add the subtitle file";
334 "-concat_time", Arg2.Float (fun f ->
335 concat_frame := Some (f *. !framerate)),
336 " <time>: where to add the subtitle file";
338 "-print", Arg2.Unit (fun _ ->
340 match !argument with
341 [] -> failwith "Not enough subtitles"
342 | (pos, lines) :: _ ->
344 Printf.fprintf Pervasives.stdout "FIRST SUBTITLE:\n";
345 fprintf_sub Pervasives.stdout (pos, lines) 0.;
346 fprintf_srt Pervasives.stdout 1 (pos, lines) 0.;
348 let rec iter list =
349 match list with
350 [] -> assert false
351 | [pos, lines] ->
352 Printf.fprintf Pervasives.stdout "\n\nLAST SUBTITLE:\n";
353 fprintf_sub Pervasives.stdout (pos, lines) 0.;
354 fprintf_srt Pervasives.stdout 1 (pos, lines) 0.;
356 | _ :: tail -> iter tail
358 iter !argument
361 ) , " : print first and last lines of file";
363 "-concat", Arg2.String (fun file ->
365 match !concat_frame with
366 None -> lprintf "No concat frame set. You must set one.\n"; exit 2
367 | Some concat_frame ->
369 argument := !argument @ read_frames file concat_frame
371 ) , " <filename> : add these subtitles to the previous ones";
373 ] (fun e ->
374 lprintf "Don't know what to do with [%s]\n" e; exit 2
376 "subconv: modify subtitles files"