Skip to content

Commit

Permalink
Add non-interleaved API
Browse files Browse the repository at this point in the history
  • Loading branch information
toots committed Jan 16, 2024
1 parent 5970c7e commit 8f7eb0b
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 30 deletions.
1 change: 1 addition & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
1.1.10 (unreleased)
======
* Fixed codec attribute for AAC.
* Added non-interleaved API for Av.

1.1.9 (202310-27)
=====
Expand Down
12 changes: 8 additions & 4 deletions av/av.ml
Original file line number Diff line number Diff line change
Expand Up @@ -254,28 +254,32 @@ external open_output :
?interrupt:(unit -> bool) ->
?format:(output, _) format ->
string ->
bool ->
(string * string) array ->
output container * string array = "ocaml_av_open_output"

let open_output ?interrupt ?format ?opts fname =
let open_output ?interrupt ?format ?(interleaved = true) ?opts fname =
let opts = opts_default opts in
let ret, unused = open_output ?interrupt ?format fname (mk_opts_array opts) in
let ret, unused =
open_output ?interrupt ?format fname interleaved (mk_opts_array opts)
in
filter_opts unused opts;
Gc.finalise ocaml_av_cleanup_av ret;
ret

external ocaml_av_open_output_stream :
(output, _) format ->
avio ->
bool ->
(string * string) array ->
output container * string array = "ocaml_av_open_output_stream"

let open_output_stream ?opts ?seek write format =
let open_output_stream ?opts ?(interleaved = true) ?seek write format =
let opts = opts_default opts in
let avio = ocaml_av_create_io 4096 None (Some write) (_seek_of_seek seek) in
let cleanup () = caml_av_input_io_finalise avio in
let output, unused =
ocaml_av_open_output_stream format avio (mk_opts_array opts)
ocaml_av_open_output_stream format avio interleaved (mk_opts_array opts)
in
filter_opts unused opts;
Gc.finalise ocaml_av_cleanup_av output;
Expand Down
13 changes: 10 additions & 3 deletions av/av.mli
Original file line number Diff line number Diff line change
Expand Up @@ -200,14 +200,16 @@ val seek :

(** {5 Output} *)

(** [Av.open_output ?interrupt ?format ?opts filename] open the output file named
(** [Av.open_output ?interrupt ?format ?interleaved ?opts filename] open the output file named
[filename]. [interrupt] is used to interrupt blocking functions, [format] may
contain an optional format, [opts] may contain any option settable on the
contain an optional format, [interleaved] indicates if FFmpeg's interleaved
API should be used, [opts] may contain any option settable on the
stream's internal AVFormat. After returning, if [opts] was passed, unused
options are left in the hash table. Raise Error if the opening failed. *)
val open_output :
?interrupt:(unit -> bool) ->
?format:(output, _) format ->
?interleaved:bool ->
?opts:opts ->
string ->
output container
Expand All @@ -218,7 +220,12 @@ val open_output :
Raise Error if the opening failed. Exceptions from the callback are caught
and result in a native [Avutil.Error `Unknown] error. *)
val open_output_stream :
?opts:opts -> ?seek:seek -> write -> (output, _) format -> output container
?opts:opts ->
?interleaved:bool ->
?seek:seek ->
write ->
(output, _) format ->
output container

(** Returns [true] if the output has already started, in which case no new *
stream or metadata can be added. *)
Expand Down
35 changes: 24 additions & 11 deletions av/av_stubs.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ typedef struct av_t {

// output
int header_written;
int (*write_frame)(AVFormatContext *, AVPacket *);
int custom_io;
} av_t;

Expand Down Expand Up @@ -1372,7 +1373,8 @@ ocaml_av_output_format_get_subtitle_codec_id(value _output_format) {

static av_t *open_output(avioformat_const AVOutputFormat *format,
char *file_name, AVIOContext *avio_context,
value _interrupt, AVDictionary **options) {
value _interrupt, int interleaved,
AVDictionary **options) {
int ret;
AVIOInterruptCB interrupt_cb = {ocaml_av_interrupt_callback, NULL};
AVIOInterruptCB *interrupt_cb_ptr = NULL;
Expand All @@ -1387,6 +1389,12 @@ static av_t *open_output(avioformat_const AVOutputFormat *format,

av->closed = 0;

if (interleaved) {
av->write_frame = &av_interleaved_write_frame;
} else {
av->write_frame = &av_write_frame;
}

if (_interrupt != Val_none) {
av->interrupt_cb = Some_val(_interrupt);
caml_register_generational_global_root(&av->interrupt_cb);
Expand Down Expand Up @@ -1486,7 +1494,8 @@ static av_t *open_output(avioformat_const AVOutputFormat *format,
}

CAMLprim value ocaml_av_open_output(value _interrupt, value _format,
value _filename, value _opts) {
value _filename, value _interleaved,
value _opts) {
CAMLparam3(_interrupt, _filename, _opts);
CAMLlocal3(ans, ret, unused);
char *filename =
Expand All @@ -1512,7 +1521,8 @@ CAMLprim value ocaml_av_open_output(value _interrupt, value _format,
format = OutputFormat_val(Some_val(_format));

// open output file
av_t *av = open_output(format, filename, NULL, _interrupt, &options);
av_t *av = open_output(format, filename, NULL, _interrupt,
Bool_val(_interleaved), &options);

// Return unused keys
count = av_dict_count(options);
Expand All @@ -1537,7 +1547,8 @@ CAMLprim value ocaml_av_open_output(value _interrupt, value _format,
CAMLreturn(ret);
}

CAMLprim value ocaml_av_open_output_format(value _format, value _opts) {
CAMLprim value ocaml_av_open_output_format(value _format, value _interleaved,
value _opts) {
CAMLparam2(_format, _opts);
CAMLlocal3(ans, ret, unused);
AVDictionary *options = NULL;
Expand All @@ -1559,7 +1570,8 @@ CAMLprim value ocaml_av_open_output_format(value _format, value _opts) {
avioformat_const AVOutputFormat *format = OutputFormat_val(_format);

// open output format
av_t *av = open_output(format, NULL, NULL, Val_none, &options);
av_t *av = open_output(format, NULL, NULL, Val_none, Bool_val(_interleaved),
&options);

// Return unused keys
count = av_dict_count(options);
Expand All @@ -1585,7 +1597,7 @@ CAMLprim value ocaml_av_open_output_format(value _format, value _opts) {
}

CAMLprim value ocaml_av_open_output_stream(value _format, value _avio,
value _opts) {
value _interleaved, value _opts) {
CAMLparam3(_format, _avio, _opts);
CAMLlocal3(ans, ret, unused);
avioformat_const AVOutputFormat *format = OutputFormat_val(_format);
Expand All @@ -1607,7 +1619,8 @@ CAMLprim value ocaml_av_open_output_stream(value _format, value _avio,
}

// open output format
av_t *av = open_output(format, NULL, avio->avio_context, Val_none, &options);
av_t *av = open_output(format, NULL, avio->avio_context, Val_none,
Bool_val(_interleaved), &options);

// Return unused keys
count = av_dict_count(options);
Expand Down Expand Up @@ -2016,7 +2029,7 @@ CAMLprim value ocaml_av_write_stream_packet(value _stream, value _time_base,
av_packet_rescale_ts(packet, rational_of_value(_time_base),
avstream->time_base);

ret = av_interleaved_write_frame(av->format_context, packet);
ret = av->write_frame(av->format_context, packet);
av->streams[stream_index]->was_keyframe = packet->flags & AV_PKT_FLAG_KEY;

caml_acquire_runtime_system();
Expand Down Expand Up @@ -2135,7 +2148,7 @@ static void write_frame(av_t *av, int stream_index, AVCodecContext *enc_ctx,
packet->pos = -1;
av_packet_rescale_ts(packet, enc_ctx->time_base, avstream->time_base);

ret = av_interleaved_write_frame(av->format_context, packet);
ret = av->write_frame(av->format_context, packet);
}

if (hw_frame)
Expand Down Expand Up @@ -2234,7 +2247,7 @@ static void write_subtitle_frame(av_t *av, int stream_index,
packet->pos = -1;

caml_release_runtime_system();
err = av_interleaved_write_frame(av->format_context, packet);
err = av->write_frame(av->format_context, packet);
caml_acquire_runtime_system();

av_packet_free(&packet);
Expand Down Expand Up @@ -2273,7 +2286,7 @@ CAMLprim value ocaml_av_flush(value _av) {
CAMLreturn(Val_unit);

caml_release_runtime_system();
ret = av_interleaved_write_frame(av->format_context, NULL);
ret = av->write_frame(av->format_context, NULL);
if (ret >= 0 && av->format_context->pb)
avio_flush(av->format_context->pb);
caml_acquire_runtime_system();
Expand Down
21 changes: 13 additions & 8 deletions avdevice/avdevice.ml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ let open_default_video_input () =

external open_output_format :
(output, _) format ->
bool ->
(string * string) array ->
output container * string array = "ocaml_av_open_output_format"

Expand All @@ -85,30 +86,34 @@ let filter_opts unused = function
(fun k v -> if Array.mem k unused then Some v else None)
opts

let open_audio_output ?opts name =
let open_audio_output ?(interleaved = true) ?opts name =
let ret, unused =
open_output_format (find_audio_output name) (mk_opts opts)
open_output_format (find_audio_output name) interleaved (mk_opts opts)
in
filter_opts unused opts;
ret

let open_default_audio_output ?opts () =
let open_default_audio_output ?(interleaved = true) ?opts () =
let ret, unused =
open_output_format (get_default_audio_output_format ()) (mk_opts opts)
open_output_format
(get_default_audio_output_format ())
interleaved (mk_opts opts)
in
filter_opts unused opts;
ret

let open_video_output ?opts name =
let open_video_output ?(interleaved = true) ?opts name =
let ret, unused =
open_output_format (find_video_output name) (mk_opts opts)
open_output_format (find_video_output name) interleaved (mk_opts opts)
in
filter_opts unused opts;
ret

let open_default_video_output ?opts () =
let open_default_video_output ?(interleaved = true) ?opts () =
let ret, unused =
open_output_format (get_default_video_output_format ()) (mk_opts opts)
open_output_format
(get_default_video_output_format ())
interleaved (mk_opts opts)
in
filter_opts unused opts;
ret
Expand Down
12 changes: 8 additions & 4 deletions avdevice/avdevice.mli
Original file line number Diff line number Diff line change
Expand Up @@ -50,19 +50,23 @@ val open_default_video_input : unit -> input container

(** Open the audio output device from its name. Raise Error if the device is not
found. *)
val open_audio_output : ?opts:opts -> string -> output container
val open_audio_output :
?interleaved:bool -> ?opts:opts -> string -> output container

(** Open the default audio output device from its name. Raise Error if the
device is not found. *)
val open_default_audio_output : ?opts:opts -> unit -> output container
val open_default_audio_output :
?interleaved:bool -> ?opts:opts -> unit -> output container

(** Open the video output device from its name. Raise Error if the device is not
found. *)
val open_video_output : ?opts:opts -> string -> output container
val open_video_output :
?interleaved:bool -> ?opts:opts -> string -> output container

(** Open the default video output device from its name. Raise Error if the
device is not found. *)
val open_default_video_output : ?opts:opts -> unit -> output container
val open_default_video_output :
?interleaved:bool -> ?opts:opts -> unit -> output container

(** Application to device communication *)
module App_to_dev : sig
Expand Down

0 comments on commit 8f7eb0b

Please sign in to comment.