avaudenc: Reorder audio channels if necessary and add proper support for channel...
authorSebastian Dröge <sebastian.droege@collabora.co.uk>
Tue, 11 Dec 2012 18:07:34 +0000 (18:07 +0000)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Tue, 11 Dec 2012 18:07:34 +0000 (18:07 +0000)
ext/libav/gstavaudenc.c
ext/libav/gstavaudenc.h
ext/libav/gstavcodecmap.c

index d3f58cc..c507a8a 100644 (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;
index 92527b9..8017ea4 100644 (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;
index b9e6c67..bbd6d60 100644 (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;