summaryrefslogtreecommitdiffstats
path: root/libhb
diff options
context:
space:
mode:
Diffstat (limited to 'libhb')
-rw-r--r--libhb/audio_remap.c148
-rw-r--r--libhb/audio_remap.h53
-rw-r--r--libhb/common.h4
-rw-r--r--libhb/deca52.c4
-rw-r--r--libhb/decavcodec.c262
-rw-r--r--libhb/decdca.c4
-rw-r--r--libhb/declpcm.c155
-rw-r--r--libhb/downmix.c1640
-rw-r--r--libhb/downmix.h67
-rw-r--r--libhb/dvd.c1
-rw-r--r--libhb/dvdnav.c1
-rw-r--r--libhb/encavcodec.c20
-rw-r--r--libhb/encavcodecaudio.c213
-rw-r--r--libhb/encfaac.c46
-rw-r--r--libhb/encvorbis.c60
-rw-r--r--libhb/hb.c101
-rw-r--r--libhb/hbffmpeg.h20
-rw-r--r--libhb/mcdeint.c17
-rw-r--r--libhb/mcdeint.h3
-rw-r--r--libhb/module.defs2
-rw-r--r--libhb/platform/macosx/encca_aac.c41
-rw-r--r--libhb/stream.c27
-rw-r--r--libhb/sync.c36
23 files changed, 757 insertions, 2168 deletions
diff --git a/libhb/audio_remap.c b/libhb/audio_remap.c
new file mode 100644
index 000000000..6d3877d3d
--- /dev/null
+++ b/libhb/audio_remap.c
@@ -0,0 +1,148 @@
+/* audio_remap.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_remap.h"
+
+// source: libavutil/audioconvert.h
+hb_chan_map_t hb_libav_chan_map =
+{
+ {
+ AV_CH_FRONT_LEFT,
+ AV_CH_FRONT_RIGHT,
+ AV_CH_FRONT_CENTER,
+ AV_CH_LOW_FREQUENCY,
+ AV_CH_BACK_LEFT,
+ AV_CH_BACK_RIGHT,
+ AV_CH_FRONT_LEFT_OF_CENTER,
+ AV_CH_FRONT_RIGHT_OF_CENTER,
+ AV_CH_BACK_CENTER,
+ AV_CH_SIDE_LEFT,
+ AV_CH_SIDE_RIGHT,
+ 0
+ }
+};
+
+// source: liba52 documentation
+hb_chan_map_t hb_liba52_chan_map =
+{
+ {
+ AV_CH_LOW_FREQUENCY,
+ AV_CH_FRONT_LEFT,
+ AV_CH_FRONT_CENTER,
+ AV_CH_FRONT_RIGHT,
+ AV_CH_BACK_CENTER,
+ AV_CH_SIDE_LEFT,
+ AV_CH_SIDE_RIGHT,
+ 0
+ }
+};
+
+// source: libdca documentation and libavcodec/dca.c
+hb_chan_map_t hb_libdca_chan_map =
+{
+ {
+ AV_CH_FRONT_LEFT_OF_CENTER,
+ AV_CH_FRONT_CENTER,
+ AV_CH_FRONT_RIGHT_OF_CENTER,
+ AV_CH_FRONT_LEFT,
+ AV_CH_FRONT_RIGHT,
+ AV_CH_SIDE_LEFT,
+ AV_CH_SIDE_RIGHT,
+ AV_CH_LOW_FREQUENCY,
+ 0
+ }
+};
+
+// source: http://xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-800004.3.9
+hb_chan_map_t hb_vorbis_chan_map =
+{
+ {
+ AV_CH_FRONT_LEFT,
+ AV_CH_FRONT_CENTER,
+ AV_CH_FRONT_RIGHT,
+ AV_CH_SIDE_LEFT,
+ AV_CH_SIDE_RIGHT,
+ AV_CH_BACK_LEFT,
+ AV_CH_BACK_CENTER,
+ AV_CH_BACK_RIGHT,
+ AV_CH_LOW_FREQUENCY,
+ 0
+ }
+};
+
+// source: https://developer.apple.com/library/mac/#documentation/musicaudio/reference/CoreAudioDataTypesRef/Reference/reference.html
+hb_chan_map_t hb_aac_chan_map =
+{
+ {
+ AV_CH_FRONT_CENTER,
+ AV_CH_FRONT_LEFT_OF_CENTER,
+ AV_CH_FRONT_RIGHT_OF_CENTER,
+ AV_CH_FRONT_LEFT,
+ AV_CH_FRONT_RIGHT,
+ AV_CH_SIDE_LEFT,
+ AV_CH_SIDE_RIGHT,
+ AV_CH_BACK_LEFT,
+ AV_CH_BACK_RIGHT,
+ AV_CH_BACK_CENTER,
+ AV_CH_LOW_FREQUENCY,
+ 0
+ }
+};
+
+int* hb_audio_remap_build_table(uint64_t layout, hb_chan_map_t *map_in, hb_chan_map_t *map_out)
+{
+ int ii, jj, idx, remap_idx, *remap_table;
+ uint64_t *input_order, *output_order;
+
+ remap_table = calloc(HB_AUDIO_REMAP_MAX_CHANNELS, sizeof(int));
+ if (!remap_table)
+ return NULL;
+
+ idx = 0;
+ input_order = map_in->channel_order;
+ output_order = map_out->channel_order;
+ for (ii = 0; output_order[ii]; ii++)
+ {
+ if (layout & output_order[ii])
+ {
+ remap_idx = 0;
+ for (jj = 0; input_order[jj]; jj++)
+ {
+ if (output_order[ii] == input_order[jj])
+ {
+ remap_table[idx++] = remap_idx++;
+ }
+ else if (layout & input_order[jj])
+ {
+ remap_idx++;
+ }
+ }
+ }
+ }
+
+ return remap_table;
+}
+
+void hb_audio_remap(int nchannels, int nsamples, hb_sample_t *samples, int *remap_table)
+{
+ int ii, jj;
+ hb_sample_t tmp[HB_AUDIO_REMAP_MAX_CHANNELS];
+
+ for (ii = 0; ii < nsamples; ii++)
+ {
+ memcpy(tmp, samples, nchannels * sizeof(hb_sample_t));
+ for (jj = 0; jj < nchannels; jj++)
+ {
+ samples[jj] = tmp[remap_table[jj]];
+ }
+ samples += nchannels;
+ }
+} \ No newline at end of file
diff --git a/libhb/audio_remap.h b/libhb/audio_remap.h
new file mode 100644
index 000000000..32ee3e9cb
--- /dev/null
+++ b/libhb/audio_remap.h
@@ -0,0 +1,53 @@
+/* audio_remap.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
+ */
+
+/* This file handles the following two scenarios:
+ *
+ * 1) remapping from liba52/libdca order to libav order
+ * - this allows downmixing liba52/libdca sources with libavresample
+ *
+ * 2) remapping from libav order to aac/vorbis order
+ * - this allows encoding audio without libavcodec (faac, ca_aac, libvorbis)
+ *
+ * Thus we only need to support:
+ *
+ * a) channels found in liba52/libdca layouts
+ * b) channels found in HB_AMIXDOWN_* layouts
+ *
+ * Notes:
+ *
+ * Left/Right Surround -> Side Left/Right
+ * Left/Right Rear Surround -> Back Left/Right */
+
+#ifndef AUDIO_REMAP_H
+#define AUDIO_REMAP_H
+
+#include <stdint.h>
+
+// we only need to support the 11 "most common" channels
+#define HB_AUDIO_REMAP_MAX_CHANNELS 11
+
+typedef float hb_sample_t;
+
+typedef struct
+{
+ uint64_t channel_order[HB_AUDIO_REMAP_MAX_CHANNELS+1];
+} hb_chan_map_t;
+
+// used to convert between various channel orders
+extern hb_chan_map_t hb_libav_chan_map;
+extern hb_chan_map_t hb_liba52_chan_map;
+extern hb_chan_map_t hb_libdca_chan_map;
+extern hb_chan_map_t hb_vorbis_chan_map;
+extern hb_chan_map_t hb_aac_chan_map;
+
+int* hb_audio_remap_build_table(uint64_t layout, hb_chan_map_t *map_in, hb_chan_map_t *map_out);
+void hb_audio_remap(int nchannels, int nsamples, hb_sample_t *samples, int *remap_table);
+
+#endif /* AUDIO_REMAP_H */
diff --git a/libhb/common.h b/libhb/common.h
index 16c7acff8..99aae30a1 100644
--- a/libhb/common.h
+++ b/libhb/common.h
@@ -20,7 +20,6 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
-#include "libavutil/audioconvert.h"
/*
* It seems WinXP doesn't align the stack of new threads to 16 bytes.
@@ -99,7 +98,8 @@ typedef struct hb_lock_s hb_lock_t;
#else
#define PRIVATE const
#endif
-#include "downmix.h"
+#include "audio_remap.h"
+#include "libavutil/audioconvert.h"
hb_list_t * hb_list_init();
int hb_list_count( hb_list_t * );
diff --git a/libhb/deca52.c b/libhb/deca52.c
index 22bfb55da..0c1708de2 100644
--- a/libhb/deca52.c
+++ b/libhb/deca52.c
@@ -8,7 +8,7 @@
*/
#include "hb.h"
-#include "downmix.h"
+#include "audio_remap.h"
#include "a52dec/a52.h"
#include "libavutil/crc.h"
@@ -484,7 +484,7 @@ static int deca52BSInfo( hb_work_object_t *w, const hb_buffer_t *b,
info->channel_layout |= AV_CH_LOW_FREQUENCY;
}
- info->channel_map = &hb_ac3_chan_map;
+ info->channel_map = &hb_liba52_chan_map;
return 1;
}
diff --git a/libhb/decavcodec.c b/libhb/decavcodec.c
index 875a94c67..a32228bf1 100644
--- a/libhb/decavcodec.c
+++ b/libhb/decavcodec.c
@@ -40,8 +40,7 @@
#include "hb.h"
#include "hbffmpeg.h"
-#include "downmix.h"
-#include "libavcodec/audioconvert.h"
+#include "audio_remap.h"
static void compute_frame_duration( hb_work_private_t *pv );
static void flushDelayQueue( hb_work_private_t *pv );
@@ -98,9 +97,16 @@ struct hb_work_private_s
int sws_width;
int sws_height;
int sws_pix_fmt;
- hb_downmix_t *downmix;
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;
};
static void decodeAudio( hb_audio_t * audio, hb_work_private_t *pv, uint8_t *data, int size, int64_t pts );
@@ -178,19 +184,19 @@ static int decavcodecaInit( hb_work_object_t * w, hb_job_t * job )
hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );
w->private_data = pv;
- pv->job = job;
- if ( job )
+ pv->job = job;
+ if (job)
pv->title = job->title;
else
pv->title = w->title;
- pv->list = hb_list_init();
+ pv->list = hb_list_init();
- int codec_id = w->codec_param;
- /*XXX*/
- if ( codec_id == 0 )
- codec_id = CODEC_ID_MP2;
+ // 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);
- codec = avcodec_find_decoder( codec_id );
+ codec = avcodec_find_decoder( w->codec_param );
if ( pv->title->opaque_priv )
{
AVFormatContext *ic = (AVFormatContext*)pv->title->opaque_priv;
@@ -200,7 +206,7 @@ static int decavcodecaInit( hb_work_object_t * w, hb_job_t * job )
}
else
{
- pv->parser = av_parser_init( codec_id );
+ pv->parser = av_parser_init( w->codec_param );
pv->context = avcodec_alloc_context3(codec);
hb_ff_set_sample_fmt( pv->context, codec );
@@ -211,36 +217,6 @@ static int decavcodecaInit( hb_work_object_t * w, hb_job_t * job )
return 1;
}
- // DTS: work around lack of 6.0/6.1 support in libhb
- if (hb_ff_dts_disable_xch(pv->context))
- {
- hb_deep_log(2, "decavcodecaInit: found DTS-ES, requesting DTS core");
- }
- else if ((!pv->context->channels || !pv->context->channel_layout) &&
- (w->audio->config.in.codec == HB_ACODEC_DCA_HD) &&
- ((w->audio->config.in.channel_layout & ~AV_CH_LOW_FREQUENCY) == AV_CH_LAYOUT_5POINT0))
- {
- /* XXX: when we are demuxing the stream ourselves, it seems we have no
- * channel count/layout info in the context until we decode audio for
- * the first time. If the scan info says the source is 5.0 or 5.1,
- * make sure XCh processing is disabled in Libav before decoding. */
- pv->context->request_channels = pv->context->channels =
- av_get_channel_layout_nb_channels(w->audio->config.in.channel_layout);
- pv->context->channel_layout = w->audio->config.in.channel_layout;
- hb_deep_log(2, "decavcodecaInit: scan detected DTS 5.0/5.1, disabling XCh processing");
- }
-
- if ( w->audio != NULL )
- {
- if ( hb_need_downmix( w->audio->config.in.channel_layout,
- w->audio->config.out.mixdown) )
- {
- pv->downmix = hb_downmix_init(w->audio->config.in.channel_layout,
- w->audio->config.out.mixdown);
- hb_downmix_set_chan_map( pv->downmix, &hb_smpte_chan_map, &hb_smpte_chan_map );
- }
- }
-
return 0;
}
@@ -283,14 +259,9 @@ static void closePrivData( hb_work_private_t ** ppv )
{
hb_list_empty( &pv->list );
}
- if ( pv->buffer )
- {
- av_free( pv->buffer );
- pv->buffer = NULL;
- }
- if ( pv->downmix )
+ if ( pv->avresample )
{
- hb_downmix_close( &(pv->downmix) );
+ avresample_free( &pv->avresample );
}
free( pv );
}
@@ -366,10 +337,9 @@ static int decavcodecaWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
// total samples to per-channel samples. 'sample_rate' converts
// per-channel samples to seconds per sample and the 90000
// is mpeg ticks per second.
- if ( pv->context->sample_rate && pv->context->channels )
+ if ( pv->context->sample_rate )
{
- pv->duration = 90000. /
- (double)( pv->context->sample_rate * pv->context->channels );
+ pv->duration = 90000. / (double)( pv->context->sample_rate );
}
decodeAudio( w->audio, pv, pout, pout_len, cur );
}
@@ -409,11 +379,8 @@ static int decavcodecaBSInfo( hb_work_object_t *w, const hb_buffer_t *buf,
{
return decavcodecaInfo( w, info );
}
- // XXX
- // We should parse the bitstream to find its parameters but for right
- // now we just return dummy values if there's a codec that will handle it.
- AVCodec *codec = avcodec_find_decoder( w->codec_param? w->codec_param :
- CODEC_ID_MP2 );
+
+ AVCodec *codec = avcodec_find_decoder( w->codec_param );
if ( ! codec )
{
// there's no ffmpeg codec for this audio type - give up
@@ -430,8 +397,6 @@ static int decavcodecaBSInfo( hb_work_object_t *w, const hb_buffer_t *buf,
{
return -1;
}
- uint8_t *buffer = av_malloc( AVCODEC_MAX_AUDIO_FRAME_SIZE );
- int out_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
unsigned char *pbuffer;
int pos, pbuffer_size;
@@ -457,21 +422,16 @@ static int decavcodecaBSInfo( hb_work_object_t *w, const hb_buffer_t *buf,
pos += len;
if ( pbuffer_size > 0 )
{
+ AVFrame frame;
+ int got_frame;
AVPacket avp;
av_init_packet( &avp );
avp.data = pbuffer;
avp.size = pbuffer_size;
- len = avcodec_decode_audio3( context, (int16_t*)buffer,
- &out_size, &avp );
+ len = avcodec_decode_audio4( context, &frame, &got_frame, &avp );
if ( len > 0 && context->sample_rate > 0 )
{
- // DTS: work around lack of 6.0/6.1 support in libhb
- if( hb_ff_dts_disable_xch( context ) )
- {
- hb_deep_log( 2, "decavcodecaBSInfo: found DTS-ES, requesting DTS core" );
- }
- int isamp = av_get_bytes_per_sample( context->sample_fmt );
info->bitrate = context->bit_rate;
info->rate = context->sample_rate;
info->rate_base = 1;
@@ -479,11 +439,7 @@ static int decavcodecaBSInfo( hb_work_object_t *w, const hb_buffer_t *buf,
hb_ff_layout_xlat(context->channel_layout,
context->channels);
ret = 1;
- if ( context->channels && isamp )
- {
- info->samples_per_frame = out_size /
- (isamp * context->channels);
- }
+ info->samples_per_frame = frame.nb_samples;
break;
}
}
@@ -493,9 +449,8 @@ static int decavcodecaBSInfo( hb_work_object_t *w, const hb_buffer_t *buf,
info->profile = context->profile;
info->level = context->level;
- info->channel_map = &hb_smpte_chan_map;
+ info->channel_map = &hb_libav_chan_map;
- av_free( buffer );
if ( parser != NULL )
av_parser_close( parser );
hb_avcodec_close( context );
@@ -1007,6 +962,8 @@ static int decavcodecvInit( hb_work_object_t * w, hb_job_t * job )
pv->title = w->title;
pv->list = hb_list_init();
+ // XXX: A bug in libav prores decoder causes incorrect decoding when
+ // threaded decode is enabled. So disable it till this bug is fixed.
if( pv->job && pv->job->title && !pv->job->title->has_resolution_change &&
w->codec_param != CODEC_ID_PRORES )
{
@@ -1024,8 +981,6 @@ static int decavcodecvInit( hb_work_object_t * w, hb_job_t * job )
pv->context = avcodec_alloc_context3(codec);
avcodec_copy_context( pv->context, ic->streams[pv->title->video_id]->codec);
pv->context->workaround_bugs = FF_BUG_AUTODETECT;
- // Depricated but still used by Libav (twits!)
- pv->context->error_recognition = FF_ER_CAREFUL;
pv->context->err_recognition = AV_EF_CRCCHECK;
pv->context->error_concealment = FF_EC_GUESS_MVS|FF_EC_DEBLOCK;
@@ -1049,8 +1004,6 @@ static int decavcodecvInit( hb_work_object_t * w, hb_job_t * job )
pv->parser = av_parser_init( w->codec_param );
pv->context = avcodec_alloc_context3( codec );
pv->context->workaround_bugs = FF_BUG_AUTODETECT;
- // Depricated but still used by Libav (twits!)
- pv->context->error_recognition = FF_ER_CAREFUL;
pv->context->err_recognition = AV_EF_CRCCHECK;
pv->context->error_concealment = FF_EC_GUESS_MVS|FF_EC_DEBLOCK;
init_video_avcodec_context( pv );
@@ -1451,28 +1404,81 @@ hb_work_object_t hb_decavcodecv =
.bsinfo = decavcodecvBSInfo
};
-static hb_buffer_t * downmixAudio(
- hb_audio_t *audio,
- hb_work_private_t *pv,
- hb_sample_t *buffer,
- int channels,
- int nsamples )
+static hb_buffer_t * downmixAudio(hb_work_private_t *pv,
+ hb_audio_t *audio,
+ AVFrame *frame)
{
- hb_buffer_t * buf = NULL;
+ 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 ( pv->downmix )
+ if (resample_changed || (pv->resample && pv->avresample == NULL))
{
- int n_ch_samples = nsamples / channels;
- int out_channels = hb_mixdown_get_discrete_channel_count( audio->config.out.mixdown );
+ 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);
+ }
- buf = hb_buffer_init( n_ch_samples * out_channels * sizeof(float) );
- hb_sample_t *samples = (hb_sample_t *)buf->data;
- hb_downmix(pv->downmix, samples, buffer, n_ch_samples);
+ 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
{
- buf = hb_buffer_init( nsamples * sizeof(float) );
- memcpy( buf->data, buffer, nsamples * sizeof(float) );
+ memcpy(buf->data, frame->data[0], out_size);
+ buf->size = frame->nb_samples * sample_size * pv->out_channels;
}
return buf;
@@ -1490,13 +1496,8 @@ static void decodeAudio( hb_audio_t * audio, hb_work_private_t *pv, uint8_t *dat
pv->pts_next = pts;
while ( pos < size )
{
- float *buffer = pv->buffer;
- if ( buffer == NULL )
- {
- pv->buffer = av_malloc( AVCODEC_MAX_AUDIO_FRAME_SIZE );
- buffer = pv->buffer;
- }
-
+ AVFrame frame;
+ int got_frame;
AVPacket avp;
av_init_packet( &avp );
avp.data = data + pos;
@@ -1504,14 +1505,12 @@ static void decodeAudio( hb_audio_t * audio, hb_work_private_t *pv, uint8_t *dat
avp.pts = pv->pts_next;
avp.dts = AV_NOPTS_VALUE;
- int out_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
- int nsamples;
- int len = avcodec_decode_audio3( context, (int16_t*)buffer, &out_size, &avp );
+ int len = avcodec_decode_audio4( context, &frame, &got_frame, &avp );
if ( len < 0 )
{
return;
}
- if ( len == 0 )
+ if ( !got_frame )
{
if ( !(loop_limit--) )
return;
@@ -1520,11 +1519,9 @@ static void decodeAudio( hb_audio_t * audio, hb_work_private_t *pv, uint8_t *dat
loop_limit = 256;
pos += len;
- if( out_size > 0 )
+ if( got_frame )
{
- int isamp = av_get_bytes_per_sample( context->sample_fmt );
- nsamples = out_size / isamp;
- double duration = nsamples * pv->duration;
+ double duration = frame.nb_samples * pv->duration;
double pts_next = pv->pts_next + duration;
// DTS-HD can be passed through to mkv
@@ -1545,50 +1542,15 @@ static void decodeAudio( hb_audio_t * audio, hb_work_private_t *pv, uint8_t *dat
continue;
}
- // We require floats for the output format. If
- // we got something different convert it.
- if ( context->sample_fmt != AV_SAMPLE_FMT_FLT )
+ hb_buffer_t * buf = downmixAudio( pv, audio, &frame );
+ if ( buf != NULL )
{
- // Note: av_audio_convert seems to be a work-in-progress but
- // looks like it will eventually handle general audio
- // mixdowns which would allow us much more flexibility
- // in handling multichannel audio in HB. If we were doing
- // anything more complicated than a one-for-one format
- // conversion we'd probably want to cache the converter
- // context in the pv.
- AVAudioConvert *ctx;
-
- ctx = av_audio_convert_alloc( AV_SAMPLE_FMT_FLT, 1,
- context->sample_fmt, 1,
- NULL, 0 );
-
- // get output buffer size then malloc a buffer
- buffer = av_malloc( nsamples * sizeof(hb_sample_t) );
-
- // we're doing straight sample format conversion which
- // behaves as if there were only one channel.
- const void * const ibuf[6] = { pv->buffer };
- void * const obuf[6] = { buffer };
- const int istride[6] = { isamp };
- const int ostride[6] = { sizeof(hb_sample_t) };
-
- av_audio_convert( ctx, obuf, ostride, ibuf, istride, nsamples );
- av_audio_convert_free( ctx );
- }
-
- hb_buffer_t * buf;
- buf = downmixAudio( audio, pv, buffer, context->channels, nsamples );
- 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;
+ buf->s.start = pv->pts_next;
+ buf->s.duration = duration;
+ buf->s.stop = pts_next;
+ hb_list_add( pv->list, buf );
- // if we allocated a buffer for sample format conversion, free it
- if ( buffer != pv->buffer )
- {
- av_free( buffer );
+ pv->pts_next = pts_next;
}
}
}
diff --git a/libhb/decdca.c b/libhb/decdca.c
index 9f426d6a4..17d0e7755 100644
--- a/libhb/decdca.c
+++ b/libhb/decdca.c
@@ -8,7 +8,7 @@
*/
#include "hb.h"
-#include "downmix.h"
+#include "audio_remap.h"
#include "dca.h"
@@ -425,7 +425,7 @@ static int decdcaBSInfo( hb_work_object_t *w, const hb_buffer_t *b,
info->channel_layout |= AV_CH_LOW_FREQUENCY;
}
- info->channel_map = &hb_qt_chan_map;
+ info->channel_map = &hb_libdca_chan_map;
dca_free( state );
return 1;
diff --git a/libhb/declpcm.c b/libhb/declpcm.c
index 5c6a0e4a1..86dd6e823 100644
--- a/libhb/declpcm.c
+++ b/libhb/declpcm.c
@@ -8,14 +8,14 @@
*/
#include "hb.h"
-#include "downmix.h"
+#include "audio_remap.h"
struct hb_work_private_s
{
hb_job_t *job;
uint32_t size; /* frame size in bytes */
- uint32_t chunks; /* number of samples pairs if paired */
- uint32_t samples; /* frame size in samples */
+ uint32_t nchunks; /* number of samples pairs if paired */
+ uint32_t nsamples; /* frame size in samples */
uint32_t pos; /* buffer offset for next input data */
int64_t next_pts; /* pts for next output frame */
@@ -29,6 +29,15 @@ struct hb_work_private_s
uint8_t sample_size; /* bits per sample */
uint8_t frame[HB_DVD_READ_BUFFER_SIZE*2];
+ 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;
};
static hb_buffer_t * Decode( hb_work_object_t * w );
@@ -53,12 +62,85 @@ static const int hdr2samplerate[] = { 48000, 96000, 44100, 32000 };
static const int hdr2samplesize[] = { 16, 20, 24, 16 };
static const uint64_t hdr2layout[] =
{
- AV_CH_LAYOUT_MONO, AV_CH_LAYOUT_STEREO,
- AV_CH_LAYOUT_2_1, AV_CH_LAYOUT_2_2,
- AV_CH_LAYOUT_5POINT0, AV_CH_LAYOUT_2_2|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER,
- AV_CH_LAYOUT_STEREO, AV_CH_LAYOUT_STEREO,
+ AV_CH_LAYOUT_MONO, AV_CH_LAYOUT_STEREO,
+ AV_CH_LAYOUT_2_1, AV_CH_LAYOUT_QUAD,
+ AV_CH_LAYOUT_5POINT0_BACK, AV_CH_LAYOUT_6POINT0_FRONT,
+ 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;
@@ -99,8 +181,8 @@ static void lpcmInfo( hb_work_object_t *w, hb_buffer_t *in )
hb_log( "declpcm: illegal frame offset %d", pv->offset );
pv->offset = 2; /*XXX*/
}
- pv->samplerate = hdr2samplerate[ ( in->data[4] >> 4 ) & 0x3 ];
- pv->nchannels = ( in->data[4] & 7 ) + 1;
+ pv->nchannels = ( in->data[4] & 7 ) + 1;
+ pv->samplerate = hdr2samplerate[ ( in->data[4] >> 4 ) & 0x3 ];
pv->sample_size = hdr2samplesize[in->data[4] >> 6];
// 20 and 24 bit lpcm is always encoded in sample pairs. So take this
@@ -142,10 +224,10 @@ static void lpcmInfo( hb_work_object_t *w, hb_buffer_t *in )
149 ) / 150;
pv->duration = frames * 150;
- pv->chunks = ( pv->duration * pv->nchannels * pv->samplerate +
+ pv->nchunks = ( pv->duration * pv->nchannels * pv->samplerate +
samples_per_chunk - 1 ) / ( 90000 * samples_per_chunk );
- pv->samples = ( pv->duration * pv->nchannels * pv->samplerate ) / 90000;
- pv->size = pv->chunks * chunk_size;
+ pv->nsamples = ( pv->duration * pv->samplerate ) / 90000;
+ pv->size = pv->nchunks * chunk_size;
pv->next_pts = in->s.start;
}
@@ -154,7 +236,13 @@ static int declpcmInit( hb_work_object_t * w, hb_job_t * job )
{
hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );
w->private_data = pv;
- pv->job = job;
+ 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);
+
return 0;
}
@@ -215,20 +303,19 @@ static int declpcmWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
static hb_buffer_t *Decode( hb_work_object_t *w )
{
hb_work_private_t *pv = w->private_data;
- hb_buffer_t *out;
- if (pv->samples == 0)
+ if (pv->nsamples == 0)
return NULL;
- out = hb_buffer_init( pv->samples * sizeof( float ) );
-
- out->s.start = pv->next_pts;
- out->s.duration = pv->duration;
- pv->next_pts += pv->duration;
- out->s.stop = pv->next_pts;
+ int size = pv->nsamples * pv->nchannels * sizeof( float );
+ if (pv->alloc_size != size)
+ {
+ pv->data = realloc( pv->data, size );
+ pv->alloc_size = size;
+ }
- float *odat = (float *)out->data;
- int count = pv->chunks / pv->nchannels;
+ float *odat = (float *)pv->data;
+ int count = pv->nchunks / pv->nchannels;
switch( pv->sample_size )
{
@@ -312,14 +399,30 @@ static hb_buffer_t *Decode( hb_work_object_t *w )
}
} break;
}
+
+ hb_buffer_t *out;
+ out = downmixAudio( pv, w->audio );
+
+ out->s.start = pv->next_pts;
+ out->s.duration = pv->duration;
+ pv->next_pts += pv->duration;
+ out->s.stop = pv->next_pts;
+
return out;
}
static void declpcmClose( hb_work_object_t * w )
{
- if ( w->private_data )
+ hb_work_private_t * pv = w->private_data;
+
+ if ( pv )
{
- free( w->private_data );
+ if ( pv->avresample )
+ {
+ avresample_free( &pv->avresample );
+ }
+ free( pv->data );
+ free( pv );
w->private_data = 0;
}
}
@@ -342,7 +445,7 @@ static int declpcmBSInfo( hb_work_object_t *w, const hb_buffer_t *b,
info->bitrate = bitrate;
info->flags = ( b->data[3] << 16 ) | ( b->data[4] << 8 ) | b->data[5];
info->channel_layout = hdr2layout[nchannels - 1];
- info->channel_map = &hb_qt_chan_map;
+ info->channel_map = &hb_libav_chan_map;
info->samples_per_frame = ( duration * rate ) / 90000;
return 1;
diff --git a/libhb/downmix.c b/libhb/downmix.c
index e5ed1c599..e69de29bb 100644
--- a/libhb/downmix.c
+++ b/libhb/downmix.c
@@ -1,1640 +0,0 @@
-/* downmix.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 <string.h>
-#include <stdlib.h>
-#include <inttypes.h>
-#include "common.h"
-#include "downmix.h"
-
-#define LVL_PLUS6DB 2.0
-#define LVL_PLUS3DB 1.4142135623730951
-#define LVL_3DB 0.7071067811865476
-#define LVL_45DB 0.5946035575013605
-#define LVL_6DB 0.5
-
-#define LVL_SQRT_1_4 0.5
-#define LVL_SQRT_3_4 0.866025404
-
-#define HB_CH_FRONT_LEFT 0x00000001
-#define HB_CH_FRONT_RIGHT 0x00000002
-#define HB_CH_FRONT_CENTER 0x00000004
-#define HB_CH_LOW_FREQUENCY 0x00000008
-#define HB_CH_BACK_LEFT 0x00000010
-#define HB_CH_BACK_RIGHT 0x00000020
-#define HB_CH_BACK_CENTER 0x00000040
-#define HB_CH_SIDE_LEFT 0x00000080
-#define HB_CH_SIDE_RIGHT 0x00000100
-
-#define HB_CH_SURROUND_MASK 0x000001f0
-#define HB_CH_MASK 0x000007ff
-
-#define HB_CH_DOLBY 0x00000800
-#define HB_CH_DPLII 0x00001000
-
-#define DOWNMIX_MONO 0
-#define DOWNMIX_STEREO 1
-#define DOWNMIX_3F 2
-#define DOWNMIX_2F1R 3
-#define DOWNMIX_3F1R 4
-#define DOWNMIX_2F2R 5
-#define DOWNMIX_3F2R 6
-#define DOWNMIX_3F4R 7
-#define DOWNMIX_DOLBY 8
-#define DOWNMIX_DPLII 9
-#define DOWNMIX_NUM_MODES 10
-
-#define DOWNMIX_CHANNEL_MASK 0x0f
-
-#define DOWNMIX_LFE_FLAG 0x10
-#define DOWNMIX_FLAGS_MASK 0x10
-
-hb_sample_t downmix_matrix[DOWNMIX_NUM_MODES][DOWNMIX_NUM_MODES][8][8] =
-{
-// MONO in
-{
- // MONO out
- { { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // STEREO out
- { { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 3F out
- { { 0, LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 1, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 2F1R out
- { { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 1, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 3F1R out
- { { 0, LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 1, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 2F2R out
- { { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 1, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 3F2R out
- { { 0, LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 1, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 3F4R out
- { { 0, LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 1 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // DOLBY out
- { { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // DPLII out
- { { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
-},
-// STEREO in
-{
- // MONO out
- { { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 },
- { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // STEREO out
- { { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 3F out
- { { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 1, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 2F1R out
- { { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 1, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 3F1R out
- { { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 1, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 2F2R out
- { { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 1, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 3F2R out
- { { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 1, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 3F4R out
- { { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 1 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // DOLBY out
- { { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // DPLII out
- { { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
-},
-// 3F in
-{
- // MONO out
- { { LVL_PLUS3DB, 0, 0, 0, 0, 0, 0, 0 },
- { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 },
- { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // STEREO out
- { { 1, 1, 0, 0, 0, 0, 0, 0 },
- { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 3F out
- { { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 1, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 2F1R out
- { { 1, 1, 0, 0, 0, 0, 0, 0 },
- { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 1, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 3F1R out
- { { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 1, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 2F2R out
- { { 1, 1, 0, 0, 0, 0, 0, 0 },
- { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 1, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 3F2R out
- { { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 1, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 3F4R out
- { { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 1 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // DOLBY out
- { { 1, 1, 0, 0, 0, 0, 0, 0 },
- { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // DPLII out
- { { 1, 1, 0, 0, 0, 0, 0, 0 },
- { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
-},
-// 2F1R in
-{
- // MONO out
- { { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 },
- { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 },
- { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // STEREO out
- { { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 3F out
- { { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 1, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 2F1R out
- { { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 1, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 3F1R out
- { { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 1, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 1, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 2F2R out
- { { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, LVL_3DB, LVL_3DB, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 1, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 3F2R out
- { { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, LVL_3DB, LVL_3DB, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 1, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 3F4R out
- { { 0, 1, 0, 0, 0, 0, 0 , 0 },
- { 0, 0, 1, 0, 0, 0, 0 , 0 },
- { 0, 0, 0, 0, 0, LVL_3DB, LVL_3DB, 0 },
- { 0, 0, 0, 0, 0, 0, 0 , 1 },
- { 0, 0, 0, 0, 0, 0, 0 , 0 },
- { 0, 0, 0, 0, 0, 0, 0 , 0 },
- { 0, 0, 0, 0, 0, 0, 0 , 0 },
- { 0, 0, 0, 0, 0, 0, 0 , 0 } },
- // DOLBY out
- { { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { -LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // DPLII out
- { { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { -LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
-},
-// 3F1R in
-{
- // MONO out
- { { LVL_PLUS3DB, 0, 0, 0, 0, 0, 0, 0 },
- { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 },
- { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 },
- { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // STEREO out
- { { 1, 1, 0, 0, 0, 0, 0, 0 },
- { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 3F out
- { { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 1, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 2F1R out
- { { 1, 1, 0, 0, 0, 0, 0, 0 },
- { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 1, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 3F1R out
- { { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 1, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 1, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 2F2R out
- { { 1, 1, 0, 0, 0, 0, 0, 0 },
- { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, LVL_3DB, LVL_3DB, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 1, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 3F2R out
- { { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, LVL_3DB, LVL_3DB, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 1, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 3F4R out
- { { 1, 0, 0, 0, 0, 0, 0 , 0 },
- { 0, 1, 0, 0, 0, 0, 0 , 0 },
- { 0, 0, 1, 0, 0, 0, 0 , 0 },
- { 0, 0, 0, 0, 0, LVL_3DB, LVL_3DB, 0 },
- { 0, 0, 0, 0, 0, 0, 0 , 1 },
- { 0, 0, 0, 0, 0, 0, 0 , 0 },
- { 0, 0, 0, 0, 0, 0, 0 , 0 },
- { 0, 0, 0, 0, 0, 0, 0 , 0 } },
- // DOLBY out
- { { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 },
- { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { -LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // DPLII out
- { { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 },
- { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { -LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
-},
-// 2F2R in
-{
- // MONO out
- { { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 },
- { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 },
- { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 },
- { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // STEREO out
- { { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 3F out
- { { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 1, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 2F1R out
- { { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, LVL_3DB, 0, 0, 0, 0, 0 },
- { 0, 0, LVL_3DB, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 1, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 3F1R out
- { { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, LVL_3DB, 0, 0, 0, 0 },
- { 0, 0, 0, LVL_3DB, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 1, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 2F2R out
- { { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 1, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 1, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 3F2R out
- { { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 1, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 1, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 1, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 3F4R out
- { { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 1, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 1, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 1 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // DOLBY out
- { { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { -LVL_6DB, LVL_6DB, 0, 0, 0, 0, 0, 0 },
- { -LVL_6DB, LVL_6DB, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // DPLII out
- { { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { -LVL_SQRT_3_4, LVL_SQRT_1_4, 0, 0, 0, 0, 0, 0 },
- { -LVL_SQRT_1_4, LVL_SQRT_3_4, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
-},
-// 3F2R in
-{
- // MONO out
- { { LVL_PLUS3DB, 0, 0, 0, 0, 0, 0, 0 },
- { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 },
- { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 },
- { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 },
- { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // STEREO out
- { { 1, 1, 0, 0, 0, 0, 0, 0 },
- { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 3F out
- { { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 1, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 2F1R out
- { { 1, 1, 0, 0, 0, 0, 0, 0 },
- { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, LVL_3DB, 0, 0, 0, 0, 0 },
- { 0, 0, LVL_3DB, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 1, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 3F1R out
- { { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, LVL_3DB, 0, 0, 0, 0 },
- { 0, 0, 0, LVL_3DB, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 1, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 2F2R out
- { { 1, 1, 0, 0, 0, 0, 0, 0 },
- { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 1, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 1, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 3F2R out
- { { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 1, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 1, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 1, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // 3F4R out
- { { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 1, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 1, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 1 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // DOLBY out
- { { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 },
- { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { -LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 },
- { -LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
- // DPLII out
- { { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 },
- { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { -LVL_SQRT_3_4, LVL_SQRT_1_4, 0, 0, 0, 0, 0, 0 },
- { -LVL_SQRT_1_4, LVL_SQRT_3_4, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 } },
-},
-// 3F4R in
-{
- // MONO out
- { { LVL_PLUS3DB, 0, 0, 0, 0, 0, 0, 0 },
- { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 },
- { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 },
- { LVL_6DB, 0, 0, 0, 0, 0, 0, 0 },
- { LVL_6DB, 0, 0, 0, 0, 0, 0, 0 },
- { LVL_6DB, 0, 0, 0, 0, 0, 0, 0 },
- { LVL_6DB, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 } },
- // STEREO out
- { { 1, 1, 0, 0, 0, 0, 0, 0 },
- { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 },
- { 0, LVL_3DB, 0, 0, 0, 0, 0, 0 },
- { LVL_3DB, 0, 0, 0, 0, 0, 0, 0 },
- { 0, LVL_3DB, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 } },
- // 3F out
- { { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, LVL_3DB, 0, 0, 0, 0, 0, 0 },
- { 0, 0, LVL_3DB, 0, 0, 0, 0, 0 },
- { 0, LVL_3DB, 0, 0, 0, 0, 0, 0 },
- { 0, 0, LVL_3DB, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 1, 0, 0, 0, 0 } },
- // 2F1R out
- { { 1, 1, 0, 0, 0, 0, 0, 0 },
- { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, LVL_6DB, 0, 0, 0, 0, 0 },
- { 0, 0, LVL_6DB, 0, 0, 0, 0, 0 },
- { 0, 0, LVL_6DB, 0, 0, 0, 0, 0 },
- { 0, 0, LVL_6DB, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 1, 0, 0, 0, 0 } },
- // 3F1R out
- { { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, LVL_6DB, 0, 0, 0, 0 },
- { 0, 0, 0, LVL_6DB, 0, 0, 0, 0 },
- { 0, 0, 0, LVL_6DB, 0, 0, 0, 0 },
- { 0, 0, 0, LVL_6DB, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 1, 0, 0, 0 } },
- // 2F2R out
- { { 1, 1, 0, 0, 0, 0, 0, 0 },
- { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, LVL_3DB, 0, 0, 0, 0, 0 },
- { 0, 0, 0, LVL_3DB, 0, 0, 0, 0 },
- { 0, 0, LVL_3DB, 0, 0, 0, 0, 0 },
- { 0, 0, 0, LVL_3DB, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 1, 0, 0, 0 } },
- // 3F2R out
- { { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, LVL_3DB, 0, 0, 0, 0 },
- { 0, 0, 0, 0, LVL_3DB, 0, 0, 0 },
- { 0, 0, 0, LVL_3DB, 0, 0, 0, 0 },
- { 0, 0, 0, 0, LVL_3DB, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 1, 0, 0 } },
- // 3F4R out
- { { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 1, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 1, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 1, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 1, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 1 } },
- // DOLBY out
- { { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 },
- { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { -LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 },
- { -LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 },
- { -LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 },
- { -LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 } },
- // DPLII out
- { { LVL_3DB, LVL_3DB, 0, 0, 0, 0, 0, 0 },
- { 1, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 1, 0, 0, 0, 0, 0, 0 },
- { -LVL_SQRT_3_4*LVL_3DB, LVL_SQRT_1_4*LVL_3DB, 0, 0, 0, 0, 0, 0 },
- { -LVL_SQRT_1_4*LVL_3DB, LVL_SQRT_3_4*LVL_3DB, 0, 0, 0, 0, 0, 0 },
- { -LVL_SQRT_3_4*LVL_3DB, LVL_SQRT_1_4*LVL_3DB, 0, 0, 0, 0, 0, 0 },
- { -LVL_SQRT_1_4*LVL_3DB, LVL_SQRT_3_4*LVL_3DB, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 } }
-},
-};
-
-static int channel_layout_map[DOWNMIX_NUM_MODES] =
-{
- // DOWNMIX_MONO
- (HB_CH_FRONT_CENTER),
- // DOWNMIX_STEREO
- (HB_CH_FRONT_LEFT|HB_CH_FRONT_RIGHT),
- // DOWNMIX_3F
- (HB_CH_FRONT_LEFT|HB_CH_FRONT_RIGHT|HB_CH_FRONT_CENTER),
- // DOWNMIX_2F1R
- (HB_CH_FRONT_LEFT|HB_CH_FRONT_RIGHT|HB_CH_BACK_CENTER),
- // DOWNMIX_3F1R
- (HB_CH_FRONT_LEFT|HB_CH_FRONT_RIGHT|HB_CH_FRONT_CENTER|HB_CH_BACK_CENTER),
- // DOWNMIX_2F2R
- (HB_CH_FRONT_LEFT|HB_CH_FRONT_RIGHT|HB_CH_BACK_LEFT|HB_CH_BACK_RIGHT),
- // DOWNMIX_3F2R
- (HB_CH_FRONT_LEFT|HB_CH_FRONT_RIGHT|HB_CH_FRONT_CENTER|HB_CH_BACK_LEFT|HB_CH_BACK_RIGHT),
- // DOWNMIX_3F4R
- (HB_CH_FRONT_LEFT|HB_CH_FRONT_RIGHT|HB_CH_FRONT_CENTER|HB_CH_SIDE_LEFT|
- HB_CH_SIDE_RIGHT|HB_CH_BACK_LEFT|HB_CH_BACK_RIGHT),
- // DOWNMIX_DOLBY
- (HB_CH_FRONT_LEFT|HB_CH_FRONT_RIGHT),
- // DOWNMIX_DPLII
- (HB_CH_FRONT_LEFT|HB_CH_FRONT_RIGHT)
-};
-
-int hb_layout_to_mode(uint64_t layout)
-{
- int mode = 0;
- if (layout & AV_CH_LOW_FREQUENCY)
- mode |= DOWNMIX_LFE_FLAG;
- switch (layout & ~AV_CH_LOW_FREQUENCY)
- {
- case AV_CH_LAYOUT_MONO:
- mode |= DOWNMIX_MONO;
- break;
- case AV_CH_LAYOUT_STEREO:
- case AV_CH_LAYOUT_STEREO_DOWNMIX:
- mode |= DOWNMIX_STEREO;
- break;
- case AV_CH_LAYOUT_SURROUND:
- mode |= DOWNMIX_3F;
- break;
- case AV_CH_LAYOUT_2_1:
- mode |= DOWNMIX_2F1R;
- break;
- case AV_CH_LAYOUT_4POINT0:
- mode |= DOWNMIX_3F1R;
- break;
- case AV_CH_LAYOUT_2_2:
- case AV_CH_LAYOUT_QUAD:
- mode |= DOWNMIX_2F2R;
- break;
- case AV_CH_LAYOUT_5POINT0:
- case AV_CH_LAYOUT_5POINT0_BACK:
- mode |= DOWNMIX_3F2R;
- break;
- case AV_CH_LAYOUT_7POINT0:
- mode |= DOWNMIX_3F4R;
- break;
- default:
- {
- switch (av_get_channel_layout_nb_channels(layout))
- {
- case 1:
- mode = DOWNMIX_MONO;
- break;
- case 2:
- mode = DOWNMIX_STEREO;
- break;
- case 3:
- mode = DOWNMIX_3F;
- break;
- case 4:
- mode = DOWNMIX_2F2R;
- break;
- case 5:
- mode = DOWNMIX_3F2R;
- break;
- case 6:
- mode = DOWNMIX_3F2R|DOWNMIX_LFE_FLAG;
- break;
- case 7:
- mode = DOWNMIX_3F4R;
- break;
- case 8:
- mode = DOWNMIX_3F4R|DOWNMIX_LFE_FLAG;
- break;
- default:
- // This will likely not sound very good ;)
- mode = DOWNMIX_STEREO;
- hb_error("hb_layout_to_mode: unsupported layout 0x%"PRIx64" with %d channels",
- layout, av_get_channel_layout_nb_channels(layout));
- break;
- }
- } break;
- }
- return mode;
-}
-
-int hb_mixdown_to_mode(uint32_t mixdown)
-{
- switch (mixdown)
- {
- case HB_AMIXDOWN_MONO:
- return DOWNMIX_MONO;
- case HB_AMIXDOWN_STEREO:
- return DOWNMIX_STEREO;
- case HB_AMIXDOWN_DOLBY:
- return DOWNMIX_DOLBY;
- case HB_AMIXDOWN_DOLBYPLII:
- return DOWNMIX_DPLII;
- case HB_AMIXDOWN_6CH:
- return DOWNMIX_3F2R|DOWNMIX_LFE_FLAG;
- default:
- return DOWNMIX_STEREO;
- }
-}
-
-
-// ffmpeg gives us SMPTE channel layout
-// We could use this layout and remap channels in encfaac,
-// but VLC may have problems with remapping, so lets
-// allow remapping to the default QuickTime order which is:
-//
-// C L R LS RS Rls Rrs LFE
-//
-// This arrangement also makes it possible to use half as
-// many downmix matrices since the matrix with and without
-// LFE are the same.
-//
-// Use hb_layout_remap to accomplish this. For convenience
-// I've provided the necessary maps.
-//
-// SMPTE channel layout
-//
-// DUAL-MONO L R
-// DUAL-MONO-LFE L R LFE
-// MONO M
-// MONO-LFE M LFE
-// STEREO L R
-// STEREO-LFE L R LFE
-// 3F L R C
-// 3F-LFE L R C LFE
-// 2F1 L R S
-// 2F1-LFE L R LFE S
-// 3F1 L R C S
-// 3F1-LFE L R C LFE S
-// 2F2 L R LS RS
-// 2F2-LFE L R LFE LS RS
-// 3F2 L R C LS RS
-// 3F2-LFE L R C LFE LS RS
-// 3F4 L R C Rls Rrs LS RS
-// 3F4-LFE L R C LFE Rls Rrs LS RS
-//
-
-#define CH_C 0
-#define CH_L 1
-#define CH_R 2
-#define CH_CS 3
-#define CH_LS 3
-#define CH_RS 4
-#define CH_Rls 5
-#define CH_Rrs 6
-#define CH_LFE 7
-
-hb_chan_map_t hb_qt_chan_map =
-{
-{
- {{ CH_C, },
- { CH_C, CH_LFE, }}, // MONO
-
- {{ CH_L, CH_R, },
- { CH_L, CH_R, CH_LFE, }}, // STEREO
-
- {{ CH_C, CH_L, CH_R, },
- { CH_C, CH_L, CH_R, CH_LFE, }}, // 3F
-
- {{ CH_L, CH_R, CH_CS, },
- { CH_L, CH_R, CH_CS, CH_LFE, }}, // 2F1R
-
- {{ CH_C, CH_L, CH_R, CH_CS, },
- { CH_C, CH_L, CH_R, CH_CS, CH_LFE, }}, // 3F1R
-
- {{ CH_L, CH_R, CH_LS, CH_RS, },
- { CH_L, CH_R, CH_LS, CH_RS, CH_LFE, }}, // 2F2R
-
- {{ CH_C, CH_L, CH_R, CH_LS, CH_RS, },
- { CH_C, CH_L, CH_R, CH_LS, CH_RS, CH_LFE, }}, // 3F2R
-
- {{ CH_C, CH_L, CH_R, CH_LS, CH_RS, CH_Rls, CH_Rrs, },
- { CH_C, CH_L, CH_R, CH_LS, CH_RS, CH_Rls, CH_Rrs, CH_LFE }}, // 3F4R
-
- {{ CH_L, CH_R, },
- { CH_L, CH_R, }}, // DOLBY
-
- {{ CH_L, CH_R, },
- { CH_L, CH_R, }} // DPLII
-},
-{
- // CH_C CH_L CH_R CH_LS/CS CH_RS CH_Rls CH_Rrs CH_LFE
- {{ 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 1 }}, // MONO
-
- {{ 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 2 }}, // STEREO
-
- {{ 0, 1, 2, 0, 0, 0, 0, 0 },
- { 0, 1, 2, 0, 0, 0, 0, 3 }}, // 3F
-
- {{ 0, 0, 1, 2, 0, 0, 0, 0 },
- { 0, 0, 1, 2, 0, 0, 0, 3 }}, // 2F1R
-
- {{ 0, 1, 2, 3, 0, 0, 0, 0 },
- { 0, 1, 2, 3, 0, 0, 0, 4 }}, // 3F1R
-
- {{ 0, 0, 1, 2, 3, 0, 0, 0 },
- { 0, 0, 1, 2, 3, 0, 0, 4 }}, // 2F2R
-
- {{ 0, 1, 2, 3, 4, 0, 0, 0 },
- { 0, 1, 2, 3, 4, 0, 0, 5 }}, // 3F2R
-
- {{ 0, 1, 2, 3, 4, 5, 6, 0 },
- { 0, 1, 2, 3, 4, 5, 6, 7 }}, // 3F4R
-
- {{ 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 }}, // DOLBY
-
- {{ 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 }} // DPLII
-}
-};
-
-hb_chan_map_t hb_smpte_chan_map =
-{
-{
- {{ CH_C, },
- { CH_C, CH_LFE, }}, // MONO
-
- {{ CH_L, CH_R, },
- { CH_L, CH_R, CH_LFE, }}, // STEREO
-
- {{ CH_L, CH_R, CH_C, },
- { CH_L, CH_R, CH_C, CH_LFE, }}, // 3F
-
- {{ CH_L, CH_R, CH_CS, },
- { CH_L, CH_R, CH_LFE, CH_CS, }}, // 2F1R
-
- {{ CH_L, CH_R, CH_C, CH_CS, },
- { CH_L, CH_R, CH_LFE, CH_CS, }}, // 3F1R
-
- {{ CH_L, CH_R, CH_LS, CH_RS, },
- { CH_L, CH_R, CH_LFE, CH_LS, CH_RS, }}, // 2F2R
-
- {{ CH_L, CH_R, CH_C, CH_LS, CH_RS, },
- { CH_L, CH_R, CH_C, CH_LFE, CH_LS, CH_RS, }}, // 3F2R
-
- {{ CH_L, CH_R, CH_C, CH_Rls, CH_Rrs, CH_LS, CH_RS },
- { CH_L, CH_R, CH_C, CH_LFE, CH_Rls, CH_Rrs, CH_LS, CH_RS }}, // 3F4R
-
- {{ CH_L, CH_R, },
- { CH_L, CH_R, }}, // DOLBY
-
- {{ CH_L, CH_R, },
- { CH_L, CH_R, }} // DPLII
-},
-{
- // CH_C CH_L CH_R CH_LS/CS CH_RS CH_Rls CH_Rrs CH_LFE
- {{ 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 1 }}, // MONO
-
- {{ 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 2 }}, // STEREO
-
- {{ 2, 0, 1, 0, 0, 0, 0, 0 },
- { 2, 0, 1, 0, 0, 0, 0, 3 }}, // 3F
-
- {{ 0, 0, 1, 2, 0, 0, 0, 0 },
- { 0, 0, 1, 3, 0, 0, 0, 2 }}, // 2F1R
-
- {{ 2, 0, 1, 3, 0, 0, 0, 0 },
- { 2, 0, 1, 4, 0, 0, 0, 3 }}, // 3F1R
-
- {{ 0, 0, 1, 2, 3, 0, 0, 0 },
- { 0, 0, 1, 3, 4, 0, 0, 2 }}, // 2F2R
-
- {{ 2, 0, 1, 3, 4, 0, 0, 0 },
- { 2, 0, 1, 4, 5, 0, 0, 3 }}, // 3F2R
-
- {{ 2, 0, 1, 5, 6, 3, 4, 0 },
- { 2, 0, 1, 6, 7, 4, 5, 3 }}, // 3F4R
-
- {{ 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 }}, // DOLBY
-
- {{ 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 }} // DPLII
-}
-};
-
-hb_chan_map_t hb_ac3_chan_map =
-{
-{
- {{ CH_C, },
- { CH_LFE, CH_C, }}, // MONO
-
- {{ CH_L, CH_R, },
- { CH_LFE, CH_L, CH_R, }}, // STEREO
-
- {{ CH_L, CH_C, CH_R, },
- { CH_LFE, CH_L, CH_C, CH_R, }}, // 3F
-
- {{ CH_L, CH_R, CH_CS, },
- { CH_LFE, CH_L, CH_R, CH_CS, }}, // 2F1R
-
- {{ CH_L, CH_C, CH_R, CH_CS, },
- { CH_LFE, CH_L, CH_C, CH_R, CH_CS, }}, // 3F1R
-
- {{ CH_L, CH_R, CH_LS, CH_RS, },
- { CH_LFE, CH_L, CH_R, CH_LS, CH_RS, }}, // 2F2R
-
- {{ CH_L, CH_C, CH_R, CH_LS, CH_RS, },
- { CH_LFE, CH_L, CH_C, CH_R, CH_LS, CH_RS, }}, // 3F2R
-
- {{ CH_L, CH_C, CH_R, CH_LS, CH_RS, CH_Rls, CH_Rrs, },
- { CH_LFE, CH_L, CH_C, CH_R, CH_LS, CH_RS, CH_Rls, CH_Rrs }}, // 3F4R
-
- {{ CH_L, CH_R, },
- { CH_L, CH_R, }}, // DOLBY
-
- {{ CH_L, CH_R, },
- { CH_L, CH_R, }} // DPLII
-},
-{
- // CH_C CH_L CH_R CH_LS/CS CH_RS CH_Rls CH_Rrs CH_LFE
- {{ 0, 0, 0, 0, 0, 0, 0, 0 },
- { 1, 0, 0, 0, 0, 0, 0, 0 }}, // MONO
-
- {{ 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 1, 2, 0, 0, 0, 0, 0 }}, // STEREO
-
- {{ 1, 0, 2, 0, 0, 0, 0, 0 },
- { 2, 1, 3, 0, 0, 0, 0, 0 }}, // 3F
-
- {{ 0, 0, 1, 2, 0, 0, 0, 0 },
- { 0, 1, 2, 3, 0, 0, 0, 0 }}, // 2F1R
-
- {{ 1, 0, 2, 3, 0, 0, 0, 0 },
- { 2, 1, 3, 4, 0, 0, 0, 0 }}, // 3F1R
-
- {{ 0, 0, 1, 2, 3, 0, 0, 0 },
- { 0, 1, 2, 3, 4, 0, 0, 0 }}, // 2F2R
-
- {{ 1, 0, 2, 3, 4, 0, 0, 0 },
- { 2, 1, 3, 4, 5, 0, 0, 0 }}, // 3F2R
-
- {{ 1, 0, 2, 3, 4, 5, 6, 0 },
- { 2, 1, 3, 4, 5, 6, 7, 0 }}, // 3F4R
-
- {{ 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 }}, // DOLBY
-
- {{ 0, 0, 1, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 0, 0, 0, 0, 0 }} // DPLII
-}
-};
-
-static const uint8_t nchans_tbl[] = {1, 2, 3, 3, 4, 4, 5, 7, 2, 2};
-
-// Takes a set of samples and remaps the channel layout
-void hb_layout_remap(hb_chan_map_t *map_in,
- hb_chan_map_t *map_out,
- uint64_t layout,
- hb_sample_t *samples,
- int nsamples)
-{
- int nchans;
- int ii, jj;
- int lfe;
- int * map;
- int * inv_map;
- int mode;
- hb_sample_t tmp[8];
-
- mode = hb_layout_to_mode(layout);
- lfe = ((mode & DOWNMIX_LFE_FLAG) != 0);
- mode = mode & DOWNMIX_CHANNEL_MASK;
- nchans = nchans_tbl[mode] + lfe;
- inv_map = map_in->inv_chan_map[mode][lfe];
- map = map_out->chan_map[mode][lfe];
-
- for (ii = 0; ii < nsamples; ii++)
- {
- for (jj = 0; jj < nchans; jj++)
- {
- tmp[jj] = samples[jj];
- }
- for (jj = 0; jj < nchans; jj++)
- {
- int ord = map[jj];
- samples[jj] = tmp[inv_map[ord]];
- }
- samples += nchans;
- }
-}
-
-static void matrix_mul(
- hb_sample_t * dst,
- hb_sample_t * src,
- int nchans_out,
- int nchans_in,
- int nsamples,
- hb_sample_t (*matrix)[8],
- hb_sample_t bias)
-{
- int nn, ii, jj;
- hb_sample_t val;
-
- for (nn = 0; nn < nsamples; nn++)
- {
- for (ii = 0; ii < nchans_out; ii++)
- {
- val = 0;
- for (jj = 0; jj < nchans_in; jj++)
- {
- val += src[jj] * matrix[jj][ii];
- }
- dst[ii] = val + bias;
- }
- src += nchans_in;
- dst += nchans_out;
- }
-}
-
-static void set_level( hb_downmix_t * downmix )
-{
- int ii, jj;
- int layout_in, layout_out;
- int mode_in;
- int mode_out;
-
- mode_in = downmix->mode_in & ~DOWNMIX_FLAGS_MASK;
- mode_out = downmix->mode_out & ~DOWNMIX_FLAGS_MASK;
-
- for (ii = 0; ii < 8; ii++)
- {
- for (jj = 0; jj < 8; jj++)
- {
- downmix->matrix[ii][jj] *= downmix->level;
- }
- }
- if (mode_out >= DOWNMIX_DOLBY)
- return;
-
- layout_in = channel_layout_map[mode_in];
- layout_out = channel_layout_map[mode_out];
-
- if (layout_in & HB_CH_FRONT_CENTER)
- {
- if (!(layout_out & HB_CH_FRONT_CENTER))
- {
- for (jj = 0; jj < 8; jj++)
- {
- downmix->matrix[downmix->center][jj] *= downmix->clev;
- }
- }
- }
- if (layout_in & (HB_CH_BACK_LEFT|HB_CH_BACK_RIGHT|HB_CH_BACK_CENTER|HB_CH_SIDE_LEFT|HB_CH_SIDE_RIGHT))
- {
- if (layout_out & (HB_CH_BACK_LEFT|HB_CH_BACK_RIGHT|HB_CH_BACK_CENTER|HB_CH_SIDE_LEFT|HB_CH_SIDE_RIGHT))
- {
- // Note, slev only gets set if input has surround, and output has none.
- return;
- }
- }
- for (jj = 0; jj < 8; jj++)
- {
- if ( downmix->left_surround >= 0 )
- downmix->matrix[downmix->left_surround][jj] *= downmix->slev;
- if ( downmix->right_surround >= 0 )
- downmix->matrix[downmix->right_surround][jj] *= downmix->slev;
- if ( downmix->rear_left_surround >= 0 )
- downmix->matrix[downmix->rear_left_surround][jj] *= downmix->slev;
- if ( downmix->rear_right_surround >= 0 )
- downmix->matrix[downmix->rear_right_surround][jj] *= downmix->slev;
- }
-}
-
-#define MIXMODE(x,y) (((x)<<4)|(y))
-// The downmix operation can result in new sample values that are
-// outside the original range of sample values. If you wish to
-// guarantee that the levels to not exceed the original range,
-// call this function after initializing downmix and setting
-// your initial levels.
-//
-// Note that this can result in generally lower volume levels
-// in the resulting downmixed audio.
-void hb_downmix_adjust_level( hb_downmix_t * downmix )
-{
- int mode_in, mode_out;
- hb_sample_t level = downmix->level;
- hb_sample_t clev = downmix->clev;
- hb_sample_t slev = downmix->slev;
-
- mode_in = downmix->mode_in & DOWNMIX_CHANNEL_MASK;
- mode_out = downmix->mode_out & DOWNMIX_CHANNEL_MASK;
-
- switch MIXMODE(mode_in, mode_out)
- {
- case MIXMODE(DOWNMIX_STEREO, DOWNMIX_MONO):
- case MIXMODE(DOWNMIX_2F2R, DOWNMIX_2F1R):
- case MIXMODE(DOWNMIX_2F2R, DOWNMIX_3F1R):
- case MIXMODE(DOWNMIX_3F2R, DOWNMIX_3F1R):
- case MIXMODE(DOWNMIX_3F4R, DOWNMIX_3F1R):
- case MIXMODE(DOWNMIX_3F4R, DOWNMIX_3F2R):
- level_3db:
- level /= LVL_PLUS3DB;
- break;
-
- case MIXMODE(DOWNMIX_3F, DOWNMIX_MONO):
- level /= LVL_PLUS3DB + clev * LVL_PLUS3DB;
- break;
-
- case MIXMODE(DOWNMIX_3F2R, DOWNMIX_2F1R):
- case MIXMODE(DOWNMIX_3F4R, DOWNMIX_2F1R):
- case MIXMODE(DOWNMIX_3F4R, DOWNMIX_2F2R):
- if (1 + clev < LVL_PLUS3DB)
- goto level_3db;
- case MIXMODE(DOWNMIX_3F, DOWNMIX_STEREO):
- case MIXMODE(DOWNMIX_3F, DOWNMIX_2F1R):
- case MIXMODE(DOWNMIX_3F, DOWNMIX_2F2R):
- case MIXMODE(DOWNMIX_3F, DOWNMIX_DOLBY):
- case MIXMODE(DOWNMIX_3F, DOWNMIX_DPLII):
- case MIXMODE(DOWNMIX_3F1R, DOWNMIX_2F1R):
- case MIXMODE(DOWNMIX_3F1R, DOWNMIX_2F2R):
- case MIXMODE(DOWNMIX_3F2R, DOWNMIX_2F2R):
- level /= 1 + clev;
- break;
-
-
- case MIXMODE(DOWNMIX_2F1R, DOWNMIX_MONO):
- level /= LVL_PLUS3DB + LVL_3DB * clev;
- break;
-
- case MIXMODE(DOWNMIX_2F1R, DOWNMIX_DOLBY):
- level /= 1 + LVL_3DB;
- break;
-
- case MIXMODE(DOWNMIX_2F1R, DOWNMIX_STEREO):
- case MIXMODE(DOWNMIX_2F1R, DOWNMIX_3F):
- case MIXMODE(DOWNMIX_3F1R, DOWNMIX_3F):
- level /= 1 + LVL_3DB * slev;
- break;
-
- case MIXMODE(DOWNMIX_3F1R, DOWNMIX_MONO):
- level /= LVL_PLUS3DB + LVL_PLUS3DB * clev + LVL_3DB * slev;
- break;
-
- case MIXMODE(DOWNMIX_3F1R, DOWNMIX_STEREO):
- level /= 1 + clev + LVL_3DB * slev;
- break;
-
- case MIXMODE(DOWNMIX_3F1R, DOWNMIX_DOLBY):
- case MIXMODE(DOWNMIX_3F1R, DOWNMIX_DPLII):
- case MIXMODE(DOWNMIX_2F2R, DOWNMIX_DOLBY):
- level /= 1 + LVL_PLUS3DB;
- break;
-
- case MIXMODE(DOWNMIX_2F2R, DOWNMIX_MONO):
- level /= LVL_PLUS3DB + LVL_PLUS3DB * slev;
- break;
-
- case MIXMODE(DOWNMIX_2F2R, DOWNMIX_STEREO):
- case MIXMODE(DOWNMIX_2F2R, DOWNMIX_3F):
- case MIXMODE(DOWNMIX_3F2R, DOWNMIX_3F):
- level /= 1 + slev;
- break;
-
- case MIXMODE(DOWNMIX_2F2R, DOWNMIX_DPLII):
- level /= 1 + LVL_SQRT_1_4 + LVL_SQRT_3_4;
- break;
-
- case MIXMODE(DOWNMIX_3F2R, DOWNMIX_MONO):
- case MIXMODE(DOWNMIX_3F4R, DOWNMIX_MONO):
- level /= LVL_PLUS3DB + LVL_PLUS3DB * clev * LVL_PLUS3DB * slev;
- break;
-
- case MIXMODE(DOWNMIX_3F2R, DOWNMIX_STEREO):
- level /= 1 + clev + slev;
- break;
-
- case MIXMODE(DOWNMIX_3F2R, DOWNMIX_DOLBY):
- level /= 1 + 3 * LVL_3DB;
- break;
-
- case MIXMODE(DOWNMIX_3F2R, DOWNMIX_DPLII):
- level /= 1 + LVL_3DB + LVL_SQRT_1_4 + LVL_SQRT_3_4;
- break;
-
- case MIXMODE(DOWNMIX_3F4R, DOWNMIX_STEREO):
- level /= 1 + clev + LVL_PLUS3DB * slev;
- break;
-
- case MIXMODE(DOWNMIX_3F4R, DOWNMIX_3F):
- level /= 1 + LVL_PLUS3DB * slev;
- break;
-
- case MIXMODE(DOWNMIX_3F4R, DOWNMIX_DOLBY):
- level /= 1 + 5 * LVL_3DB;
- break;
-
- case MIXMODE(DOWNMIX_3F4R, DOWNMIX_DPLII):
- level /= 1 + LVL_3DB + 2 * LVL_SQRT_1_4 + 2 * LVL_SQRT_3_4;
- }
-
- downmix->level = level;
- downmix->matrix_initialized = 0;
-}
-
-void hb_downmix_set_bias( hb_downmix_t * downmix, hb_sample_t bias )
-{
- downmix->bias = bias;
-}
-
-// Changes the downmix mode if it needs changing after initialization
-static void set_mode( hb_downmix_t * downmix )
-{
- int ii, jj;
- int mode_in, mode_out;
- hb_sample_t (*matrix)[8];
-
- mode_in = downmix->mode_in & ~DOWNMIX_FLAGS_MASK;
- mode_out = downmix->mode_out & ~DOWNMIX_FLAGS_MASK;
-
- matrix = downmix_matrix[mode_in][mode_out];
-
- for (ii = 0; ii < 8; ii++)
- {
- for (jj = 0; jj < 8; jj++)
- {
- downmix->matrix[ii][jj] = matrix[ii][jj];
- }
- }
-}
-
-// Changes the downmix mode if it needs changing after initialization
-int hb_downmix_set_mode( hb_downmix_t * downmix, int layout, int mixdown )
-{
- int lfe_in, lfe_out;
- int mode_in, mode_out;
-
- if ( downmix == NULL )
- return -1;
-
- mode_in = hb_layout_to_mode(layout);
- mode_out = hb_mixdown_to_mode(mixdown);
- downmix->mode_in = mode_in;
- downmix->mode_out = mode_out;
-
- mode_in = downmix->mode_in & ~DOWNMIX_FLAGS_MASK;
- mode_out = downmix->mode_out & ~DOWNMIX_FLAGS_MASK;
-
- if (mode_in >= DOWNMIX_NUM_MODES || mode_out >= DOWNMIX_NUM_MODES)
- return -1;
-
- lfe_in = ((downmix->mode_in & DOWNMIX_LFE_FLAG) != 0);
- lfe_out = ((downmix->mode_out & DOWNMIX_LFE_FLAG) != 0);
-
- downmix->nchans_in = nchans_tbl[mode_in] + lfe_in;
- downmix->nchans_out = nchans_tbl[mode_out] + lfe_out;
-
- downmix->matrix_initialized = 0;
- return 0;
-}
-
-// Changes the downmix levels if they need changing after initialization
-void hb_downmix_set_level( hb_downmix_t * downmix, hb_sample_t clev, hb_sample_t slev, hb_sample_t level )
-{
- if ( downmix == NULL )
- return;
-
- downmix->clev = clev;
- downmix->slev = slev;
- downmix->level = level;
- downmix->matrix_initialized = 0;
-}
-
-static void set_chan_map( hb_downmix_t * downmix )
-{
- int nchans;
- int ii, jj;
- int lfe;
- int * map;
- int * inv_map;
- int mode;
- hb_sample_t matrix[8][8];
-
- // Copy the matrix
- for ( ii = 0; ii < 8; ii++ )
- {
- for ( jj = 0; jj < 8; jj++ )
- {
- matrix[ii][jj] = downmix->matrix[ii][jj];
- }
- }
-
- // Rearrange the rows to correspond to the input channel order
- lfe = ((downmix->mode_in & DOWNMIX_LFE_FLAG) != 0);
- mode = downmix->mode_in & DOWNMIX_CHANNEL_MASK;
- nchans = nchans_tbl[mode] + lfe;
- map = downmix->map_in.chan_map[mode][lfe];
- inv_map = hb_qt_chan_map.inv_chan_map[mode][lfe];
-
- downmix->center = -1;
- downmix->left_surround = -1;
- downmix->right_surround = -1;
- downmix->rear_left_surround = -1;
- downmix->rear_right_surround = -1;
- for ( ii = 0; ii < nchans; ii++ )
- {
- int ord = map[ii];
- int row = inv_map[ord];
- switch (ord)
- {
- case CH_C:
- downmix->center = ii;
- break;
- case CH_LS:
- downmix->left_surround = ii;
- break;
- case CH_RS:
- downmix->right_surround = ii;
- break;
- case CH_Rls:
- downmix->rear_right_surround = ii;
- break;
- case CH_Rrs:
- downmix->rear_left_surround = ii;
- break;
- }
- for ( jj = 0; jj < 8; jj++ )
- {
- downmix->matrix[ii][jj] = matrix[row][jj];
- }
- }
-
- // Copy the matrix
- for ( ii = 0; ii < 8; ii++ )
- {
- for ( jj = 0; jj < 8; jj++ )
- {
- matrix[ii][jj] = downmix->matrix[ii][jj];
- }
- }
-
- // Rearrange the columns to correspond to the output channel order
- lfe = ((downmix->mode_out & DOWNMIX_LFE_FLAG) != 0);
- mode = downmix->mode_out & DOWNMIX_CHANNEL_MASK;
- nchans = nchans_tbl[mode] + lfe;
- map = downmix->map_out.chan_map[mode][lfe];
- inv_map = hb_qt_chan_map.inv_chan_map[mode][lfe];
- for ( ii = 0; ii < nchans; ii++ )
- {
- int ord = map[ii];
- int col = inv_map[ord];
- for ( jj = 0; jj < 8; jj++ )
- {
- downmix->matrix[jj][ii] = matrix[jj][col];
- }
- }
-}
-
-void hb_downmix_set_chan_map(
- hb_downmix_t * downmix,
- hb_chan_map_t * map_in,
- hb_chan_map_t * map_out )
-{
- downmix->map_in = *map_in;
- downmix->map_out = *map_out;
- downmix->matrix_initialized = 0;
-}
-
-hb_downmix_t * hb_downmix_init(int layout, int mixdown)
-{
- hb_downmix_t * downmix = calloc(1, sizeof(hb_downmix_t));
-
- if (downmix == NULL)
- return NULL;
- if ( hb_downmix_set_mode( downmix, layout, mixdown ) < 0 )
- {
- free( downmix );
- return NULL;
- }
- // Set some good default values
- hb_downmix_set_level( downmix, LVL_3DB, LVL_3DB, 1.0 );
- downmix->bias = 0.0;
- downmix->matrix_initialized = 0;
- // The default input and output channel order is QT
- hb_downmix_set_chan_map( downmix, &hb_qt_chan_map, &hb_qt_chan_map );
- return downmix;
-}
-
-void hb_downmix_close( hb_downmix_t **downmix )
-{
- if (*downmix != NULL)
- free(*downmix);
- *downmix = NULL;
-}
-
-static void init_matrix( hb_downmix_t * downmix )
-{
- if ( !downmix->matrix_initialized )
- {
- set_mode( downmix );
- set_chan_map( downmix );
- set_level(downmix);
- downmix->matrix_initialized = 1;
- }
-}
-
-void hb_downmix( hb_downmix_t * downmix, hb_sample_t * dst, hb_sample_t * src, int nsamples)
-{
- init_matrix( downmix );
- matrix_mul( dst, src, downmix->nchans_out, downmix->nchans_in,
- nsamples, downmix->matrix, downmix->bias );
-}
-
-int hb_need_downmix( int layout, int mixdown )
-{
- int mode_in, mode_out;
-
- mode_in = hb_layout_to_mode(layout);
- mode_out = hb_mixdown_to_mode(mixdown);
-
- return (mode_in != mode_out);
-}
diff --git a/libhb/downmix.h b/libhb/downmix.h
index b67889f56..e69de29bb 100644
--- a/libhb/downmix.h
+++ b/libhb/downmix.h
@@ -1,67 +0,0 @@
-/* downmix.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
- */
-#ifndef DOWNMIX_H
-#define DOWNMIX_H
-
-typedef float hb_sample_t;
-
-typedef struct
-{
- int chan_map[10][2][8];
- int inv_chan_map[10][2][8];
-} hb_chan_map_t;
-
-typedef struct
-{
- int mode_in;
- int mode_out;
- int nchans_in;
- int nchans_out;
- hb_sample_t matrix[8][8];
- int matrix_initialized;
- hb_sample_t clev;
- hb_sample_t slev;
- hb_sample_t level;
- hb_sample_t bias;
- hb_chan_map_t map_in;
- hb_chan_map_t map_out;
-
- int center;
- int left_surround;
- int right_surround;
- int rear_left_surround;
- int rear_right_surround;
-} hb_downmix_t;
-
-// For convenience, a map to convert smpte channel layout
-// to QuickTime channel layout.
-// Map Indicies are mode, lfe, channel respectively
-extern hb_chan_map_t hb_smpte_chan_map;
-extern hb_chan_map_t hb_ac3_chan_map;
-extern hb_chan_map_t hb_qt_chan_map;
-
-hb_downmix_t * hb_downmix_init(int layout, int mixdown);
-void hb_downmix_close( hb_downmix_t **downmix );
-int hb_downmix_set_mode( hb_downmix_t * downmix, int layout, int mixdown );
-void hb_downmix_set_level( hb_downmix_t * downmix, hb_sample_t clev, hb_sample_t slev, hb_sample_t level );
-void hb_downmix_adjust_level( hb_downmix_t * downmix );
-void hb_downmix_set_bias( hb_downmix_t * downmix, hb_sample_t bias );
-void hb_downmix_set_chan_map(
- hb_downmix_t * downmix,
- hb_chan_map_t * map_in,
- hb_chan_map_t * map_out );
-void hb_downmix( hb_downmix_t * downmix, hb_sample_t * dst, hb_sample_t * src, int nsamples);
-void hb_layout_remap(hb_chan_map_t *map_in,
- hb_chan_map_t *map_out,
- uint64_t layout,
- hb_sample_t *samples,
- int nsamples);
-int hb_need_downmix( int layout, int mixdown );
-
-#endif /* DOWNMIX_H */
diff --git a/libhb/dvd.c b/libhb/dvd.c
index 19325c1d4..6af2e7908 100644
--- a/libhb/dvd.c
+++ b/libhb/dvd.c
@@ -363,6 +363,7 @@ static hb_title_t * hb_dvdread_title_scan( hb_dvd_t * e, int t, uint64_t min_dur
case 0x03:
audio->id = 0xc0 + position;
audio->config.in.codec = HB_ACODEC_FFMPEG;
+ audio->config.in.codec_param = CODEC_ID_MP2;
codec_name = "MPEG";
break;
diff --git a/libhb/dvdnav.c b/libhb/dvdnav.c
index 2e4918095..d6e97c1a5 100644
--- a/libhb/dvdnav.c
+++ b/libhb/dvdnav.c
@@ -512,6 +512,7 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t, uint64_t min_dura
case 0x03:
audio->id = 0xc0 + position;
audio->config.in.codec = HB_ACODEC_FFMPEG;
+ audio->config.in.codec_param = CODEC_ID_MP2;
codec_name = "MPEG";
break;
diff --git a/libhb/encavcodec.c b/libhb/encavcodec.c
index 037a7aef2..44453477f 100644
--- a/libhb/encavcodec.c
+++ b/libhb/encavcodec.c
@@ -451,17 +451,25 @@ int encavcodecWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
if ( pv->context->codec )
{
+ int ret;
+ AVPacket pkt;
+ int got_packet;
+
+ av_init_packet(&pkt);
/* Should be way too large */
buf = hb_video_buffer_init( job->width, job->height );
- buf->size = avcodec_encode_video( pv->context, buf->data, buf->alloc,
- frame );
- if ( buf->size <= 0 )
+ pkt.data = buf->data;
+ pkt.size = buf->alloc;
+
+ ret = avcodec_encode_video2( pv->context, &pkt, frame, &got_packet );
+ if ( ret < 0 || pkt.size <= 0 || !got_packet )
{
hb_buffer_close( &buf );
}
else
{
- int64_t frameno = pv->context->coded_frame->pts;
+ int64_t frameno = pkt.pts;
+ buf->size = pkt.size;
buf->s.start = get_frame_start( pv, frameno );
buf->s.stop = get_frame_stop( pv, frameno );
buf->s.flags &= ~HB_FRAME_REF;
@@ -492,7 +500,7 @@ int encavcodecWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
case AV_PICTURE_TYPE_I:
{
buf->s.flags |= HB_FRAME_REF;
- if ( pv->context->coded_frame->key_frame )
+ if ( pkt.flags & AV_PKT_FLAG_KEY )
{
buf->s.frametype = HB_FRAME_IDR;
}
@@ -504,7 +512,7 @@ int encavcodecWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
default:
{
- if ( pv->context->coded_frame->key_frame )
+ if ( pkt.flags & AV_PKT_FLAG_KEY )
{
buf->s.flags |= HB_FRAME_REF;
buf->s.frametype = HB_FRAME_KEY;
diff --git a/libhb/encavcodecaudio.c b/libhb/encavcodecaudio.c
index 14df3f317..001000b9a 100644
--- a/libhb/encavcodecaudio.c
+++ b/libhb/encavcodecaudio.c
@@ -9,8 +9,7 @@
#include "hb.h"
#include "hbffmpeg.h"
-#include "downmix.h"
-#include "libavcodec/audioconvert.h"
+#include "audio_remap.h"
struct hb_work_private_s
{
@@ -23,6 +22,9 @@ struct hb_work_private_s
unsigned long output_bytes;
hb_list_t * list;
uint8_t * buf;
+
+ AVAudioResampleContext *avresample;
+ int *remap_table;
};
static int encavcodecaInit( hb_work_object_t *, hb_job_t * );
@@ -49,8 +51,6 @@ static int encavcodecaInit( hb_work_object_t * w, hb_job_t * job )
pv->job = job;
- pv->out_discrete_channels = hb_mixdown_get_discrete_channel_count( audio->config.out.mixdown );
-
codec = avcodec_find_encoder( w->codec_param );
if( !codec )
{
@@ -60,40 +60,30 @@ static int encavcodecaInit( hb_work_object_t * w, hb_job_t * job )
}
context = avcodec_alloc_context3(codec);
- AVDictionary *av_opts = NULL;
- if ( w->codec_param == CODEC_ID_AAC )
+ 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);
+
+ if (pv->out_discrete_channels > 2 &&
+ audio->config.in.channel_map != &hb_libav_chan_map)
{
- av_dict_set( &av_opts, "stereo_mode", "ms_off", 0 );
+ pv->remap_table = hb_audio_remap_build_table(context->channel_layout,
+ audio->config.in.channel_map,
+ &hb_libav_chan_map);
}
- if ( w->codec_param == CODEC_ID_AC3 )
+ else
{
- if( audio->config.out.mixdown == HB_AMIXDOWN_DOLBY ||
- audio->config.out.mixdown == HB_AMIXDOWN_DOLBYPLII )
- {
- av_dict_set( &av_opts, "dsur_mode", "on", 0 );
- }
+ pv->remap_table = NULL;
}
- switch (audio->config.out.mixdown)
+ AVDictionary *av_opts = NULL;
+ if (w->codec_param == CODEC_ID_AAC)
+ {
+ av_dict_set(&av_opts, "stereo_mode", "ms_off", 0);
+ }
+ else if (w->codec_param == CODEC_ID_AC3 && mode != AV_MATRIX_ENCODING_NONE)
{
- case HB_AMIXDOWN_MONO:
- context->channel_layout = AV_CH_LAYOUT_MONO;
- break;
-
- case HB_AMIXDOWN_STEREO:
- case HB_AMIXDOWN_DOLBY:
- case HB_AMIXDOWN_DOLBYPLII:
- context->channel_layout = AV_CH_LAYOUT_STEREO;
- break;
-
- case HB_AMIXDOWN_6CH:
- context->channel_layout = AV_CH_LAYOUT_5POINT1;
- break;
-
- default:
- context->channel_layout = AV_CH_LAYOUT_STEREO;
- hb_log("encavcodecaInit: bad mixdown");
- break;
+ av_dict_set(&av_opts, "dsur_mode", "on", 0);
}
if( audio->config.out.bitrate > 0 )
@@ -146,6 +136,31 @@ 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;
}
@@ -159,11 +174,20 @@ static int encavcodecaInit( hb_work_object_t * w, hb_job_t * job )
static void Finalize( hb_work_object_t * w )
{
hb_work_private_t * pv = w->private_data;
- hb_buffer_t * buf = hb_buffer_init( pv->output_bytes );
+ hb_buffer_t * buf;
// Finalize with NULL input needed by FLAC to generate md5sum
// in context extradata
- avcodec_encode_audio( pv->context, buf->data, buf->alloc, NULL );
+
+ // Prepare output packet
+ AVPacket pkt;
+ int got_packet;
+ buf = hb_buffer_init( pv->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 );
// Then we need to recopy the header since it was modified
@@ -198,11 +222,36 @@ static void encavcodecaClose( hb_work_object_t * w )
if ( pv->list )
hb_list_empty( &pv->list );
+ if (pv->avresample != NULL)
+ {
+ avresample_free(&pv->avresample);
+ }
+
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 )
{
hb_work_private_t * pv = w->private_data;
@@ -217,65 +266,67 @@ static hb_buffer_t * Encode( hb_work_object_t * w )
hb_list_getbytes( pv->list, pv->buf, pv->input_samples * sizeof( float ),
&pts, &pos);
-
- // XXX: ffaac fails to remap from the internal libav* channel map (SMPTE) to the native AAC channel map
- // do it here - this hack should be removed if Libav fixes the bug
- hb_chan_map_t * out_map = ( w->codec_param == CODEC_ID_AAC ) ? &hb_qt_chan_map : &hb_smpte_chan_map;
-
- if (audio->config.in.channel_map != out_map)
+ if (pv->remap_table != NULL)
{
- hb_layout_remap(audio->config.in.channel_map, out_map,
- pv->context->channel_layout, (float*)pv->buf,
- pv->samples_per_frame);
+ hb_audio_remap(pv->out_discrete_channels, pv->samples_per_frame,
+ (hb_sample_t*)pv->buf, pv->remap_table);
}
+ // 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?
- if ( pv->context->sample_fmt != AV_SAMPLE_FMT_FLT )
+ convertAudioFormat(pv, &frame);
+
+ // Prepare output packet
+ AVPacket pkt;
+ int got_packet;
+ buf = hb_buffer_init( pv->output_bytes );
+ av_init_packet(&pkt);
+ pkt.data = buf->data;
+ pkt.size = buf->alloc;
+
+ // Encode
+ int ret = avcodec_encode_audio2( pv->context, &pkt, &frame, &got_packet);
+ if ( ret < 0 )
{
- int isamp, osamp;
- AVAudioConvert *ctx;
-
- isamp = av_get_bytes_per_sample( AV_SAMPLE_FMT_FLT );
- osamp = av_get_bytes_per_sample( pv->context->sample_fmt );
- ctx = av_audio_convert_alloc( pv->context->sample_fmt, 1,
- AV_SAMPLE_FMT_FLT, 1,
- NULL, 0 );
-
- // get output buffer size then malloc a buffer
- //nsamples = out_size / isamp;
- //buffer = av_malloc( nsamples * sizeof(hb_sample_t) );
-
- // we're doing straight sample format conversion which
- // behaves as if there were only one channel.
- const void * const ibuf[6] = { pv->buf };
- void * const obuf[6] = { pv->buf };
- const int istride[6] = { isamp };
- const int ostride[6] = { osamp };
-
- av_audio_convert( ctx, obuf, ostride, ibuf, istride, pv->input_samples );
- av_audio_convert_free( ctx );
+ hb_log( "encavcodeca: avcodec_encode_audio failed" );
+ hb_buffer_close( &buf );
+ return NULL;
}
-
- buf = hb_buffer_init( pv->output_bytes );
- buf->size = avcodec_encode_audio( pv->context, buf->data, buf->alloc,
- (short*)pv->buf );
- buf->s.start = pts + 90000 * pos / pv->out_discrete_channels / sizeof( float ) / audio->config.out.samplerate;
- buf->s.stop = buf->s.start + 90000 * pv->samples_per_frame / audio->config.out.samplerate;
+ if ( got_packet && pkt.size )
+ {
+ buf->size = pkt.size;
- buf->s.type = AUDIO_BUF;
- buf->s.frametype = HB_FRAME_AUDIO;
+ // 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 });
- if ( !buf->size )
- {
- hb_buffer_close( &buf );
- return Encode( w );
+ buf->s.stop = buf->s.start + 90000 * pv->samples_per_frame / audio->config.out.samplerate;
+
+ buf->s.type = AUDIO_BUF;
+ buf->s.frametype = HB_FRAME_AUDIO;
}
- else if (buf->size < 0)
+ else
{
- hb_log( "encavcodeca: avcodec_encode_audio failed" );
hb_buffer_close( &buf );
- return NULL;
+ return Encode( w );
}
return buf;
diff --git a/libhb/encfaac.c b/libhb/encfaac.c
index d01afce8a..6782605e9 100644
--- a/libhb/encfaac.c
+++ b/libhb/encfaac.c
@@ -8,6 +8,7 @@
*/
#include "hb.h"
+#include "audio_remap.h"
#include "faac.h"
@@ -72,7 +73,7 @@ int encfaacInit( hb_work_object_t * w, hb_job_t * job )
pv->job = job;
/* pass the number of channels used into the private work data */
- pv->out_discrete_channels = hb_mixdown_get_discrete_channel_count( audio->config.out.mixdown );
+ pv->out_discrete_channels = hb_mixdown_get_discrete_channel_count(audio->config.out.mixdown);
/* if the sample rate is 'auto' and that has given us an invalid output */
/* rate, map it to the next highest output rate or 48K if above the highest. */
@@ -109,13 +110,20 @@ int encfaacInit( hb_work_object_t * w, hb_job_t * job )
cfg->aacObjectType = LOW;
cfg->allowMidside = 1;
- if (pv->out_discrete_channels == 6) {
- /* we are preserving 5.1 audio into 6-channel AAC,
- so indicate that we have an lfe channel */
- cfg->useLfe = 1;
- } else {
- cfg->useLfe = 0;
- }
+ // LFE, remapping
+ uint64_t layout;
+ layout = hb_ff_mixdown_xlat(audio->config.out.mixdown, NULL);
+ cfg->useLfe = !!(layout & AV_CH_LOW_FREQUENCY);
+ if (pv->out_discrete_channels > 2 &&
+ audio->config.in.channel_map != &hb_aac_chan_map)
+ {
+ int *remap_table;
+ remap_table = hb_audio_remap_build_table(layout,
+ audio->config.in.channel_map,
+ &hb_aac_chan_map);
+ // faac does its own remapping
+ memcpy(cfg->channel_map, remap_table, pv->out_discrete_channels * sizeof(int));
+ }
cfg->useTns = 0;
cfg->bitRate = audio->config.out.bitrate * 1000 / pv->out_discrete_channels; /* Per channel */
@@ -123,28 +131,6 @@ int encfaacInit( hb_work_object_t * w, hb_job_t * job )
cfg->outputFormat = 0;
cfg->inputFormat = FAAC_INPUT_FLOAT;
- if( ( audio->config.out.mixdown == HB_AMIXDOWN_6CH ) && ( audio->config.in.channel_map != &hb_qt_chan_map ) )
- {
- if( audio->config.in.channel_map == &hb_ac3_chan_map )
- {
- cfg->channel_map[0] = 2;
- cfg->channel_map[1] = 1;
- cfg->channel_map[2] = 3;
- cfg->channel_map[3] = 4;
- cfg->channel_map[4] = 5;
- cfg->channel_map[5] = 0;
- }
- else if( audio->config.in.channel_map == &hb_smpte_chan_map )
- {
- cfg->channel_map[0] = 2;
- cfg->channel_map[1] = 0;
- cfg->channel_map[2] = 1;
- cfg->channel_map[3] = 4;
- cfg->channel_map[4] = 5;
- cfg->channel_map[5] = 3;
- }
- }
-
if( !faacEncSetConfiguration( pv->faac, cfg ) )
{
hb_log( "faacEncSetConfiguration failed" );
diff --git a/libhb/encvorbis.c b/libhb/encvorbis.c
index b0c7ea0ce..da631592c 100644
--- a/libhb/encvorbis.c
+++ b/libhb/encvorbis.c
@@ -8,6 +8,7 @@
*/
#include "hb.h"
+#include "audio_remap.h"
#include "vorbis/vorbisenc.h"
@@ -40,9 +41,9 @@ struct hb_work_private_s
uint64_t pts;
hb_list_t * list;
- int out_discrete_channels;
- int channel_map[6];
- int64_t prev_blocksize;
+ int out_discrete_channels;
+ int * remap_table;
+ int64_t prev_blocksize;
};
int encvorbisInit( hb_work_object_t * w, hb_job_t * job )
@@ -53,7 +54,7 @@ int encvorbisInit( hb_work_object_t * w, hb_job_t * job )
hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );
w->private_data = pv;
- pv->out_discrete_channels = hb_mixdown_get_discrete_channel_count( audio->config.out.mixdown );
+ pv->out_discrete_channels = hb_mixdown_get_discrete_channel_count(audio->config.out.mixdown);
pv->job = job;
@@ -134,48 +135,13 @@ int encvorbisInit( hb_work_object_t * w, hb_job_t * job )
pv->list = hb_list_init();
- switch (pv->out_discrete_channels) {
- case 1:
- pv->channel_map[0] = 0;
- break;
- case 6:
- // Vorbis uses the following channel map = L C R Ls Rs Lfe
- if( audio->config.in.channel_map == &hb_ac3_chan_map )
- {
- pv->channel_map[0] = 1;
- pv->channel_map[1] = 2;
- pv->channel_map[2] = 3;
- pv->channel_map[3] = 4;
- pv->channel_map[4] = 5;
- pv->channel_map[5] = 0;
- }
- else if( audio->config.in.channel_map == &hb_smpte_chan_map )
- {
- pv->channel_map[0] = 0;
- pv->channel_map[1] = 2;
- pv->channel_map[2] = 1;
- pv->channel_map[3] = 4;
- pv->channel_map[4] = 5;
- pv->channel_map[5] = 3;
- }
- else // &hb_qt_chan_map
- {
- pv->channel_map[0] = 1;
- pv->channel_map[1] = 0;
- pv->channel_map[2] = 2;
- pv->channel_map[3] = 3;
- pv->channel_map[4] = 4;
- pv->channel_map[5] = 5;
- }
- break;
- default:
- hb_log("encvorbis.c: Unable to correctly proccess %d channels, assuming stereo.", pv->out_discrete_channels);
- case 2:
- // Assume stereo
- pv->channel_map[0] = 0;
- pv->channel_map[1] = 1;
- break;
- }
+ // remapping
+ uint64_t layout;
+ layout = hb_ff_mixdown_xlat(audio->config.out.mixdown, NULL);
+ pv->remap_table = hb_audio_remap_build_table(layout,
+ audio->config.in.channel_map,
+ &hb_vorbis_chan_map);
+
return 0;
}
@@ -273,7 +239,7 @@ static hb_buffer_t * Encode( hb_work_object_t * w )
{
for( j = 0; j < pv->out_discrete_channels; j++)
{
- buffer[j][i] = ((float *) pv->buf)[(pv->out_discrete_channels * i + pv->channel_map[j])];
+ buffer[j][i] = ((float *) pv->buf)[(pv->out_discrete_channels * i + pv->remap_table[j])];
}
}
diff --git a/libhb/hb.c b/libhb/hb.c
index b5c721953..c6b569caf 100644
--- a/libhb/hb.c
+++ b/libhb/hb.c
@@ -105,15 +105,16 @@ void hb_avcodec_init()
av_register_all();
}
-int hb_avcodec_open(AVCodecContext *avctx, AVCodec *codec, AVDictionary **av_opts, int thread_count)
+int hb_avcodec_open(AVCodecContext *avctx, AVCodec *codec,
+ AVDictionary **av_opts, int thread_count)
{
int ret;
- if ( ( thread_count == HB_FFMPEG_THREADS_AUTO || thread_count > 0 ) &&
- ( codec->type == AVMEDIA_TYPE_VIDEO ) )
+ if ((thread_count == HB_FFMPEG_THREADS_AUTO || thread_count > 0) &&
+ (codec->type == AVMEDIA_TYPE_VIDEO))
{
- avctx->thread_count = ( thread_count == HB_FFMPEG_THREADS_AUTO ) ?
- hb_get_cpu_count() / 2 + 1 : thread_count;
+ avctx->thread_count = (thread_count == HB_FFMPEG_THREADS_AUTO) ?
+ hb_get_cpu_count() / 2 + 1 : thread_count;
avctx->thread_type = FF_THREAD_FRAME|FF_THREAD_SLICE;
avctx->thread_safe_callbacks = 1;
}
@@ -134,16 +135,16 @@ int hb_avcodec_close(AVCodecContext *avctx)
}
-int hb_avpicture_fill( AVPicture *pic, hb_buffer_t *buf )
+int hb_avpicture_fill(AVPicture *pic, hb_buffer_t *buf)
{
int ret, ii;
- for( ii = 0; ii < 4; ii++ )
+ for (ii = 0; ii < 4; ii++)
pic->linesize[ii] = buf->plane[ii].stride;
- ret = av_image_fill_pointers( pic->data, buf->f.fmt,
- buf->plane[0].height_stride,
- buf->data, pic->linesize );
+ ret = av_image_fill_pointers(pic->data, buf->f.fmt,
+ buf->plane[0].height_stride,
+ buf->data, pic->linesize);
if (ret != buf->size)
{
hb_error("Internal error hb_avpicture_fill expected %d, got %d",
@@ -209,45 +210,61 @@ hb_sws_get_context(int srcW, int srcH, enum PixelFormat srcFormat,
return ctx;
}
+uint64_t hb_ff_mixdown_xlat(int hb_mixdown, int *downmix_mode)
+{
+ uint64_t ff_layout = 0;
+ int mode = AV_MATRIX_ENCODING_NONE;
+ switch (hb_mixdown)
+ {
+ // Passthru
+ case HB_AMIXDOWN_NONE:
+ break;
+
+ case HB_AMIXDOWN_MONO:
+ ff_layout = AV_CH_LAYOUT_MONO;
+ break;
+
+ case HB_AMIXDOWN_DOLBY:
+ ff_layout = AV_CH_LAYOUT_STEREO;
+ mode = AV_MATRIX_ENCODING_DOLBY;
+ break;
+
+ case HB_AMIXDOWN_DOLBYPLII:
+ ff_layout = AV_CH_LAYOUT_STEREO;
+ mode = AV_MATRIX_ENCODING_DPLII;
+ break;
+
+ case HB_AMIXDOWN_STEREO:
+ ff_layout = AV_CH_LAYOUT_STEREO;
+ break;
+
+ case HB_AMIXDOWN_6CH:
+ ff_layout = AV_CH_LAYOUT_5POINT1;
+ break;
+
+ default:
+ ff_layout = AV_CH_LAYOUT_STEREO;
+ hb_log("unrecognized channel layout");
+ break;
+ }
+ if (downmix_mode != NULL)
+ *downmix_mode = mode;
+ return ff_layout;
+}
+
uint64_t hb_ff_layout_xlat(uint64_t ff_channel_layout, int nchannels)
{
uint64_t hb_layout = ff_channel_layout;
if (!hb_layout ||
av_get_channel_layout_nb_channels(hb_layout) != nchannels)
{
- switch (nchannels)
+ hb_layout = av_get_default_channel_layout(nchannels);
+ if (!hb_layout)
{
- // TODO: use av_get_default_channel_layout when available
- case 1:
- hb_layout = AV_CH_LAYOUT_MONO;
- break;
- case 2:
- hb_layout = AV_CH_LAYOUT_STEREO;
- break;
- case 3:
- hb_layout = AV_CH_LAYOUT_SURROUND;
- break;
- case 4:
- hb_layout = AV_CH_LAYOUT_QUAD;
- break;
- case 5:
- hb_layout = AV_CH_LAYOUT_5POINT0;
- break;
- case 6:
- hb_layout = AV_CH_LAYOUT_5POINT1;
- break;
- case 7:
- hb_layout = AV_CH_LAYOUT_5POINT1|AV_CH_BACK_CENTER;
- break;
- case 8:
- hb_layout = AV_CH_LAYOUT_7POINT1;
- break;
- default:
- // This will likely not sound very good ;)
- hb_layout = AV_CH_LAYOUT_STEREO;
- hb_error("hb_ff_layout_xlat: unsupported layout 0x%"PRIx64" with %d channels",
- ff_channel_layout, nchannels);
- break;
+ // This will likely not sound very good ;)
+ hb_layout = AV_CH_LAYOUT_STEREO;
+ hb_error("hb_ff_layout_xlat: unsupported layout 0x%"PRIx64" with %d channels",
+ ff_channel_layout, nchannels);
}
}
return hb_layout;
diff --git a/libhb/hbffmpeg.h b/libhb/hbffmpeg.h
index e4cf63474..138094bc8 100644
--- a/libhb/hbffmpeg.h
+++ b/libhb/hbffmpeg.h
@@ -14,16 +14,20 @@
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
#include "libswscale/swscale.h"
+#include "libavresample/avresample.h"
#define HB_FFMPEG_THREADS_AUTO (-1) // let hb_avcodec_open decide thread_count
void hb_avcodec_init(void);
-int hb_avcodec_open( AVCodecContext *, struct AVCodec *, AVDictionary **av_opts, int thread_count );
-int hb_avcodec_close( AVCodecContext * );
+int hb_avcodec_open(AVCodecContext *, AVCodec *, AVDictionary **av_opts, int thread_count);
+int hb_avcodec_close(AVCodecContext *);
+
uint64_t hb_ff_layout_xlat(uint64_t ff_channel_layout, int nchannels);
-struct SwsContext* hb_sws_get_context( int srcW, int srcH,
- enum PixelFormat srcFormat, int dstW, int dstH,
- enum PixelFormat dstFormat, int flags);
-void hb_ff_set_sample_fmt(AVCodecContext *context, AVCodec *codec);
-int hb_ff_dts_disable_xch( AVCodecContext *c );
-int hb_avpicture_fill( AVPicture *pic, hb_buffer_t *buf );
+uint64_t hb_ff_mixdown_xlat(int hb_mixdown, int *downmix_mode);
+void hb_ff_set_sample_fmt(AVCodecContext *context, AVCodec *codec);
+
+struct SwsContext*
+hb_sws_get_context(int srcW, int srcH, enum PixelFormat srcFormat,
+ int dstW, int dstH, enum PixelFormat dstFormat,
+ int flags);
+int hb_avpicture_fill(AVPicture *pic, hb_buffer_t *buf);
diff --git a/libhb/mcdeint.c b/libhb/mcdeint.c
index 2ffb722f7..4c4c10cef 100644
--- a/libhb/mcdeint.c
+++ b/libhb/mcdeint.c
@@ -58,7 +58,6 @@ void mcdeint_init( mcdeint_private_t * pv,
avctx_enc->flags = CODEC_FLAG_QSCALE | CODEC_FLAG_LOW_DELAY;
avctx_enc->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
avctx_enc->global_quality = 1;
- avctx_enc->flags2 = CODEC_FLAG2_MEMC_ONLY;
avctx_enc->me_cmp = FF_CMP_SAD; //SSE;
avctx_enc->me_sub_cmp = FF_CMP_SAD; //SSE;
avctx_enc->mb_cmp = FF_CMP_SSE;
@@ -80,8 +79,7 @@ void mcdeint_init( mcdeint_private_t * pv,
}
pv->mcdeint_frame = avcodec_alloc_frame();
- pv->mcdeint_outbuf_size = width * height * 10;
- pv->mcdeint_outbuf = malloc( pv->mcdeint_outbuf_size );
+ av_new_packet( &pv->mcdeint_pkt, width * height * 10 );
}
}
@@ -96,10 +94,7 @@ void mcdeint_close( mcdeint_private_t * pv )
hb_avcodec_close( pv->mcdeint_avctx_enc );
av_freep( &pv->mcdeint_avctx_enc );
}
- if( pv->mcdeint_outbuf )
- {
- free( pv->mcdeint_outbuf );
- }
+ av_free_packet( &pv->mcdeint_pkt );
}
}
@@ -127,10 +122,10 @@ void mcdeint_filter( uint8_t ** dst,
pv->mcdeint_avctx_enc->me_sub_cmp = FF_CMP_SAD;
pv->mcdeint_frame->quality = pv->mcdeint_qp * FF_QP2LAMBDA;
- avcodec_encode_video( pv->mcdeint_avctx_enc,
- pv->mcdeint_outbuf,
- pv->mcdeint_outbuf_size,
- pv->mcdeint_frame );
+ int got_packet;
+
+ avcodec_encode_video2( pv->mcdeint_avctx_enc,
+ &pv->mcdeint_pkt, pv->mcdeint_frame, &got_packet );
pv->mcdeint_frame_dec = pv->mcdeint_avctx_enc->coded_frame;
diff --git a/libhb/mcdeint.h b/libhb/mcdeint.h
index 2c47e1ce6..35b5a76fc 100644
--- a/libhb/mcdeint.h
+++ b/libhb/mcdeint.h
@@ -12,8 +12,7 @@ struct mcdeint_private_s
int mcdeint_mode;
int mcdeint_qp;
- int mcdeint_outbuf_size;
- uint8_t * mcdeint_outbuf;
+ AVPacket mcdeint_pkt;
AVCodecContext * mcdeint_avctx_enc;
AVFrame * mcdeint_frame;
AVFrame * mcdeint_frame_dec;
diff --git a/libhb/module.defs b/libhb/module.defs
index 3fefae82d..63acb9b9d 100644
--- a/libhb/module.defs
+++ b/libhb/module.defs
@@ -92,7 +92,7 @@ LIBHB.dll = $(LIBHB.build/)hb.dll
LIBHB.lib = $(LIBHB.build/)hb.lib
LIBHB.dll.libs = $(foreach n, \
- a52 ass avcodec avformat avutil dca dvdnav dvdread faac fontconfig freetype mkv mpeg2 mp3lame mp4v2 \
+ a52 ass avcodec avformat avutil avresample dca dvdnav dvdread faac fontconfig freetype mkv mpeg2 mp3lame mp4v2 \
ogg samplerate swscale theora vorbis vorbisenc x264 xml2 bluray, \
$(CONTRIB.build/)lib/lib$(n).a )
diff --git a/libhb/platform/macosx/encca_aac.c b/libhb/platform/macosx/encca_aac.c
index d67e039b2..7839ed930 100644
--- a/libhb/platform/macosx/encca_aac.c
+++ b/libhb/platform/macosx/encca_aac.c
@@ -8,7 +8,7 @@
*/
#include "hb.h"
-#include "downmix.h"
+#include "audio_remap.h"
#include <AudioToolbox/AudioToolbox.h>
#include <CoreAudio/CoreAudio.h>
@@ -49,8 +49,7 @@ struct hb_work_private_s
uint64_t pts, ibytes;
Float64 osamplerate;
- uint64_t layout;
- hb_chan_map_t *ichanmap;
+ int *remap_table;
};
#define MP4ESDescrTag 0x03
@@ -289,22 +288,17 @@ int encCoreAudioInit(hb_work_object_t *w, hb_job_t *job, enum AAC_MODE mode)
pv->osamplerate = output.mSampleRate;
audio->config.out.samples_per_frame = pv->isamples;
- // set channel map and layout (for remapping)
- pv->ichanmap = audio->config.in.channel_map;
- switch (audio->config.out.mixdown)
+ // channel remapping
+ if (pv->nchannels > 2 && audio->config.in.channel_map != &hb_aac_chan_map)
{
- case HB_AMIXDOWN_MONO:
- pv->layout = AV_CH_LAYOUT_MONO;
- break;
- case HB_AMIXDOWN_STEREO:
- case HB_AMIXDOWN_DOLBY:
- case HB_AMIXDOWN_DOLBYPLII:
- pv->layout = AV_CH_LAYOUT_STEREO;
- break;
- case HB_AMIXDOWN_6CH:
- default:
- pv->layout = AV_CH_LAYOUT_5POINT1;
- break;
+ uint64_t layout = hb_ff_mixdown_xlat(audio->config.out.mixdown, NULL);
+ pv->remap_table = hb_audio_remap_build_table(layout,
+ audio->config.in.channel_map,
+ &hb_aac_chan_map);
+ }
+ else
+ {
+ pv->remap_table = NULL;
}
// get maximum output size
@@ -350,6 +344,10 @@ void encCoreAudioClose(hb_work_object_t *w)
{
free(pv->buf);
}
+ if (pv->remap_table != NULL)
+ {
+ free(pv->remap_table);
+ }
hb_list_empty(&pv->list);
free(pv);
w->private_data = NULL;
@@ -394,10 +392,11 @@ static OSStatus inInputDataProc(AudioConverterRef converter, UInt32 *npackets,
*npackets = buffers->mBuffers[0].mDataByteSize / pv->isamplesiz;
pv->ibytes -= buffers->mBuffers[0].mDataByteSize;
- if (pv->ichanmap != &hb_qt_chan_map)
+ if (pv->remap_table != NULL)
{
- hb_layout_remap(pv->ichanmap, &hb_qt_chan_map, pv->layout,
- (float*)buffers->mBuffers[0].mData, *npackets);
+ hb_audio_remap(pv->nchannels, *npackets,
+ (hb_sample_t*)buffers->mBuffers[0].mData,
+ pv->remap_table);
}
return noErr;
diff --git a/libhb/stream.c b/libhb/stream.c
index 3e4a682e3..4c9cb347c 100644
--- a/libhb/stream.c
+++ b/libhb/stream.c
@@ -5085,13 +5085,13 @@ static int ffmpeg_open( hb_stream_t *stream, hb_title_t *title, int scan )
return 1;
fail:
- if ( info_ic ) av_close_input_file( info_ic );
+ if ( info_ic ) avformat_close_input( &info_ic );
return 0;
}
static void ffmpeg_close( hb_stream_t *d )
{
- av_close_input_file( d->ffmpeg_ic );
+ avformat_close_input( &d->ffmpeg_ic );
if ( d->ffmpeg_pkt != NULL )
{
free( d->ffmpeg_pkt );
@@ -5104,23 +5104,9 @@ static void add_ffmpeg_audio( hb_title_t *title, hb_stream_t *stream, int id )
AVStream *st = stream->ffmpeg_ic->streams[id];
AVCodecContext *codec = st->codec;
AVDictionaryEntry *tag;
- int layout;
- // DTS: work around lack of 6.0/6.1 support in libhb
- if( hb_ff_dts_disable_xch( codec ) )
- {
- hb_deep_log( 2, "add_ffmpeg_audio: found DTS-ES, requesting DTS core" );
- }
-
- // scan will ignore any audio without a bitrate. Since we've already
- // typed the audio in order to determine its codec we set up the audio
- // paramters here.
- layout = hb_ff_layout_xlat( codec->channel_layout, codec->channels );
- if ( !layout )
- {
- // Unsupported layout
- return;
- }
+ // scan will ignore any audio without a bitrate. Since we've already typed the
+ // audio in order to determine its codec we set up the audio parameters here.
if ( codec->bit_rate || codec->sample_rate )
{
hb_audio_t *audio = calloc( 1, sizeof(*audio) );;
@@ -5173,8 +5159,9 @@ static void add_ffmpeg_audio( hb_title_t *title, hb_stream_t *stream, int id )
audio->config.in.bitrate = 1;
audio->config.in.samplerate = codec->sample_rate;
audio->config.in.samples_per_frame = codec->frame_size;
- audio->config.in.channel_layout = layout;
- audio->config.in.channel_map = &hb_smpte_chan_map;
+ audio->config.in.channel_map = &hb_libav_chan_map;
+ audio->config.in.channel_layout = hb_ff_layout_xlat(codec->channel_layout,
+ codec->channels);
}
tag = av_dict_get( st->metadata, "language", NULL, 0 );
diff --git a/libhb/sync.c b/libhb/sync.c
index 181d0acb3..fc01c3b12 100644
--- a/libhb/sync.c
+++ b/libhb/sync.c
@@ -922,7 +922,6 @@ static void InitAudio( hb_job_t * job, hb_sync_common_t * common, int i )
gap */
AVCodec * codec;
AVCodecContext * c;
- short * zeros;
switch ( w->audio->config.out.codec )
{
@@ -966,8 +965,18 @@ static void InitAudio( hb_job_t * job, hb_sync_common_t * common, int i )
return;
}
- int input_size = c->frame_size * av_get_bytes_per_sample( c->sample_fmt ) * c->channels;
+ // Prepare input frame
+ AVFrame frame;
+ uint8_t * zeros;
+
+ frame.nb_samples= c->frame_size;
+ int input_size = av_samples_get_buffer_size(NULL, c->channels,
+ frame.nb_samples, c->sample_fmt, 1);
zeros = calloc( 1, input_size );
+ avcodec_fill_audio_frame(&frame, c->channels,
+ c->sample_fmt, zeros, input_size, 1);
+ frame.pts = 0;
+
// Allocate enough space for the encoded silence
// The output should be < the input
sync->silence_buf = malloc( input_size );
@@ -977,19 +986,26 @@ static void InitAudio( hb_job_t * job, hb_sync_common_t * common, int i )
int ii;
for ( ii = 0; ii < 10; ii++ )
{
- sync->silence_size = avcodec_encode_audio( c, sync->silence_buf,
- input_size, zeros );
+ // Prepare output packet
+ AVPacket pkt;
+ int got_packet;
+ av_init_packet(&pkt);
+ pkt.data = zeros;
+ pkt.size = input_size;
+
+ int ret = avcodec_encode_audio2( c, &pkt, &frame, &got_packet);
+ if ( ret < 0 )
+ {
+ hb_log( "sync: avcodec_encode_audio failed" );
+ break;
+ }
- if (sync->silence_size)
+ if ( got_packet )
{
+ sync->silence_size = pkt.size;
break;
}
}
- if (!sync->silence_size)
- {
- hb_log( "sync: avcodec_encode_audio failed" );
- }
-
free( zeros );
hb_avcodec_close( c );
av_free( c );