faad: optimize channel remap, avoid potential memcpy
authorWim Taymans <wim.taymans@collabora.co.uk>
Tue, 20 Mar 2012 15:34:33 +0000 (16:34 +0100)
committerWim Taymans <wim.taymans@collabora.co.uk>
Tue, 20 Mar 2012 15:34:33 +0000 (16:34 +0100)
Combine the channel remap and copy in one operation. Calculate the channel remap
table only once, make a shortcut when we are not doing any remapping.

ext/faad/gstfaad.c
ext/faad/gstfaad.h

index 54a14f3..8cae672 100644 (file)
@@ -473,14 +473,13 @@ gst_faad_update_caps (GstFaad * faad, faacDecFrameInfo * info)
   gboolean ret;
   gboolean fmt_change = FALSE;
   GstAudioInfo ainfo;
+  gint i;
 
   /* see if we need to renegotiate */
   if (info->samplerate != faad->samplerate ||
       info->channels != faad->channels || !faad->channel_positions) {
     fmt_change = TRUE;
   } else {
-    gint i;
-
     for (i = 0; i < info->channels; i++) {
       if (info->channel_position[i] != faad->channel_positions[i]) {
         fmt_change = TRUE;
@@ -520,6 +519,19 @@ gst_faad_update_caps (GstFaad * faad, faacDecFrameInfo * info)
   if (ainfo.position[0] != GST_AUDIO_CHANNEL_POSITION_NONE)
     ainfo.flags &= ~GST_AUDIO_FLAG_UNPOSITIONED;
 
+  /* get the remap table */
+  memset (faad->reorder_map, 0, sizeof (faad->reorder_map));
+  faad->need_reorder = FALSE;
+  if (gst_audio_get_channel_reorder_map (faad->channels, faad->aac_positions,
+          faad->gst_positions, faad->reorder_map)) {
+    for (i = 0; i < faad->channels; i++) {
+      if (faad->reorder_map[i] != i) {
+        faad->need_reorder = TRUE;
+        break;
+      }
+    }
+  }
+
   ret = gst_audio_decoder_set_output_format (GST_AUDIO_DECODER (faad), &ainfo);
 
   return ret;
@@ -720,6 +732,7 @@ init:
   info.error = 0;
 
   do {
+    GstMapInfo map;
 
     if (!faad->packetised) {
       /* faad only really parses ADTS header at Init time, not when decoding,
@@ -746,6 +759,8 @@ init:
         (guint) info.bytesconsumed, (guint) info.samples);
 
     if (out && info.samples > 0) {
+      guint channels, samples;
+
       if (!gst_faad_update_caps (faad, &info))
         goto negotiation_failed;
 
@@ -753,12 +768,30 @@ init:
       if (info.samples > G_MAXUINT / faad->bps)
         goto sample_overflow;
 
+      channels = faad->channels;
       /* note: info.samples is total samples, not per channel */
+      samples = info.samples / channels;
+
       /* FIXME, add bufferpool and allocator support to the base class */
       outbuf = gst_buffer_new_allocate (NULL, info.samples * faad->bps, NULL);
-      gst_buffer_fill (outbuf, 0, out, info.samples * faad->bps);
-      gst_audio_buffer_reorder_channels (outbuf, GST_AUDIO_FORMAT_S16,
-          faad->channels, faad->aac_positions, faad->gst_positions);
+
+      gst_buffer_map (outbuf, &map, GST_MAP_READWRITE);
+      if (faad->need_reorder) {
+        gint16 *dest, *src, i, j;
+
+        dest = (gint16 *) map.data;
+        src = (gint16 *) out;
+
+        for (i = 0; i < samples; i++) {
+          for (j = 0; j < channels; j++) {
+            dest[faad->reorder_map[j]] = *src++;
+          }
+          dest += channels;
+        }
+      } else {
+        memcpy (map.data, out, map.size);
+      }
+      gst_buffer_unmap (outbuf, &map);
 
       ret = gst_audio_decoder_finish_frame (dec, outbuf, 1);
     }
index 52b98c3..0dd94bb 100644 (file)
@@ -50,6 +50,8 @@ typedef struct _GstFaad {
   guint      bps;        /* bytes per sample                      */
   guchar    *channel_positions;
   GstAudioChannelPosition aac_positions[6], gst_positions[6];
+  gboolean   need_reorder;
+  gint       reorder_map[64];
 
   guint8     fake_codec_data[2];
   guint32    last_header;