summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRodeo <[email protected]>2012-10-20 23:29:33 +0000
committerRodeo <[email protected]>2012-10-20 23:29:33 +0000
commit305fc5798105e9a16f83868116d0a38a2919a638 (patch)
tree607b57a009cfa57fb6191fec6655df42167675a1
parent4916c07f34cf97a79ca76f8163a9e7e258491bce (diff)
hb_audio_remap improvements:
- 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
-rw-r--r--libhb/audio_remap.c183
-rw-r--r--libhb/audio_remap.h68
-rw-r--r--libhb/deca52.c22
-rw-r--r--libhb/encfaac.c16
-rw-r--r--libhb/encvorbis.c14
-rw-r--r--libhb/platform/macosx/encca_aac.c8
6 files changed, 197 insertions, 114 deletions
diff --git a/libhb/audio_remap.c b/libhb/audio_remap.c
index 10e1336d7..6daaee9fb 100644
--- a/libhb/audio_remap.c
+++ b/libhb/audio_remap.c
@@ -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;
}
diff --git a/libhb/audio_remap.h b/libhb/audio_remap.h
index ca8d916cf..a776fe57b 100644
--- a/libhb/audio_remap.h
+++ b/libhb/audio_remap.h
@@ -27,58 +27,80 @@
#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 */
diff --git a/libhb/deca52.c b/libhb/deca52.c
index 2736d3f1c..510e1ea88 100644
--- a/libhb/deca52.c
+++ b/libhb/deca52.c
@@ -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 */
diff --git a/libhb/encfaac.c b/libhb/encfaac.c
index c6a3f8a16..c8754f7d7 100644
--- a/libhb/encfaac.c
+++ b/libhb/encfaac.c
@@ -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:
diff --git a/libhb/encvorbis.c b/libhb/encvorbis.c
index 4bd36b43a..d02297195 100644
--- a/libhb/encvorbis.c
+++ b/libhb/encvorbis.c
@@ -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;
diff --git a/libhb/platform/macosx/encca_aac.c b/libhb/platform/macosx/encca_aac.c
index 5c5069cd4..4d6352511 100644
--- a/libhb/platform/macosx/encca_aac.c
+++ b/libhb/platform/macosx/encca_aac.c
@@ -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;
}