fdkaacdec: Use predefined channel layouts

This limits the decoder to the layouts predefined for the encoder
(including the MPEG standard layouts) but greatly simplifies the
implementation.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1561>
This commit is contained in:
Jan Alexander Steffens (heftig) 2018-12-05 01:07:19 +01:00 committed by GStreamer Marge Bot
parent e0d5e022a1
commit d4b4ffc944
2 changed files with 91 additions and 159 deletions

View file

@ -21,6 +21,7 @@
#include "config.h"
#endif
#include "gstfdkaac.h"
#include "gstfdkaacdec.h"
#include <gst/pbutils/pbutils.h>
@ -78,6 +79,9 @@ gst_fdkaacdec_start (GstAudioDecoder * dec)
GST_DEBUG_OBJECT (self, "start");
gst_audio_info_init (&self->info);
self->sample_rate = 0;
return TRUE;
}
@ -184,6 +188,71 @@ gst_fdkaacdec_set_format (GstAudioDecoder * dec, GstCaps * caps)
return TRUE;
}
static gboolean
gst_fdkaacdec_map_channel_config (GstFdkAacDec * self, const CStreamInfo * in,
gboolean * updated)
{
const GstFdkAacChannelLayout *layout;
CHANNEL_MODE config = in->channelConfig;
INT channels = in->numChannels;
if (self->config == config && self->channels == channels) {
GST_TRACE_OBJECT (self,
"Reusing cached positions for channelConfig %d (%d channels)",
config, channels);
return TRUE;
}
self->config = config;
self->channels = channels;
*updated = TRUE;
for (layout = channel_layouts; layout->channels; layout++) {
if (layout->mode == config && layout->channels == channels)
break;
}
if (!layout->channels) {
GST_ERROR_OBJECT (self, "Unknown channelConfig %d (%d channels)",
config, channels);
return FALSE;
}
GST_INFO_OBJECT (self, "Known channelConfig %d (%d channels)",
config, channels);
memcpy (self->positions, layout->positions,
channels * sizeof *self->positions);
return TRUE;
}
static gboolean
gst_fdkaacdec_update_info (GstFdkAacDec * self)
{
GstAudioChannelPosition positions[8];
GstAudioInfo *info = &self->info;
gint channels = self->channels;
memcpy (positions, self->positions, channels * sizeof *positions);
if (!gst_audio_channel_positions_to_valid_order (positions, channels)) {
GST_ERROR_OBJECT (self, "Failed to reorder channels");
return FALSE;
}
gst_audio_info_set_format (info, GST_AUDIO_FORMAT_S16, self->sample_rate,
channels, positions);
if (!gst_audio_decoder_set_output_format (GST_AUDIO_DECODER (self), info)) {
GST_ERROR_OBJECT (self, "Failed to set output format");
return FALSE;
}
self->need_reorder = memcmp (positions, self->positions,
channels * sizeof *positions) != 0;
return TRUE;
}
static GstFlowReturn
gst_fdkaacdec_handle_frame (GstAudioDecoder * dec, GstBuffer * inbuf)
{
@ -192,12 +261,10 @@ gst_fdkaacdec_handle_frame (GstAudioDecoder * dec, GstBuffer * inbuf)
GstBuffer *outbuf;
GstMapInfo imap;
AAC_DECODER_ERROR err;
UINT flags = 0;
guint size, valid;
CStreamInfo *stream_info;
GstAudioInfo info;
guint flags = 0, i;
GstAudioChannelPosition pos[64], gst_pos[64];
gboolean need_reorder;
gboolean updated = FALSE;
if (inbuf) {
gst_buffer_ref (inbuf);
@ -237,176 +304,33 @@ gst_fdkaacdec_handle_frame (GstAudioDecoder * dec, GstBuffer * inbuf)
goto out;
}
/* FIXME: Don't recalculate this on every buffer */
if (stream_info->numChannels == 1) {
pos[0] = GST_AUDIO_CHANNEL_POSITION_MONO;
} else {
gint n_front = 0, n_back = 0, n_lfe = 0;
/* FIXME: Can this be simplified somehow? */
for (i = 0; i < stream_info->numChannels; i++) {
if (stream_info->pChannelType[i] == ACT_FRONT) {
n_front++;
} else if (stream_info->pChannelType[i] == ACT_BACK) {
n_back++;
} else if (stream_info->pChannelType[i] == ACT_LFE) {
n_lfe++;
} else {
GST_ERROR_OBJECT (self, "Channel type %d not supported",
stream_info->pChannelType[i]);
ret = GST_FLOW_NOT_NEGOTIATED;
goto out;
}
}
for (i = 0; i < stream_info->numChannels; i++) {
if (stream_info->pChannelType[i] == ACT_FRONT) {
if (stream_info->pChannelIndices[i] == 0) {
if (n_front & 1)
pos[i] = GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER;
else if (n_front > 2)
pos[i] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER;
else
pos[i] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
} else if (stream_info->pChannelIndices[i] == 1) {
if ((n_front & 1) && n_front > 3)
pos[i] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER;
else if (n_front & 1)
pos[i] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
else if (n_front > 2)
pos[i] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER;
else
pos[i] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
} else if (stream_info->pChannelIndices[i] == 2) {
if ((n_front & 1) && n_front > 3)
pos[i] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER;
else if (n_front & 1)
pos[i] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
else if (n_front > 2)
pos[i] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
else
g_assert_not_reached ();
} else if (stream_info->pChannelIndices[i] == 3) {
if ((n_front & 1) && n_front > 3)
pos[i] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
else if (n_front & 1)
g_assert_not_reached ();
else if (n_front > 2)
pos[i] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
else
g_assert_not_reached ();
} else if (stream_info->pChannelIndices[i] == 4) {
if ((n_front & 1) && n_front > 2)
pos[i] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
else if (n_front & 1)
g_assert_not_reached ();
else if (n_front > 2)
g_assert_not_reached ();
else
g_assert_not_reached ();
} else {
GST_ERROR_OBJECT (self, "Front channel index %d not supported",
stream_info->pChannelIndices[i]);
ret = GST_FLOW_NOT_NEGOTIATED;
goto out;
}
} else if (stream_info->pChannelType[i] == ACT_BACK) {
if (stream_info->pChannelIndices[i] == 0) {
if (n_back & 1)
pos[i] = GST_AUDIO_CHANNEL_POSITION_REAR_CENTER;
else if (n_back > 2)
pos[i] = GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT;
else
pos[i] = GST_AUDIO_CHANNEL_POSITION_REAR_LEFT;
} else if (stream_info->pChannelIndices[i] == 1) {
if ((n_back & 1) && n_back > 3)
pos[i] = GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT;
else if (n_back & 1)
pos[i] = GST_AUDIO_CHANNEL_POSITION_REAR_LEFT;
else if (n_back > 2)
pos[i] = GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT;
else
pos[i] = GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT;
} else if (stream_info->pChannelIndices[i] == 2) {
if ((n_back & 1) && n_back > 3)
pos[i] = GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT;
else if (n_back & 1)
pos[i] = GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT;
else if (n_back > 2)
pos[i] = GST_AUDIO_CHANNEL_POSITION_REAR_LEFT;
else
g_assert_not_reached ();
} else if (stream_info->pChannelIndices[i] == 3) {
if ((n_back & 1) && n_back > 3)
pos[i] = GST_AUDIO_CHANNEL_POSITION_REAR_LEFT;
else if (n_back & 1)
g_assert_not_reached ();
else if (n_back > 2)
pos[i] = GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT;
else
g_assert_not_reached ();
} else if (stream_info->pChannelIndices[i] == 4) {
if ((n_back & 1) && n_back > 3)
pos[i] = GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT;
else if (n_back & 1)
g_assert_not_reached ();
else if (n_back > 2)
g_assert_not_reached ();
else
g_assert_not_reached ();
} else {
GST_ERROR_OBJECT (self, "Side channel index %d not supported",
stream_info->pChannelIndices[i]);
ret = GST_FLOW_NOT_NEGOTIATED;
goto out;
}
} else if (stream_info->pChannelType[i] == ACT_LFE) {
if (stream_info->pChannelIndices[i] == 0) {
pos[i] = GST_AUDIO_CHANNEL_POSITION_LFE1;
} else {
GST_ERROR_OBJECT (self, "LFE channel index %d not supported",
stream_info->pChannelIndices[i]);
ret = GST_FLOW_NOT_NEGOTIATED;
goto out;
}
} else {
GST_ERROR_OBJECT (self, "Channel type %d not supported",
stream_info->pChannelType[i]);
ret = GST_FLOW_NOT_NEGOTIATED;
goto out;
}
}
if (stream_info->sampleRate != self->sample_rate) {
self->sample_rate = stream_info->sampleRate;
updated = TRUE;
}
memcpy (gst_pos, pos,
sizeof (GstAudioChannelPosition) * stream_info->numChannels);
if (!gst_audio_channel_positions_to_valid_order (gst_pos,
stream_info->numChannels)) {
if (!gst_fdkaacdec_map_channel_config (self, stream_info, &updated)) {
ret = GST_FLOW_NOT_NEGOTIATED;
goto out;
}
need_reorder =
memcmp (pos, gst_pos,
sizeof (GstAudioChannelPosition) * stream_info->numChannels) != 0;
gst_audio_info_set_format (&info, GST_AUDIO_FORMAT_S16,
stream_info->sampleRate, stream_info->numChannels, gst_pos);
if (!gst_audio_decoder_set_output_format (dec, &info)) {
GST_ERROR_OBJECT (self, "Failed to set output format");
if (updated && !gst_fdkaacdec_update_info (self)) {
ret = GST_FLOW_NOT_NEGOTIATED;
goto out;
}
outbuf =
gst_audio_decoder_allocate_output_buffer (dec,
stream_info->frameSize * GST_AUDIO_INFO_BPF (&info));
stream_info->frameSize * GST_AUDIO_INFO_BPF (&self->info));
gst_buffer_fill (outbuf, 0, self->decode_buffer,
gst_buffer_get_size (outbuf));
if (need_reorder) {
gst_audio_buffer_reorder_channels (outbuf, GST_AUDIO_INFO_FORMAT (&info),
GST_AUDIO_INFO_CHANNELS (&info), pos, gst_pos);
if (self->need_reorder) {
gst_audio_buffer_reorder_channels (outbuf,
GST_AUDIO_INFO_FORMAT (&self->info),
GST_AUDIO_INFO_CHANNELS (&self->info),
self->positions, self->info.position);
}
finish:

View file

@ -47,6 +47,14 @@ struct _GstFdkAacDec {
HANDLE_AACDECODER dec;
gint16 *decode_buffer;
gint decode_buffer_size;
INT sample_rate;
CHANNEL_MODE config;
INT channels;
GstAudioChannelPosition positions[8];
gboolean need_reorder;
GstAudioInfo info;
};
struct _GstFdkAacDecClass {