diff options
author | Rodeo <[email protected]> | 2012-10-20 23:29:33 +0000 |
---|---|---|
committer | Rodeo <[email protected]> | 2012-10-20 23:29:33 +0000 |
commit | 305fc5798105e9a16f83868116d0a38a2919a638 (patch) | |
tree | 607b57a009cfa57fb6191fec6655df42167675a1 /libhb | |
parent | 4916c07f34cf97a79ca76f8163a9e7e258491bce (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
Diffstat (limited to 'libhb')
-rw-r--r-- | libhb/audio_remap.c | 183 | ||||
-rw-r--r-- | libhb/audio_remap.h | 68 | ||||
-rw-r--r-- | libhb/deca52.c | 22 | ||||
-rw-r--r-- | libhb/encfaac.c | 16 | ||||
-rw-r--r-- | libhb/encvorbis.c | 14 | ||||
-rw-r--r-- | libhb/platform/macosx/encca_aac.c | 8 |
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; } |