avaudenc: Reorder audio channels if necessary and add proper support for channel layouts

This commit is contained in:
Sebastian Dröge 2012-12-11 18:07:34 +00:00
parent 64a2a8bdae
commit fbe1221d70
3 changed files with 49 additions and 0 deletions

View file

@ -283,6 +283,15 @@ gst_ffmpegaudenc_set_format (GstAudioEncoder * encoder, GstAudioInfo * info)
ffmpegaudenc->context->ticks_per_frame = 1;
}
if (ffmpegaudenc->context->channel_layout) {
gst_ffmpeg_channel_layout_to_gst (ffmpegaudenc->context->channel_layout,
ffmpegaudenc->context->channels, ffmpegaudenc->ffmpeg_layout);
ffmpegaudenc->needs_reorder =
(memcmp (ffmpegaudenc->ffmpeg_layout, info->position,
sizeof (GstAudioChannelPosition) *
ffmpegaudenc->context->channels) != 0);
}
/* open codec */
if (gst_ffmpeg_avcodec_open (ffmpegaudenc->context, oclass->in_plugin) < 0) {
if (ffmpegaudenc->context->priv_data)
@ -540,6 +549,15 @@ gst_ffmpegaudenc_handle_frame (GstAudioEncoder * encoder, GstBuffer * inbuf)
", size %" G_GSIZE_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)),
GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf)), gst_buffer_get_size (inbuf));
/* Reorder channels to the GStreamer channel order */
if (ffmpegaudenc->needs_reorder) {
GstAudioInfo *info = gst_audio_encoder_get_audio_info (encoder);
inbuf = gst_buffer_make_writable (inbuf);
gst_audio_buffer_reorder_channels (inbuf, info->finfo->format,
info->channels, info->position, ffmpegaudenc->ffmpeg_layout);
}
gst_buffer_map (inbuf, &map, GST_MAP_READ);
in_data = map.data;
size = map.size;

View file

@ -46,6 +46,9 @@ struct _GstFFMpegAudEnc
/* other settings are copied over straight,
* include a context here, rather than copy-and-past it from avcodec.h */
AVCodecContext config;
GstAudioChannelPosition ffmpeg_layout[64];
gboolean needs_reorder;
};
typedef struct _GstFFMpegAudEncClass GstFFMpegAudEncClass;

View file

@ -66,6 +66,32 @@ static const struct
AV_CH_STEREO_RIGHT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}
};
static guint64
gst_ffmpeg_channel_positions_to_layout (GstAudioChannelPosition * pos,
gint channels)
{
gint i, j;
guint64 ret = 0;
gint channels_found = 0;
if (!pos)
return 0;
for (i = 0; i < channels; i++) {
for (j = 0; j < G_N_ELEMENTS (_ff_to_gst_layout); j++) {
if (_ff_to_gst_layout[j].gst == pos[i]) {
ret |= _ff_to_gst_layout[i].ff;
channels_found++;
break;
}
}
}
if (channels_found != channels)
return 0;
return ret;
}
gboolean
gst_ffmpeg_channel_layout_to_gst (guint64 channel_layout, gint channels,
GstAudioChannelPosition * pos)
@ -2325,6 +2351,8 @@ gst_ffmpeg_audioinfo_to_context (GstAudioInfo * info, AVCodecContext * context)
context->channels = info->channels;
context->sample_rate = info->rate;
context->channel_layout =
gst_ffmpeg_channel_positions_to_layout (info->position, info->channels);
codec = context->codec;