Skip to content

Commit

Permalink
Add avfilter to transcode_aac to respect frame size.
Browse files Browse the repository at this point in the history
  • Loading branch information
toots committed Jul 9, 2024
1 parent e593390 commit e82ceb5
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 6 deletions.
13 changes: 11 additions & 2 deletions avutil/avutil.ml
Original file line number Diff line number Diff line change
Expand Up @@ -681,8 +681,17 @@ let add_audio_opts ?channels ?channel_layout ~sample_rate ~sample_format
Hashtbl.add opts "ar" (`Int sample_rate);
on_opt channels (fun channels -> Hashtbl.add opts "ac" (`Int channels));
on_opt channel_layout (fun channel_layout ->
Hashtbl.add opts "channel_layout"
(`String (Channel_layout.get_description channel_layout)));
let param =
match Channel_layout.get_native_id channel_layout with
| Some id -> `Int64 id
| None ->
let channel_layout =
Channel_layout.get_default
(Channel_layout.get_nb_channels channel_layout)
in
`Int64 (Option.get (Channel_layout.get_native_id channel_layout))
in
Hashtbl.add opts "channel_layout" param);
Hashtbl.add opts "sample_fmt" (`Int (Sample_format.get_id sample_format));
Hashtbl.add opts "time_base" (`String (string_of_rational time_base))

Expand Down
2 changes: 1 addition & 1 deletion examples/dune
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@
(executable
(name transcode_aac)
(modules transcode_aac)
(libraries ffmpeg-av))
(libraries ffmpeg-av ffmpeg-avfilter))

(executable
(name transcoding)
Expand Down
81 changes: 78 additions & 3 deletions examples/transcode_aac.ml
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,29 @@ let () =

if Array.length Sys.argv = 4 && Sys.argv.(3) = "macosx" then exit 0;

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

let src = Av.open_input Sys.argv.(1) in

let idx, istream, params = Av.find_best_audio_stream src in

let () =
match Avcodec.descriptor params with
| Some { name = d; _ } ->
Printf.printf
"Input format: %s (channel layout: %s, sample format: %s, sample \
rate: %d)\n\
%!"
d
(Avutil.Channel_layout.get_description
(Avcodec.Audio.get_channel_layout params))
(Option.value ~default:"(unknown)"
(Avutil.Sample_format.get_name
(Avcodec.Audio.get_sample_format params)))
(Avcodec.Audio.get_sample_rate params)
| _ -> Printf.printf "Unknown input format..\n!"
in

let codec = Avcodec.Audio.find_encoder_by_name "aac" in

let channel_layout = Avcodec.Audio.get_channel_layout params in
Expand All @@ -25,10 +41,69 @@ let () =
~time_base ~codec
in

let () =
match Avcodec.descriptor (Av.get_codec_params ostream) with
| Some { name = d; _ } ->
Printf.printf
"Output format: %s (channel layout: %s, sample format: %s, sample \
rate: %d)\n\
%!"
d
(Avutil.Channel_layout.get_description
(Avcodec.Audio.get_channel_layout params))
(Option.value ~default:"(unknown)"
(Avutil.Sample_format.get_name
(Avcodec.Audio.get_sample_format params)))
(Avcodec.Audio.get_sample_rate params)
| _ -> Printf.printf "Unknown output format..\n!"
in

let filter = ref None in
let get_filter frame =
match !filter with
| Some f -> f
| None ->
let in_params =
{
Avfilter.Utils.sample_rate =
Avutil.Audio.frame_get_sample_rate frame;
channel_layout = Avutil.Audio.frame_get_channel_layout frame;
sample_format = Avutil.Audio.frame_get_sample_format frame;
}
in
let in_time_base = { Avutil.num = 1; den = sample_rate } in
let out_frame_size =
if List.mem `Variable_frame_size (Avcodec.capabilities codec) then
512
else Av.get_frame_size ostream
in
let out_params =
{ Avfilter.Utils.sample_rate; sample_format; channel_layout }
in
let f =
Avfilter.Utils.init_audio_converter ~in_params ~in_time_base
~out_params ~out_frame_size ()
in
filter := Some f;
f
in

let pts = ref 0L in
let on_frame frame =
Avutil.Frame.set_pts frame (Some !pts);
pts := Int64.add !pts (Int64.of_int (Avutil.Audio.frame_nb_samples frame));
Av.write_frame ostream frame
in

let write_frame frame =
let filter = get_filter frame in
Avfilter.Utils.convert_audio filter on_frame (`Frame frame)
in

let rec f () =
match Av.read_input ~audio_frame:[istream] src with
| `Audio_frame (i, frame) when i = idx ->
Av.write_frame ostream frame;
write_frame frame;
f ()
| exception Avutil.Error `Eof -> ()
| _ -> f ()
Expand Down

0 comments on commit e82ceb5

Please sign in to comment.