File: fps.ml

package info (click to toggle)
ocaml-ffmpeg 1.2.7-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 908 kB
  • sloc: ansic: 6,412; ml: 6,166; makefile: 3
file content (156 lines) | stat: -rw-r--r-- 4,868 bytes parent folder | download | duplicates (2)
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
let () = Printexc.record_backtrace true

let () =
  if Array.length Sys.argv < 3 then (
    Printf.printf "usage: %s input_file output_file\n" Sys.argv.(0);
    exit 1);

  Avutil.Log.set_level `Debug;
  Avutil.Log.set_callback print_string;

  let src = Av.open_input Sys.argv.(1) in
  let dst = Av.open_output Sys.argv.(2) in
  let audio_codec = Avcodec.Audio.find_encoder_by_name "aac" in
  let video_codec = Avcodec.Video.find_encoder_by_name "mpeg4" in

  let audio_input, oass =
    Av.find_best_audio_stream src |> fun (i, audio_input, params) ->
    let channel_layout = Avcodec.Audio.get_channel_layout params in
    let sample_format = Avcodec.Audio.get_sample_format params in
    let sample_rate = Avcodec.Audio.get_sample_rate params in
    let time_base = { Avutil.num = 1; den = sample_rate } in
    ( audio_input,
      ( i,
        Av.new_audio_stream ~channel_layout ~sample_format ~sample_rate
          ~time_base ~codec:audio_codec dst ) )
  in

  let frame_rate = { Avutil.num = 25; den = 1 } in
  let time_base = { Avutil.num = 1; den = 25 } in

  let video_params, video_input, ovss =
    Av.find_best_video_stream src |> fun (i, video_input, params) ->
    let width = Avcodec.Video.get_width params in
    let height = Avcodec.Video.get_height params in
    let pixel_format =
      match Avcodec.Video.get_pixel_format params with
        | None -> failwith "Pixel format unknown!"
        | Some f -> f
    in
    ( params,
      video_input,
      ( i,
        Av.new_video_stream ~pixel_format ~frame_rate ~time_base ~width ~height
          ~codec:video_codec dst ) )
  in

  let filter =
    let config = Avfilter.init () in
    let _buffer =
      let time_base = Av.get_time_base video_input in
      let pixel_aspect = Av.get_pixel_aspect video_input in
      let pixel_format =
        match Avcodec.Video.get_pixel_format video_params with
          | None -> failwith "Pixel format unknown!"
          | Some f -> f
      in
      let width = Avcodec.Video.get_width video_params in
      let height = Avcodec.Video.get_height video_params in
      let args =
        [
          `Pair ("video_size", `String (Printf.sprintf "%dx%x" width height));
          `Pair ("pix_fmt", `Int (Avutil.Pixel_format.get_id pixel_format));
          `Pair ("time_base", `Rational time_base);
        ]
        @
        match pixel_aspect with
          | Some p -> [`Pair ("pixel_aspect", `Rational p)]
          | None -> []
      in
      Avfilter.(attach ~args ~name:"buffer" buffer config)
    in
    let fps =
      let args =
        [
          `Pair
            ( "fps",
              `String
                (Printf.sprintf "%d/%d" frame_rate.Avutil.num
                   frame_rate.Avutil.den) );
        ]
      in
      let fps = Avfilter.find "fps" in
      Avfilter.attach ~args ~name:"fps" fps config
    in
    let sink = Avfilter.(attach ~name:"sink" buffersink config) in
    Avfilter.link
      (List.hd Avfilter.(_buffer.io.outputs.video))
      (List.hd Avfilter.(fps.io.inputs.video));
    Avfilter.link
      (List.hd Avfilter.(fps.io.outputs.video))
      (List.hd Avfilter.(sink.io.inputs.video));
    Avfilter.launch config
  in

  let _, output = List.hd Avfilter.(filter.outputs.video) in
  let context = output.context in
  let time_base = Avfilter.time_base context in
  let frame_rate = Avfilter.frame_rate context in
  let pixel_aspect = Avfilter.pixel_aspect context in
  Printf.printf
    "Sink info:\n\
     time_base: %d/%d\n\
     frame_rate: %d/%d\n\
     width: %d\n\
     height: %d\n\
     pixel_aspect: %s\n"
    time_base.Avutil.num time_base.Avutil.den frame_rate.Avutil.num
    frame_rate.Avutil.den (Avfilter.width context) (Avfilter.height context)
    (match pixel_aspect with
      | None -> "0/1"
      | Some { Avutil.num; den } -> Printf.sprintf "%d/%d" num den);

  let process_video i frm =
    try
      let stream = List.assoc i [ovss] in
      let _, input = List.hd Avfilter.(filter.inputs.video) in
      input frm;
      let rec flush () =
        try
          Av.write_frame stream (output.handler ());
          flush ()
        with Avutil.Error `Eagain -> ()
      in
      flush ()
    with
      | Not_found -> ()
      | Avutil.Error `Eof when frm = `Flush -> ()
  in

  let process_audio i frm =
    try
      let stream = List.assoc i [oass] in
      Av.write_frame stream frm
    with Not_found -> ()
  in

  let rec f () =
    match
      Av.read_input ~audio_frame:[audio_input] ~video_frame:[video_input] src
    with
      | `Audio_frame (i, frame) ->
          process_audio i frame;
          f ()
      | `Video_frame (i, frame) ->
          process_video i (`Frame frame);
          f ()
      | exception Avutil.Error `Eof -> process_video (fst ovss) `Flush
      | _ -> f ()
  in
  f ();

  Av.close src;
  Av.close dst;

  Gc.full_major ();
  Gc.full_major ()