From 282ddc84776683667e417a62186be57b97be3eab Mon Sep 17 00:00:00 2001 From: Rodeo Date: Wed, 21 Nov 2012 18:29:34 +0000 Subject: Improve support for planar audio. - encavcodecaudio: use libavresample directly (instead of via the hb_audio_resample wrapper), and add support for planar output - hb_audio_resample: add support for planar input - hb_audio_remap: add support for planar input - deca52: output planar float samples (no re-interleaving) git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@5073 b64f7644-9d1e-0410-96f1-a4d463321fa5 --- libhb/audio_remap.c | 129 ++++++++++++++++++++++++-------- libhb/audio_remap.h | 8 +- libhb/audio_resample.c | 83 ++++++++++++--------- libhb/audio_resample.h | 8 +- libhb/deca52.c | 92 +++++++++++++++-------- libhb/decavcodec.c | 4 +- libhb/declpcm.c | 4 +- libhb/encavcodecaudio.c | 152 +++++++++++++++++++++++--------------- libhb/platform/macosx/encca_aac.c | 3 +- 9 files changed, 311 insertions(+), 172 deletions(-) (limited to 'libhb') diff --git a/libhb/audio_remap.c b/libhb/audio_remap.c index 6daaee9fb..afc9c3209 100644 --- a/libhb/audio_remap.c +++ b/libhb/audio_remap.c @@ -81,32 +81,100 @@ hb_chan_map_t hb_aac_chan_map = } }; -static void remap_planar(uint8_t *tmp_buf, uint8_t *samples, int nsamples, - int nchannels, int sample_size, int *remap_table) +static void remap_planar(uint8_t **samples, int nsamples, + int nchannels, int *remap_table) { - int ii, stride = nsamples * sample_size; - memcpy(tmp_buf, samples, nchannels * stride); + int ii; + uint8_t *tmp_buf[HB_AUDIO_REMAP_MAX_CHANNELS]; + memcpy(tmp_buf, samples, nchannels * sizeof(uint8_t*)); for (ii = 0; ii < nchannels; ii++) { - memcpy(samples + (ii * stride), - tmp_buf + (remap_table[ii] * stride), stride); + samples[ii] = tmp_buf[remap_table[ii]]; } } -static void remap_interleaved(uint8_t *tmp_buf, uint8_t *samples, int nsamples, - int nchannels, int sample_size, int *remap_table) +static void remap_u8_interleaved(uint8_t **samples, int nsamples, + int nchannels, int *remap_table) { - int ii, jj, stride = nchannels * sample_size; - memcpy(tmp_buf, samples, nsamples * stride); + int ii, jj; + uint8_t *samples_u8 = (*samples); + uint8_t tmp_buf[HB_AUDIO_REMAP_MAX_CHANNELS]; for (ii = 0; ii < nsamples; ii++) { + memcpy(tmp_buf, samples_u8, nchannels * sizeof(uint8_t)); for (jj = 0; jj < nchannels; jj++) { - memcpy(samples + (jj * sample_size), - tmp_buf + (remap_table[jj] * sample_size), sample_size); + samples_u8[jj] = tmp_buf[remap_table[jj]]; } - samples += stride; - tmp_buf += stride; + samples_u8 += nchannels; + } +} + +static void remap_s16_interleaved(uint8_t **samples, int nsamples, + int nchannels, int *remap_table) +{ + int ii, jj; + int16_t *samples_s16 = (int16_t*)(*samples); + int16_t tmp_buf[HB_AUDIO_REMAP_MAX_CHANNELS]; + for (ii = 0; ii < nsamples; ii++) + { + memcpy(tmp_buf, samples_s16, nchannels * sizeof(int16_t)); + for (jj = 0; jj < nchannels; jj++) + { + samples_s16[jj] = tmp_buf[remap_table[jj]]; + } + samples_s16 += nchannels; + } +} + +static void remap_s32_interleaved(uint8_t **samples, int nsamples, + int nchannels, int *remap_table) +{ + int ii, jj; + int32_t *samples_s32 = (int32_t*)(*samples); + int32_t tmp_buf[HB_AUDIO_REMAP_MAX_CHANNELS]; + for (ii = 0; ii < nsamples; ii++) + { + memcpy(tmp_buf, samples_s32, nchannels * sizeof(int32_t)); + for (jj = 0; jj < nchannels; jj++) + { + samples_s32[jj] = tmp_buf[remap_table[jj]]; + } + samples_s32 += nchannels; + } +} + +static void remap_flt_interleaved(uint8_t **samples, int nsamples, + int nchannels, int *remap_table) +{ + int ii, jj; + float *samples_flt = (float*)(*samples); + float tmp_buf[HB_AUDIO_REMAP_MAX_CHANNELS]; + for (ii = 0; ii < nsamples; ii++) + { + memcpy(tmp_buf, samples_flt, nchannels * sizeof(float)); + for (jj = 0; jj < nchannels; jj++) + { + samples_flt[jj] = tmp_buf[remap_table[jj]]; + } + samples_flt += nchannels; + } +} + +static void remap_dbl_interleaved(uint8_t **samples, int nsamples, + int nchannels, int *remap_table) +{ + int ii, jj; + double *samples_dbl = (double*)(*samples); + double tmp_buf[HB_AUDIO_REMAP_MAX_CHANNELS]; + for (ii = 0; ii < nsamples; ii++) + { + memcpy(tmp_buf, samples_dbl, nchannels * sizeof(double)); + for (jj = 0; jj < nchannels; jj++) + { + samples_dbl[jj] = tmp_buf[remap_table[jj]]; + } + samples_dbl += nchannels; } } @@ -133,11 +201,23 @@ hb_audio_remap_t* hb_audio_remap_init(enum AVSampleFormat sample_fmt, break; case AV_SAMPLE_FMT_U8: + remap->remap = &remap_u8_interleaved; + break; + case AV_SAMPLE_FMT_S16: + remap->remap = &remap_s16_interleaved; + break; + case AV_SAMPLE_FMT_S32: + remap->remap = &remap_s32_interleaved; + break; + case AV_SAMPLE_FMT_FLT: + remap->remap = &remap_flt_interleaved; + break; + case AV_SAMPLE_FMT_DBL: - remap->remap = &remap_interleaved; + remap->remap = &remap_dbl_interleaved; break; default: @@ -145,7 +225,6 @@ hb_audio_remap_t* hb_audio_remap_init(enum AVSampleFormat sample_fmt, 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) @@ -156,14 +235,6 @@ hb_audio_remap_t* hb_audio_remap_init(enum AVSampleFormat sample_fmt, 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; @@ -215,21 +286,15 @@ 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, uint8_t *samples, int nsamples) +void hb_audio_remap(hb_audio_remap_t *remap, uint8_t **samples, int nsamples) { if (remap != NULL && remap->remap_needed) { - // 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); + remap->remap(samples, nsamples, remap->nchannels, remap->table); } } diff --git a/libhb/audio_remap.h b/libhb/audio_remap.h index a776fe57b..0bdd23bb7 100644 --- a/libhb/audio_remap.h +++ b/libhb/audio_remap.h @@ -40,15 +40,13 @@ typedef struct typedef struct { int nchannels; - int sample_size; int remap_needed; - 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]; - void (*remap)(uint8_t *tmp_buf, uint8_t *samples, int nsamples, - int nchannels, int sample_size, int *remap_table); + void (*remap)(uint8_t **samples, int nsamples, + int nchannels, int *remap_table); } hb_audio_remap_t; /* @@ -88,7 +86,7 @@ void hb_audio_remap_free(hb_audio_remap_t *remap); * * The remap parameter can be NULL (no remapping). */ -void hb_audio_remap(hb_audio_remap_t *remap, uint8_t *samples, +void hb_audio_remap(hb_audio_remap_t *remap, uint8_t **samples, int nsamples); /* diff --git a/libhb/audio_resample.c b/libhb/audio_resample.c index 927a3b7c4..cc9b50d8b 100644 --- a/libhb/audio_resample.c +++ b/libhb/audio_resample.c @@ -12,27 +12,36 @@ #include "audio_resample.h" hb_audio_resample_t* hb_audio_resample_init(enum AVSampleFormat sample_fmt, - int hb_amixdown, int do_remix, - int normalize_mix_level) + int hb_amixdown, int normalize_mix) { hb_audio_resample_t *resample = calloc(1, sizeof(hb_audio_resample_t)); if (resample == NULL) { hb_error("hb_audio_resample_init: failed to allocate resample"); - return NULL; + goto fail; + } + + // avresample context, initialized in hb_audio_resample_update() + resample->avresample = NULL; + + // we don't support planar output yet + if (av_sample_fmt_is_planar(sample_fmt)) + { + hb_error("hb_audio_resample_init: planar output not supported ('%s')", + av_get_sample_fmt_name(sample_fmt)); + goto fail; } // convert mixdown to channel_layout/matrix_encoding combo - int channels, matrix_encoding; + int matrix_encoding; uint64_t channel_layout = hb_ff_mixdown_xlat(hb_amixdown, &matrix_encoding); - channels = av_get_channel_layout_nb_channels(channel_layout); - if (do_remix && (hb_amixdown == HB_AMIXDOWN_LEFT || - hb_amixdown == HB_AMIXDOWN_RIGHT)) + /* + * When downmixing, Dual Mono to Mono is a special case: + * the audio must remain 2-channel until all conversions are done. + */ + if (hb_amixdown == HB_AMIXDOWN_LEFT || hb_amixdown == HB_AMIXDOWN_RIGHT) { - /* When downmixing, Dual Mono to Mono is a special case: - * the audio must remain 2-channel until all conversions are done. */ - channels = 2; channel_layout = AV_CH_LAYOUT_STEREO; resample->dual_mono_downmix = 1; resample->dual_mono_right_only = (hb_amixdown == HB_AMIXDOWN_RIGHT); @@ -42,35 +51,34 @@ hb_audio_resample_t* hb_audio_resample_init(enum AVSampleFormat sample_fmt, resample->dual_mono_downmix = 0; } - // requested channel_layout - resample->out.channels = channels; + // requested output channel_layout, sample_fmt + resample->out.channels = av_get_channel_layout_nb_channels(channel_layout); resample->out.channel_layout = channel_layout; resample->out.matrix_encoding = matrix_encoding; - resample->out.normalize_mix_level = normalize_mix_level; - - // requested sample_fmt + resample->out.normalize_mix_level = normalize_mix; resample->out.sample_fmt = sample_fmt; resample->out.sample_size = av_get_bytes_per_sample(sample_fmt); // set default input characteristics - resample->in.sample_fmt = resample->out.sample_fmt; - resample->in.channel_layout = resample->out.channel_layout; - resample->in.center_mix_level = HB_MIXLEV_DEFAULT; - resample->in.surround_mix_level = HB_MIXLEV_DEFAULT; + resample->in.sample_fmt = resample->out.sample_fmt; + resample->in.channel_layout = resample->out.channel_layout; + resample->in.center_mix_level = HB_MIXLEV_DEFAULT; + resample->in.surround_mix_level = HB_MIXLEV_DEFAULT; // by default, no conversion needed - resample->resample_needed = 0; - resample->avresample = NULL; - resample->do_remix = !!do_remix; - + resample->resample_needed = 0; return resample; + +fail: + hb_audio_resample_free(resample); + return NULL; } void hb_audio_resample_set_channel_layout(hb_audio_resample_t *resample, uint64_t channel_layout, int channels) { - if (resample != NULL && resample->do_remix) + if (resample != NULL) { channel_layout = hb_ff_layout_xlat(channel_layout, channels); if (channel_layout == AV_CH_LAYOUT_STEREO_DOWNMIX) @@ -86,7 +94,7 @@ void hb_audio_resample_set_mix_levels(hb_audio_resample_t *resample, double surround_mix_level, double center_mix_level) { - if (resample != NULL && resample->do_remix) + if (resample != NULL) { resample->in.center_mix_level = center_mix_level; resample->in.surround_mix_level = surround_mix_level; @@ -193,7 +201,7 @@ void hb_audio_resample_free(hb_audio_resample_t *resample) } hb_buffer_t* hb_audio_resample(hb_audio_resample_t *resample, - void *samples, int nsamples) + uint8_t **samples, int nsamples) { if (resample == NULL) { @@ -224,7 +232,7 @@ hb_buffer_t* hb_audio_resample(hb_audio_resample_t *resample, out_samples = avresample_convert(resample->avresample, (void**)&out->data, out_linesize, nsamples, - (void**)&samples, in_linesize, nsamples); + (void**)samples, in_linesize, nsamples); if (out_samples <= 0) { @@ -243,24 +251,27 @@ hb_buffer_t* hb_audio_resample(hb_audio_resample_t *resample, out_size = (out_samples * resample->out.sample_size * resample->out.channels); out = hb_buffer_init(out_size); - memcpy(out->data, samples, out_size); + memcpy(out->data, samples[0], out_size); } - /* Dual Mono to Mono. + /* + * Dual Mono to Mono. * - * Copy all left or right samples to the first half of the buffer - * and halve the size */ + * Copy all left or right samples to the first half of the buffer and halve + * the buffer size. + */ if (resample->dual_mono_downmix) { - int ii; - int jj = !!resample->dual_mono_right_only; - float *audio_samples = (float*)out->data; + int ii, jj = !!resample->dual_mono_right_only; + int sample_size = resample->out.sample_size; + uint8_t *audio_samples = out->data; for (ii = 0; ii < out_samples; ii++) { - audio_samples[ii] = audio_samples[jj]; + memcpy(audio_samples + (ii * sample_size), + audio_samples + (jj * sample_size), sample_size); jj += 2; } - out->size = out_samples * resample->out.sample_size; + out->size = out_samples * sample_size; } return out; diff --git a/libhb/audio_resample.h b/libhb/audio_resample.h index baee471a6..62a536d61 100644 --- a/libhb/audio_resample.h +++ b/libhb/audio_resample.h @@ -27,7 +27,6 @@ typedef struct { - int do_remix; int dual_mono_downmix; int dual_mono_right_only; @@ -67,12 +66,9 @@ typedef struct * * Also sets the default audio input characteristics, so that they are the same * as the output characteristics (no conversion needed). - * - * If do_remix is 0, it will be assumed that any remixing was *already* done. */ hb_audio_resample_t* hb_audio_resample_init(enum AVSampleFormat sample_fmt, - int hb_amixdown, int do_remix, - int normalize_mix_level); + int hb_amixdown, int normalize_mix); /* The following functions set the audio input characteristics. * @@ -110,6 +106,6 @@ void hb_audio_resample_free(hb_audio_resample_t *resample); * resampling is only done when necessary. */ hb_buffer_t* hb_audio_resample(hb_audio_resample_t *resample, - void *samples, int nsamples); + uint8_t **samples, int nsamples); #endif /* AUDIO_RESAMPLE_H */ diff --git a/libhb/deca52.c b/libhb/deca52.c index 3a6e71e95..ba7c38485 100644 --- a/libhb/deca52.c +++ b/libhb/deca52.c @@ -35,12 +35,13 @@ struct hb_work_private_s hb_list_t *list; const AVCRC *crc_table; uint8_t frame[3840]; - uint8_t buf[1536 * 6 * sizeof(float)]; // decoded samples (1 frame, 6 channels) + uint8_t buf[6][6][256 * sizeof(float)]; // decoded frame (up to 6 channels, 6 blocks * 256 samples) + uint8_t *samples[6]; // pointers to the start of each plane (1 per channel) int nchannels; - int remap_table[6]; int use_mix_levels; uint64_t channel_layout; + hb_audio_remap_t *remap; hb_audio_resample_t *resample; }; @@ -133,17 +134,17 @@ static int deca52Init(hb_work_object_t *w, hb_job_t *job) pv->list = hb_list_init(); pv->crc_table = av_crc_get_table(AV_CRC_16_ANSI); - /* Downmixing */ + /* + * Decoding, remapping, downmixing + */ if (audio->config.out.codec != HB_ACODEC_AC3_PASS) { - /* We want AV_SAMPLE_FMT_FLT samples */ - pv->level = 1.0; - pv->dynamic_range_compression = - audio->config.out.dynamic_range_compression; - + /* + * Output AV_SAMPLE_FMT_FLT samples + */ pv->resample = hb_audio_resample_init(AV_SAMPLE_FMT_FLT, - audio->config.out.mixdown, 1, + audio->config.out.mixdown, audio->config.out.normalize_mix_level); if (pv->resample == NULL) { @@ -151,12 +152,39 @@ static int deca52Init(hb_work_object_t *w, hb_job_t *job) return 1; } - /* liba52 doesn't provide us with Lt/Rt mix levels. + /* + * Decode to AV_SAMPLE_FMT_FLTP + */ + pv->level = 1.0; + pv->dynamic_range_compression = + audio->config.out.dynamic_range_compression; + hb_audio_resample_set_sample_fmt(pv->resample, AV_SAMPLE_FMT_FLTP); + + /* + * liba52 doesn't provide Lt/Rt mix levels, only Lo/Ro. + * * When doing an Lt/Rt downmix, ignore mix levels - * (this matches what liba52's own downmix code does). */ + * (this matches what liba52's own downmix code does). + */ pv->use_mix_levels = !(audio->config.out.mixdown == HB_AMIXDOWN_DOLBY || audio->config.out.mixdown == HB_AMIXDOWN_DOLBYPLII); + + /* + * Remap from liba52 to Libav channel order + */ + pv->remap = hb_audio_remap_init(AV_SAMPLE_FMT_FLTP, &hb_libav_chan_map, + &hb_liba52_chan_map); + if (pv->remap == NULL) + { + hb_error("deca52Init: hb_audio_remap_init() failed"); + return 1; + } + } + else + { + pv->remap = NULL; + pv->resample = NULL; } return 0; @@ -179,6 +207,7 @@ static void deca52Close(hb_work_object_t *w) } hb_audio_resample_free(pv->resample); + hb_audio_remap_free(pv->remap); hb_list_empty(&pv->list); a52_free(pv->state); free(pv); @@ -317,9 +346,12 @@ static hb_buffer_t* Decode(hb_work_object_t *w) } else { - int i, j, k; + int i, j; + float *block_samples; - /* Feed liba52 */ + /* + * Feed liba52 + */ a52_frame(pv->state, pv->frame, &pv->flags, &pv->level, 0); /* @@ -348,11 +380,10 @@ static hb_buffer_t* Decode(hb_work_object_t *w) { pv->channel_layout = new_layout; pv->nchannels = av_get_channel_layout_nb_channels(new_layout); + hb_audio_remap_set_channel_layout(pv->remap, pv->channel_layout); hb_audio_resample_set_channel_layout(pv->resample, pv->channel_layout, pv->nchannels); - hb_audio_remap_build_table(&hb_libav_chan_map, &hb_liba52_chan_map, - pv->channel_layout, pv->remap_table); } if (pv->use_mix_levels) { @@ -366,28 +397,29 @@ static hb_buffer_t* Decode(hb_work_object_t *w) return NULL; } - // decode all blocks before downmixing + /* + * decode all blocks before downmixing + */ for (i = 0; i < 6; i++) { - float *samples_in, *samples_out; - a52_block(pv->state); - samples_in = (float*)a52_samples(pv->state); - samples_out = (float*)(pv->buf + - (i * pv->nchannels * 256 * sizeof(float))); - - // Planar -> interleaved, remap to Libav channel order - for (j = 0; j < 256; j++) + block_samples = (float*)a52_samples(pv->state); + + /* + * reset pv->samples (may have been modified by hb_audio_remap) + * + * copy samples to our internal buffer + */ + for (j = 0; j < pv->nchannels; j++) { - for (k = 0; k < pv->nchannels; k++) - { - samples_out[(pv->nchannels*j)+k] = - samples_in[(256*pv->remap_table[k])+j]; - } + pv->samples[j] = (uint8_t*)pv->buf[j]; + memcpy(pv->buf[j][i], block_samples, 256 * sizeof(float)); + block_samples += 256; } } - out = hb_audio_resample(pv->resample, (void*)pv->buf, 1536); + hb_audio_remap(pv->remap, pv->samples, 1536); + out = hb_audio_resample(pv->resample, pv->samples, 1536); } if (out != NULL) diff --git a/libhb/decavcodec.c b/libhb/decavcodec.c index dd3c8879d..5248d5f52 100644 --- a/libhb/decavcodec.c +++ b/libhb/decavcodec.c @@ -190,7 +190,7 @@ static int decavcodecaInit( hb_work_object_t * w, hb_job_t * job ) { pv->resample = hb_audio_resample_init(AV_SAMPLE_FMT_FLT, - w->audio->config.out.mixdown, 1, + w->audio->config.out.mixdown, w->audio->config.out.normalize_mix_level); if (pv->resample == NULL) { @@ -1481,7 +1481,7 @@ static void decodeAudio(hb_audio_t *audio, hb_work_private_t *pv, uint8_t *data, hb_log("decavcodec: hb_audio_resample_update() failed"); return; } - out = hb_audio_resample(pv->resample, (void*)frame.data[0], + out = hb_audio_resample(pv->resample, frame.extended_data, frame.nb_samples); } diff --git a/libhb/declpcm.c b/libhb/declpcm.c index e62e042d3..03210af81 100644 --- a/libhb/declpcm.c +++ b/libhb/declpcm.c @@ -163,7 +163,7 @@ static int declpcmInit( hb_work_object_t * w, hb_job_t * job ) pv->resample = hb_audio_resample_init(AV_SAMPLE_FMT_FLT, - w->audio->config.out.mixdown, 1, + w->audio->config.out.mixdown, w->audio->config.out.normalize_mix_level); if (pv->resample == NULL) { @@ -337,7 +337,7 @@ static hb_buffer_t *Decode( hb_work_object_t *w ) hb_log("declpcm: hb_audio_resample_update() failed"); return NULL; } - out = hb_audio_resample(pv->resample, (void*)pv->data, pv->nsamples); + out = hb_audio_resample(pv->resample, &pv->data, pv->nsamples); if (out != NULL) { diff --git a/libhb/encavcodecaudio.c b/libhb/encavcodecaudio.c index 867b56cc5..8da52d8b8 100644 --- a/libhb/encavcodecaudio.c +++ b/libhb/encavcodecaudio.c @@ -9,7 +9,6 @@ #include "hb.h" #include "hbffmpeg.h" -#include "audio_resample.h" struct hb_work_private_s { @@ -18,12 +17,13 @@ struct hb_work_private_s int out_discrete_channels; int samples_per_frame; + unsigned long max_output_bytes; unsigned long input_samples; - unsigned long output_bytes; + uint8_t * output_buf; + uint8_t * input_buf; hb_list_t * list; - uint8_t * buf; - hb_audio_resample_t *resample; + AVAudioResampleContext *avresample; }; static int encavcodecaInit( hb_work_object_t *, hb_job_t * ); @@ -46,8 +46,9 @@ static int encavcodecaInit(hb_work_object_t *w, hb_job_t *job) hb_audio_t *audio = w->audio; hb_work_private_t *pv = calloc(1, sizeof(hb_work_private_t)); - w->private_data = pv; - pv->job = job; + w->private_data = pv; + pv->job = job; + pv->list = hb_list_init(); codec = avcodec_find_encoder(w->codec_param); if (codec == NULL) @@ -113,29 +114,45 @@ static int encavcodecaInit(hb_work_object_t *w, hb_job_t *job) } av_dict_free(&av_opts); + pv->context = context; + pv->samples_per_frame = context->frame_size; + pv->input_samples = context->frame_size * context->channels; + pv->input_buf = malloc(pv->input_samples * sizeof(float)); + pv->max_output_bytes = (pv->input_samples * + av_get_bytes_per_sample(context->sample_fmt)); + // sample_fmt conversion - pv->resample = hb_audio_resample_init(context->sample_fmt, - audio->config.out.mixdown, 0, 0); - hb_audio_resample_set_sample_fmt(pv->resample, AV_SAMPLE_FMT_FLT); - if (hb_audio_resample_update(pv->resample)) + if (context->sample_fmt != AV_SAMPLE_FMT_FLT) { - hb_error("encavcodecaInit: hb_audio_resample_update() failed"); - hb_audio_resample_free(pv->resample); - return 1; + pv->output_buf = malloc(pv->max_output_bytes); + pv->avresample = avresample_alloc_context(); + if (pv->avresample == NULL) + { + hb_error("encavcodecaInit: avresample_alloc_context() failed"); + return 1; + } + av_opt_set_int(pv->avresample, "in_sample_fmt", + AV_SAMPLE_FMT_FLT, 0); + av_opt_set_int(pv->avresample, "out_sample_fmt", + context->sample_fmt, 0); + av_opt_set_int(pv->avresample, "in_channel_layout", + context->channel_layout, 0); + av_opt_set_int(pv->avresample, "out_channel_layout", + context->channel_layout, 0); + if (avresample_open(pv->avresample)) + { + hb_error("encavcodecaInit: avresample_open() failed"); + avresample_free(&pv->avresample); + return 1; + } + } + else + { + pv->avresample = NULL; + pv->output_buf = pv->input_buf; } - pv->context = context; - pv->samples_per_frame = context->frame_size; audio->config.out.samples_per_frame = pv->samples_per_frame; - pv->input_samples = pv->samples_per_frame * pv->out_discrete_channels; - - // Set a reasonable maximum output size - pv->output_bytes = (context->channels * context->frame_size * - av_get_bytes_per_sample(context->sample_fmt)); - - pv->buf = malloc(pv->input_samples * sizeof(float)); - - pv->list = hb_list_init(); if (context->extradata != NULL) { @@ -154,10 +171,9 @@ static int encavcodecaInit(hb_work_object_t *w, hb_job_t *job) **********************************************************************/ // Some encoders (e.g. flac) require a final NULL encode in order to // finalize things. -static void Finalize( hb_work_object_t * w ) +static void Finalize(hb_work_object_t *w) { - hb_work_private_t * pv = w->private_data; - hb_buffer_t * buf; + hb_work_private_t *pv = w->private_data; // Finalize with NULL input needed by FLAC to generate md5sum // in context extradata @@ -165,18 +181,19 @@ static void Finalize( hb_work_object_t * w ) // Prepare output packet AVPacket pkt; int got_packet; - buf = hb_buffer_init( pv->output_bytes ); + hb_buffer_t *buf = hb_buffer_init(pv->max_output_bytes); av_init_packet(&pkt); pkt.data = buf->data; pkt.size = buf->alloc; - avcodec_encode_audio2( pv->context, &pkt, NULL, &got_packet); - hb_buffer_close( &buf ); + avcodec_encode_audio2(pv->context, &pkt, NULL, &got_packet); + hb_buffer_close(&buf); // Then we need to recopy the header since it was modified - if ( pv->context->extradata ) + if (pv->context->extradata != NULL) { - memcpy( w->config->extradata.bytes, pv->context->extradata, pv->context->extradata_size ); + memcpy(w->config->extradata.bytes, pv->context->extradata, + pv->context->extradata_size); w->config->extradata.length = pv->context->extradata_size; } } @@ -196,19 +213,25 @@ static void encavcodecaClose(hb_work_object_t * w) hb_avcodec_close(pv->context); } - if (pv->buf != NULL) + if (pv->output_buf != NULL) + { + free(pv->output_buf); + } + if (pv->input_buf != NULL && pv->input_buf != pv->output_buf) { - free(pv->buf); - pv->buf = NULL; + free(pv->input_buf); } + pv->output_buf = pv->input_buf = NULL; if (pv->list != NULL) { hb_list_empty(&pv->list); } - hb_audio_resample_free(pv->resample); - pv->resample = NULL; + if (pv->avresample != NULL) + { + avresample_free(&pv->avresample); + } free(pv); w->private_data = NULL; @@ -219,7 +242,6 @@ static hb_buffer_t* Encode(hb_work_object_t *w) { hb_work_private_t *pv = w->private_data; hb_audio_t *audio = w->audio; - hb_buffer_t *resampled, *out; uint64_t pts, pos; if (hb_list_bytes(pv->list) < pv->input_samples * sizeof(float)) @@ -227,30 +249,47 @@ static hb_buffer_t* Encode(hb_work_object_t *w) return NULL; } - hb_list_getbytes(pv->list, pv->buf, pv->input_samples * sizeof(float), &pts, - &pos); - - // sample_fmt conversion - resampled = hb_audio_resample(pv->resample, (void*)pv->buf, - pv->samples_per_frame); + hb_list_getbytes(pv->list, pv->input_buf, pv->input_samples * sizeof(float), + &pts, &pos); // Prepare input frame - AVFrame frame; - frame.nb_samples= pv->samples_per_frame; - int size = av_samples_get_buffer_size(NULL, pv->context->channels, - frame.nb_samples, - pv->context->sample_fmt, 1); - avcodec_fill_audio_frame(&frame, pv->context->channels, - pv->context->sample_fmt, resampled->data, size, 1); - // Libav requires timebase of audio input frames to be in sample_rate units - frame.pts = pts + (90000 * pos / pv->out_discrete_channels / - sizeof(float) / audio->config.out.samplerate); + int out_linesize; + int out_size = av_samples_get_buffer_size(&out_linesize, + pv->context->channels, + pv->samples_per_frame, + pv->context->sample_fmt, 1); + AVFrame frame = { .nb_samples = pv->samples_per_frame, }; + avcodec_fill_audio_frame(&frame, + pv->context->channels, pv->context->sample_fmt, + pv->output_buf, out_size, 1); + if (pv->avresample != NULL) + { + int in_linesize; + av_samples_get_buffer_size(&in_linesize, pv->context->channels, + frame.nb_samples, AV_SAMPLE_FMT_FLT, 1); + int out_samples = avresample_convert(pv->avresample, + (void**)frame.extended_data, + out_linesize, frame.nb_samples, + (void**)&pv->input_buf, + in_linesize, frame.nb_samples); + if (out_samples != pv->samples_per_frame) + { + // we're not doing sample rate conversion, so this shouldn't happen + hb_log("encavcodecaWork: avresample_convert() failed"); + return NULL; + } + } + + // Libav requires that timebase of audio frames be in sample_rate units + frame.pts = pts + (90000 * pos / (sizeof(float) * + pv->out_discrete_channels * + audio->config.out.samplerate)); frame.pts = av_rescale(frame.pts, pv->context->sample_rate, 90000); // Prepare output packet AVPacket pkt; int got_packet; - out = hb_buffer_init(pv->output_bytes); + hb_buffer_t *out = hb_buffer_init(pv->max_output_bytes); av_init_packet(&pkt); pkt.data = out->data; pkt.size = out->alloc; @@ -260,7 +299,6 @@ static hb_buffer_t* Encode(hb_work_object_t *w) if (ret < 0) { hb_log("encavcodeca: avcodec_encode_audio failed"); - hb_buffer_close(&resampled); hb_buffer_close(&out); return NULL; } @@ -287,12 +325,10 @@ static hb_buffer_t* Encode(hb_work_object_t *w) } else { - hb_buffer_close(&resampled); hb_buffer_close(&out); return Encode(w); } - hb_buffer_close(&resampled); return out; } diff --git a/libhb/platform/macosx/encca_aac.c b/libhb/platform/macosx/encca_aac.c index 4d6352511..fe592e340 100644 --- a/libhb/platform/macosx/encca_aac.c +++ b/libhb/platform/macosx/encca_aac.c @@ -389,7 +389,8 @@ 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, (uint8_t*)buffers->mBuffers[0].mData, *npackets); + hb_audio_remap(pv->remap, (uint8_t**)(&buffers->mBuffers[0].mData), + (int)(*npackets)); return noErr; } -- cgit v1.2.3