diff options
author | Rodeo <[email protected]> | 2012-07-15 16:40:46 +0000 |
---|---|---|
committer | Rodeo <[email protected]> | 2012-07-15 16:40:46 +0000 |
commit | ebe7a46debf25f8c6b84320f69dd00d83a5a0b45 (patch) | |
tree | 74e1656d9dd884e96f0e4b5f8d0072dcf89ad515 /libhb | |
parent | 8dafff9bfd96dcbbd10247b0ef7eee4cfddfaa6e (diff) |
hb_audio_resample: libvaresample wrapper.
Avoids having code that's mostly identical in multiple files.
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@4838 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'libhb')
-rw-r--r-- | libhb/audio_resample.c | 170 | ||||
-rw-r--r-- | libhb/audio_resample.h | 81 | ||||
-rw-r--r-- | libhb/decavcodec.c | 187 | ||||
-rw-r--r-- | libhb/declpcm.c | 110 | ||||
-rw-r--r-- | libhb/encavcodecaudio.c | 183 |
5 files changed, 400 insertions, 331 deletions
diff --git a/libhb/audio_resample.c b/libhb/audio_resample.c new file mode 100644 index 000000000..21a831d3e --- /dev/null +++ b/libhb/audio_resample.c @@ -0,0 +1,170 @@ +/* audio_resample.c + * + * Copyright (c) 2003-2012 HandBrake Team + * This file is part of the HandBrake source code + * Homepage: <http://handbrake.fr/> + * It may be used under the terms of the GNU General Public License v2. + * For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html + */ + +#include "common.h" +#include "hbffmpeg.h" +#include "audio_resample.h" + +hb_audio_resample_t* hb_audio_resample_init(enum AVSampleFormat output_sample_fmt, + uint64_t output_channel_layout, + enum AVMatrixEncoding matrix_encoding) +{ + hb_audio_resample_t *resample = malloc(sizeof(hb_audio_resample_t)); + if (resample == NULL) + return NULL; + + resample->out.sample_fmt = output_sample_fmt; + resample->out.sample_size = av_get_bytes_per_sample(output_sample_fmt); + resample->out.channel_layout = output_channel_layout; + resample->out.channels = + av_get_channel_layout_nb_channels(output_channel_layout); + resample->out.matrix_encoding = matrix_encoding; + resample->resample_needed = 0; + resample->avresample = NULL; + + return resample; +} + +int hb_audio_resample_update(hb_audio_resample_t *resample, + enum AVSampleFormat new_sample_fmt, + uint64_t new_channel_layout, + int new_channels) +{ + if (resample == NULL) + { + hb_error("hb_audio_resample_update: resample is NULL"); + return 1; + } + + new_channel_layout = hb_ff_layout_xlat(new_channel_layout, new_channels); + + resample->resample_needed = + (resample->resample_needed || + resample->out.sample_fmt != new_sample_fmt || + resample->out.channel_layout != new_channel_layout); + + int resample_changed = + (resample->resample_needed && + (resample->in.sample_fmt != new_sample_fmt || + resample->in.channel_layout != new_channel_layout)); + + if (resample_changed || (resample->resample_needed && + resample->avresample == NULL)) + { + if (resample->avresample == NULL) + { + resample->avresample = avresample_alloc_context(); + if (resample->avresample == NULL) + { + hb_error("hb_audio_resample_update: avresample_alloc_context() failed"); + return 1; + } + + av_opt_set_int(resample->avresample, "out_sample_fmt", + resample->out.sample_fmt, 0); + av_opt_set_int(resample->avresample, "out_channel_layout", + resample->out.channel_layout, 0); + av_opt_set_int(resample->avresample, "matrix_encoding", + resample->out.matrix_encoding, 0); + } + else if (resample_changed) + { + avresample_close(resample->avresample); + } + + if (av_get_bytes_per_sample(new_sample_fmt) <= 2) + av_opt_set_int(resample->avresample, "internal_sample_fmt", + AV_SAMPLE_FMT_S16P, 0); + av_opt_set_int(resample->avresample, "in_sample_fmt", + new_sample_fmt, 0); + av_opt_set_int(resample->avresample, "in_channel_layout", + new_channel_layout, 0); + + if (avresample_open(resample->avresample) < 0) + { + hb_error("hb_audio_resample_update: avresample_open() failed"); + // avresample won't open, start over + avresample_free(&resample->avresample); + return 1; + } + + resample->in.sample_fmt = new_sample_fmt; + resample->in.channel_layout = new_channel_layout; + } + + return 0; +} + +void hb_audio_resample_free(hb_audio_resample_t *resample) +{ + if (resample != NULL) + { + if (resample->avresample != NULL) + { + avresample_free(&resample->avresample); + } + free(resample); + } +} + +hb_buffer_t* hb_audio_resample(hb_audio_resample_t *resample, + void *samples, int nsamples) +{ + if (resample == NULL) + { + hb_error("hb_audio_resample: resample is NULL"); + return NULL; + } + if (resample->resample_needed && resample->avresample == NULL) + { + hb_error("hb_audio_resample: resample needed but libavresample context " + "is NULL"); + return NULL; + } + + int out_size; + hb_buffer_t *out; + + if (resample->resample_needed) + { + int out_samples; + // set in/out linesize and out_size + av_samples_get_buffer_size(&resample->in.linesize, + resample->in.channels, nsamples, + resample->in.sample_fmt, 0); + out_size = av_samples_get_buffer_size(&resample->out.linesize, + resample->out.channels, nsamples, + resample->out.sample_fmt, 0); + out = hb_buffer_init(out_size); + + out_samples = avresample_convert(resample->avresample, + (void**)&out->data, + resample->out.linesize, nsamples, + (void**)&samples, + resample->in.linesize, nsamples); + + if (out_samples < 0) + { + hb_log("hb_audio_resample: avresample_convert() failed"); + hb_buffer_close(&out); + return NULL; + } + out->size = (out_samples * + resample->out.sample_size * resample->out.channels); + } + else + { + out_size = (nsamples * + resample->out.sample_size * resample->out.channels); + out = hb_buffer_init(out_size); + memcpy(out->data, samples, out_size); + } + + return out; +} diff --git a/libhb/audio_resample.h b/libhb/audio_resample.h new file mode 100644 index 000000000..5982905e6 --- /dev/null +++ b/libhb/audio_resample.h @@ -0,0 +1,81 @@ +/* audio_resample.h + * + * Copyright (c) 2003-2012 HandBrake Team + * This file is part of the HandBrake source code + * Homepage: <http://handbrake.fr/> + * It may be used under the terms of the GNU General Public License v2. + * For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html + */ + +/* Implements a libavresample wrapper for convenience. + * + * Supports sample_fmt and channel_layout conversion. + * + * sample_rate conversion will come later (libavresample doesn't support + * sample_rate conversion with float samples yet). */ + +#ifndef AUDIO_RESAMPLE_H +#define AUDIO_RESAMPLE_H + +#include <stdint.h> +#include "libavutil/audioconvert.h" +#include "libavresample/avresample.h" + +typedef struct +{ + int resample_needed; + AVAudioResampleContext *avresample; + + struct + { + int channels; + int linesize; + uint64_t channel_layout; + enum AVSampleFormat sample_fmt; + } in; + + struct + { + int channels; + int linesize; + int sample_size; + uint64_t channel_layout; + enum AVSampleFormat sample_fmt; + enum AVMatrixEncoding matrix_encoding; + } out; +} hb_audio_resample_t; + +/* Initialize an hb_audio_resample_t to convert audio to the requested + * sample_fmt and channel_layout, using the specified matrix_encoding. + * + * Input characteristics are set via hb_audio_resample_update(). + */ +hb_audio_resample_t* hb_audio_resample_init(enum AVSampleFormat output_sample_fmt, + uint64_t output_channel_layout, + enum AVMatrixEncoding matrix_encoding); + +/* Update an hb_audio_resample_t, setting the input sample characteristics. + * + * Can be called whenever the input type may change. + * + * new_channel_layout is sanitized automatically. + */ +int hb_audio_resample_update(hb_audio_resample_t *resample, + enum AVSampleFormat new_sample_fmt, + uint64_t new_channel_layout, + int new_channels); + +/* Free an hb_audio_remsample_t. */ +void hb_audio_resample_free(hb_audio_resample_t *resample); + +/* Convert input samples to the requested output characteristics + * (sample_fmt and channel_layout + matrix_encoding). + * + * Returns an hb_buffer_t with the converted output. + * + * resampling is only done when necessary. + */ +hb_buffer_t* hb_audio_resample(hb_audio_resample_t *resample, + void *samples, int nsamples); + +#endif /* AUDIO_RESAMPLE_H */ diff --git a/libhb/decavcodec.c b/libhb/decavcodec.c index a32228bf1..0d5e44929 100644 --- a/libhb/decavcodec.c +++ b/libhb/decavcodec.c @@ -41,6 +41,7 @@ #include "hb.h" #include "hbffmpeg.h" #include "audio_remap.h" +#include "audio_resample.h" static void compute_frame_duration( hb_work_private_t *pv ); static void flushDelayQueue( hb_work_private_t *pv ); @@ -100,13 +101,7 @@ struct hb_work_private_s int cadence[12]; int wait_for_keyframe; - AVAudioResampleContext *avresample; - int resample; - int out_channels; - int stereo_downmix_mode; - uint64_t out_channel_layout; - uint64_t resample_channel_layout; - enum AVSampleFormat resample_sample_fmt; + hb_audio_resample_t *resample; }; static void decodeAudio( hb_audio_t * audio, hb_work_private_t *pv, uint8_t *data, int size, int64_t pts ); @@ -191,10 +186,19 @@ static int decavcodecaInit( hb_work_object_t * w, hb_job_t * job ) pv->title = w->title; pv->list = hb_list_init(); - // initialize output settings for avresample - pv->out_channels = hb_mixdown_get_discrete_channel_count(w->audio->config.out.mixdown); - pv->out_channel_layout = hb_ff_mixdown_xlat(w->audio->config.out.mixdown, - &pv->stereo_downmix_mode); + /* Downmixing & sample_fmt conversion */ + if (!(w->audio->config.out.codec & HB_ACODEC_PASS_FLAG)) + { + int mode; + uint64_t layout = hb_ff_mixdown_xlat(w->audio->config.out.mixdown, + &mode); + pv->resample = hb_audio_resample_init(AV_SAMPLE_FMT_FLT, layout, mode); + if (pv->resample == NULL) + { + hb_log("decavcodecaInit: hb_audio_resample_init() failed"); + return 1; + } + } codec = avcodec_find_decoder( w->codec_param ); if ( pv->title->opaque_priv ) @@ -259,10 +263,7 @@ static void closePrivData( hb_work_private_t ** ppv ) { hb_list_empty( &pv->list ); } - if ( pv->avresample ) - { - avresample_free( &pv->avresample ); - } + hb_audio_resample_free(pv->resample); free( pv ); } *ppv = NULL; @@ -1404,153 +1405,69 @@ hb_work_object_t hb_decavcodecv = .bsinfo = decavcodecvBSInfo }; -static hb_buffer_t * downmixAudio(hb_work_private_t *pv, - hb_audio_t *audio, - AVFrame *frame) -{ - uint64_t in_layout; - int resample_changed; - - in_layout = hb_ff_layout_xlat(pv->context->channel_layout, pv->context->channels); - pv->resample = (pv->resample || - pv->out_channel_layout != in_layout || - pv->context->sample_fmt != AV_SAMPLE_FMT_FLT); - resample_changed = (pv->resample && - (pv->resample_channel_layout != in_layout || - pv->resample_sample_fmt != pv->context->sample_fmt)); - - if (resample_changed || (pv->resample && pv->avresample == NULL)) - { - if (pv->avresample == NULL) - { - pv->avresample = avresample_alloc_context(); - if (pv->avresample == NULL) - { - hb_error("Failed to initialize avresample"); - return NULL; - } - // output settings only need to be set once - av_opt_set_int(pv->avresample, "out_sample_fmt", AV_SAMPLE_FMT_FLT, 0); - av_opt_set_int(pv->avresample, "out_channel_layout", pv->out_channel_layout, 0); - av_opt_set_int(pv->avresample, "matrix_encoding", pv->stereo_downmix_mode, 0); - } - else if (resample_changed) - { - avresample_close(pv->avresample); - } - - av_opt_set_int(pv->avresample, "in_channel_layout", in_layout, 0); - av_opt_set_int(pv->avresample, "in_sample_fmt", pv->context->sample_fmt, 0); - if (av_get_bytes_per_sample(pv->context->sample_fmt) <= 2) - av_opt_set_int(pv->avresample, "internal_sample_fmt", AV_SAMPLE_FMT_S16P, 0); - - if (avresample_open(pv->avresample) < 0) - { - hb_error("Failed to open libavresample"); - return NULL; - } - - pv->resample_channel_layout = in_layout; - pv->resample_sample_fmt = pv->context->sample_fmt; - } - - hb_buffer_t *buf; - int out_size, out_linesize, sample_size; - sample_size = av_get_bytes_per_sample(AV_SAMPLE_FMT_FLT); - out_size = av_samples_get_buffer_size(&out_linesize, pv->out_channels, - frame->nb_samples, AV_SAMPLE_FMT_FLT, !pv->resample); - buf = hb_buffer_init(out_size); - - if (pv->resample) - { - int out_samples; - out_samples = avresample_convert(pv->avresample, - (void**)&buf->data, out_linesize, frame->nb_samples, - (void**)frame->data, frame->linesize[0], frame->nb_samples); - - if (out_samples < 0) - { - hb_error("avresample_convert() failed"); - return NULL; - } - buf->size = out_samples * sample_size * pv->out_channels; - } - else - { - memcpy(buf->data, frame->data[0], out_size); - buf->size = frame->nb_samples * sample_size * pv->out_channels; - } - - return buf; -} - -static void decodeAudio( hb_audio_t * audio, hb_work_private_t *pv, uint8_t *data, int size, int64_t pts ) +static void decodeAudio(hb_audio_t *audio, hb_work_private_t *pv, uint8_t *data, + int size, int64_t pts) { AVCodecContext *context = pv->context; - int pos = 0; int loop_limit = 256; + int pos = 0; - // If we are givn a pts, use it. - // But don't loose partial ticks. - if ( pts != -1 && (int64_t)pv->pts_next != pts ) + // If we are given a pts, use it; but don't lose partial ticks. + if (pts != -1 && (int64_t)pv->pts_next != pts) pv->pts_next = pts; - while ( pos < size ) + while (pos < size) { AVFrame frame; int got_frame; AVPacket avp; - av_init_packet( &avp ); + av_init_packet(&avp); avp.data = data + pos; avp.size = size - pos; - avp.pts = pv->pts_next; - avp.dts = AV_NOPTS_VALUE; + avp.pts = pv->pts_next; + avp.dts = AV_NOPTS_VALUE; - int len = avcodec_decode_audio4( context, &frame, &got_frame, &avp ); - if ( len < 0 ) + int len = avcodec_decode_audio4(context, &frame, &got_frame, &avp); + if ((len < 0) || (!got_frame && !(loop_limit--))) { return; } - if ( !got_frame ) - { - if ( !(loop_limit--) ) - return; - } else + { loop_limit = 256; + } pos += len; - if( got_frame ) + + if (got_frame) { + hb_buffer_t *out; double duration = frame.nb_samples * pv->duration; double pts_next = pv->pts_next + duration; - // DTS-HD can be passed through to mkv - if( audio->config.out.codec & HB_ACODEC_PASS_FLAG ) + if (audio->config.out.codec & HB_ACODEC_PASS_FLAG) { - // Note that even though we are doing passthru, we had - // to decode so that we know the stop time and the - // pts of the next audio packet. - hb_buffer_t * buf; - - buf = hb_buffer_init( avp.size ); - memcpy( buf->data, avp.data, avp.size ); - buf->s.start = pv->pts_next; - buf->s.duration = duration; - buf->s.stop = pts_next; - hb_list_add( pv->list, buf ); - pv->pts_next = pts_next; - continue; + // Note that even though we are doing passthru, we had to decode + // so that we know the stop time and the pts of the next audio + // packet. + out = hb_buffer_init(avp.size); + memcpy(out->data, avp.data, avp.size); } - - hb_buffer_t * buf = downmixAudio( pv, audio, &frame ); - if ( buf != NULL ) + else { - buf->s.start = pv->pts_next; - buf->s.duration = duration; - buf->s.stop = pts_next; - hb_list_add( pv->list, buf ); + hb_audio_resample_update(pv->resample, pv->context->sample_fmt, + pv->context->channel_layout, + pv->context->channels); + out = hb_audio_resample(pv->resample, (void*)frame.data[0], + frame.nb_samples); + } - pv->pts_next = pts_next; + if (out != NULL) + { + out->s.start = pv->pts_next; + out->s.duration = duration; + out->s.stop = pts_next; + pv->pts_next = pts_next; + hb_list_add(pv->list, out); } } } diff --git a/libhb/declpcm.c b/libhb/declpcm.c index 86dd6e823..e48bf5db7 100644 --- a/libhb/declpcm.c +++ b/libhb/declpcm.c @@ -8,7 +8,9 @@ */ #include "hb.h" +#include "hbffmpeg.h" #include "audio_remap.h" +#include "audio_resample.h" struct hb_work_private_s { @@ -32,12 +34,7 @@ struct hb_work_private_s uint8_t * data; uint32_t alloc_size; - AVAudioResampleContext *avresample; - int resample; - int out_channels; - int stereo_downmix_mode; - uint64_t out_channel_layout; - uint64_t resample_channel_layout; + hb_audio_resample_t *resample; }; static hb_buffer_t * Decode( hb_work_object_t * w ); @@ -68,79 +65,6 @@ static const uint64_t hdr2layout[] = AV_CH_LAYOUT_STEREO, AV_CH_LAYOUT_STEREO, }; -static hb_buffer_t * downmixAudio(hb_work_private_t *pv, - hb_audio_t *audio) -{ - int64_t in_layout; - int resample_changed; - - in_layout = hdr2layout[pv->nchannels - 1]; - pv->resample = pv->resample || (pv->out_channel_layout != in_layout); - resample_changed = pv->resample && (pv->resample_channel_layout != in_layout); - - if (resample_changed || (pv->resample && pv->avresample == NULL)) - { - if (pv->avresample == NULL) - { - pv->avresample = avresample_alloc_context(); - if (pv->avresample == NULL) - { - hb_error("Failed to initialize avresample"); - return NULL; - } - // some settings only need to be set once - av_opt_set_int(pv->avresample, "in_sample_fmt", AV_SAMPLE_FMT_FLT, 0); - av_opt_set_int(pv->avresample, "out_sample_fmt", AV_SAMPLE_FMT_FLT, 0); - av_opt_set_int(pv->avresample, "out_channel_layout", pv->out_channel_layout, 0); - av_opt_set_int(pv->avresample, "matrix_encoding", pv->stereo_downmix_mode, 0); - } - else if (resample_changed) - { - avresample_close(pv->avresample); - } - - av_opt_set_int(pv->avresample, "in_channel_layout", in_layout, 0); - - if (avresample_open(pv->avresample) < 0) - { - hb_error("Failed to open libavresample"); - return NULL; - } - - pv->resample_channel_layout = in_layout; - } - - hb_buffer_t *buf; - int out_size, out_linesize, sample_size; - sample_size = av_get_bytes_per_sample(AV_SAMPLE_FMT_FLT); - out_size = av_samples_get_buffer_size(&out_linesize, pv->out_channels, - pv->nsamples, AV_SAMPLE_FMT_FLT, !pv->resample); - buf = hb_buffer_init(out_size); - - if (pv->resample) - { - int in_linesize, out_samples; - in_linesize = pv->nsamples * pv->nchannels * sample_size; - out_samples = avresample_convert(pv->avresample, - (void**)&buf->data, out_linesize, pv->nsamples, - (void**)&pv->data, in_linesize, pv->nsamples); - - if (out_samples < 0) - { - hb_error("avresample_convert() failed"); - return NULL; - } - buf->size = out_samples * sample_size * pv->out_channels; - } - else - { - memcpy(buf->data, pv->data, out_size); - buf->size = pv->nsamples * sample_size * pv->out_channels; - } - - return buf; -} - static void lpcmInfo( hb_work_object_t *w, hb_buffer_t *in ) { hb_work_private_t * pv = w->private_data; @@ -238,10 +162,14 @@ static int declpcmInit( hb_work_object_t * w, hb_job_t * job ) w->private_data = pv; pv->job = job; - // initialize output settings for avresample - pv->out_channels = hb_mixdown_get_discrete_channel_count(w->audio->config.out.mixdown); - pv->out_channel_layout = hb_ff_mixdown_xlat(w->audio->config.out.mixdown, - &pv->stereo_downmix_mode); + int mode; + uint64_t layout = hb_ff_mixdown_xlat(w->audio->config.out.mixdown, &mode); + pv->resample = hb_audio_resample_init(AV_SAMPLE_FMT_FLT, layout, mode); + if (pv->resample == NULL) + { + hb_error("declpcmInit: hb_audio_resample_init() failed"); + return 1; + } return 0; } @@ -401,7 +329,13 @@ static hb_buffer_t *Decode( hb_work_object_t *w ) } hb_buffer_t *out; - out = downmixAudio( pv, w->audio ); + hb_audio_resample_update(pv->resample, AV_SAMPLE_FMT_FLT, + hdr2layout[pv->nchannels - 1], pv->nchannels); + out = hb_audio_resample(pv->resample, (void*)pv->data, pv->nsamples); + if (out == NULL) + { + return NULL; + } out->s.start = pv->next_pts; out->s.duration = pv->duration; @@ -417,10 +351,7 @@ static void declpcmClose( hb_work_object_t * w ) if ( pv ) { - if ( pv->avresample ) - { - avresample_free( &pv->avresample ); - } + hb_audio_resample_free(pv->resample); free( pv->data ); free( pv ); w->private_data = 0; @@ -444,7 +375,8 @@ static int declpcmBSInfo( hb_work_object_t *w, const hb_buffer_t *b, info->rate_base = 1; info->bitrate = bitrate; info->flags = ( b->data[3] << 16 ) | ( b->data[4] << 8 ) | b->data[5]; - info->channel_layout = hdr2layout[nchannels - 1]; + info->channel_layout = hb_ff_layout_xlat(hdr2layout[nchannels - 1], + nchannels); info->channel_map = &hb_libav_chan_map; info->samples_per_frame = ( duration * rate ) / 90000; diff --git a/libhb/encavcodecaudio.c b/libhb/encavcodecaudio.c index 5871f306b..37cb78769 100644 --- a/libhb/encavcodecaudio.c +++ b/libhb/encavcodecaudio.c @@ -10,6 +10,7 @@ #include "hb.h" #include "hbffmpeg.h" #include "audio_remap.h" +#include "audio_resample.h" struct hb_work_private_s { @@ -23,8 +24,8 @@ struct hb_work_private_s hb_list_t * list; uint8_t * buf; - AVAudioResampleContext *avresample; - hb_audio_remap_t *remap; + hb_audio_remap_t *remap; + hb_audio_resample_t *resample; }; static int encavcodecaInit( hb_work_object_t *, hb_job_t * ); @@ -61,17 +62,11 @@ static int encavcodecaInit( hb_work_object_t * w, hb_job_t * job ) context = avcodec_alloc_context3(codec); int mode; - context->channel_layout = hb_ff_mixdown_xlat(audio->config.out.mixdown, &mode); - pv->out_discrete_channels = hb_mixdown_get_discrete_channel_count(audio->config.out.mixdown); - - // channel remapping - // note: unnecessary once everything is downmixed using libavresample - pv->remap = hb_audio_remap_init(context->channel_layout, &hb_libav_chan_map, - audio->config.in.channel_map); - if (pv->remap == NULL) - { - hb_log("encavcodecaInit: hb_audio_remap_init() failed"); - } + context->channel_layout = hb_ff_mixdown_xlat(audio->config.out.mixdown, + &mode); + context->channels = pv->out_discrete_channels = + hb_mixdown_get_discrete_channel_count(audio->config.out.mixdown); + context->sample_rate = audio->config.out.samplerate; AVDictionary *av_opts = NULL; if (w->codec_param == CODEC_ID_AAC) @@ -94,8 +89,6 @@ static int encavcodecaInit( hb_work_object_t * w, hb_job_t * job ) if( audio->config.out.compression_level >= 0 ) context->compression_level = audio->config.out.compression_level; - context->sample_rate = audio->config.out.samplerate; - context->channels = pv->out_discrete_channels; // Try to set format to float. Fallback to whatever is supported. hb_ff_set_sample_fmt( context, codec ); @@ -113,6 +106,26 @@ static int encavcodecaInit( hb_work_object_t * w, hb_job_t * job ) } av_dict_free( &av_opts ); + // channel remapping + pv->remap = hb_audio_remap_init(context->channel_layout, &hb_libav_chan_map, + audio->config.in.channel_map); + if (pv->remap == NULL) + { + hb_log("encavcodecaInit: hb_audio_remap_init() failed"); + } + + // sample_fmt conversion + pv->resample = hb_audio_resample_init(context->sample_fmt, + context->channel_layout, + AV_MATRIX_ENCODING_NONE); + if (hb_audio_resample_update(pv->resample, AV_SAMPLE_FMT_FLT, + context->channel_layout, context->channels)) + { + hb_error("encavcodecaInit: hb_audio_resample_update() failed"); + hb_audio_resample_free(pv->resample); + return 1; + } + pv->context = context; audio->config.out.samples_per_frame = pv->samples_per_frame = context->frame_size; @@ -133,31 +146,6 @@ static int encavcodecaInit( hb_work_object_t * w, hb_job_t * job ) w->config->extradata.length = context->extradata_size; } - // Check if sample format conversion is necessary - if (AV_SAMPLE_FMT_FLT != pv->context->sample_fmt) - { - // Set up avresample to do conversion - pv->avresample = avresample_alloc_context(); - if (pv->avresample == NULL) - { - hb_error("Failed to initialize avresample"); - return 1; - } - - uint64_t layout; - layout = hb_ff_layout_xlat(context->channel_layout, context->channels); - av_opt_set_int(pv->avresample, "in_channel_layout", layout, 0); - av_opt_set_int(pv->avresample, "out_channel_layout", layout, 0); - 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); - - if (avresample_open(pv->avresample) < 0) - { - hb_error("Failed to open avresample"); - avresample_free(&pv->avresample); - return 1; - } - } return 0; } @@ -221,116 +209,97 @@ static void encavcodecaClose(hb_work_object_t * w) hb_list_empty(&pv->list); } - if (pv->avresample != NULL) - { - avresample_free(&pv->avresample); - } + hb_audio_remap_free(pv->remap); + pv->remap = NULL; - if (pv->remap != NULL) - { - hb_audio_remap_free(pv->remap); - } + hb_audio_resample_free(pv->resample); + pv->resample = NULL; free(pv); w->private_data = NULL; } } -static void convertAudioFormat( hb_work_private_t *pv, AVFrame *frame ) -{ - if (pv->avresample != NULL) - { - int out_samples, out_linesize; - - av_samples_get_buffer_size(&out_linesize, pv->context->channels, - frame->nb_samples, pv->context->sample_fmt, 0); - - out_samples = avresample_convert(pv->avresample, - (void **)frame->data, out_linesize, frame->nb_samples, - (void **)frame->data, frame->linesize[0], frame->nb_samples); - - if (out_samples < 0) - { - hb_error("avresample_convert() failed"); - } - } -} - -static hb_buffer_t * Encode( hb_work_object_t * w ) +static hb_buffer_t* Encode(hb_work_object_t *w) { - hb_work_private_t * pv = w->private_data; + hb_work_private_t *pv = w->private_data; + hb_audio_t *audio = w->audio; + hb_buffer_t *resampled, *out; uint64_t pts, pos; - hb_audio_t * audio = w->audio; - hb_buffer_t * buf; - if( hb_list_bytes( pv->list ) < pv->input_samples * sizeof( float ) ) + if (hb_list_bytes(pv->list) < pv->input_samples * sizeof(float)) { return NULL; } - hb_list_getbytes( pv->list, pv->buf, pv->input_samples * sizeof( float ), - &pts, &pos); + hb_list_getbytes(pv->list, pv->buf, pv->input_samples * sizeof(float), &pts, + &pos); + // channel remapping and sample_fmt conversion hb_audio_remap(pv->remap, (hb_sample_t*)pv->buf, pv->samples_per_frame); + resampled = hb_audio_resample(pv->resample, (void*)pv->buf, + pv->samples_per_frame); // 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, pv->buf, size, 1); - frame.pts = pts + 90000 * pos / pv->out_discrete_channels / sizeof( float ) / audio->config.out.samplerate; - - // libav requires that timebase of audio input frames to be - // in sample_rate units. - frame.pts = av_rescale( frame.pts, pv->context->sample_rate, 90000); - - // Do we need to convert our internal float format? - convertAudioFormat(pv, &frame); + 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); + frame.pts = av_rescale(frame.pts, pv->context->sample_rate, 90000); // Prepare output packet AVPacket pkt; int got_packet; - buf = hb_buffer_init( pv->output_bytes ); + out = hb_buffer_init(pv->output_bytes); av_init_packet(&pkt); - pkt.data = buf->data; - pkt.size = buf->alloc; + pkt.data = out->data; + pkt.size = out->alloc; // Encode - int ret = avcodec_encode_audio2( pv->context, &pkt, &frame, &got_packet); - if ( ret < 0 ) + int ret = avcodec_encode_audio2(pv->context, &pkt, &frame, &got_packet); + if (ret < 0) { - hb_log( "encavcodeca: avcodec_encode_audio failed" ); - hb_buffer_close( &buf ); + hb_log("encavcodeca: avcodec_encode_audio failed"); + hb_buffer_close(&resampled); + hb_buffer_close(&out); return NULL; } - if ( got_packet && pkt.size ) + if (got_packet && pkt.size) { - buf->size = pkt.size; + out->size = pkt.size; - // The output pts from libav is in context->time_base. Convert - // it back to our timebase. + // The output pts from libav is in context->time_base. Convert it back + // to our timebase. // // Also account for the "delay" factor that libav seems to arbitrarily - // subtract from the packet. Not sure WTH they think they are doing - // by offseting the value in a negative direction. - buf->s.start = av_rescale_q( pkt.pts + pv->context->delay, - pv->context->time_base, (AVRational){ 1, 90000 }); + // subtract from the packet. Not sure WTH they think they are doing by + // offsetting the value in a negative direction. + out->s.start = av_rescale_q(pv->context->delay + pkt.pts, + pv->context->time_base, + (AVRational){1, 90000}); - buf->s.stop = buf->s.start + 90000 * pv->samples_per_frame / audio->config.out.samplerate; + out->s.stop = out->s.start + (90000 * pv->samples_per_frame / + audio->config.out.samplerate); - buf->s.type = AUDIO_BUF; - buf->s.frametype = HB_FRAME_AUDIO; + out->s.type = AUDIO_BUF; + out->s.frametype = HB_FRAME_AUDIO; } else { - hb_buffer_close( &buf ); - return Encode( w ); + hb_buffer_close(&resampled); + hb_buffer_close(&out); + return Encode(w); } - return buf; + hb_buffer_close(&resampled); + return out; } static hb_buffer_t * Flush( hb_work_object_t * w ) |