1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2024-12-23 12:43:46 +02:00

libopus: convert to new channel layout API

Signed-off-by: James Almer <jamrial@gmail.com>
This commit is contained in:
Anton Khirnov 2019-06-03 17:54:20 +02:00 committed by James Almer
parent e0bb126de8
commit e869c06ef5
4 changed files with 69 additions and 41 deletions

View File

@ -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] : (avc->ch_layout.nb_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++)

View File

@ -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,16 +190,16 @@ 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]) {
"channel layout for %d channels.\n", avctx->ch_layout.nb_channels);
} else if (av_channel_layout_compare(&avctx->ch_layout, &ff_vorbis_ch_layouts[avctx->ch_layout.nb_channels - 1])) {
char name[32];
av_get_channel_layout_string(name, sizeof(name), avctx->channels,
avctx->channel_layout);
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, mapping_family);
@ -238,7 +238,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 +261,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 +349,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 +367,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 +386,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 +401,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 +410,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 +457,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 +471,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);

View File

@ -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;

View File

@ -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,