ffmpegdec: Correctly reorder audio channels to the GStreamer order if necessary

This commit is contained in:
Sebastian Dröge 2012-01-10 10:37:50 +01:00
parent 09efbe103f
commit 3d6c803917
3 changed files with 68 additions and 35 deletions

View file

@ -102,46 +102,52 @@ static const struct
CH_STEREO_RIGHT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}
};
static gboolean
gst_ff_channel_layout_to_gst (guint64 channel_layout, guint channels,
gboolean
gst_ffmpeg_channel_layout_to_gst (AVCodecContext * context,
GstAudioChannelPosition * pos)
{
guint nchannels = 0, i, j;
guint nchannels = 0, channels = context->channels;
guint64 channel_layout = context->channel_layout;
gboolean none_layout = FALSE;
for (i = 0; i < 64; i++) {
if ((channel_layout & (G_GUINT64_CONSTANT (1) << i)) != 0) {
nchannels++;
}
}
if (channel_layout == 0) {
nchannels = channels;
none_layout = TRUE;
}
} else {
guint i, j;
if (nchannels != channels) {
GST_ERROR ("Number of channels is different (%u != %u)", channels,
nchannels);
return FALSE;
}
for (i = 0; i < 64; i++) {
if ((channel_layout & (G_GUINT64_CONSTANT (1) << i)) != 0) {
nchannels++;
}
}
for (i = 0, j = 0; i < G_N_ELEMENTS (_ff_to_gst_layout); i++) {
if ((channel_layout & _ff_to_gst_layout[i].ff) != 0) {
pos[j++] = _ff_to_gst_layout[i].gst;
if (nchannels != channels) {
GST_ERROR ("Number of channels is different (%u != %u)", channels,
nchannels);
nchannels = channels;
none_layout = TRUE;
} else {
if (_ff_to_gst_layout[i].gst == GST_AUDIO_CHANNEL_POSITION_NONE)
for (i = 0, j = 0; i < G_N_ELEMENTS (_ff_to_gst_layout); i++) {
if ((channel_layout & _ff_to_gst_layout[i].ff) != 0) {
pos[j++] = _ff_to_gst_layout[i].gst;
if (_ff_to_gst_layout[i].gst == GST_AUDIO_CHANNEL_POSITION_NONE)
none_layout = TRUE;
}
}
if (j != nchannels) {
GST_WARNING
("Unknown channels in channel layout - assuming NONE layout");
none_layout = TRUE;
}
}
}
if (j != nchannels) {
GST_WARNING ("Unknown channels in channel layout - assuming NONE layout");
none_layout = TRUE;
}
if (!none_layout
&& !gst_audio_check_valid_channel_positions (pos, nchannels, TRUE)) {
&& !gst_audio_check_valid_channel_positions (pos, nchannels, FALSE)) {
GST_ERROR ("Invalid channel layout %" G_GUINT64_FORMAT
" - assuming NONE layout", channel_layout);
none_layout = TRUE;
@ -153,9 +159,9 @@ gst_ff_channel_layout_to_gst (guint64 channel_layout, guint channels,
} else if (nchannels == 2) {
pos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
pos[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
} else if (channel_layout == 0) {
return FALSE;
} else {
guint i;
for (i = 0; i < nchannels; i++)
pos[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
}
@ -322,17 +328,13 @@ gst_ff_aud_caps_new (AVCodecContext * context, enum CodecID codec_id,
/* fixed, non-probing context */
if (context != NULL && context->channels != -1) {
GstAudioInfo info;
GstAudioChannelPosition pos[64];
guint64 channel_layout = context->channel_layout;
gst_audio_info_init (&info);
caps = gst_caps_new_simple (mimetype,
"rate", G_TYPE_INT, context->sample_rate,
"channels", G_TYPE_INT, context->channels, NULL);
if (gst_ff_channel_layout_to_gst (channel_layout, context->channels, pos)) {
if (gst_ffmpeg_channel_layout_to_gst (context, pos)) {
guint64 mask;
if (gst_audio_channel_positions_to_mask (pos, context->channels, &mask)) {

View file

@ -26,7 +26,7 @@
#include <libavcodec/avcodec.h>
#endif
#include <gst/gst.h>
#include <gst/audio/audio.h>
#include <gst/video/video.h>
/*
@ -127,5 +127,8 @@ gst_ffmpeg_formatid_get_codecids (const gchar *format_name,
AVOutputFormat * plugin);
gboolean
gst_ffmpeg_channel_layout_to_gst (AVCodecContext * context,
GstAudioChannelPosition * pos);
#endif /* __GST_FFMPEG_CODECMAP_H__ */

View file

@ -97,6 +97,8 @@ struct _GstFFMpegDec
gint channels;
gint samplerate;
gint depth;
GstAudioChannelPosition ffmpeg_layout[64], gst_layout[64];
} audio;
} format;
@ -1350,13 +1352,18 @@ update_audio_context (GstFFMpegDec * ffmpegdec, gboolean force)
{
AVCodecContext *context = ffmpegdec->context;
gint depth;
GstAudioChannelPosition pos[64] = { 0, };
depth = av_smp_format_depth (context->sample_fmt);
gst_ffmpeg_channel_layout_to_gst (context, pos);
if (!force && ffmpegdec->format.audio.samplerate ==
context->sample_rate &&
ffmpegdec->format.audio.channels == context->channels &&
ffmpegdec->format.audio.depth == depth)
ffmpegdec->format.audio.depth == depth &&
memcmp (ffmpegdec->format.audio.ffmpeg_layout, pos,
sizeof (GstAudioChannelPosition) * context->channels) == 0)
return FALSE;
GST_DEBUG_OBJECT (ffmpegdec,
@ -1368,6 +1375,8 @@ update_audio_context (GstFFMpegDec * ffmpegdec, gboolean force)
ffmpegdec->format.audio.samplerate = context->sample_rate;
ffmpegdec->format.audio.channels = context->channels;
ffmpegdec->format.audio.depth = depth;
memcpy (ffmpegdec->format.audio.ffmpeg_layout, pos,
sizeof (GstAudioChannelPosition) * context->channels);
return TRUE;
}
@ -1389,6 +1398,13 @@ gst_ffmpegdec_audio_negotiate (GstFFMpegDec * ffmpegdec, gboolean force)
if (caps == NULL)
goto no_caps;
/* Get GStreamer channel layout */
memcpy (ffmpegdec->format.audio.gst_layout,
ffmpegdec->format.audio.ffmpeg_layout,
sizeof (GstAudioChannelPosition) * ffmpegdec->format.audio.channels);
gst_audio_channel_positions_to_valid_order (ffmpegdec->format.
audio.gst_layout, ffmpegdec->format.audio.channels);
GST_LOG_OBJECT (ffmpegdec, "output caps %" GST_PTR_FORMAT, caps);
if (!gst_pad_set_caps (ffmpegdec->srcpad, caps))
@ -2226,7 +2242,19 @@ gst_ffmpegdec_audio_frame (GstFFMpegDec * ffmpegdec,
"Decode audio: len=%d, have_data=%d", len, have_data);
if (len >= 0 && have_data > 0) {
/* FIXME: Reorder here */
GstAudioFormat fmt;
/* Reorder channels to the GStreamer channel order */
/* Only the width really matters here... and it's stored as depth */
fmt =
gst_audio_format_build_integer (TRUE, G_BYTE_ORDER,
ffmpegdec->format.audio.depth, ffmpegdec->format.audio.depth);
gst_audio_reorder_channels (odata, have_data, fmt,
ffmpegdec->format.audio.channels,
ffmpegdec->format.audio.ffmpeg_layout,
ffmpegdec->format.audio.gst_layout);
/* Buffer size */
gst_buffer_unmap (*outbuf, odata, have_data);