]> granicus.if.org Git - handbrake/commitdiff
hb_audio_remap improvements:
authorRodeo <tdskywalker@gmail.com>
Sat, 20 Oct 2012 23:29:33 +0000 (23:29 +0000)
committerRodeo <tdskywalker@gmail.com>
Sat, 20 Oct 2012 23:29:33 +0000 (23:29 +0000)
- support for additional sample formats

- support for variable channel layouts

git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@5023 b64f7644-9d1e-0410-96f1-a4d463321fa5

libhb/audio_remap.c
libhb/audio_remap.h
libhb/deca52.c
libhb/encfaac.c
libhb/encvorbis.c
libhb/platform/macosx/encca_aac.c

index 10e1336d7a7a26d7e3ebaca1530144b787566c7b..6daaee9fbbb24288f5ab59ce7230b7d8b85c8b80 100644 (file)
@@ -81,73 +81,164 @@ hb_chan_map_t hb_aac_chan_map =
     }
 };
 
-hb_audio_remap_t* hb_audio_remap_init(uint64_t channel_layout,
-                                      hb_chan_map_t *map_out,
-                                      hb_chan_map_t *map_in)
+static void remap_planar(uint8_t *tmp_buf, uint8_t *samples, int nsamples,
+                         int nchannels, int sample_size, int *remap_table)
 {
-    hb_audio_remap_t *remap = malloc(sizeof(hb_audio_remap_t));
-    if (remap == NULL)
-        return NULL;
-
-    remap->remap_table = hb_audio_remap_build_table(channel_layout,
-                                                    map_out, map_in);
-    if (remap->remap_table == NULL)
+    int ii, stride = nsamples * sample_size;
+    memcpy(tmp_buf, samples, nchannels * stride);
+    for (ii = 0; ii < nchannels; ii++)
     {
-        hb_audio_remap_free(remap);
-        return NULL;
+        memcpy(samples + (ii              * stride),
+               tmp_buf + (remap_table[ii] * stride), stride);
     }
+}
 
-    int ii;
-    remap->nchannels    = av_get_channel_layout_nb_channels(channel_layout);
-    remap->sample_size  = remap->nchannels * sizeof(hb_sample_t);
-    remap->remap_needed = 0;
-    for (ii = 0; ii < remap->nchannels; ii++)
+static void remap_interleaved(uint8_t *tmp_buf, uint8_t *samples, int nsamples,
+                              int nchannels, int sample_size, int *remap_table)
+{
+    int ii, jj, stride = nchannels * sample_size;
+    memcpy(tmp_buf, samples, nsamples * stride);
+    for (ii = 0; ii < nsamples; ii++)
     {
-        if (remap->remap_table[ii] != ii)
+        for (jj = 0; jj < nchannels; jj++)
         {
-            remap->remap_needed = 1;
-            break;
+            memcpy(samples + (jj              * sample_size),
+                   tmp_buf + (remap_table[jj] * sample_size), sample_size);
         }
+        samples += stride;
+        tmp_buf += stride;
+    }
+}
+
+hb_audio_remap_t* hb_audio_remap_init(enum AVSampleFormat sample_fmt,
+                                      hb_chan_map_t *channel_map_out,
+                                      hb_chan_map_t *channel_map_in)
+{
+    hb_audio_remap_t *remap = calloc(1, sizeof(hb_audio_remap_t));
+    if (remap == NULL)
+    {
+        hb_error("hb_audio_remap_init: failed to allocate remap");
+        goto fail;
+    }
+
+    // sample format
+    switch (sample_fmt)
+    {
+        case AV_SAMPLE_FMT_U8P:
+        case AV_SAMPLE_FMT_S16P:
+        case AV_SAMPLE_FMT_S32P:
+        case AV_SAMPLE_FMT_FLTP:
+        case AV_SAMPLE_FMT_DBLP:
+            remap->remap = &remap_planar;
+            break;
+
+        case AV_SAMPLE_FMT_U8:
+        case AV_SAMPLE_FMT_S16:
+        case AV_SAMPLE_FMT_S32:
+        case AV_SAMPLE_FMT_FLT:
+        case AV_SAMPLE_FMT_DBL:
+            remap->remap = &remap_interleaved;
+            break;
+
+        default:
+            hb_error("hb_audio_remap_init: unsupported sample format '%s'",
+                     av_get_sample_fmt_name(sample_fmt));
+            goto fail;
     }
+    remap->sample_size = av_get_bytes_per_sample(sample_fmt);
+
+    // input/output channel order
+    if (channel_map_in == NULL || channel_map_out == NULL)
+    {
+        hb_error("hb_audio_remap_init: invalid channel map(s)");
+        goto fail;
+    }
+    remap->channel_map_in  = channel_map_in;
+    remap->channel_map_out = channel_map_out;
+
+    // temp buffer - we don't know the required size yet
+    remap->buf = hb_buffer_init(0);
+    if (remap->buf == NULL)
+    {
+        hb_error("hb_audio_remap_init: failed to allocate remap->buf");
+        goto fail;
+    }
+
+    // remap can't be done until the channel layout has been set
+    remap->remap_needed = 0;
 
     return remap;
+
+fail:
+    hb_audio_remap_free(remap);
+    return NULL;
 }
 
-void hb_audio_remap_free(hb_audio_remap_t *remap)
+void hb_audio_remap_set_channel_layout(hb_audio_remap_t *remap,
+                                       uint64_t channel_layout)
 {
     if (remap != NULL)
     {
-        if (remap->remap_table != NULL)
+        int ii;
+        remap->remap_needed = 0;
+        remap->nchannels    = av_get_channel_layout_nb_channels(channel_layout);
+
+        // in some cases, remapping is not necessary and/or supported
+        if (remap->nchannels > HB_AUDIO_REMAP_MAX_CHANNELS)
         {
-            free(remap->remap_table);
+            hb_log("hb_audio_remap_set_channel_layout: too many channels (%d)",
+                   remap->nchannels);
+            return;
         }
+        if (remap->channel_map_in == remap->channel_map_out)
+        {
+            return;
+        }
+
+        // build the table and check whether remapping is necessary
+        hb_audio_remap_build_table(remap->channel_map_out,
+                                   remap->channel_map_in, channel_layout,
+                                   remap->table);
+        for (ii = 0; ii < remap->nchannels; ii++)
+        {
+            if (remap->table[ii] != ii)
+            {
+                remap->remap_needed = 1;
+                break;
+            }
+        }
+    }
+}
+
+
+void hb_audio_remap_free(hb_audio_remap_t *remap)
+{
+    if (remap != NULL)
+    {
+        if (remap->buf != NULL)
+            hb_buffer_close(&remap->buf);
         free(remap);
     }
 }
 
-void hb_audio_remap(hb_audio_remap_t *remap, hb_sample_t *samples, int nsamples)
+void hb_audio_remap(hb_audio_remap_t *remap, uint8_t *samples, int nsamples)
 {
     if (remap != NULL && remap->remap_needed)
     {
-        int ii, jj;
-
-        for (ii = 0; ii < nsamples; ii++)
-        {
-            memcpy(remap->tmp, samples, remap->sample_size);
-            for (jj = 0; jj < remap->nchannels; jj++)
-            {
-                samples[jj] = remap->tmp[remap->remap_table[jj]];
-            }
-            samples += remap->nchannels;
-        }
+        // make sure our temp buffer can hold a copy of all samples
+        hb_buffer_realloc(remap->buf, nsamples * remap->sample_size *
+                          remap->nchannels);
+        remap->remap(remap->buf->data, samples, nsamples, remap->nchannels,
+                     remap->sample_size, remap->table);
     }
 }
 
-int* hb_audio_remap_build_table(uint64_t channel_layout,
-                                hb_chan_map_t *map_out,
-                                hb_chan_map_t *map_in)
+void hb_audio_remap_build_table(hb_chan_map_t *channel_map_out,
+                                hb_chan_map_t *channel_map_in,
+                                uint64_t channel_layout,
+                                int *remap_table)
 {
-    int ii, jj, nchannels, out_chan_idx, remap_idx, *remap_table;
+    int ii, jj, nchannels, out_chan_idx, remap_idx;
     uint64_t *channels_in, *channels_out;
 
     if (channel_layout == AV_CH_LAYOUT_STEREO_DOWNMIX)
@@ -156,19 +247,19 @@ int* hb_audio_remap_build_table(uint64_t channel_layout,
         channel_layout = AV_CH_LAYOUT_STEREO;
     }
     nchannels = av_get_channel_layout_nb_channels(channel_layout);
-    remap_table = malloc(nchannels * sizeof(int));
-    if (remap_table == NULL)
-        return NULL;
+
+    // clear remap table before (re-)building it
+    memset(remap_table, 0, nchannels * sizeof(int));
 
     out_chan_idx = 0;
-    channels_in  = map_in->channel_order_map;
-    channels_out = map_out->channel_order_map;
+    channels_in  = channel_map_in ->channel_order_map;
+    channels_out = channel_map_out->channel_order_map;
     for (ii = 0; channels_out[ii] && out_chan_idx < nchannels; ii++)
     {
         if (channel_layout & channels_out[ii])
         {
             remap_idx = 0;
-            for (jj = 0; channels_in[jj]; jj++)
+            for (jj = 0; channels_in[jj] && remap_idx < nchannels; jj++)
             {
                 if (channels_out[ii] == channels_in[jj])
                 {
@@ -182,6 +273,4 @@ int* hb_audio_remap_build_table(uint64_t channel_layout,
             }
         }
     }
-
-    return remap_table;
 }
index ca8d916cf179061be2ba41e5abcd512bfbd0d322..a776fe57b27e850403bb4cab7ff3dd029067e1ba 100644 (file)
 #define AUDIO_REMAP_H
 
 #include <stdint.h>
+#include "libavutil/samplefmt.h"
 
 /* we only need to support the 11 "most common" channels */
 #define HB_AUDIO_REMAP_MAX_CHANNELS 11
 
-typedef float hb_sample_t;
+typedef struct
+{
+    uint64_t channel_order_map[HB_AUDIO_REMAP_MAX_CHANNELS + 1];
+} hb_chan_map_t;
 
 typedef struct
 {
     int nchannels;
     int sample_size;
     int remap_needed;
-    int *remap_table;
-    hb_sample_t tmp[HB_AUDIO_REMAP_MAX_CHANNELS];
-} hb_audio_remap_t;
+    hb_buffer_t *buf;
+    hb_chan_map_t *channel_map_in;
+    hb_chan_map_t *channel_map_out;
+    int table[HB_AUDIO_REMAP_MAX_CHANNELS];
 
-typedef struct
-{
-    uint64_t channel_order_map[HB_AUDIO_REMAP_MAX_CHANNELS+1];
-} hb_chan_map_t;
+    void (*remap)(uint8_t *tmp_buf, uint8_t *samples, int nsamples,
+                  int nchannels, int sample_size, int *remap_table);
+} hb_audio_remap_t;
 
-/* Predefined channel maps for common channel orders. */
+/*
+ * Predefined channel maps for common channel orders.
+ */
 extern hb_chan_map_t hb_libav_chan_map;
 extern hb_chan_map_t hb_liba52_chan_map;
 extern hb_chan_map_t hb_vorbis_chan_map;
 extern hb_chan_map_t hb_aac_chan_map;
 
-/* Initialize an hb_audio_remap_t to remap audio with the specified channel
- * layout, from the input channel order (indicated by map_in) to the output
- * channel order (indicated by map_out).
+/*
+ * Initialize an hb_audio_remap_t to remap audio with the specified sample
+ * format, from the input to the output channel order (indicated by
+ * channel_map_in and channel_map_out, respectively).
  */
-hb_audio_remap_t* hb_audio_remap_init(uint64_t channel_layout,
-                                      hb_chan_map_t *map_out,
-                                      hb_chan_map_t *map_in);
+hb_audio_remap_t* hb_audio_remap_init(enum AVSampleFormat sample_fmt,
+                                      hb_chan_map_t *channel_map_out,
+                                      hb_chan_map_t *channel_map_in);
 
-/* Free an hb_audio_remap_t. */
+/*
+ * Updates an hb_audio_remap_t's number of channels and remap table to work with
+ * the specified channel layout.
+ *
+ * Must be called at least once before remapping.
+ */
+void              hb_audio_remap_set_channel_layout(hb_audio_remap_t *remap,
+                                                    uint64_t channel_layout);
+
+/*
+ * Free an hb_audio_remap_t.
+ */
 void              hb_audio_remap_free(hb_audio_remap_t *remap);
 
-/* Remap audio between 2 different channel orders, using the settings specified
+/*
+ * Remap audio between 2 different channel orders, using the settings specified
  * in the remap paremeter. Remapping is only done when necessary.
  *
  * The remap parameter can be NULL (no remapping).
  */
-void              hb_audio_remap(hb_audio_remap_t *remap,
-                                 hb_sample_t *samples,
+void              hb_audio_remap(hb_audio_remap_t *remap, uint8_t *samples,
                                  int nsamples);
 
-/* Generate a table used to remap audio between 2 different channel orders.
+/*
+ * Generate a table used to remap audio between 2 different channel orders.
  *
  * Usage: output_sample[channel_idx] = input_sample[remap_table[channel_idx]]
+ *
+ * remap_table is allocated by the caller.
  */
-int*              hb_audio_remap_build_table(uint64_t channel_layout,
-                                             hb_chan_map_t *map_out,
-                                             hb_chan_map_t *map_in);
+void              hb_audio_remap_build_table(hb_chan_map_t *channel_map_out,
+                                             hb_chan_map_t *channel_map_in,
+                                             uint64_t channel_layout,
+                                             int *remap_table);
 
 #endif /* AUDIO_REMAP_H */
index 2736d3f1cbf1f4ffa643e6de8662e04e3e86821b..510e1ea88c960211fc92eada559b04b883288fc3 100644 (file)
@@ -37,10 +37,10 @@ struct hb_work_private_s
     uint8_t       frame[3840];
 
     int                 nchannels;
+    int                 remap_table[6];
     int                 use_mix_levels;
     uint64_t            channel_layout;
     hb_audio_resample_t *resample;
-    int                 *remap_table;
 };
 
 static int  deca52Init( hb_work_object_t *, hb_job_t * );
@@ -177,10 +177,6 @@ static void deca52Close(hb_work_object_t *w)
                pv->frames, pv->crc_errors, pv->bytes_dropped);
     }
 
-    if (pv->remap_table != NULL)
-    {
-        free(pv->remap_table);
-    }
     hb_audio_resample_free(pv->resample);
     hb_list_empty(&pv->list);
     a52_free(pv->state);
@@ -343,20 +339,10 @@ static hb_buffer_t* Decode(hb_work_object_t *w)
                                lfeon2layout[(pv->flags & A52_LFE) != 0]);
         if (new_layout != pv->channel_layout)
         {
-            if (pv->remap_table != NULL)
-            {
-                free(pv->remap_table);
-            }
-            pv->remap_table = hb_audio_remap_build_table(new_layout,
-                                                         &hb_libav_chan_map,
-                                                         &hb_liba52_chan_map);
-            if (pv->remap_table == NULL)
-            {
-                hb_error("deca52: hb_audio_remap_build_table() failed");
-                return NULL;
-            }
             pv->channel_layout = new_layout;
-            pv->nchannels = av_get_channel_layout_nb_channels(new_layout);
+            pv->nchannels      = av_get_channel_layout_nb_channels(new_layout);
+            hb_audio_remap_build_table(&hb_libav_chan_map, &hb_liba52_chan_map,
+                                       pv->channel_layout, pv->remap_table);
         }
 
         /* 6 blocks per frame, 256 samples per block, pv->nchannels channels */
index c6a3f8a16bf1cb9b5e5d30814dded784d591d0c2..c8754f7d718c26aed33f1c6f0d9294ff4c62ad29 100644 (file)
@@ -74,18 +74,10 @@ int encfaacInit( hb_work_object_t * w, hb_job_t * job )
     cfg->allowMidside  = 1;
 
     /* channel configuration & remapping */
-    uint64_t layout;
-    int *remap_table;
-    layout = hb_ff_mixdown_xlat(audio->config.out.mixdown, NULL);
-    remap_table = hb_audio_remap_build_table(layout, &hb_aac_chan_map,
-                                             audio->config.in.channel_map);
-    if (remap_table != NULL)
-    {
-        // faac does its own remapping
-        memcpy(cfg->channel_map, remap_table,
-               pv->out_discrete_channels * sizeof(int));
-        free(remap_table);
-    }
+    uint64_t layout = hb_ff_mixdown_xlat(audio->config.out.mixdown, NULL);
+    hb_audio_remap_build_table(&hb_aac_chan_map, audio->config.in.channel_map,
+                               layout, cfg->channel_map);
+
     switch (audio->config.out.mixdown)
     {
         case HB_AMIXDOWN_7POINT1:
index 4bd36b43aedac387cc39796d4e2de9597ea2d6c1..d02297195173d6cb01b825e5eba105e43bb03349 100644 (file)
@@ -43,7 +43,7 @@ struct hb_work_private_s
     int64_t   prev_blocksize;
     int       out_discrete_channels;
 
-    int       *remap_table;
+    int       remap_table[8];
 };
 
 int encvorbisInit(hb_work_object_t *w, hb_job_t *job)
@@ -129,14 +129,9 @@ int encvorbisInit(hb_work_object_t *w, hb_job_t *job)
 
     // channel remapping
     uint64_t layout = hb_ff_mixdown_xlat(audio->config.out.mixdown, NULL);
-    pv->remap_table = hb_audio_remap_build_table(layout, &hb_vorbis_chan_map,
-                                                 audio->config.in.channel_map);
-    if (pv->remap_table == NULL)
-    {
-        hb_error("encvorbisInit: hb_audio_remap_build_table() failed");
-        *job->die = 1;
-        return -1;
-    }
+    hb_audio_remap_build_table(&hb_vorbis_chan_map,
+                               audio->config.in.channel_map, layout,
+                               pv->remap_table);
 
     return 0;
 }
@@ -160,7 +155,6 @@ void encvorbisClose(hb_work_object_t * w)
         hb_list_empty(&pv->list);
     }
 
-    free(pv->remap_table);
     free(pv->buf);
     free(pv);
     w->private_data = NULL;
index 5c5069cd41cbdeda5148380d083746cc79aa8310..4d6352511f66a7722fc3d4c4d011c1bce886c740 100644 (file)
@@ -289,13 +289,14 @@ int encCoreAudioInit(hb_work_object_t *w, hb_job_t *job, enum AAC_MODE mode)
     audio->config.out.samples_per_frame = pv->isamples;
 
     // channel remapping
-    uint64_t layout = hb_ff_mixdown_xlat(audio->config.out.mixdown, NULL);
-    pv->remap = hb_audio_remap_init(layout, &hb_aac_chan_map,
+    pv->remap = hb_audio_remap_init(AV_SAMPLE_FMT_FLT, &hb_aac_chan_map,
                                     audio->config.in.channel_map);
     if (pv->remap == NULL)
     {
         hb_error("encCoreAudioInit: hb_audio_remap_init() failed");
     }
+    uint64_t layout = hb_ff_mixdown_xlat(audio->config.out.mixdown, NULL);
+    hb_audio_remap_set_channel_layout(pv->remap, layout);
 
     // get maximum output size
     AudioConverterGetProperty(pv->converter,
@@ -388,8 +389,7 @@ static OSStatus inInputDataProc(AudioConverterRef converter, UInt32 *npackets,
     *npackets = buffers->mBuffers[0].mDataByteSize / pv->isamplesiz;
     pv->ibytes -= buffers->mBuffers[0].mDataByteSize;
 
-    hb_audio_remap(pv->remap,
-                   (hb_sample_t*)buffers->mBuffers[0].mData, *npackets);
+    hb_audio_remap(pv->remap, (uint8_t*)buffers->mBuffers[0].mData, *npackets);
 
     return noErr;
 }