Skip to content

Commit

Permalink
Switch to new channel layout API.
Browse files Browse the repository at this point in the history
  • Loading branch information
toots committed Feb 23, 2024
1 parent dff5996 commit ad9224b
Show file tree
Hide file tree
Showing 34 changed files with 443 additions and 276 deletions.
2 changes: 2 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* Added support to get all streams from output container
* Removed unreliable `Av.was_keyframe`
* Added `on_keyframe` to `Av.write_frame`.
* Switched to new channel layout API.

1.1.10 (2024-01-17)
======
Expand All @@ -18,6 +19,7 @@
* Added AV_CODEC_ID_NONE to all codec id classes
to prevent unecessary failures when passing it
as detected coded_id.
=======

1.1.8 (2023-07-01)
=====
Expand Down
20 changes: 5 additions & 15 deletions av/av.ml
Original file line number Diff line number Diff line change
Expand Up @@ -318,30 +318,20 @@ external new_audio_stream :
_ container ->
int ->
[ `Encoder ] Avcodec.Audio.t ->
int ->
Channel_layout.t ->
(string * string) array ->
int * string array = "ocaml_av_new_audio_stream"

let new_audio_stream ?opts ?channels ?channel_layout ~sample_rate ~sample_format
let new_audio_stream ?opts ~channel_layout ~sample_rate ~sample_format
~time_base ~codec container =
let opts =
mk_audio_opts ?opts ?channels ?channel_layout ~sample_rate ~sample_format
~time_base ()
in
let channels =
match (channels, channel_layout) with
| Some n, _ -> n
| None, Some layout -> Avutil.Channel_layout.get_nb_channels layout
| None, None ->
raise
(Error
(`Failure
"At least one of channels or channel_layout must be passed!"))
mk_audio_opts ?opts ~channel_layout ~sample_rate ~sample_format ~time_base
()
in
let ret, unused =
new_audio_stream container
(Sample_format.get_id sample_format)
codec channels (mk_opts_array opts)
codec channel_layout (mk_opts_array opts)
in
filter_opts unused opts;
mk_stream container ret
Expand Down
5 changes: 1 addition & 4 deletions av/av.mli
Original file line number Diff line number Diff line change
Expand Up @@ -268,8 +268,6 @@ val initialize_stream_copy :
After returning, if [opts] was passed, unused options are left in the hash
table.
At least one of [channels] or [channel_layout] must be passed.
Frames passed to this stream for encoding must have a PTS set according to
the given [time_base]. [1/sample_rate] is usually a good value for the
[time_base].
Expand All @@ -285,8 +283,7 @@ val initialize_stream_copy :
Raise Error if the opening failed. *)
val new_audio_stream :
?opts:opts ->
?channels:int ->
?channel_layout:Channel_layout.t ->
channel_layout:Channel_layout.t ->
sample_rate:int ->
sample_format:Avutil.Sample_format.t ->
time_base:Avutil.rational ->
Expand Down
24 changes: 14 additions & 10 deletions av/av_stubs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1708,7 +1708,7 @@ static stream_t *new_stream(av_t *av, const AVCodec *codec) {

AVStream *avstream = avformat_new_stream(av->format_context, codec);
if (!avstream) {
free(stream);
free_stream(stream);
caml_raise_out_of_memory();
}

Expand Down Expand Up @@ -1764,18 +1764,21 @@ static void init_stream_encoder(AVBufferRef *device_ctx, AVBufferRef *frame_ctx,
}

static stream_t *new_audio_stream(av_t *av, enum AVSampleFormat sample_fmt,
int channels, const AVCodec *codec,
AVChannelLayout *channel_layout,
const AVCodec *codec,
AVDictionary **options) {
stream_t *stream = new_stream(av, codec);
int ret;

AVCodecContext *enc_ctx = stream->codec_context;

enc_ctx->sample_fmt = sample_fmt;
enc_ctx->channels = channels;
// Detect new API
#ifdef AV_CHANNEL_LAYOUT_MONO
av_channel_layout_default(&enc_ctx->ch_layout, channels);
#endif
ret = av_channel_layout_copy(&enc_ctx->ch_layout, channel_layout);

if (ret < 0) {
free_stream(stream);
ocaml_avutil_raise_error(ret);
}

init_stream_encoder(NULL, NULL, av, stream, options);

Expand Down Expand Up @@ -1809,7 +1812,7 @@ CAMLprim value ocaml_av_initialize_stream_copy(value _av, value _stream_index,
}

CAMLprim value ocaml_av_new_audio_stream(value _av, value _sample_fmt,
value _codec, value _channels,
value _codec, value _channel_layout,
value _opts) {
CAMLparam2(_av, _opts);
CAMLlocal2(ans, unused);
Expand All @@ -1831,8 +1834,9 @@ CAMLprim value ocaml_av_new_audio_stream(value _av, value _sample_fmt,
}
}

stream_t *stream = new_audio_stream(Av_val(_av), Int_val(_sample_fmt),
Int_val(_channels), codec, &options);
stream_t *stream =
new_audio_stream(Av_val(_av), Int_val(_sample_fmt),
AVChannelLayout_val(_channel_layout), codec, &options);

// Return unused keys
count = av_dict_count(options);
Expand Down
19 changes: 12 additions & 7 deletions av/av_stubs.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#ifndef _AV_STUBS_H_
#ifndef _AV_STUBS_H_
#define _AV_STUBS_H_

#include <caml/mlvalues.h>
Expand All @@ -15,19 +15,24 @@ AVFormatContext *ocaml_av_get_format_context(value *p_av);

/***** AVInputFormat *****/

#define InputFormat_val(v) (*(avioformat_const AVInputFormat**)Data_abstract_val(v))
#define InputFormat_val(v) \
(*(avioformat_const AVInputFormat **)Data_abstract_val(v))

void value_of_inputFormat(avioformat_const AVInputFormat *inputFormat, value * p_value);
void value_of_inputFormat(avioformat_const AVInputFormat *inputFormat,
value *p_value);

/***** AVOutputFormat *****/

#define OutputFormat_val(v) (*(avioformat_const AVOutputFormat**)Data_abstract_val(v))
#define OutputFormat_val(v) \
(*(avioformat_const AVOutputFormat **)Data_abstract_val(v))

value value_of_outputFormat(avioformat_const AVOutputFormat *outputFormat);

/***** Control message *****/
value * ocaml_av_get_control_message_callback(struct AVFormatContext *ctx);
value *ocaml_av_get_control_message_callback(struct AVFormatContext *ctx);

void ocaml_av_set_control_message_callback(value *p_av, av_format_control_message c_callback, value *p_ocaml_callback);
void ocaml_av_set_control_message_callback(value *p_av,
av_format_control_message c_callback,
value *p_ocaml_callback);

#endif // _AV_STUBS_H_
#endif // _AV_STUBS_H_
2 changes: 1 addition & 1 deletion av/config/discover.ml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module C = Configurator.V1

let packages = [("avutil", "55.78.100"); ("avformat", "57.83.100")]
let packages = [("avutil", "57.24.100"); ("avformat", "57.83.100")]

let () =
C.main ~name:"ffmpeg-av-pkg-config" (fun c ->
Expand Down
26 changes: 10 additions & 16 deletions avcodec/avcodec.ml
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,11 @@ module Audio = struct
let find_best_channel_layout codec default =
try
let channel_layouts = get_supported_channel_layouts codec in
if List.mem default channel_layouts then default
if
List.exists
(fun layout -> Avutil.Channel_layout.compare layout default)
channel_layouts
then default
else (match channel_layouts with h :: _ -> h | [] -> default)
with Not_found -> default

Expand Down Expand Up @@ -384,31 +388,21 @@ module Audio = struct
external create_encoder :
int ->
[ `Encoder ] t ->
int ->
Channel_layout.t ->
(string * string) array ->
audio encoder * string array = "ocaml_avcodec_create_audio_encoder"

let create_encoder ?opts ?channels ?channel_layout ~sample_rate ~sample_format
let create_encoder ?opts ~channel_layout ~sample_rate ~sample_format
~time_base codec =
let opts = opts_default opts in
let _opts =
mk_audio_opts ~opts ?channels ?channel_layout ~sample_rate ~sample_format
~time_base ()
in
let channels =
match (channels, channel_layout) with
| Some n, _ -> n
| None, Some layout -> Avutil.Channel_layout.get_nb_channels layout
| None, None ->
raise
(Error
(`Failure
"At least one of channels or channel_layout must be passed!"))
mk_audio_opts ~opts ~channel_layout ~sample_rate ~sample_format ~time_base
()
in
let encoder, unused =
create_encoder
(Sample_format.get_id sample_format)
codec channels (mk_opts_array _opts)
codec channel_layout (mk_opts_array _opts)
in
filter_opts unused opts;
encoder
Expand Down
3 changes: 1 addition & 2 deletions avcodec/avcodec.mli
Original file line number Diff line number Diff line change
Expand Up @@ -238,8 +238,7 @@ module Audio : sig
Raise Error if the encoder creation failed. *)
val create_encoder :
?opts:opts ->
?channels:int ->
?channel_layout:Channel_layout.t ->
channel_layout:Channel_layout.t ->
sample_rate:int ->
sample_format:Avutil.Sample_format.t ->
time_base:Avutil.rational ->
Expand Down
50 changes: 13 additions & 37 deletions avcodec/avcodec_stubs.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
#include "hw_config_method_stubs.h"
#include "media_types_stubs.h"

#include <libavutil/replaygain.h>
#include <libavcodec/bsf.h>
#include <libavutil/replaygain.h>

#ifndef AV_PKT_FLAG_DISPOSABLE
#define AV_PKT_FLAG_DISPOSABLE 0x0010
Expand Down Expand Up @@ -662,7 +662,8 @@ CAMLprim value ocaml_avcodec_encoder_time_base(value _encoder) {
}

CAMLprim value ocaml_avcodec_create_audio_encoder(value _sample_fmt,
value _codec, value _channels,
value _codec,
value _channel_layout,
value _opts) {
CAMLparam2(_opts, _codec);
CAMLlocal3(ret, ans, unused);
Expand Down Expand Up @@ -700,11 +701,11 @@ CAMLprim value ocaml_avcodec_create_audio_encoder(value _sample_fmt,
}

ctx->codec_context->sample_fmt = Int_val(_sample_fmt);
ctx->codec_context->channels = Int_val(_channels);
// Detect new API
#ifdef AV_CHANNEL_LAYOUT_MONO
av_channel_layout_default(&ctx->codec_context->ch_layout, Int_val(_channels));
#endif

err = av_channel_layout_copy(&ctx->codec_context->ch_layout,
AVChannelLayout_val(_channel_layout));
if (err < 0)
ocaml_avutil_raise_error(err);

// Open the codec
caml_release_runtime_system();
Expand Down Expand Up @@ -1290,9 +1291,9 @@ CAMLprim value ocaml_avcodec_get_supported_channel_layouts(value _codec) {
List_init(list);
const AVCodec *codec = AvCodec_val(_codec);

if (codec->channel_layouts) {
for (i = 0; codec->channel_layouts[i] != 0; i++)
List_add(list, cons, Val_ChannelLayout(codec->channel_layouts[i]));
if (codec->ch_layouts) {
for (i = 0; codec->ch_layouts[i].nb_channels != 0; i++)
List_add(list, cons, value_of_channel_layout(&codec->ch_layouts[i]));
}

CAMLreturn(list);
Expand Down Expand Up @@ -1338,16 +1339,12 @@ CAMLprim value ocaml_avcodec_parameters_get_channel_layout(value _cp) {
CAMLparam1(_cp);
AVCodecParameters *cp = CodecParameters_val(_cp);

if (cp->channel_layout == 0) {
cp->channel_layout = av_get_default_channel_layout(cp->channels);
}

CAMLreturn(Val_ChannelLayout(cp->channel_layout));
CAMLreturn(value_of_channel_layout(&cp->ch_layout));
}

CAMLprim value ocaml_avcodec_parameters_get_nb_channels(value _cp) {
CAMLparam1(_cp);
CAMLreturn(Val_int(CodecParameters_val(_cp)->channels));
CAMLreturn(Val_int(CodecParameters_val(_cp)->ch_layout.nb_channels));
}

CAMLprim value ocaml_avcodec_parameters_get_sample_format(value _cp) {
Expand All @@ -1361,27 +1358,6 @@ CAMLprim value ocaml_avcodec_parameters_get_sample_rate(value _cp) {
CAMLreturn(Val_int(CodecParameters_val(_cp)->sample_rate));
}

CAMLprim value ocaml_avcodec_parameters_audio_copy(value _codec_id,
value _channel_layout,
value _sample_format,
value _sample_rate,
value _cp) {
CAMLparam4(_codec_id, _channel_layout, _sample_format, _cp);
CAMLlocal1(ans);

value_of_codec_parameters_copy(CodecParameters_val(_cp), &ans);

AVCodecParameters *dst = CodecParameters_val(ans);

dst->codec_id = AudioCodecID_val(_codec_id);
dst->channel_layout = ChannelLayout_val(_channel_layout);
dst->channels = av_get_channel_layout_nb_channels(dst->channel_layout);
dst->format = SampleFormat_val(_sample_format);
dst->sample_rate = Int_val(_sample_rate);

CAMLreturn(ans);
}

/**** Video codec ID ****/

CAMLprim value ocaml_avcodec_get_video_codec_id_name(value _codec_id) {
Expand Down
2 changes: 1 addition & 1 deletion avcodec/config/discover.ml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ let () =
| Some pc -> (
match
C.Pkg_config.query_expr_err pc ~package:"libavcodec"
~expr:"libavcodec >= 58.87.100"
~expr:"libavcodec >= 59.24.100"
with
| Error msg -> failwith msg
| Ok deps -> deps)
Expand Down
19 changes: 11 additions & 8 deletions avfilter/avfilter.ml
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,9 @@ module Utils = struct
`Pair ("time_base", `Rational in_time_base);
`Pair
( "channel_layout",
`Int64 (Avutil.Channel_layout.get_id in_params.channel_layout) );
`String
(Avutil.Channel_layout.get_description in_params.channel_layout)
);
`Pair
( "sample_fmt",
`Int (Avutil.Sample_format.get_id in_params.sample_format) );
Expand All @@ -447,19 +449,20 @@ module Utils = struct
[
`Pair ("in_sample_rate", `Int in_params.sample_rate);
`Pair
( "in_channel_layout",
`Int64
(Avutil.Channel_layout.get_id in_params.channel_layout) );
( "in_chlayout",
`String
(Avutil.Channel_layout.get_description
in_params.channel_layout) );
`Pair
( "in_sample_fmt",
`Int (Avutil.Sample_format.get_id in_params.sample_format)
);
`Pair ("out_sample_rate", `Int out_params.sample_rate);
`Pair
( "out_channel_layout",
`Int64
(Avutil.Channel_layout.get_id out_params.channel_layout)
);
( "out_chlayout",
`String
(Avutil.Channel_layout.get_description
out_params.channel_layout) );
`Pair
( "out_sample_fmt",
`Int (Avutil.Sample_format.get_id out_params.sample_format)
Expand Down
8 changes: 6 additions & 2 deletions avfilter/avfilter_stubs.c
Original file line number Diff line number Diff line change
Expand Up @@ -465,11 +465,15 @@ CAMLprim value ocaml_avfilter_buffersink_get_channels(value _src) {

CAMLprim value ocaml_avfilter_buffersink_get_channel_layout(value _src) {
CAMLparam0();
CAMLlocal1(ret);
AVFilterContext *filter_ctx = AvFilterContext_val(_src);
AVChannelLayout channel_layout;
int err = av_buffersink_get_ch_layout(filter_ctx, &channel_layout);

uint64_t layout = av_buffersink_get_channel_layout(filter_ctx);
ret = value_of_channel_layout(&channel_layout);
av_channel_layout_uninit(&channel_layout);

CAMLreturn(Val_ChannelLayout(layout));
CAMLreturn(ret);
}

CAMLprim value ocaml_avfilter_buffersink_get_sample_rate(value _src) {
Expand Down
Loading

0 comments on commit ad9224b

Please sign in to comment.