From dea4469f0d69f572947d7d676e2288ed35f96a38 Mon Sep 17 00:00:00 2001 From: Romain Beauxis Date: Fri, 6 Oct 2023 19:35:10 -0500 Subject: [PATCH] Switch to new channel layout API. --- CHANGES | 2 + av/av.ml | 20 +-- av/av.mli | 5 +- av/av_stubs.c | 24 ++-- av/av_stubs.h | 19 +-- av/config/discover.ml | 2 +- avcodec/avcodec.ml | 26 ++-- avcodec/avcodec.mli | 3 +- avcodec/avcodec_stubs.c | 50 ++------ avcodec/config/discover.ml | 2 +- avfilter/avfilter.ml | 19 +-- avfilter/avfilter_stubs.c | 8 +- avfilter/config/discover.ml | 2 +- avutil/avutil.ml | 39 ++++-- avutil/avutil.mli | 24 ++-- avutil/avutil_stubs.c | 212 +++++++++++++++++++++++--------- avutil/avutil_stubs.h | 65 +++++----- examples/all_channel_layouts.ml | 8 ++ examples/aresample.ml | 11 +- examples/audio_decoding.ml | 5 +- examples/audio_device.ml | 5 +- examples/decode_audio.ml | 4 +- examples/decode_stream.ml | 4 +- examples/demuxing_decoding.ml | 4 +- examples/dune | 5 + examples/encode_audio.ml | 5 +- examples/encode_stream.ml | 11 +- examples/encoding.ml | 6 +- examples/fps.ml | 5 +- examples/fps_samplerate.ml | 5 +- swresample/swresample_stubs.c | 50 +++++--- swresample/swresample_stubs.h | 2 +- test/dune | 2 + test/resample.ml | 65 ++++++++-- 34 files changed, 443 insertions(+), 276 deletions(-) create mode 100644 examples/all_channel_layouts.ml diff --git a/CHANGES b/CHANGES index 081df0e6..da326f66 100644 --- a/CHANGES +++ b/CHANGES @@ -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) ====== @@ -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) ===== diff --git a/av/av.ml b/av/av.ml index 03591b35..ce26d383 100644 --- a/av/av.ml +++ b/av/av.ml @@ -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 diff --git a/av/av.mli b/av/av.mli index 128176ab..38ce1daa 100644 --- a/av/av.mli +++ b/av/av.mli @@ -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]. @@ -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 -> diff --git a/av/av_stubs.c b/av/av_stubs.c index fd0526df..3d5e3611 100644 --- a/av/av_stubs.c +++ b/av/av_stubs.c @@ -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(); } @@ -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); @@ -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); @@ -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); diff --git a/av/av_stubs.h b/av/av_stubs.h index 3980a226..50beb557 100644 --- a/av/av_stubs.h +++ b/av/av_stubs.h @@ -1,4 +1,4 @@ -#ifndef _AV_STUBS_H_ +#ifndef _AV_STUBS_H_ #define _AV_STUBS_H_ #include @@ -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_ diff --git a/av/config/discover.ml b/av/config/discover.ml index 40698d17..33275851 100644 --- a/av/config/discover.ml +++ b/av/config/discover.ml @@ -1,7 +1,7 @@ module C = Configurator.V1 let packages = - [("avutil", "55.78.100"); ("avformat", "57.83.100"); ("avcodec", "60.29.100")] + [("avutil", "57.24.100"); ("avformat", "57.83.100"); ("avcodec", "60.29.100")] let () = C.main ~name:"ffmpeg-av-pkg-config" (fun c -> diff --git a/avcodec/avcodec.ml b/avcodec/avcodec.ml index d7f26ff8..a1065e7e 100644 --- a/avcodec/avcodec.ml +++ b/avcodec/avcodec.ml @@ -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 @@ -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 diff --git a/avcodec/avcodec.mli b/avcodec/avcodec.mli index 17ae3f53..f7f16a59 100644 --- a/avcodec/avcodec.mli +++ b/avcodec/avcodec.mli @@ -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 -> diff --git a/avcodec/avcodec_stubs.c b/avcodec/avcodec_stubs.c index 50bdba25..022f8363 100644 --- a/avcodec/avcodec_stubs.c +++ b/avcodec/avcodec_stubs.c @@ -17,8 +17,8 @@ #include "hw_config_method_stubs.h" #include "media_types_stubs.h" -#include #include +#include #ifndef AV_PKT_FLAG_DISPOSABLE #define AV_PKT_FLAG_DISPOSABLE 0x0010 @@ -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); @@ -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(); @@ -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); @@ -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) { @@ -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) { diff --git a/avcodec/config/discover.ml b/avcodec/config/discover.ml index 5e7c17bc..585c1402 100644 --- a/avcodec/config/discover.ml +++ b/avcodec/config/discover.ml @@ -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) diff --git a/avfilter/avfilter.ml b/avfilter/avfilter.ml index d8120b15..df1413f9 100644 --- a/avfilter/avfilter.ml +++ b/avfilter/avfilter.ml @@ -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) ); @@ -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) diff --git a/avfilter/avfilter_stubs.c b/avfilter/avfilter_stubs.c index b167ebbe..d103e663 100644 --- a/avfilter/avfilter_stubs.c +++ b/avfilter/avfilter_stubs.c @@ -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) { diff --git a/avfilter/config/discover.ml b/avfilter/config/discover.ml index a7e032e2..c78510e2 100644 --- a/avfilter/config/discover.ml +++ b/avfilter/config/discover.ml @@ -11,7 +11,7 @@ let () = | Some pc -> ( match C.Pkg_config.query_expr_err pc ~package:"libavfilter" - ~expr:"libavfilter >= 6.107.100" + ~expr:"libavfilter >= 8.28.100" with | Error msg -> failwith msg | Ok deps -> deps) diff --git a/avutil/avutil.ml b/avutil/avutil.ml index 261a786b..d027e40c 100644 --- a/avutil/avutil.ml +++ b/avutil/avutil.ml @@ -51,9 +51,6 @@ module Frame = struct external best_effort_timestamp : _ t -> Int64.t option = "ocaml_avutil_frame_best_effort_timestamp" - external pkt_duration : _ t -> Int64.t option - = "ocaml_avutil_frame_pkt_duration" - external copy : 'a t -> 'b t -> unit = "ocaml_avutil_frame_copy" end @@ -201,12 +198,13 @@ module Pixel_format = struct end module Channel_layout = struct - type t = Channel_layout.t + type layout = Channel_layout.t + type t - external get_description : t -> int -> string - = "ocaml_avutil_get_channel_layout_description" + external compare : t -> t -> bool = "ocaml_avutil_compare_channel_layout" - let get_description ?(channels = -1) ch = get_description ch channels + external get_description : t -> string + = "ocaml_avutil_get_channel_layout_description" external find : string -> t = "ocaml_avutil_get_channel_layout" @@ -214,8 +212,27 @@ module Channel_layout = struct = "ocaml_avutil_get_channel_layout_nb_channels" external get_default : int -> t = "ocaml_avutil_get_default_channel_layout" - external get_id : t -> int64 = "ocaml_avutil_get_channel_layout_id" - external from_id : int64 -> t = "ocaml_avutil_channel_layout_of_id" + + type opaque + + external start_standard_iteration : unit -> opaque + = "ocaml_avutil_start_standard_iteration" + + external get_standard : opaque -> t option = "ocaml_avutil_get_standard" + + let standard_layouts = + let start = start_standard_iteration () in + let rec f ret = + match get_standard start with Some l -> f (l :: ret) | None -> ret + in + f [] + + let mono = find "mono" + let stereo = find "stereo" + let five_point_one = find "5.1" + + external get_native_id : t -> int64 option + = "ocaml_avutil_get_channel_native_id" end module Sample_format = struct @@ -498,7 +515,7 @@ module Options = struct spec with values = append - (fun v -> Channel_layout.from_id (default_int64 v)) + (fun v -> Channel_layout.find (default_string v)) values; } | `Sample_fmt ({ values; _ } as spec) -> @@ -665,7 +682,7 @@ let add_audio_opts ?channels ?channel_layout ~sample_rate ~sample_format on_opt channels (fun channels -> Hashtbl.add opts "ac" (`Int channels)); on_opt channel_layout (fun channel_layout -> Hashtbl.add opts "channel_layout" - (`Int64 (Channel_layout.get_id channel_layout))); + (`String (Channel_layout.get_description channel_layout))); Hashtbl.add opts "sample_fmt" (`Int (Sample_format.get_id sample_format)); Hashtbl.add opts "time_base" (`String (string_of_rational time_base)) diff --git a/avutil/avutil.mli b/avutil/avutil.mli index b365352d..f354b80e 100644 --- a/avutil/avutil.mli +++ b/avutil/avutil.mli @@ -55,9 +55,6 @@ module Frame : sig (** [Avutil.frame_best_effort_timestamp frame] returns the frame timestamp estimated using various heuristics, in stream time base *) val best_effort_timestamp : _ t -> Int64.t option - (** duration of the corresponding packet, expressed in AVStream->time_base units. *) - val pkt_duration : _ t -> Int64.t option - (** [Avutil.frame_copy src dst] copies data from [src] into [dst] *) val copy : 'a t -> 'b t -> unit end @@ -141,7 +138,19 @@ end (** Formats for channels layouts. *) module Channel_layout : sig (** Channel layout formats. *) - type t = Channel_layout.t + type layout = Channel_layout.t + + type t + + (** List of standard channel layouts. *) + val standard_layouts : t list + + val stereo : t + val mono : t + val five_point_one : t + + (** Compare two channel layouts. *) + val compare : t -> t -> bool (** Return a channel layout id that matches name. Raises [Not_found] otherwise. name can be one or several of the following notations, @@ -158,7 +167,7 @@ module Channel_layout : sig val find : string -> t (** Return a description of the channel layout. *) - val get_description : ?channels:int -> t -> string + val get_description : t -> string (** Return the number of channels in the channel layout. *) val get_nb_channels : t -> int @@ -167,9 +176,8 @@ module Channel_layout : sig [Not_found] if not found. *) val get_default : int -> t - (** Return the internal ID for a channel layout. This number should be passed - as the "channel_layout" [opts] in [Av.new_audio_stream] .*) - val get_id : t -> int64 + (** Return a native channel layout ID, suitable for filters channel_layout. *) + val get_native_id : t -> int64 option end (** Formats for audio samples. *) diff --git a/avutil/avutil_stubs.c b/avutil/avutil_stubs.c index bf2b31ca..b704be25 100644 --- a/avutil/avutil_stubs.c +++ b/avutil/avutil_stubs.c @@ -326,14 +326,119 @@ CAMLprim value ocaml_avutil_time_base() { } /**** Channel layout ****/ -CAMLprim value ocaml_avutil_get_channel_layout_description( - value _channel_layout, value channels) { + +static void finalize_channel_layout(value v) { + AVChannelLayout *channel_layout = AVChannelLayout_val(v); + av_channel_layout_uninit(channel_layout); + av_free(channel_layout); +} + +static struct custom_operations channel_layout_ops = { + "ocaml_avchannel_layout", finalize_channel_layout, + custom_compare_default, custom_hash_default, + custom_serialize_default, custom_deserialize_default}; + +value value_of_channel_layout(const AVChannelLayout *channel_layout) { + value ret; + AVChannelLayout *ch_layout; + int err; + + if (!channel_layout) + Fail("Empty channel_layout"); + + ch_layout = av_malloc(sizeof(AVChannelLayout)); + err = av_channel_layout_copy(ch_layout, channel_layout); + + if (err) { + av_free(ch_layout); + ocaml_avutil_raise_error(err); + } + + ret = caml_alloc_custom(&channel_layout_ops, sizeof(AVChannelLayout *), 0, 1); + AVChannelLayout_val(ret) = ch_layout; + + return ret; +} + +#define AVChannelLayoutOpaque_val(v) (*(void ***)Data_custom_val(v)) + +static void finalize_opaque(value v) { + void **opaque = AVChannelLayoutOpaque_val(v); + av_free(opaque); +} + +static struct custom_operations opaque_ops = { + "ocaml_avchannel_layout_opaque", finalize_opaque, + custom_compare_default, custom_hash_default, + custom_serialize_default, custom_deserialize_default}; + +CAMLprim value ocaml_avutil_start_standard_iteration() { + CAMLparam0(); + CAMLlocal1(ret); + + void **opaque = av_malloc(sizeof(void *)); + + if (!opaque) + caml_raise_out_of_memory(); + + *opaque = NULL; + + ret = caml_alloc_custom(&opaque_ops, sizeof(void *), 0, 1); + AVChannelLayoutOpaque_val(ret) = opaque; + + CAMLreturn(ret); +} + +CAMLprim value ocaml_avutil_get_standard(value _opaque) { + CAMLparam1(_opaque); + CAMLlocal1(ret); + void **opaque = AVChannelLayoutOpaque_val(_opaque); + const AVChannelLayout *channel_layout = av_channel_layout_standard(opaque); + + if (!channel_layout) + CAMLreturn(Val_none); + + ret = caml_alloc_tuple(1); + Store_field(ret, 0, value_of_channel_layout(channel_layout)); + + CAMLreturn(ret); +} + +CAMLprim value ocaml_avutil_compare_channel_layout(value _layout1, + value _layout2) { + CAMLparam2(_layout1, _layout2); + int ret = av_channel_layout_compare(AVChannelLayout_val(_layout1), + AVChannelLayout_val(_layout2)); + + if (ret < 0) + ocaml_avutil_raise_error(ret); + + CAMLreturn(Val_bool(!ret)); +} + +CAMLprim value ocaml_avutil_get_channel_native_id(value _channel_layout) { + CAMLparam1(_channel_layout); + CAMLlocal1(ans); + + AVChannelLayout *channel_layout = AVChannelLayout_val(_channel_layout); + + if (channel_layout->order != AV_CHANNEL_ORDER_NATIVE) + CAMLreturn(Val_none); + + ans = caml_alloc_tuple(1); + Store_field(ans, 0, caml_copy_int64(channel_layout->u.mask)); + CAMLreturn(ans); +} + +CAMLprim value +ocaml_avutil_get_channel_layout_description(value _channel_layout) { CAMLparam1(_channel_layout); char buf[1024]; - uint64_t channel_layout = ChannelLayout_val(_channel_layout); + AVChannelLayout *channel_layout = AVChannelLayout_val(_channel_layout); + int err = av_channel_layout_describe(channel_layout, buf, sizeof(buf)); - av_get_channel_layout_string(buf, sizeof(buf), Int_val(channels), - channel_layout); + if (err < 0) + ocaml_avutil_raise_error(err); CAMLreturn(caml_copy_string(buf)); } @@ -341,46 +446,36 @@ CAMLprim value ocaml_avutil_get_channel_layout_description( CAMLprim value ocaml_avutil_get_channel_layout_nb_channels(value _channel_layout) { CAMLparam1(_channel_layout); - CAMLreturn(Val_int( - av_get_channel_layout_nb_channels(ChannelLayout_val(_channel_layout)))); + AVChannelLayout *channel_layout = AVChannelLayout_val(_channel_layout); + CAMLreturn(Val_int(channel_layout->nb_channels)); } CAMLprim value ocaml_avutil_get_default_channel_layout(value _nb_channels) { CAMLparam0(); + CAMLlocal1(ret); + AVChannelLayout channel_layout; - int64_t ret = av_get_default_channel_layout(Int_val(_nb_channels)); + av_channel_layout_default(&channel_layout, Int_val(_nb_channels)); - if (ret == 0) - caml_raise_not_found(); + ret = value_of_channel_layout(&channel_layout); + av_channel_layout_uninit(&channel_layout); - CAMLreturn(Val_ChannelLayout(ret)); + CAMLreturn(ret); } CAMLprim value ocaml_avutil_get_channel_layout(value _name) { CAMLparam1(_name); - char *name = strndup(String_val(_name), caml_string_length(_name)); - - if (!name) - caml_raise_out_of_memory(); - - int64_t ret = av_get_channel_layout(name); - - free(name); + CAMLlocal1(ret); + AVChannelLayout channel_layout; + int err = av_channel_layout_from_string(&channel_layout, String_val(_name)); - if (ret == 0) - caml_raise_not_found(); + if (err) + ocaml_avutil_raise_error(err); - CAMLreturn(Val_ChannelLayout(ret)); -} + ret = value_of_channel_layout(&channel_layout); + av_channel_layout_uninit(&channel_layout); -CAMLprim value ocaml_avutil_get_channel_layout_id(value _channel_layout) { - CAMLparam1(_channel_layout); - CAMLreturn(caml_copy_int64(ChannelLayout_val(_channel_layout))); -} - -CAMLprim value ocaml_avutil_channel_layout_of_id(value v) { - CAMLparam0(); - CAMLreturn(Val_ChannelLayout(Int64_val(v))); + CAMLreturn(ret); } /**** Sample format ****/ @@ -606,20 +701,6 @@ value value_of_frame(AVFrame *frame) { return ret; } -CAMLprim value ocaml_avutil_frame_pkt_duration(value _frame) { - CAMLparam1(_frame); - CAMLlocal1(ret); - AVFrame *frame = Frame_val(_frame); - - if (frame->pkt_duration == 0) - CAMLreturn(Val_none); - - ret = caml_alloc_tuple(1); - Store_field(ret, 0, caml_copy_int64(frame->pkt_duration)); - - CAMLreturn(ret); -} - CAMLprim value ocaml_avutil_frame_pts(value _frame) { CAMLparam1(_frame); CAMLlocal1(ret); @@ -806,7 +887,7 @@ CAMLprim value ocaml_avutil_audio_create_frame(value _sample_fmt, value _samples) { CAMLparam2(_sample_fmt, _channel_layout); enum AVSampleFormat sample_fmt = SampleFormat_val(_sample_fmt); - uint64_t channel_layout = ChannelLayout_val(_channel_layout); + AVChannelLayout *channel_layout = AVChannelLayout_val(_channel_layout); int sample_rate = Int_val(_samplerate); int nb_samples = Int_val(_samples); int ret; @@ -817,7 +898,13 @@ CAMLprim value ocaml_avutil_audio_create_frame(value _sample_fmt, caml_raise_out_of_memory(); frame->format = sample_fmt; - frame->channel_layout = channel_layout; + + ret = av_channel_layout_copy(&frame->ch_layout, channel_layout); + if (ret < 0) { + av_frame_free(&frame); + ocaml_avutil_raise_error(ret); + } + frame->sample_rate = sample_rate; frame->nb_samples = nb_samples; @@ -849,18 +936,14 @@ CAMLprim value ocaml_avutil_audio_frame_get_channels(value _frame) { CAMLparam1(_frame); AVFrame *frame = Frame_val(_frame); -#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(59, 19, 100) - CAMLreturn(Val_int(frame->channels)); -#else CAMLreturn(Val_int(frame->ch_layout.nb_channels)); -#endif } CAMLprim value ocaml_avutil_audio_frame_get_channel_layout(value _frame) { CAMLparam1(_frame); AVFrame *frame = Frame_val(_frame); - CAMLreturn(Val_ChannelLayout((frame->channel_layout))); + CAMLreturn(value_of_channel_layout(&frame->ch_layout)); } CAMLprim value ocaml_avutil_audio_frame_nb_samples(value _frame) { @@ -882,13 +965,12 @@ CAMLprim value ocaml_avutil_audio_frame_copy_samples(value _src, value _src_ofs, int len = Int_val(_len); int planar = av_sample_fmt_is_planar(dst->format); - int channels = dst->channels; + int channels = dst->ch_layout.nb_channels; int planes = planar ? channels : 1; int i; if (src->nb_samples < src_ofs + len || dst->nb_samples < dst_ofs + len || - dst->channels != src->channels || - dst->channel_layout != src->channel_layout) + av_channel_layout_compare(&dst->ch_layout, &src->ch_layout)) ocaml_avutil_raise_error(AVERROR(EINVAL)); av_assert2(!src->channel_layout || @@ -1103,6 +1185,7 @@ CAMLprim value ocaml_avutil_get_opt(value _type, value search_children, double d; AVRational r; int w_out, h_out; + AVChannelLayout channel_layout; enum AVPixelFormat pf; enum AVSampleFormat sf; AVDictionary *dict = NULL; @@ -1206,12 +1289,15 @@ CAMLprim value ocaml_avutil_get_opt(value _type, value search_children, break; case PVV_Channel_layout: - err = av_opt_get_channel_layout((void *)obj, (const char *)String_val(name), - search_flags, &i); + err = av_opt_get_chlayout((void *)obj, (const char *)String_val(name), + search_flags, &channel_layout); if (err < 0) ocaml_avutil_raise_error(err); - CAMLreturn(Val_ChannelLayout(i)); + ret = value_of_channel_layout(&channel_layout); + av_channel_layout_uninit(&channel_layout); + + CAMLreturn(ret); break; case PVV_Dict: @@ -1245,6 +1331,7 @@ CAMLprim value ocaml_avutil_av_opt_iter(value _cursor, value _class) { CAMLparam2(_cursor, _class); CAMLlocal4(_opt, _type, _tmp, _spec); int unimplement_option = 0; + AVChannelLayout channel_layout; const AVClass *class; const struct AVOption *option; @@ -1321,11 +1408,14 @@ CAMLprim value ocaml_avutil_av_opt_iter(value _cursor, value _class) { Store_field(_spec, 0, _tmp); } break; - case AV_OPT_TYPE_CHANNEL_LAYOUT: + case AV_OPT_TYPE_CHLAYOUT: _type = PVV_Channel_layout; - if (av_get_channel_name(option->default_val.i64)) { - Store_field(_tmp, 0, Val_ChannelLayout(option->default_val.i64)); + if (option->default_val.str && + av_channel_layout_from_string(&channel_layout, + option->default_val.str)) { + Store_field(_tmp, 0, value_of_channel_layout(&channel_layout)); Store_field(_spec, 0, _tmp); + av_channel_layout_uninit(&channel_layout); } break; case AV_OPT_TYPE_PIXEL_FMT: diff --git a/avutil/avutil_stubs.h b/avutil/avutil_stubs.h index 3baeaf9a..7d60c91f 100644 --- a/avutil/avutil_stubs.h +++ b/avutil/avutil_stubs.h @@ -1,31 +1,33 @@ -#ifndef _AVUTIL_STUBS_H_ +#ifndef _AVUTIL_STUBS_H_ #define _AVUTIL_STUBS_H_ #include #include -#include -#include +#include #include #include +#include #include -#include +#include #include "polymorphic_variant_values_stubs.h" #define Val_none Val_int(0) #ifndef Some_val -#define Some_val(v) Field(v,0) +#define Some_val(v) Field(v, 0) #endif #define ERROR_MSG_SIZE 256 #define EXN_ERROR "ffmpeg_exn_error" -#define Fail(...) { \ - snprintf(ocaml_av_exn_msg, ERROR_MSG_SIZE, __VA_ARGS__); \ - caml_callback(*caml_named_value("ffmpeg_exn_failure"), caml_copy_string(ocaml_av_exn_msg)); \ +#define Fail(...) \ + { \ + snprintf(ocaml_av_exn_msg, ERROR_MSG_SIZE, __VA_ARGS__); \ + caml_callback(*caml_named_value("ffmpeg_exn_failure"), \ + caml_copy_string(ocaml_av_exn_msg)); \ } void ocaml_avutil_raise_error(int err); @@ -34,35 +36,33 @@ extern char ocaml_av_exn_msg[]; #define List_init(list) (list) = Val_emptylist -#define List_add(list, cons, val) { \ - (cons) = caml_alloc(2, 0); \ - Store_field((cons), 0, (val)); \ - Store_field((cons), 1, (list)); \ - (list) = (cons); \ +#define List_add(list, cons, val) \ + { \ + (cons) = caml_alloc(2, 0); \ + Store_field((cons), 0, (val)); \ + Store_field((cons), 1, (list)); \ + (list) = (cons); \ } - /***** Global initialisation *****/ void ocaml_ffmpeg_register_thread(); /**** AVRational ****/ -#define rational_of_value(v) ((AVRational){Int_val(Field((v), 0)), Int_val(Field((v), 1))}) - -void value_of_rational(const AVRational * r, value * pv); +#define rational_of_value(v) \ + ((AVRational){Int_val(Field((v), 0)), Int_val(Field((v), 1))}) +void value_of_rational(const AVRational *r, value *pv); /**** Time format ****/ int64_t second_fractions_of_time_format(value time_format); - /**** Channel layout ****/ -uint64_t ChannelLayout_val(value v); - -value Val_ChannelLayout(uint64_t cl); +#define AVChannelLayout_val(v) (*(struct AVChannelLayout **)Data_custom_val(v)) +value value_of_channel_layout(const AVChannelLayout *); /**** Sample format ****/ @@ -75,7 +75,6 @@ enum AVSampleFormat AVSampleFormat_of_Sample_format(int i); value Val_SampleFormat(enum AVSampleFormat sf); enum caml_ba_kind bigarray_kind_of_AVSampleFormat(enum AVSampleFormat sf); - /**** Pixel format ****/ int PixelFormat_val(value); @@ -94,12 +93,12 @@ value Val_HwDeviceType(enum AVHWDeviceType t); /***** AVFrame *****/ -#define Frame_val(v) (*(struct AVFrame**)Data_custom_val(v)) +#define Frame_val(v) (*(struct AVFrame **)Data_custom_val(v)) value value_of_frame(AVFrame *frame); /***** AVSubtitle *****/ -#define Subtitle_val(v) (*(struct AVSubtitle**)Data_custom_val(v)) +#define Subtitle_val(v) (*(struct AVSubtitle **)Data_custom_val(v)) value value_of_subtitle(AVSubtitle *subtitle); @@ -107,9 +106,12 @@ int subtitle_header_default(AVCodecContext *avctx); /***** AVPixelFormat *****/ -#define AvPixFmtDescriptor_val(v) (*(const AVPixFmtDescriptor**)Data_abstract_val(v)) +#define AvPixFmtDescriptor_val(v) \ + (*(const AVPixFmtDescriptor **)Data_abstract_val(v)) -static inline value value_of_avpixfmtdescriptor(value ret, const AVPixFmtDescriptor *avpixfmtdescriptor) { +static inline value +value_of_avpixfmtdescriptor(value ret, + const AVPixFmtDescriptor *avpixfmtdescriptor) { ret = caml_alloc(1, Abstract_tag); AvPixFmtDescriptor_val(ret) = avpixfmtdescriptor; return ret; @@ -117,7 +119,7 @@ static inline value value_of_avpixfmtdescriptor(value ret, const AVPixFmtDescrip /****** AVOptions ******/ -#define AvClass_val(v) (*(const AVClass**)Data_abstract_val(v)) +#define AvClass_val(v) (*(const AVClass **)Data_abstract_val(v)) static inline value value_of_avclass(value ret, const AVClass *avclass) { ret = caml_alloc(1, Abstract_tag); @@ -125,15 +127,16 @@ static inline value value_of_avclass(value ret, const AVClass *avclass) { return ret; } -#define AvOptions_val(v) (*(const struct AVOption**)Data_abstract_val(v)) +#define AvOptions_val(v) (*(const struct AVOption **)Data_abstract_val(v)) -static inline value value_of_avoptions(value ret, const struct AVOption *avoptions) { +static inline value value_of_avoptions(value ret, + const struct AVOption *avoptions) { ret = caml_alloc(1, Abstract_tag); AvOptions_val(ret) = avoptions; return ret; } -#define AvObj_val(v) (*(void**)Data_abstract_val(v)) +#define AvObj_val(v) (*(void **)Data_abstract_val(v)) static inline value value_of_avobj(value ret, void *avobj) { ret = caml_alloc(1, Abstract_tag); @@ -141,4 +144,4 @@ static inline value value_of_avobj(value ret, void *avobj) { return ret; } -#endif // _AVUTIL_STUBS_H_ +#endif // _AVUTIL_STUBS_H_ diff --git a/examples/all_channel_layouts.ml b/examples/all_channel_layouts.ml new file mode 100644 index 00000000..2cc4f782 --- /dev/null +++ b/examples/all_channel_layouts.ml @@ -0,0 +1,8 @@ +open Avutil + +let () = + List.iter + (fun layout -> + Printf.printf "Channel layout: %s\n%!" + (Channel_layout.get_description layout)) + Channel_layout.standard_layouts diff --git a/examples/aresample.ml b/examples/aresample.ml index a2254be2..a8a45ed9 100644 --- a/examples/aresample.ml +++ b/examples/aresample.ml @@ -15,15 +15,14 @@ let () = 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 channels = Avcodec.Audio.get_nb_channels 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 ~channels ~channel_layout ~sample_format ~sample_rate - ~time_base ~codec:audio_codec dst ) + Av.new_audio_stream ~channel_layout ~sample_format ~sample_rate ~time_base + ~codec:audio_codec dst ) in let frame_size = @@ -40,9 +39,8 @@ let () = Avutil.Sample_format.get_id (Avcodec.Audio.get_sample_format audio_params) in - let channels = Avcodec.Audio.get_nb_channels audio_params in let channel_layout = - Avutil.Channel_layout.get_id + Avutil.Channel_layout.get_description (Avcodec.Audio.get_channel_layout audio_params) in let args = @@ -50,8 +48,7 @@ let () = `Pair ("time_base", `Rational time_base); `Pair ("sample_rate", `Int sample_rate); `Pair ("sample_fmt", `Int sample_format); - `Pair ("channels", `Int channels); - `Pair ("channel_layout", `Int64 channel_layout); + `Pair ("channel_layout", `String channel_layout); ] in { diff --git a/examples/audio_decoding.ml b/examples/audio_decoding.ml index 78e1e042..e6a1facb 100644 --- a/examples/audio_decoding.ml +++ b/examples/audio_decoding.ml @@ -33,7 +33,10 @@ let () = let options = [`Engine_soxr] in - let rsp = FrameToS32Bytes.from_codec ~options icodec `Stereo 44100 in + let rsp = + FrameToS32Bytes.from_codec ~options icodec Avutil.Channel_layout.stereo + 44100 + in let rec f () = match Av.read_input ~audio_frame:[istream] input with diff --git a/examples/audio_device.ml b/examples/audio_device.ml index 8887f3c2..dd6a2aa0 100644 --- a/examples/audio_device.ml +++ b/examples/audio_device.ml @@ -31,7 +31,6 @@ let () = let codec = Avcodec.Audio.find_encoder_by_name "flac" in let channel_layout = Avcodec.Audio.get_channel_layout params in - let channels = Avcodec.Audio.get_nb_channels 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 @@ -43,8 +42,8 @@ let () = with Avutil.Error _ -> Av.open_output Sys.argv.(2) in let dst_stream = - Av.new_audio_stream ~channels ~channel_layout ~sample_format ~sample_rate - ~time_base ~codec dst + Av.new_audio_stream ~channel_layout ~sample_format ~sample_rate ~time_base + ~codec dst in Avdevice.Dev_to_app.( diff --git a/examples/decode_audio.ml b/examples/decode_audio.ml index a563b92e..42b17fb2 100644 --- a/examples/decode_audio.ml +++ b/examples/decode_audio.ml @@ -34,7 +34,9 @@ let () = let out_file = Av.open_output Sys.argv.(3) in let codec = Avcodec.Audio.find_encoder_by_name Sys.argv.(4) in - let channel_layout = Avcodec.Audio.find_best_channel_layout codec `Stereo in + let channel_layout = + Avcodec.Audio.find_best_channel_layout codec Avutil.Channel_layout.stereo + in let sample_format = Avcodec.Audio.find_best_sample_format codec `Dbl in let sample_rate = Avcodec.Audio.find_best_sample_rate codec 44100 in let time_base = { Avutil.num = 1; den = sample_rate } in diff --git a/examples/decode_stream.ml b/examples/decode_stream.ml index 92909970..53a7a913 100644 --- a/examples/decode_stream.ml +++ b/examples/decode_stream.ml @@ -17,7 +17,9 @@ let () = let in_fd = Unix.openfile Sys.argv.(1) [Unix.O_RDONLY] 0 in let out_file = Av.open_output Sys.argv.(2) in let codec = Avcodec.Audio.find_encoder_by_name Sys.argv.(3) in - let channel_layout = Avcodec.Audio.find_best_channel_layout codec `Stereo in + let channel_layout = + Avcodec.Audio.find_best_channel_layout codec Avutil.Channel_layout.stereo + in let sample_format = Avcodec.Audio.find_best_sample_format codec `Dbl in let sample_rate = Avcodec.Audio.find_best_sample_rate codec 44100 in let time_base = { Avutil.num = 1; den = sample_rate } in diff --git a/examples/demuxing_decoding.ml b/examples/demuxing_decoding.ml index d9e4fb45..c5bce402 100644 --- a/examples/demuxing_decoding.ml +++ b/examples/demuxing_decoding.ml @@ -30,7 +30,9 @@ let () = let audio_index, audio_stream, audio_codec = Av.find_best_audio_stream src in - let a_ctx = AudioConverter.from_codec audio_codec `Stereo 44100 in + let a_ctx = + AudioConverter.from_codec audio_codec Avutil.Channel_layout.stereo 44100 + in let audio_output_file = open_out_bin audio_output_filename in let video_index, video_stream, _ = Av.find_best_video_stream src in diff --git a/examples/dune b/examples/dune index b7c295c2..84e5f661 100644 --- a/examples/dune +++ b/examples/dune @@ -113,6 +113,11 @@ (modules all_codecs) (libraries ffmpeg-avcodec)) +(executable + (name all_channel_layouts) + (modules all_channel_layouts) + (libraries ffmpeg-avutil)) + (executable (name all_bitstream_filters) (modules all_bitstream_filters) diff --git a/examples/encode_audio.ml b/examples/encode_audio.ml index 958d4e5d..f02cce81 100644 --- a/examples/encode_audio.ml +++ b/examples/encode_audio.ml @@ -19,7 +19,7 @@ let () = let out_sample_format = Audio.find_best_sample_format codec `Dbl in let time_base = { Avutil.num = 1; den = sample_rate } in let encoder = - Audio.create_encoder ~channel_layout:`Stereo ~channels:2 ~time_base + Audio.create_encoder ~channel_layout:Avutil.Channel_layout.stereo ~time_base ~sample_format:out_sample_format ~sample_rate codec in @@ -37,7 +37,8 @@ let () = let out_sample_format = Audio.find_best_sample_format codec `Dbl in let rsp = - Resampler.create `Mono sample_rate `Stereo ~out_sample_format sample_rate + Resampler.create Avutil.Channel_layout.mono sample_rate + Avutil.Channel_layout.stereo ~out_sample_format sample_rate in let c = 2. *. pi *. 440. /. float_of_int sample_rate in diff --git a/examples/encode_stream.ml b/examples/encode_stream.ml index d28892d9..49fc6a3a 100644 --- a/examples/encode_stream.ml +++ b/examples/encode_stream.ml @@ -20,8 +20,8 @@ let () = let out_sample_rate = if Sys.argv.(2) = "flac" then 22050 else 44100 in let rsp = - Resampler.create `Mono sample_rate `Stereo ~out_sample_format - out_sample_rate + Resampler.create Avutil.Channel_layout.mono sample_rate + Avutil.Channel_layout.stereo ~out_sample_format out_sample_rate in let c = 2. *. pi *. 440. /. float_of_int sample_rate in @@ -50,8 +50,9 @@ let () = Hashtbl.add opts "foo" (`String "bla"); let stream = - Av.new_audio_stream ~channels:2 ~time_base ~sample_format:out_sample_format - ~sample_rate:out_sample_rate ~codec ~opts output + Av.new_audio_stream ~channel_layout:Avutil.Channel_layout.stereo ~time_base + ~sample_format:out_sample_format ~sample_rate:out_sample_rate ~codec ~opts + output in let out_frame_size = @@ -63,7 +64,7 @@ let () = let in_params = { Avfilter.Utils.sample_rate = out_sample_rate; - channel_layout = `Stereo; + channel_layout = Avutil.Channel_layout.stereo; sample_format = out_sample_format; } in diff --git a/examples/encoding.ml b/examples/encoding.ml index c4fddee1..9abe3c1a 100644 --- a/examples/encoding.ml +++ b/examples/encoding.ml @@ -62,15 +62,15 @@ let () = let audio_pts = ref 0L in let sample_format = Avcodec.Audio.find_best_sample_format codec `Dbl in let oas = - Av.new_audio_stream ~channel_layout:`Stereo ~time_base ~sample_rate - ~sample_format ~codec dst + Av.new_audio_stream ~channel_layout:Avutil.Channel_layout.stereo ~time_base + ~sample_rate ~sample_format ~codec dst in let params = Av.get_codec_params oas in let audio_frame_size = Av.get_frame_size oas in Av.set_metadata oas [("Media", "Audio")]; - let rsp = Resampler.to_codec `Mono sample_rate params in + let rsp = Resampler.to_codec Avutil.Channel_layout.mono sample_rate params in let c = 2. *. pi *. 440. /. float_of_int sample_rate in diff --git a/examples/fps.ml b/examples/fps.ml index 761b7c26..0ad5a1d1 100644 --- a/examples/fps.ml +++ b/examples/fps.ml @@ -16,14 +16,13 @@ let () = 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 channels = Avcodec.Audio.get_nb_channels 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 ~channels ~channel_layout ~sample_format - ~sample_rate ~time_base ~codec:audio_codec dst ) ) + 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 diff --git a/examples/fps_samplerate.ml b/examples/fps_samplerate.ml index 3b308f6f..2083db4d 100644 --- a/examples/fps_samplerate.ml +++ b/examples/fps_samplerate.ml @@ -16,14 +16,13 @@ let () = 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 channels = Avcodec.Audio.get_nb_channels 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 ~channels ~channel_layout ~sample_format - ~sample_rate ~time_base ~codec:audio_codec dst ) ) + 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 diff --git a/swresample/swresample_stubs.c b/swresample/swresample_stubs.c index b70f428a..a08bd7b7 100644 --- a/swresample/swresample_stubs.c +++ b/swresample/swresample_stubs.c @@ -49,7 +49,7 @@ struct swr_t { SwrContext *context; struct audio_t in; struct audio_t out; - int64_t out_channel_layout; + AVChannelLayout out_ch_layout; int out_sample_rate; int out_vect_nb_samples; @@ -246,7 +246,13 @@ static void alloc_out_frame(swr_t *swr, int nb_samples, value *out_vect) { } frame->nb_samples = nb_samples; - frame->channel_layout = swr->out_channel_layout; + + ret = av_channel_layout_copy(&frame->ch_layout, &swr->out_ch_layout); + if (ret < 0) { + av_frame_free(&frame); + ocaml_avutil_raise_error(ret); + } + frame->format = swr->out.sample_fmt; frame->sample_rate = swr->out_sample_rate; @@ -539,19 +545,22 @@ static struct custom_operations swr_ops = { #define NB_OPTIONS_TYPES 3 -static SwrContext *swresample_set_context( - swr_t *swr, int64_t in_channel_layout, enum AVSampleFormat in_sample_fmt, - int in_sample_rate, int64_t out_channel_layout, - enum AVSampleFormat out_sample_fmt, int out_sample_rate, value options[]) { +static SwrContext * +swresample_set_context(swr_t *swr, AVChannelLayout *in_channel_layout, + enum AVSampleFormat in_sample_fmt, int in_sample_rate, + AVChannelLayout *out_channel_layout, + enum AVSampleFormat out_sample_fmt, int out_sample_rate, + value options[]) { if (!swr->context && !(swr->context = swr_alloc())) caml_raise_out_of_memory(); SwrContext *ctx = swr->context; + int ret; if (in_channel_layout) { - av_opt_set_channel_layout(ctx, "in_channel_layout", in_channel_layout, 0); + av_opt_set_chlayout(ctx, "in_chlayout", in_channel_layout, 0); - swr->in.nb_channels = av_get_channel_layout_nb_channels(in_channel_layout); + swr->in.nb_channels = in_channel_layout->nb_channels; } if (in_sample_fmt != AV_SAMPLE_FMT_NONE) { @@ -565,10 +574,14 @@ static SwrContext *swresample_set_context( } if (out_channel_layout) { - av_opt_set_channel_layout(ctx, "out_channel_layout", out_channel_layout, 0); - swr->out_channel_layout = out_channel_layout; - swr->out.nb_channels = - av_get_channel_layout_nb_channels(out_channel_layout); + av_opt_set_chlayout(ctx, "out_chlayout", out_channel_layout, 0); + + ret = av_channel_layout_copy(&swr->out_ch_layout, out_channel_layout); + + if (ret < 0) + ocaml_avutil_raise_error(ret); + + swr->out.nb_channels = out_channel_layout->nb_channels; } if (out_sample_fmt != AV_SAMPLE_FMT_NONE) { @@ -581,7 +594,7 @@ static SwrContext *swresample_set_context( swr->out_sample_rate = out_sample_rate; } - int i, ret = 0; + int i; for (i = 0; options[i]; i++) { int64_t val = DitherType_val_no_raise(options[i]); @@ -618,9 +631,11 @@ static SwrContext *swresample_set_context( return ctx; } -swr_t *swresample_create(vector_kind in_vector_kind, int64_t in_channel_layout, +swr_t *swresample_create(vector_kind in_vector_kind, + AVChannelLayout *in_channel_layout, enum AVSampleFormat in_sample_fmt, int in_sample_rate, - vector_kind out_vect_kind, int64_t out_channel_layout, + vector_kind out_vect_kind, + AVChannelLayout *out_channel_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate, value options[]) { swr_t *swr = (swr_t *)calloc(1, sizeof(swr_t)); @@ -707,11 +722,12 @@ CAMLprim value ocaml_swresample_create( CAMLlocal1(ans); vector_kind in_vector_kind = Int_val(_in_vector_kind); - int64_t in_channel_layout = ChannelLayout_val(_in_channel_layout); + AVChannelLayout *in_channel_layout = AVChannelLayout_val(_in_channel_layout); enum AVSampleFormat in_sample_fmt = SampleFormat_val(_in_sample_fmt); int in_sample_rate = Int_val(_in_sample_rate); vector_kind out_vect_kind = Int_val(_out_vect_kind); - int64_t out_channel_layout = ChannelLayout_val(_out_channel_layout); + AVChannelLayout *out_channel_layout = + AVChannelLayout_val(_out_channel_layout); enum AVSampleFormat out_sample_fmt = SampleFormat_val(_out_sample_fmt); int out_sample_rate = Int_val(_out_sample_rate); value options[NB_OPTIONS_TYPES + 1]; diff --git a/swresample/swresample_stubs.h b/swresample/swresample_stubs.h index e4abdb15..d0cc0b51 100644 --- a/swresample/swresample_stubs.h +++ b/swresample/swresample_stubs.h @@ -2,6 +2,6 @@ #include "avutil_stubs.h" -typedef enum _vector_kind {Str, P_Str, Fa, P_Fa, Ba, P_Ba, Frm} vector_kind; +typedef enum _vector_kind { Str, P_Str, Fa, P_Fa, Ba, P_Ba, Frm } vector_kind; typedef struct swr_t swr_t; diff --git a/test/dune b/test/dune index b04ebe32..46f2718f 100644 --- a/test/dune +++ b/test/dune @@ -7,6 +7,7 @@ (package ffmpeg) (deps (:all_codecs ../examples/all_codecs.exe) + (:all_channel_layouts ../examples/all_channel_layouts.exe) (:all_bitstream_filters ../examples/all_bitstream_filters.exe) (:hw_encode ../examples/hw_encode.exe) (:list_filters ../examples/list_filters.exe) @@ -31,6 +32,7 @@ (progn (run %{list_filters}) (run %{all_codecs}) + (run %{all_channel_layouts}) (run %{all_bitstream_filters}) (run %{hw_encode} nvenc.mp4 h264_nvenc device) (run %{hw_encode} nvenc.mp4 h264_nvenc frame) diff --git a/test/resample.ml b/test/resample.ml index 0aba4083..2c0d6acf 100644 --- a/test/resample.ml +++ b/test/resample.ml @@ -31,21 +31,58 @@ let frate = float_of_int rate let test () = let dst1 = open_out_bin "test_swresample_out1.raw" in - let r = R.create `Mono rate `Stereo 44100 in + let r = + R.create Avutil.Channel_layout.mono rate Avutil.Channel_layout.stereo 44100 + in let dst2 = open_out_bin "test_swresample_out2.raw" in - let r0 = R0.create `Mono rate `_5point1 96000 in - let r1 = R1.create `_5point1 ~in_sample_format:`S16 96000 `Stereo 16000 in - let r2 = R2.create `Stereo 16000 `Surround 44100 in - let r3 = R3.create `Surround 44100 `Stereo 48000 in - let r4 = R4.create `Stereo 48000 `Stereo_downmix 31000 in - let r5 = R5.create `Stereo_downmix 31000 `Stereo 73347 in - let r6 = R6.create `Stereo 73347 `Stereo 44100 in - let r7 = R7.create `Stereo 44100 `Stereo 48000 in - let r8 = R8.create `Stereo 48000 `Stereo 96000 in - let r9 = R9.create `Stereo 96000 `Stereo 44100 in - let r10 = R10.create `Stereo 44100 `Mono 44100 in + let r0 = + R0.create Avutil.Channel_layout.mono rate + Avutil.Channel_layout.five_point_one 96000 + in + let r1 = + R1.create Avutil.Channel_layout.five_point_one ~in_sample_format:`S16 96000 + Avutil.Channel_layout.stereo 16000 + in + let r2 = + R2.create Avutil.Channel_layout.stereo 16000 Avutil.Channel_layout.stereo + 44100 + in + let r3 = + R3.create Avutil.Channel_layout.stereo 44100 Avutil.Channel_layout.stereo + 48000 + in + let r4 = + R4.create Avutil.Channel_layout.stereo 48000 + Avutil.Channel_layout.(find "downmix") + 31000 + in + let r5 = + R5.create + Avutil.Channel_layout.(find "downmix") + 31000 Avutil.Channel_layout.stereo 73347 + in + let r6 = + R6.create Avutil.Channel_layout.stereo 73347 Avutil.Channel_layout.stereo + 44100 + in + let r7 = + R7.create Avutil.Channel_layout.stereo 44100 Avutil.Channel_layout.stereo + 48000 + in + let r8 = + R8.create Avutil.Channel_layout.stereo 48000 Avutil.Channel_layout.stereo + 96000 + in + let r9 = + R9.create Avutil.Channel_layout.stereo 96000 Avutil.Channel_layout.stereo + 44100 + in + let r10 = + R10.create Avutil.Channel_layout.stereo 44100 Avutil.Channel_layout.mono + 44100 + in for note = 0 to 95 do let freq = 22.5 *. (2. ** (foi note /. 12.)) in @@ -84,7 +121,9 @@ let test () = try let src = Av.open_input url in let idx, is, ic = src |> Av.find_best_audio_stream in - let rsp = Converter.from_codec ic `Stereo 44100 in + let rsp = + Converter.from_codec ic Avutil.Channel_layout.stereo 44100 + in let p = try String.rindex url '/' + 1 with Not_found -> 0 in let audio_output_filename =