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 ()
|