File: aresample.ml

package info (click to toggle)
ocaml-ffmpeg 1.2.8-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 924 kB
  • sloc: ansic: 6,448; ml: 6,294; makefile: 3
file content (128 lines) | stat: -rw-r--r-- 3,827 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
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
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 "ac3" in

  let audio_params, audio_input, idx, 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
    ( params,
      audio_input,
      i,
      Av.new_audio_stream ~channel_layout ~sample_format ~sample_rate ~time_base
        ~codec:audio_codec dst )
  in

  let frame_size =
    if List.mem `Variable_frame_size (Avcodec.capabilities audio_codec) then 512
    else Av.get_frame_size oass
  in

  let filter =
    let config = Avfilter.init () in
    let abuffer =
      let time_base = Av.get_time_base audio_input in
      let sample_rate = Avcodec.Audio.get_sample_rate audio_params in
      let sample_format =
        Avutil.Sample_format.get_id
          (Avcodec.Audio.get_sample_format audio_params)
      in
      let channel_layout =
        Avutil.Channel_layout.get_description
          (Avcodec.Audio.get_channel_layout audio_params)
      in
      let args =
        [
          `Pair ("time_base", `Rational time_base);
          `Pair ("sample_rate", `Int sample_rate);
          `Pair ("sample_fmt", `Int sample_format);
          `Pair ("channel_layout", `String channel_layout);
        ]
      in
      let abuffer =
        Avfilter.attach ~args ~name:"audio_input" Avfilter.abuffer config
      in
      {
        Avfilter.node_name = "in";
        node_args = Some args;
        node_pad = List.hd abuffer.io.outputs.audio;
      }
    in
    let outputs = { Avfilter.audio = [abuffer]; video = [] } in
    let abuffersink =
      Avfilter.attach ~name:"audio_output" Avfilter.abuffersink config
    in
    let sink =
      {
        Avfilter.node_name = "out";
        node_args = None;
        node_pad = List.hd abuffersink.io.inputs.audio;
      }
    in
    let inputs = { Avfilter.audio = [sink]; video = [] } in
    Avfilter.parse { inputs; outputs }
      "aresample=22050,aformat=channel_layouts=stereo" config;
    Avfilter.launch config
  in

  let _, output = List.hd Avfilter.(filter.outputs.audio) in
  let context = output.context in
  Avfilter.set_frame_size context frame_size;
  let time_base = Avfilter.time_base context in
  Printf.printf
    "Sink info:\n\
     time_base: %d/%d\n\
     channels: %d\n\
     channel_layout: %s\n\
     sample_rate: %d\n"
    time_base.Avutil.num time_base.Avutil.den
    (Avfilter.channels context)
    (Avutil.Channel_layout.get_description (Avfilter.channel_layout context))
    (Avfilter.sample_rate context);

  let process_audio i frm =
    try
      assert (i = idx);
      let _, input = List.hd Avfilter.(filter.inputs.audio) in
      input frm;
      let rec flush () =
        try
          Av.write_frame oass (output.handler ());
          flush ()
        with Avutil.Error `Eagain -> ()
      in
      flush ()
    with Not_found -> ()
  in

  Gc.full_major ();
  Gc.full_major ();

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

  Av.close src;
  Av.close dst;

  Gc.full_major ();
  Gc.full_major ()