mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-26 06:54:49 +00:00
ffmpegdec: Correctly reorder audio channels to the GStreamer order if necessary
This commit is contained in:
parent
09efbe103f
commit
3d6c803917
3 changed files with 68 additions and 35 deletions
|
@ -102,46 +102,52 @@ static const struct
|
||||||
CH_STEREO_RIGHT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}
|
CH_STEREO_RIGHT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}
|
||||||
};
|
};
|
||||||
|
|
||||||
static gboolean
|
gboolean
|
||||||
gst_ff_channel_layout_to_gst (guint64 channel_layout, guint channels,
|
gst_ffmpeg_channel_layout_to_gst (AVCodecContext * context,
|
||||||
GstAudioChannelPosition * pos)
|
GstAudioChannelPosition * pos)
|
||||||
{
|
{
|
||||||
guint nchannels = 0, i, j;
|
guint nchannels = 0, channels = context->channels;
|
||||||
|
guint64 channel_layout = context->channel_layout;
|
||||||
gboolean none_layout = FALSE;
|
gboolean none_layout = FALSE;
|
||||||
|
|
||||||
for (i = 0; i < 64; i++) {
|
|
||||||
if ((channel_layout & (G_GUINT64_CONSTANT (1) << i)) != 0) {
|
|
||||||
nchannels++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (channel_layout == 0) {
|
if (channel_layout == 0) {
|
||||||
nchannels = channels;
|
nchannels = channels;
|
||||||
none_layout = TRUE;
|
none_layout = TRUE;
|
||||||
}
|
} else {
|
||||||
|
guint i, j;
|
||||||
|
|
||||||
if (nchannels != channels) {
|
for (i = 0; i < 64; i++) {
|
||||||
GST_ERROR ("Number of channels is different (%u != %u)", channels,
|
if ((channel_layout & (G_GUINT64_CONSTANT (1) << i)) != 0) {
|
||||||
nchannels);
|
nchannels++;
|
||||||
return FALSE;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0, j = 0; i < G_N_ELEMENTS (_ff_to_gst_layout); i++) {
|
if (nchannels != channels) {
|
||||||
if ((channel_layout & _ff_to_gst_layout[i].ff) != 0) {
|
GST_ERROR ("Number of channels is different (%u != %u)", channels,
|
||||||
pos[j++] = _ff_to_gst_layout[i].gst;
|
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;
|
none_layout = TRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (j != nchannels) {
|
|
||||||
GST_WARNING ("Unknown channels in channel layout - assuming NONE layout");
|
|
||||||
none_layout = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!none_layout
|
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
|
GST_ERROR ("Invalid channel layout %" G_GUINT64_FORMAT
|
||||||
" - assuming NONE layout", channel_layout);
|
" - assuming NONE layout", channel_layout);
|
||||||
none_layout = TRUE;
|
none_layout = TRUE;
|
||||||
|
@ -153,9 +159,9 @@ gst_ff_channel_layout_to_gst (guint64 channel_layout, guint channels,
|
||||||
} else if (nchannels == 2) {
|
} else if (nchannels == 2) {
|
||||||
pos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
|
pos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
|
||||||
pos[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
|
pos[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
|
||||||
} else if (channel_layout == 0) {
|
|
||||||
return FALSE;
|
|
||||||
} else {
|
} else {
|
||||||
|
guint i;
|
||||||
|
|
||||||
for (i = 0; i < nchannels; i++)
|
for (i = 0; i < nchannels; i++)
|
||||||
pos[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
|
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 */
|
/* fixed, non-probing context */
|
||||||
if (context != NULL && context->channels != -1) {
|
if (context != NULL && context->channels != -1) {
|
||||||
GstAudioInfo info;
|
|
||||||
GstAudioChannelPosition pos[64];
|
GstAudioChannelPosition pos[64];
|
||||||
guint64 channel_layout = context->channel_layout;
|
|
||||||
|
|
||||||
gst_audio_info_init (&info);
|
|
||||||
|
|
||||||
caps = gst_caps_new_simple (mimetype,
|
caps = gst_caps_new_simple (mimetype,
|
||||||
"rate", G_TYPE_INT, context->sample_rate,
|
"rate", G_TYPE_INT, context->sample_rate,
|
||||||
"channels", G_TYPE_INT, context->channels, NULL);
|
"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;
|
guint64 mask;
|
||||||
|
|
||||||
if (gst_audio_channel_positions_to_mask (pos, context->channels, &mask)) {
|
if (gst_audio_channel_positions_to_mask (pos, context->channels, &mask)) {
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
#include <libavcodec/avcodec.h>
|
#include <libavcodec/avcodec.h>
|
||||||
#endif
|
#endif
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
#include <gst/audio/audio.h>
|
||||||
#include <gst/video/video.h>
|
#include <gst/video/video.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -127,5 +127,8 @@ gst_ffmpeg_formatid_get_codecids (const gchar *format_name,
|
||||||
AVOutputFormat * plugin);
|
AVOutputFormat * plugin);
|
||||||
|
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gst_ffmpeg_channel_layout_to_gst (AVCodecContext * context,
|
||||||
|
GstAudioChannelPosition * pos);
|
||||||
|
|
||||||
#endif /* __GST_FFMPEG_CODECMAP_H__ */
|
#endif /* __GST_FFMPEG_CODECMAP_H__ */
|
||||||
|
|
|
@ -97,6 +97,8 @@ struct _GstFFMpegDec
|
||||||
gint channels;
|
gint channels;
|
||||||
gint samplerate;
|
gint samplerate;
|
||||||
gint depth;
|
gint depth;
|
||||||
|
|
||||||
|
GstAudioChannelPosition ffmpeg_layout[64], gst_layout[64];
|
||||||
} audio;
|
} audio;
|
||||||
} format;
|
} format;
|
||||||
|
|
||||||
|
@ -1350,13 +1352,18 @@ update_audio_context (GstFFMpegDec * ffmpegdec, gboolean force)
|
||||||
{
|
{
|
||||||
AVCodecContext *context = ffmpegdec->context;
|
AVCodecContext *context = ffmpegdec->context;
|
||||||
gint depth;
|
gint depth;
|
||||||
|
GstAudioChannelPosition pos[64] = { 0, };
|
||||||
|
|
||||||
depth = av_smp_format_depth (context->sample_fmt);
|
depth = av_smp_format_depth (context->sample_fmt);
|
||||||
|
|
||||||
|
gst_ffmpeg_channel_layout_to_gst (context, pos);
|
||||||
|
|
||||||
if (!force && ffmpegdec->format.audio.samplerate ==
|
if (!force && ffmpegdec->format.audio.samplerate ==
|
||||||
context->sample_rate &&
|
context->sample_rate &&
|
||||||
ffmpegdec->format.audio.channels == context->channels &&
|
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;
|
return FALSE;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (ffmpegdec,
|
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.samplerate = context->sample_rate;
|
||||||
ffmpegdec->format.audio.channels = context->channels;
|
ffmpegdec->format.audio.channels = context->channels;
|
||||||
ffmpegdec->format.audio.depth = depth;
|
ffmpegdec->format.audio.depth = depth;
|
||||||
|
memcpy (ffmpegdec->format.audio.ffmpeg_layout, pos,
|
||||||
|
sizeof (GstAudioChannelPosition) * context->channels);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -1389,6 +1398,13 @@ gst_ffmpegdec_audio_negotiate (GstFFMpegDec * ffmpegdec, gboolean force)
|
||||||
if (caps == NULL)
|
if (caps == NULL)
|
||||||
goto no_caps;
|
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);
|
GST_LOG_OBJECT (ffmpegdec, "output caps %" GST_PTR_FORMAT, caps);
|
||||||
|
|
||||||
if (!gst_pad_set_caps (ffmpegdec->srcpad, 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);
|
"Decode audio: len=%d, have_data=%d", len, have_data);
|
||||||
|
|
||||||
if (len >= 0 && have_data > 0) {
|
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 */
|
/* Buffer size */
|
||||||
gst_buffer_unmap (*outbuf, odata, have_data);
|
gst_buffer_unmap (*outbuf, odata, have_data);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue