Skip to content

Commit

Permalink
Refactor output feormat handling
Browse files Browse the repository at this point in the history
  • Loading branch information
dmorn committed Nov 2, 2023
1 parent 07f4744 commit a0b01b3
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 39 deletions.
44 changes: 21 additions & 23 deletions c_src/decoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,19 @@ int is_planar(enum AVSampleFormat fmt) {
}
}

int alloc_resampler(Decoder *ctx, FormatOpts output_opts) {
AVChannelLayout *output_layout;
int alloc_resampler(Decoder *ctx) {
AVCodecContext *codec_ctx;
int errn;

codec_ctx = ctx->codec_ctx;

output_layout = malloc(sizeof(AVChannelLayout));
av_channel_layout_copy(output_layout, &ctx->codec_ctx->ch_layout);
output_layout->nb_channels = output_opts.channels;

ctx->output_ch_layout = output_layout;

output_opts.sample_format =
av_get_packed_sample_fmt(output_opts.sample_format);

if ((errn = swr_alloc_set_opts2(
&(ctx->resampler_ctx), output_layout, output_opts.sample_format,
output_opts.sample_rate, &codec_ctx->ch_layout,
codec_ctx->sample_fmt, codec_ctx->sample_rate, 0, NULL)) != 0)
if ((errn = swr_alloc_set_opts2(&(ctx->resampler_ctx), ctx->output.ch_layout,
ctx->output.sample_format,
ctx->output.sample_rate,
&codec_ctx->ch_layout, codec_ctx->sample_fmt,
codec_ctx->sample_rate, 0, NULL)) != 0)
return errn;

ctx->output_fmt = malloc(sizeof(FormatOpts));
*ctx->output_fmt = output_opts;

return swr_init(ctx->resampler_ctx);
}

Expand All @@ -65,7 +53,16 @@ int decoder_alloc(Decoder **ctx, DecoderOpts opts) {

ictx = (Decoder *)malloc(sizeof(Decoder));
ictx->codec_ctx = codec_ctx;
if ((errn = alloc_resampler(ictx, opts.output_opts)) < 0)
ictx->output.ch_layout = malloc(sizeof(AVChannelLayout));
av_channel_layout_copy(ictx->output.ch_layout, &codec_ctx->ch_layout);
ictx->output.ch_layout->nb_channels = opts.output.nb_channels;
ictx->output.sample_rate = opts.output.sample_rate;
// Planar formats are not supported as they require a different procedure to
// lay down the plain bits contained in their frames.
ictx->output.sample_format =
av_get_packed_sample_fmt(opts.output.sample_format);

if ((errn = alloc_resampler(ictx)) < 0)
return errn;

*ctx = ictx;
Expand All @@ -88,9 +85,9 @@ int decoder_read_frame(Decoder *ctx, AVFrame *frame) {
AVFrame *resampled_frame;
resampled_frame = av_frame_alloc();
resampled_frame->nb_samples = frame->nb_samples;
resampled_frame->ch_layout = *ctx->output_ch_layout;
resampled_frame->sample_rate = frame->sample_rate;
resampled_frame->format = ctx->output_fmt->sample_format;
resampled_frame->ch_layout = *ctx->output.ch_layout;
resampled_frame->sample_rate = ctx->output.sample_rate;
resampled_frame->format = ctx->output.sample_format;

if ((errn = av_frame_get_buffer(resampled_frame, 0)) != 0)
return errn;
Expand All @@ -110,9 +107,10 @@ int decoder_read_frame(Decoder *ctx, AVFrame *frame) {

int decoder_free(Decoder **ctx) {
avcodec_free_context(&(*ctx)->codec_ctx);

if ((*ctx)->resampler_ctx) {
swr_free(&(*ctx)->resampler_ctx);
free((*ctx)->output_fmt);
av_channel_layout_uninit((*ctx)->output.ch_layout);
}

free(*ctx);
Expand Down
20 changes: 11 additions & 9 deletions c_src/decoder.h
Original file line number Diff line number Diff line change
@@ -1,28 +1,30 @@
#include "libavcodec/codec_par.h"
#include "libavutil/channel_layout.h"
#include "libavutil/samplefmt.h"
#include "libswresample/swresample.h"
#include <libavcodec/avcodec.h>

typedef struct {
int sample_rate;
int channels;
enum AVSampleFormat sample_format;
} FormatOpts;

typedef struct {
AVCodecContext *codec_ctx;
SwrContext *resampler_ctx;

FormatOpts *output_fmt;
AVChannelLayout *output_ch_layout;
struct {
int sample_rate;
enum AVSampleFormat sample_format;
AVChannelLayout *ch_layout;
} output;
} Decoder;

typedef struct {
int codec_id;
AVCodecParameters *params;
AVRational timebase;

FormatOpts output_opts;
struct {
int sample_rate;
int nb_channels;
enum AVSampleFormat sample_format;
} output;
} DecoderOpts;

int decoder_alloc(Decoder **ctx, DecoderOpts opts);
Expand Down
14 changes: 7 additions & 7 deletions c_src/libav.c
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ ERL_NIF_TERM enif_decoder_alloc(ErlNifEnv *env, int argc,
Decoder *ctx;
DecoderOpts *opts;
int buf_size = 256;
int nb_channels;
char *buf;
int errn;

Expand All @@ -252,15 +253,15 @@ ERL_NIF_TERM enif_decoder_alloc(ErlNifEnv *env, int argc,

// Output opts
enif_get_map_value(env, argv[1], enif_make_atom(env, "sample_rate"), &tmp);
enif_get_int(env, tmp, &opts->output_opts.sample_rate);
enif_get_int(env, tmp, &opts->output.sample_rate);

enif_get_map_value(env, argv[1], enif_make_atom(env, "channels"), &tmp);
enif_get_int(env, tmp, &opts->output_opts.channels);
enif_get_int(env, tmp, &opts->output.nb_channels);

enif_get_map_value(env, argv[1], enif_make_atom(env, "sample_format"), &tmp);
buf = malloc(buf_size);
enif_get_string(env, tmp, buf, buf_size, ERL_NIF_LATIN1);
opts->output_opts.sample_format = av_get_sample_fmt(buf);
opts->output.sample_format = av_get_sample_fmt(buf);

if ((errn = decoder_alloc(&ctx, *opts)) < 0)
return enif_make_av_error(env, errn);
Expand Down Expand Up @@ -298,14 +299,13 @@ ERL_NIF_TERM enif_decoder_stream_format(ErlNifEnv *env, int argc,
if (ctx->codec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {

enif_make_map_put(env, map, enif_make_atom(env, "channels"),
enif_make_int(env, ctx->codec_ctx->ch_layout.nb_channels),
enif_make_int(env, ctx->output.ch_layout->nb_channels),
&map);
enif_make_map_put(env, map, enif_make_atom(env, "sample_rate"),
enif_make_int(env, ctx->codec_ctx->sample_rate), &map);
enif_make_int(env, ctx->output.sample_rate), &map);
enif_make_map_put(
env, map, enif_make_atom(env, "sample_format"),
enif_make_string(env,
av_get_sample_fmt_name(ctx->output_fmt->sample_format),
enif_make_string(env, av_get_sample_fmt_name(ctx->output.sample_format),
ERL_NIF_UTF8),
&map);
}
Expand Down
22 changes: 22 additions & 0 deletions test/avx/decoder_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,28 @@ defmodule AVx.DecoderTest do
end
end

test "decodes into a different format" do
{:ok, demuxer} = Demuxer.new_from_file(List.first(@inputs))
[aac] = Demuxer.read_streams(demuxer)
packets = Demuxer.consume_packets(demuxer, [aac.stream_index])

output_format = %{
sample_rate: 128_000,
channels: 1,
sample_format: "s16"
}

{:ok, decoder} = Decoder.new(aac, output_format)
assert ^output_format = Decoder.stream_format(decoder)

frame_count =
packets
|> Decoder.decode_frames(decoder)
|> Enum.count()

assert frame_count == 564
end

defp assert_frames(packets, decoder, expected_frames, ext) do
count =
packets
Expand Down

0 comments on commit a0b01b3

Please sign in to comment.