mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-11-21 10:55:51 +02:00
libopus: convert to new channel layout API
Signed-off-by: James Almer <jamrial@gmail.com>
This commit is contained in:
parent
e0bb126de8
commit
e869c06ef5
@ -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++)
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user