summaryrefslogtreecommitdiffstats
path: root/libhb/audio_remap.c
diff options
context:
space:
mode:
Diffstat (limited to 'libhb/audio_remap.c')
-rw-r--r--libhb/audio_remap.c183
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;
}