summaryrefslogtreecommitdiffstats
path: root/libhb
diff options
context:
space:
mode:
authorRodeo <[email protected]>2012-07-15 16:40:46 +0000
committerRodeo <[email protected]>2012-07-15 16:40:46 +0000
commitebe7a46debf25f8c6b84320f69dd00d83a5a0b45 (patch)
tree74e1656d9dd884e96f0e4b5f8d0072dcf89ad515 /libhb
parent8dafff9bfd96dcbbd10247b0ef7eee4cfddfaa6e (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.c170
-rw-r--r--libhb/audio_resample.h81
-rw-r--r--libhb/decavcodec.c187
-rw-r--r--libhb/declpcm.c110
-rw-r--r--libhb/encavcodecaudio.c183
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 )