[FFmpeg-devel] [PATCH 229/281] libopus: convert to new channel layout API
James Almer
jamrial at gmail.com
Thu Jan 13 04:05:08 EET 2022
From: Anton Khirnov <anton at khirnov.net>
Signed-off-by: James Almer <jamrial at gmail.com>
---
libavcodec/libopusdec.c | 39 +++++++++++++-----------
libavcodec/libopusenc.c | 65 ++++++++++++++++++++++------------------
libavcodec/vorbis.h | 3 ++
libavcodec/vorbis_data.c | 18 +++++++++++
4 files changed, 79 insertions(+), 46 deletions(-)
diff --git a/libavcodec/libopusdec.c b/libavcodec/libopusdec.c
index 86ef715205..abffd5f463 100644
--- a/libavcodec/libopusdec.c
+++ b/libavcodec/libopusdec.c
@@ -50,55 +50,60 @@ struct libopus_context {
static av_cold int libopus_decode_init(AVCodecContext *avc)
{
struct libopus_context *opus = avc->priv_data;
- int ret, channel_map = 0, gain_db = 0, nb_streams, nb_coupled;
+ int ret, channel_map = 0, gain_db = 0, nb_streams, nb_coupled, channels;
uint8_t mapping_arr[8] = { 0, 1 }, *mapping;
- avc->channels = avc->extradata_size >= 10 ? avc->extradata[9] : (avc->channels == 1) ? 1 : 2;
- if (avc->channels <= 0) {
+ channels = avc->extradata_size >= 10 ? avc->extradata[9] : (channels == 1) ? 1 : 2;
+ if (channels <= 0) {
av_log(avc, AV_LOG_WARNING,
- "Invalid number of channels %d, defaulting to stereo\n", avc->channels);
- avc->channels = 2;
+ "Invalid number of channels %d, defaulting to stereo\n", channels);
+ channels = 2;
}
avc->sample_rate = 48000;
avc->sample_fmt = avc->request_sample_fmt == AV_SAMPLE_FMT_FLT ?
AV_SAMPLE_FMT_FLT : AV_SAMPLE_FMT_S16;
- avc->channel_layout = avc->channels > 8 ? 0 :
- ff_vorbis_channel_layouts[avc->channels - 1];
+ av_channel_layout_uninit(&avc->ch_layout);
+ if (channels > 8) {
+ avc->ch_layout.order = AV_CHANNEL_ORDER_UNSPEC;
+ avc->ch_layout.nb_channels = channels;
+ } else {
+ av_channel_layout_copy(&avc->ch_layout, &ff_vorbis_ch_layouts[channels - 1]);
+ }
if (avc->extradata_size >= OPUS_HEAD_SIZE) {
opus->pre_skip = AV_RL16(avc->extradata + 10);
gain_db = sign_extend(AV_RL16(avc->extradata + 16), 16);
channel_map = AV_RL8 (avc->extradata + 18);
}
- if (avc->extradata_size >= OPUS_HEAD_SIZE + 2 + avc->channels) {
+ if (avc->extradata_size >= OPUS_HEAD_SIZE + 2 + channels) {
nb_streams = avc->extradata[OPUS_HEAD_SIZE + 0];
nb_coupled = avc->extradata[OPUS_HEAD_SIZE + 1];
- if (nb_streams + nb_coupled != avc->channels)
+ if (nb_streams + nb_coupled != channels)
av_log(avc, AV_LOG_WARNING, "Inconsistent channel mapping.\n");
mapping = avc->extradata + OPUS_HEAD_SIZE + 2;
} else {
- if (avc->channels > 2 || channel_map) {
+ if (channels > 2 || channel_map) {
av_log(avc, AV_LOG_ERROR,
- "No channel mapping for %d channels.\n", avc->channels);
+ "No channel mapping for %d channels.\n", channels);
return AVERROR(EINVAL);
}
nb_streams = 1;
- nb_coupled = avc->channels > 1;
+ nb_coupled = channels > 1;
mapping = mapping_arr;
}
- if (avc->channels > 2 && avc->channels <= 8) {
- const uint8_t *vorbis_offset = ff_vorbis_channel_layout_offsets[avc->channels - 1];
+ if (channels > 2 && channels <= 8) {
+ const uint8_t *vorbis_offset = ff_vorbis_channel_layout_offsets[channels - 1];
int ch;
/* Remap channels from Vorbis order to ffmpeg order */
- for (ch = 0; ch < avc->channels; ch++)
+ for (ch = 0; ch < channels; ch++)
mapping_arr[ch] = mapping[vorbis_offset[ch]];
mapping = mapping_arr;
}
- opus->dec = opus_multistream_decoder_create(avc->sample_rate, avc->channels,
+ opus->dec = opus_multistream_decoder_create(avc->sample_rate, channels,
nb_streams, nb_coupled,
mapping, &ret);
if (!opus->dec) {
@@ -178,7 +183,7 @@ static int libopus_decode(AVCodecContext *avc, void *data,
#ifndef OPUS_SET_GAIN
{
- int i = avc->channels * nb_samples;
+ int i = avc->ch_layout.nb_channels * nb_samples;
if (avc->sample_fmt == AV_SAMPLE_FMT_FLT) {
float *pcm = (float *)frame->data[0];
for (; i > 0; i--, pcm++)
diff --git a/libavcodec/libopusenc.c b/libavcodec/libopusenc.c
index 45b23fcbb5..401a2c17c8 100644
--- a/libavcodec/libopusenc.c
+++ b/libavcodec/libopusenc.c
@@ -91,7 +91,7 @@ static void libopus_write_header(AVCodecContext *avctx, int stream_count,
const uint8_t *channel_mapping)
{
uint8_t *p = avctx->extradata;
- int channels = avctx->channels;
+ int channels = avctx->ch_layout.nb_channels;
bytestream_put_buffer(&p, "OpusHead", 8);
bytestream_put_byte(&p, 1); /* Version */
@@ -180,9 +180,9 @@ static int libopus_configure_encoder(AVCodecContext *avctx, OpusMSEncoder *enc,
static int libopus_check_max_channels(AVCodecContext *avctx,
int max_channels) {
- if (avctx->channels > max_channels) {
+ if (avctx->ch_layout.nb_channels > max_channels) {
av_log(avctx, AV_LOG_ERROR, "Opus mapping family undefined for %d channels.\n",
- avctx->channels);
+ avctx->ch_layout.nb_channels);
return AVERROR(EINVAL);
}
@@ -190,21 +190,26 @@ static int libopus_check_max_channels(AVCodecContext *avctx,
}
static int libopus_check_vorbis_layout(AVCodecContext *avctx, int mapping_family) {
- av_assert2(avctx->channels < FF_ARRAY_ELEMS(ff_vorbis_channel_layouts));
+ av_assert2(avctx->ch_layout.nb_channels < FF_ARRAY_ELEMS(ff_vorbis_ch_layouts));
- if (!avctx->channel_layout) {
+ if (avctx->ch_layout.order == AV_CHANNEL_ORDER_UNSPEC) {
av_log(avctx, AV_LOG_WARNING,
"No channel layout specified. Opus encoder will use Vorbis "
- "channel layout for %d channels.\n", avctx->channels);
- } else if (avctx->channel_layout != ff_vorbis_channel_layouts[avctx->channels - 1]) {
- char name[32];
- av_get_channel_layout_string(name, sizeof(name), avctx->channels,
- avctx->channel_layout);
- av_log(avctx, AV_LOG_ERROR,
- "Invalid channel layout %s for specified mapping family %d.\n",
- name, mapping_family);
+ "channel layout for %d channels.\n", avctx->ch_layout.nb_channels);
+ } else {
+ AVChannelLayout chl;
+ av_channel_layout_copy(&chl, &ff_vorbis_ch_layouts[avctx->ch_layout.nb_channels - 1]);
- return AVERROR(EINVAL);
+ if (av_channel_layout_compare(&avctx->ch_layout, &chl)) {
+ char name[32];
+
+ av_channel_layout_describe(&avctx->ch_layout, name, sizeof(name));
+ av_log(avctx, AV_LOG_ERROR,
+ "Invalid channel layout %s for specified mapping family %d.\n",
+ name ? name : "", mapping_family);
+
+ return AVERROR(EINVAL);
+ }
}
return 0;
@@ -238,7 +243,7 @@ static int libopus_validate_layout_and_get_channel_map(
ret = libopus_check_max_channels(avctx, 8);
if (ret == 0) {
ret = libopus_check_vorbis_layout(avctx, mapping_family);
- channel_map = ff_vorbis_channel_layout_offsets[avctx->channels - 1];
+ channel_map = ff_vorbis_channel_layout_offsets[avctx->ch_layout.nb_channels - 1];
}
break;
case 255:
@@ -261,6 +266,7 @@ static av_cold int libopus_encode_init(AVCodecContext *avctx)
OpusMSEncoder *enc;
uint8_t libopus_channel_mapping[255];
int ret = OPUS_OK;
+ int channels = avctx->ch_layout.nb_channels;
int av_ret;
int coupled_stream_count, header_size, frame_size;
int mapping_family;
@@ -348,17 +354,17 @@ static av_cold int libopus_encode_init(AVCodecContext *avctx)
* libopus multistream API to avoid surround masking. */
/* Set the mapping family so that the value is correct in the header */
- mapping_family = avctx->channels > 2 ? 1 : 0;
- coupled_stream_count = opus_coupled_streams[avctx->channels - 1];
- opus->stream_count = avctx->channels - coupled_stream_count;
+ mapping_family = channels > 2 ? 1 : 0;
+ coupled_stream_count = opus_coupled_streams[channels - 1];
+ opus->stream_count = channels - coupled_stream_count;
memcpy(libopus_channel_mapping,
- opus_vorbis_channel_map[avctx->channels - 1],
- avctx->channels * sizeof(*libopus_channel_mapping));
+ opus_vorbis_channel_map[channels - 1],
+ channels * sizeof(*libopus_channel_mapping));
enc = opus_multistream_encoder_create(
- avctx->sample_rate, avctx->channels, opus->stream_count,
+ avctx->sample_rate, channels, opus->stream_count,
coupled_stream_count,
- libavcodec_libopus_channel_map[avctx->channels - 1],
+ libavcodec_libopus_channel_map[channels - 1],
opus->opts.application, &ret);
} else {
/* Use the newer multistream API. The encoder will set the channel
@@ -366,7 +372,7 @@ static av_cold int libopus_encode_init(AVCodecContext *avctx)
* use surround masking analysis to save bits. */
mapping_family = opus->opts.mapping_family;
enc = opus_multistream_surround_encoder_create(
- avctx->sample_rate, avctx->channels, mapping_family,
+ avctx->sample_rate, channels, mapping_family,
&opus->stream_count, &coupled_stream_count, libopus_channel_mapping,
opus->opts.application, &ret);
}
@@ -385,10 +391,10 @@ static av_cold int libopus_encode_init(AVCodecContext *avctx)
"No bit rate set. Defaulting to %"PRId64" bps.\n", avctx->bit_rate);
}
- if (avctx->bit_rate < 500 || avctx->bit_rate > 256000 * avctx->channels) {
+ if (avctx->bit_rate < 500 || avctx->bit_rate > 256000 * channels) {
av_log(avctx, AV_LOG_ERROR, "The bit rate %"PRId64" bps is unsupported. "
"Please choose a value between 500 and %d.\n", avctx->bit_rate,
- 256000 * avctx->channels);
+ 256000 * channels);
ret = AVERROR(EINVAL);
goto fail;
}
@@ -400,7 +406,7 @@ static av_cold int libopus_encode_init(AVCodecContext *avctx)
}
/* Header includes channel mapping table if and only if mapping family is NOT 0 */
- header_size = 19 + (mapping_family == 0 ? 0 : 2 + avctx->channels);
+ header_size = 19 + (mapping_family == 0 ? 0 : 2 + channels);
avctx->extradata = av_malloc(header_size + AV_INPUT_BUFFER_PADDING_SIZE);
if (!avctx->extradata) {
av_log(avctx, AV_LOG_ERROR, "Failed to allocate extradata.\n");
@@ -409,7 +415,7 @@ static av_cold int libopus_encode_init(AVCodecContext *avctx)
}
avctx->extradata_size = header_size;
- opus->samples = av_calloc(frame_size, avctx->channels *
+ opus->samples = av_calloc(frame_size, channels *
av_get_bytes_per_sample(avctx->sample_fmt));
if (!opus->samples) {
av_log(avctx, AV_LOG_ERROR, "Failed to allocate samples buffer.\n");
@@ -456,7 +462,8 @@ static int libopus_encode(AVCodecContext *avctx, AVPacket *avpkt,
{
LibopusEncContext *opus = avctx->priv_data;
const int bytes_per_sample = av_get_bytes_per_sample(avctx->sample_fmt);
- const int sample_size = avctx->channels * bytes_per_sample;
+ const int channels = avctx->ch_layout.nb_channels;
+ const int sample_size = channels * bytes_per_sample;
uint8_t *audio;
int ret;
int discard_padding;
@@ -469,7 +476,7 @@ static int libopus_encode(AVCodecContext *avctx, AVPacket *avpkt,
audio = opus->samples;
libopus_copy_samples_with_channel_map(
audio, frame->data[0], opus->encoder_channel_map,
- avctx->channels, frame->nb_samples, bytes_per_sample);
+ channels, frame->nb_samples, bytes_per_sample);
} else if (frame->nb_samples < opus->opts.packet_size) {
audio = opus->samples;
memcpy(audio, frame->data[0], frame->nb_samples * sample_size);
diff --git a/libavcodec/vorbis.h b/libavcodec/vorbis.h
index 69ddbd2982..f80187feee 100644
--- a/libavcodec/vorbis.h
+++ b/libavcodec/vorbis.h
@@ -26,7 +26,10 @@
extern const float ff_vorbis_floor1_inverse_db_table[256];
extern const float * const ff_vorbis_vwin[8];
extern const uint8_t ff_vorbis_channel_layout_offsets[8][8];
+#if FF_API_OLD_CHANNEL_LAYOUT
extern const uint64_t ff_vorbis_channel_layouts[9];
+#endif
+extern const AVChannelLayout ff_vorbis_ch_layouts[9];
typedef struct vorbis_floor1_entry {
uint16_t x;
diff --git a/libavcodec/vorbis_data.c b/libavcodec/vorbis_data.c
index fd7e291de2..4f4ea03f15 100644
--- a/libavcodec/vorbis_data.c
+++ b/libavcodec/vorbis_data.c
@@ -34,6 +34,7 @@ const uint8_t ff_vorbis_channel_layout_offsets[8][8] = {
{ 0, 2, 1, 7, 5, 6, 3, 4 },
};
+#if FF_API_OLD_CHANNEL_LAYOUT
const uint64_t ff_vorbis_channel_layouts[9] = {
AV_CH_LAYOUT_MONO,
AV_CH_LAYOUT_STEREO,
@@ -45,6 +46,23 @@ const uint64_t ff_vorbis_channel_layouts[9] = {
AV_CH_LAYOUT_7POINT1,
0
};
+#endif
+
+const AVChannelLayout ff_vorbis_ch_layouts[9] = {
+ AV_CHANNEL_LAYOUT_MONO,
+ AV_CHANNEL_LAYOUT_STEREO,
+ AV_CHANNEL_LAYOUT_SURROUND,
+ AV_CHANNEL_LAYOUT_QUAD,
+ AV_CHANNEL_LAYOUT_5POINT0_BACK,
+ AV_CHANNEL_LAYOUT_5POINT1_BACK,
+ {
+ .nb_channels = 7,
+ .order = AV_CHANNEL_ORDER_NATIVE,
+ .u.mask = AV_CH_LAYOUT_5POINT1 | AV_CH_BACK_CENTER,
+ },
+ AV_CHANNEL_LAYOUT_7POINT1,
+ { 0 }
+};
DECLARE_ALIGNED(16, static const float, vwin64)[32] = {
0.0009460463F, 0.0085006468F, 0.0235352254F, 0.0458950567F,
--
2.34.1
More information about the ffmpeg-devel
mailing list