diff options
Diffstat (limited to 'libhb/audio_remap.c')
-rw-r--r-- | libhb/audio_remap.c | 183 |
1 files changed, 136 insertions, 47 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; } |