summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjstebbins <[email protected]>2010-04-02 15:10:48 +0000
committerjstebbins <[email protected]>2010-04-02 15:10:48 +0000
commiteb4ffde8a29cf9b77a84440fa6c404e94eb9b6a6 (patch)
treeea5149118b167b07f4a33f4f0cf9f1a8ea7ee61f
parent13eb2d6d5e7ad894d0dfe808dc3cb26a062d48b7 (diff)
downmix support for ffmpeg audio sources
now we can eat our own dogfood. i.e. aac 6ch discrete input now works, along with any other multi-channel audio ffmpeg can toss at us. git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@3182 b64f7644-9d1e-0410-96f1-a4d463321fa5
-rw-r--r--gtk/src/hb-backend.c13
-rw-r--r--libhb/common.h1
-rw-r--r--libhb/decavcodec.c109
-rw-r--r--libhb/downmix.c1348
-rw-r--r--libhb/downmix.h41
-rw-r--r--libhb/hb.c45
-rw-r--r--libhb/hbffmpeg.h1
-rw-r--r--libhb/stream.c27
-rw-r--r--libhb/work.c59
9 files changed, 1542 insertions, 102 deletions
diff --git a/gtk/src/hb-backend.c b/gtk/src/hb-backend.c
index 53b71fd2d..dbcb437a9 100644
--- a/gtk/src/hb-backend.c
+++ b/gtk/src/hb-backend.c
@@ -1397,8 +1397,6 @@ ghb_grey_combo_options(GtkBuilder *builder)
allow_6ch = acodec & ~HB_ACODEC_LAME;
if (audio)
{
- allow_mono = allow_mono &&
- (audio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA));
gint layout = audio->in.channel_layout & HB_INPUT_CH_LAYOUT_DISCRETE_NO_LFE_MASK;
allow_stereo =
((layout == HB_INPUT_CH_LAYOUT_MONO && !allow_mono) || layout >= HB_INPUT_CH_LAYOUT_STEREO);
@@ -1408,7 +1406,6 @@ ghb_grey_combo_options(GtkBuilder *builder)
(layout == HB_INPUT_CH_LAYOUT_DOLBY);
allow_dpl2 = (layout == HB_INPUT_CH_LAYOUT_3F2R);
allow_6ch = allow_6ch &&
- (audio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
(layout == HB_INPUT_CH_LAYOUT_3F2R) &&
(audio->in.channel_layout & HB_INPUT_CH_LAYOUT_HAS_LFE);
}
@@ -1449,9 +1446,7 @@ ghb_get_best_mix(gint titleindex, gint track, gint acodec, gint mix)
audio = get_hb_audio(titleindex, track);
if (audio)
{
- allow_mono =
- (audio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
- (acodec & ~HB_ACODEC_LAME);
+ allow_mono = (acodec & ~HB_ACODEC_LAME);
gint layout = audio->in.channel_layout & HB_INPUT_CH_LAYOUT_DISCRETE_NO_LFE_MASK;
allow_stereo =
((layout == HB_INPUT_CH_LAYOUT_MONO && !allow_mono) || layout >= HB_INPUT_CH_LAYOUT_STEREO);
@@ -1461,7 +1456,6 @@ ghb_get_best_mix(gint titleindex, gint track, gint acodec, gint mix)
(layout == HB_INPUT_CH_LAYOUT_DOLBY);
allow_dpl2 = (layout == HB_INPUT_CH_LAYOUT_3F2R);
allow_6ch =
- (audio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
(acodec & ~HB_ACODEC_LAME) &&
(layout == HB_INPUT_CH_LAYOUT_3F2R) &&
(audio->in.channel_layout & HB_INPUT_CH_LAYOUT_HAS_LFE);
@@ -4096,9 +4090,7 @@ ghb_validate_audio(signal_user_data_t *ud)
gboolean allow_dolby = TRUE;
gboolean allow_dpl2 = TRUE;
gboolean allow_6ch = TRUE;
- allow_mono =
- (taudio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
- (codec & ~HB_ACODEC_LAME);
+ allow_mono = (codec & ~HB_ACODEC_LAME);
gint layout = taudio->in.channel_layout & HB_INPUT_CH_LAYOUT_DISCRETE_NO_LFE_MASK;
allow_stereo =
((layout == HB_INPUT_CH_LAYOUT_MONO && !allow_mono) || layout >= HB_INPUT_CH_LAYOUT_STEREO);
@@ -4108,7 +4100,6 @@ ghb_validate_audio(signal_user_data_t *ud)
(layout == HB_INPUT_CH_LAYOUT_DOLBY);
allow_dpl2 = (layout == HB_INPUT_CH_LAYOUT_3F2R);
allow_6ch =
- (taudio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
(codec & ~HB_ACODEC_LAME) &&
(layout == HB_INPUT_CH_LAYOUT_3F2R) &&
(taudio->in.channel_layout & HB_INPUT_CH_LAYOUT_HAS_LFE);
diff --git a/libhb/common.h b/libhb/common.h
index 0c06ba967..cf1dc02d8 100644
--- a/libhb/common.h
+++ b/libhb/common.h
@@ -361,6 +361,7 @@ struct hb_job_s
#define HB_INPUT_CH_LAYOUT_2F2R 0x0722022
#define HB_INPUT_CH_LAYOUT_3F2R 0x0832032
#define HB_INPUT_CH_LAYOUT_4F2R 0x0942042
+#define HB_INPUT_CH_LAYOUT_3F4R 0x0a34034
#define HB_INPUT_CH_LAYOUT_HAS_LFE 0x0000100
/* define some macros to extract the various information from the HB_AMIXDOWN_XXXX values */
#define HB_INPUT_CH_LAYOUT_GET_DISCRETE_FRONT_COUNT( a ) ( ( a & HB_INPUT_CH_LAYOUT_DISCRETE_FRONT_MASK ) >> 16 )
diff --git a/libhb/decavcodec.c b/libhb/decavcodec.c
index 352c0bd1b..e083d517e 100644
--- a/libhb/decavcodec.c
+++ b/libhb/decavcodec.c
@@ -61,6 +61,7 @@
#include "hb.h"
#include "hbffmpeg.h"
+#include "downmix.h"
#include "libavcodec/audioconvert.h"
static int decavcodecInit( hb_work_object_t *, hb_job_t * );
@@ -108,9 +109,11 @@ struct hb_work_private_s
pts_heap_t pts_heap;
void* buffer;
struct SwsContext *sws_context; // if we have to rescale or convert color space
+ hb_downmix_t *downmix;
+ hb_sample_t *downmix_buffer;
};
-static void decodeAudio( hb_work_private_t *pv, uint8_t *data, int size );
+static void decodeAudio( hb_audio_t * audio, hb_work_private_t *pv, uint8_t *data, int size );
static hb_buffer_t *link_buf_list( hb_work_private_t *pv );
@@ -200,6 +203,14 @@ static int decavcodecInit( hb_work_object_t * w, hb_job_t * job )
pv->context = avcodec_alloc_context();
hb_avcodec_open( pv->context, codec );
+ if ( w->audio != NULL &&
+ 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);
+ }
+
return 0;
}
@@ -241,6 +252,15 @@ static void decavcodecClose( hb_work_object_t * w )
av_free( pv->buffer );
pv->buffer = NULL;
}
+ if ( pv->downmix )
+ {
+ hb_downmix_close( &(pv->downmix) );
+ }
+ if ( pv->downmix_buffer )
+ {
+ free( pv->downmix_buffer );
+ pv->downmix_buffer = NULL;
+ }
free( pv );
w->private_data = NULL;
}
@@ -311,7 +331,7 @@ static int decavcodecWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
pv->duration = 90000. /
(double)( pv->context->sample_rate * pv->context->channels );
}
- decodeAudio( pv, parser_output_buffer, parser_output_buffer_len );
+ decodeAudio( w->audio, pv, parser_output_buffer, parser_output_buffer_len );
}
}
*buf_out = link_buf_list( pv );
@@ -337,18 +357,6 @@ static int decavcodecInfo( hb_work_object_t *w, hb_work_info_t *info )
return 0;
}
-static const int chan2layout[] = {
- HB_INPUT_CH_LAYOUT_MONO, // We should allow no audio really.
- HB_INPUT_CH_LAYOUT_MONO,
- HB_INPUT_CH_LAYOUT_STEREO,
- HB_INPUT_CH_LAYOUT_2F1R,
- HB_INPUT_CH_LAYOUT_2F2R,
- HB_INPUT_CH_LAYOUT_3F2R,
- HB_INPUT_CH_LAYOUT_4F2R,
- HB_INPUT_CH_LAYOUT_STEREO,
- HB_INPUT_CH_LAYOUT_STEREO,
-};
-
static int decavcodecBSInfo( hb_work_object_t *w, const hb_buffer_t *buf,
hb_work_info_t *info )
{
@@ -412,7 +420,8 @@ static int decavcodecBSInfo( hb_work_object_t *w, const hb_buffer_t *buf,
info->bitrate = context->bit_rate;
info->rate = context->sample_rate;
info->rate_base = 1;
- info->channel_layout = chan2layout[context->channels & 7];
+ info->channel_layout =
+ hb_ff_layout_xlat(context->channel_layout, context->channels);
ret = 1;
break;
}
@@ -1056,6 +1065,15 @@ static int decavcodecviInit( hb_work_object_t * w, hb_job_t * job )
pv->list = hb_list_init();
pv->pts_next = -1;
pv->pts = -1;
+
+ if ( w->audio != NULL &&
+ 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);
+ }
+
return 0;
}
@@ -1125,7 +1143,7 @@ static int decavcodecviInfo( hb_work_object_t *w, hb_work_info_t *info )
return 0;
}
-static void decodeAudio( hb_work_private_t *pv, uint8_t *data, int size )
+static void decodeAudio( hb_audio_t * audio, hb_work_private_t *pv, uint8_t *data, int size )
{
AVCodecContext *context = pv->context;
int pos = 0;
@@ -1145,6 +1163,7 @@ static void decodeAudio( hb_work_private_t *pv, uint8_t *data, int size )
avp.size = size - pos;
int out_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
+ int nsamples;
int len = avcodec_decode_audio3( context, buffer, &out_size, &avp );
if ( len <= 0 )
{
@@ -1169,8 +1188,8 @@ static void decodeAudio( hb_work_private_t *pv, uint8_t *data, int size )
context->sample_fmt, 1,
NULL, 0 );
// get output buffer size (in 2-byte samples) then malloc a buffer
- out_size = ( out_size * 2 ) / isamp;
- buffer = av_malloc( out_size );
+ nsamples = out_size / isamp;
+ buffer = av_malloc( nsamples * 2 );
// we're doing straight sample format conversion which behaves as if
// there were only one channel.
@@ -1179,26 +1198,56 @@ static void decodeAudio( hb_work_private_t *pv, uint8_t *data, int size )
const int istride[6] = { isamp };
const int ostride[6] = { 2 };
- av_audio_convert( ctx, obuf, ostride, ibuf, istride, out_size >> 1 );
+ av_audio_convert( ctx, obuf, ostride, ibuf, istride, nsamples );
av_audio_convert_free( ctx );
}
- hb_buffer_t *buf = hb_buffer_init( 2 * out_size );
+ else
+ {
+ nsamples = out_size / 2;
+ }
- // convert from bytes to total samples
- out_size >>= 1;
+ hb_buffer_t * buf;
+
+ if ( pv->downmix )
+ {
+ pv->downmix_buffer = realloc(pv->downmix_buffer, nsamples * sizeof(hb_sample_t));
+
+ int i;
+ for( i = 0; i < nsamples; ++i )
+ {
+ pv->downmix_buffer[i] = buffer[i];
+ }
+
+ int n_ch_samples = nsamples / context->channels;
+ hb_layout_remap( hb_smpte_chan_map, pv->downmix_buffer,
+ audio->config.in.channel_layout, n_ch_samples );
+
+ int channels = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->config.out.mixdown);
+
+ buf = hb_buffer_init( n_ch_samples * channels * sizeof(float) );
+ hb_sample_t *samples = (hb_sample_t *)buf->data;
+ hb_downmix(pv->downmix, samples, pv->downmix_buffer, n_ch_samples);
+ }
+ else
+ {
+ buf = hb_buffer_init( nsamples * sizeof(float) );
+ float *fl32 = (float *)buf->data;
+ int i;
+ for( i = 0; i < nsamples; ++i )
+ {
+ fl32[i] = buffer[i];
+ }
+ int n_ch_samples = nsamples / context->channels;
+ hb_layout_remap( hb_smpte_chan_map, fl32,
+ audio->config.in.channel_layout, n_ch_samples );
+ }
double pts = pv->pts_next;
buf->start = pts;
- pts += out_size * pv->duration;
+ pts += nsamples * pv->duration;
buf->stop = pts;
pv->pts_next = pts;
- float *fl32 = (float *)buf->data;
- int i;
- for( i = 0; i < out_size; ++i )
- {
- fl32[i] = buffer[i];
- }
hb_list_add( pv->list, buf );
// if we allocated a buffer for sample format conversion, free it
@@ -1251,7 +1300,7 @@ static int decavcodecaiWork( hb_work_object_t *w, hb_buffer_t **buf_in,
pv->pts_next = in->start;
}
prepare_ffmpeg_buffer( in );
- decodeAudio( pv, in->data, in->size );
+ decodeAudio( w->audio, pv, in->data, in->size );
*buf_out = link_buf_list( pv );
return HB_WORK_OK;
diff --git a/libhb/downmix.c b/libhb/downmix.c
new file mode 100644
index 000000000..0ab9b90f3
--- /dev/null
+++ b/libhb/downmix.c
@@ -0,0 +1,1348 @@
+/* $Id: downmix.c,v 1.15 2005/03/17 19:22:47 stebbins Exp $
+
+ 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. */
+
+#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_3 0.577350269
+#define LVL_SQRT_2_3 0.816496581
+
+#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_2_3, -LVL_SQRT_1_3, 0, 0, 0, 0, 0, 0 },
+ { -LVL_SQRT_1_3, LVL_SQRT_2_3, 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_2_3, -LVL_SQRT_1_3, 0, 0, 0, 0, 0, 0 },
+ { -LVL_SQRT_1_3, LVL_SQRT_2_3, 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_2_3*LVL_3DB, -LVL_SQRT_1_3*LVL_3DB, 0, 0, 0, 0, 0, 0 },
+ { -LVL_SQRT_1_3*LVL_3DB, LVL_SQRT_2_3*LVL_3DB, 0, 0, 0, 0, 0, 0 },
+ { LVL_SQRT_2_3*LVL_3DB, -LVL_SQRT_1_3*LVL_3DB, 0, 0, 0, 0, 0, 0 },
+ { -LVL_SQRT_1_3*LVL_3DB, LVL_SQRT_2_3*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(int layout)
+{
+ int mode;
+ switch (layout & HB_INPUT_CH_LAYOUT_DISCRETE_NO_LFE_MASK)
+ {
+ case HB_INPUT_CH_LAYOUT_MONO:
+ mode = DOWNMIX_MONO;
+ break;
+ case HB_INPUT_CH_LAYOUT_STEREO:
+ mode = DOWNMIX_STEREO;
+ break;
+ case HB_INPUT_CH_LAYOUT_3F:
+ mode = DOWNMIX_3F;
+ break;
+ case HB_INPUT_CH_LAYOUT_2F1R:
+ mode = DOWNMIX_2F1R;
+ break;
+ case HB_INPUT_CH_LAYOUT_3F1R:
+ mode = DOWNMIX_3F1R;
+ break;
+ case HB_INPUT_CH_LAYOUT_2F2R:
+ mode = DOWNMIX_2F2R;
+ break;
+ case HB_INPUT_CH_LAYOUT_3F2R:
+ mode = DOWNMIX_3F2R;
+ break;
+ case HB_INPUT_CH_LAYOUT_4F2R:
+ mode = DOWNMIX_3F2R|DOWNMIX_LFE_FLAG;
+ break;
+ case HB_INPUT_CH_LAYOUT_3F4R:
+ mode = DOWNMIX_3F4R;
+ break;
+ case HB_INPUT_CH_LAYOUT_DOLBY:
+ mode = DOWNMIX_STEREO;
+ break;
+ default:
+ mode = DOWNMIX_STEREO;
+ break;
+ }
+ if (layout & HB_INPUT_CH_LAYOUT_DISCRETE_LFE_MASK)
+ mode |= DOWNMIX_LFE_FLAG;
+ 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
+//
+
+// Map Indicies are mode, lfe, channel respectively
+int hb_ac3_chan_map[10][2][8] =
+{
+// w/o LFE w/ LFE
+// C L R LS RS Rls Rrs L R C LS RS Rls Rls LFE
+ {{ 0, }, { 1, 0, }}, // MONO
+ {{ 0, 1, }, { 1, 2, 0, }}, // STEREO
+ {{ 1, 0, 2, }, { 2, 1, 3, 0, }}, // 3F
+ {{ 0, 1, 2, }, { 1, 2, 3, 0, }}, // 2F1R
+ {{ 1, 0, 2, 3, }, { 2, 1, 3, 4, 0, }}, // 3F1R
+ {{ 0, 1, 2, 3, }, { 1, 2, 3, 4, 0, }}, // 2F2R
+ {{ 1, 0, 2, 3, 4, }, { 2, 1, 3, 4, 5, 0, }}, // 3F2R
+ {{ 1, 0, 2, 3, 4, 5, 6, }, { 2, 1, 3, 4, 5, 6, 7, 0 }}, // 3F4R
+ {{ 0, 1, }, { 0, 1, }}, // DOLBY
+ {{ 0, 1, }, { 0, 1, }} // DPLII
+};
+
+int hb_smpte_chan_map[10][2][8] =
+{
+// w/o LFE w/ LFE
+// L R C LS RS Rls Rrs L R C LS RS Rls Rls LFE
+ {{ 0, }, { 0, 1, }}, // MONO
+ {{ 0, 1, }, { 0, 1, 2, }}, // STEREO
+ {{ 2, 0, 1, }, { 2, 0, 1, 3, }}, // 3F
+ {{ 0, 1, 2, }, { 0, 1, 3, 2, }}, // 2F1R
+ {{ 2, 0, 1, 3, }, { 2, 0, 1, 4, 3, }}, // 3F1R
+ {{ 0, 1, 2, 3, }, { 0, 1, 3, 4, 2, }}, // 2F2R
+ {{ 2, 0, 1, 3, 4, }, { 2, 0, 1, 4, 5, 3, }}, // 3F2R
+ {{ 2, 0, 1, 5, 6, 3, 4, }, { 2, 0, 1, 6, 7, 4, 5, 3 }}, // 3F4R
+ {{ 0, 1, }, { 0, 1, }}, // DOLBY
+ {{ 0, 1, }, { 0, 1, }} // 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( int (*layouts)[2][8], hb_sample_t * samples, int layout, int nsamples )
+{
+ int nchans;
+ int ii, jj;
+ int lfe;
+ int * map;
+ int mode;
+ hb_sample_t tmp[6];
+
+ mode = hb_layout_to_mode(layout);
+ lfe = ((mode & DOWNMIX_LFE_FLAG) != 0);
+ mode = mode & DOWNMIX_CHANNEL_MASK;
+ nchans = nchans_tbl[mode] + lfe;
+ map = layouts[mode][lfe];
+
+ for (ii = 0; ii < nsamples; ii++)
+ {
+ for (jj = 0; jj < nchans; jj++)
+ {
+ tmp[jj] = samples[jj];
+ }
+ for (jj = 0; jj < nchans; jj++)
+ {
+ samples[jj] = tmp[map[jj]];
+ }
+ 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_sample_t (*matrix)[8],
+ hb_sample_t clev,
+ hb_sample_t slev,
+ hb_sample_t level,
+ int mode_in,
+ int mode_out)
+{
+ int ii, jj;
+ int spos;
+ int layout_in, layout_out;
+
+ for (ii = 0; ii < 8; ii++)
+ {
+ for (jj = 0; jj < 8; jj++)
+ {
+ matrix[ii][jj] *= level;
+ }
+ }
+ if (mode_out >= DOWNMIX_DOLBY)
+ return;
+
+ spos = 3;
+ layout_in = channel_layout_map[mode_in];
+ layout_out = channel_layout_map[mode_out];
+
+ if (!(layout_in & HB_CH_FRONT_CENTER))
+ {
+ spos--;
+ }
+ else
+ {
+ if (!(layout_out & HB_CH_FRONT_CENTER))
+ {
+ for (jj = 0; jj < 8; jj++)
+ {
+ matrix[0][jj] *= 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;
+ }
+ }
+ if (layout_in & (HB_CH_SIDE_LEFT|HB_CH_SIDE_RIGHT))
+ {
+ for (jj = 0; jj < 8; jj++)
+ {
+ matrix[spos][jj] *= slev;
+ matrix[spos+1][jj] *= slev;
+ }
+ spos += 2;
+ }
+ else if (layout_in & (HB_CH_BACK_CENTER))
+ {
+ for (jj = 0; jj < 8; jj++)
+ {
+ matrix[spos][jj] *= slev;
+ }
+ }
+ if (layout_in & (HB_CH_BACK_LEFT|HB_CH_BACK_RIGHT))
+ {
+ for (jj = 0; jj < 8; jj++)
+ {
+ matrix[spos][jj] *= slev;
+ matrix[spos+1][jj] *= 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 ii, jj;
+ int mode_in, mode_out;
+ hb_sample_t level = 1.0;
+ 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_3 + LVL_SQRT_2_3;
+ 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_3 + LVL_SQRT_2_3;
+ 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_3 + 2 * LVL_SQRT_2_3;
+ }
+
+ for (ii = 0; ii < 8; ii++)
+ {
+ for (jj = 0; jj < 8; jj++)
+ {
+ downmix->matrix[ii][jj] *= level;
+ }
+ }
+}
+
+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
+int hb_downmix_set_mode( hb_downmix_t * downmix, int layout, int mixdown )
+{
+ int ii, jj;
+ int lfe_in, lfe_out;
+ int mode_in, mode_out;
+ hb_sample_t (*matrix)[8];
+
+ 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;
+
+ 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];
+ }
+ }
+
+ 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;
+ 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 )
+{
+ int ii, jj;
+ int mode_in, mode_out;
+ hb_sample_t (*matrix)[8];
+
+ if ( downmix == NULL )
+ return;
+
+ 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;
+
+ 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];
+ }
+ }
+ downmix->clev = clev;
+ downmix->slev = slev;
+ downmix->level = level;
+ set_level(downmix->matrix, clev, slev, level, mode_in, mode_out);
+}
+
+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
+ downmix->clev = LVL_3DB;
+ downmix->slev = LVL_3DB;
+ downmix->level = 1.0;
+ downmix->bias = 0.0;
+ set_level(downmix->matrix, LVL_3DB, LVL_3DB, 1.0,
+ downmix->mode_in, downmix->mode_out);
+ return downmix;
+}
+
+void hb_downmix_close( hb_downmix_t **downmix )
+{
+ if (*downmix != NULL)
+ free(*downmix);
+ *downmix = NULL;
+}
+
+void hb_downmix( hb_downmix_t * downmix, hb_sample_t * dst, hb_sample_t * src, int nsamples)
+{
+ 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
new file mode 100644
index 000000000..f9710488b
--- /dev/null
+++ b/libhb/downmix.h
@@ -0,0 +1,41 @@
+/* $Id: downmix.h,v 1.51 2005/11/04 13:09:40 stebbins Exp $
+
+ 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. */
+
+#ifndef DOWNMIX_H
+#define DOWNMIX_H
+
+typedef float hb_sample_t;
+
+typedef struct
+{
+ int mode_in;
+ int mode_out;
+ int nchans_in;
+ int nchans_out;
+ hb_sample_t matrix[8][8];
+ hb_sample_t clev;
+ hb_sample_t slev;
+ hb_sample_t level;
+ hb_sample_t bias;
+} hb_downmix_t;
+
+// For convenience, a map to convert smpte channel layout
+// to QuickTime channel layout.
+// Map Indicies are mode, lfe, channel respectively
+extern int hb_smpte_chan_map[10][2][8];
+extern int hb_ac3_chan_map[10][2][8];
+
+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( hb_downmix_t * downmix, hb_sample_t * dst, hb_sample_t * src, int nsamples);
+void hb_layout_remap( int (*layouts)[2][8], hb_sample_t * samples, int layout, int nsamples );
+int hb_need_downmix( int layout, int mixdown );
+
+#endif /* DOWNMIX_H */
diff --git a/libhb/hb.c b/libhb/hb.c
index 6f1e1ff37..8e53a7a51 100644
--- a/libhb/hb.c
+++ b/libhb/hb.c
@@ -80,6 +80,51 @@ int hb_avcodec_close(AVCodecContext *avctx)
return ret;
}
+int hb_ff_layout_xlat(int64_t ff_channel_layout, int channels)
+{
+ switch (ff_channel_layout)
+ {
+ case CH_LAYOUT_MONO:
+ return HB_INPUT_CH_LAYOUT_MONO;
+ case CH_LAYOUT_STEREO:
+ return HB_INPUT_CH_LAYOUT_STEREO;
+ case CH_LAYOUT_SURROUND:
+ return HB_INPUT_CH_LAYOUT_3F;
+ case CH_LAYOUT_4POINT0:
+ return HB_INPUT_CH_LAYOUT_3F1R;
+ case CH_LAYOUT_2_2:
+ return HB_INPUT_CH_LAYOUT_2F2R;
+ case CH_LAYOUT_QUAD:
+ return HB_INPUT_CH_LAYOUT_2F2R;
+ case CH_LAYOUT_5POINT0:
+ // ffmpeg like to neglect to signal LFE
+ if (channels == 6)
+ return HB_INPUT_CH_LAYOUT_3F2R|HB_INPUT_CH_LAYOUT_HAS_LFE;
+ return HB_INPUT_CH_LAYOUT_3F2R;
+ case CH_LAYOUT_5POINT1:
+ return HB_INPUT_CH_LAYOUT_3F2R|HB_INPUT_CH_LAYOUT_HAS_LFE;
+ case CH_LAYOUT_5POINT0_BACK:
+ // ffmpeg like to neglect to signal LFE
+ if (channels == 6)
+ return HB_INPUT_CH_LAYOUT_3F2R|HB_INPUT_CH_LAYOUT_HAS_LFE;
+ return HB_INPUT_CH_LAYOUT_3F2R;
+ case CH_LAYOUT_5POINT1_BACK:
+ return HB_INPUT_CH_LAYOUT_3F2R|HB_INPUT_CH_LAYOUT_HAS_LFE;
+ case CH_LAYOUT_7POINT0:
+ // ffmpeg like to neglect to signal LFE
+ if (channels == 8)
+ return HB_INPUT_CH_LAYOUT_3F4R|HB_INPUT_CH_LAYOUT_HAS_LFE;
+ return HB_INPUT_CH_LAYOUT_3F4R;
+ case CH_LAYOUT_7POINT1:
+ return HB_INPUT_CH_LAYOUT_3F4R|HB_INPUT_CH_LAYOUT_HAS_LFE;
+ case CH_LAYOUT_STEREO_DOWNMIX:
+ return HB_INPUT_CH_LAYOUT_STEREO;
+ default:
+ return HB_INPUT_CH_LAYOUT_STEREO;
+ }
+ return HB_INPUT_CH_LAYOUT_STEREO;
+}
+
/**
* Registers work objects, by adding the work object to a liked list.
* @param w Handle to hb_work_object_t to register.
diff --git a/libhb/hbffmpeg.h b/libhb/hbffmpeg.h
index e0a7634d3..7c17e1a64 100644
--- a/libhb/hbffmpeg.h
+++ b/libhb/hbffmpeg.h
@@ -9,3 +9,4 @@
void hb_avcodec_init(void);
int hb_avcodec_open( AVCodecContext *, struct AVCodec * );
int hb_avcodec_close( AVCodecContext * );
+int hb_ff_layout_xlat(int64_t ff_layout, int channels);
diff --git a/libhb/stream.c b/libhb/stream.c
index 9d0ce8071..f75400f45 100644
--- a/libhb/stream.c
+++ b/libhb/stream.c
@@ -1435,6 +1435,18 @@ static void set_audio_description( hb_audio_t *audio, iso639_lang_t *lang )
sizeof( audio->config.lang.description ), "%s (%s)",
strlen(lang->native_name) ? lang->native_name : lang->eng_name,
codec_name );
+
+ if (audio->config.in.codec == HB_ACODEC_FFMPEG)
+ {
+ int layout = audio->config.in.channel_layout;
+ char *desc = audio->config.lang.description +
+ strlen( audio->config.lang.description );
+ sprintf( desc, " (%d.%d ch)",
+ HB_INPUT_CH_LAYOUT_GET_DISCRETE_FRONT_COUNT(layout) +
+ HB_INPUT_CH_LAYOUT_GET_DISCRETE_REAR_COUNT(layout),
+ HB_INPUT_CH_LAYOUT_GET_DISCRETE_LFE_COUNT(layout) );
+ }
+
snprintf( audio->config.lang.simple, sizeof( audio->config.lang.simple ), "%s",
strlen(lang->native_name) ? lang->native_name : lang->eng_name );
snprintf( audio->config.lang.iso639_2, sizeof( audio->config.lang.iso639_2 ),
@@ -2777,18 +2789,6 @@ static void add_ffmpeg_audio( hb_title_t *title, hb_stream_t *stream, int id )
// paramters here.
if ( codec->bit_rate || codec->sample_rate )
{
- static const int chan2layout[] = {
- HB_INPUT_CH_LAYOUT_MONO, // We should allow no audio really.
- HB_INPUT_CH_LAYOUT_MONO,
- HB_INPUT_CH_LAYOUT_STEREO,
- HB_INPUT_CH_LAYOUT_2F1R,
- HB_INPUT_CH_LAYOUT_2F2R,
- HB_INPUT_CH_LAYOUT_3F2R,
- HB_INPUT_CH_LAYOUT_4F2R,
- HB_INPUT_CH_LAYOUT_STEREO,
- HB_INPUT_CH_LAYOUT_STEREO,
- };
-
hb_audio_t *audio = calloc( 1, sizeof(*audio) );;
audio->id = id;
@@ -2807,7 +2807,8 @@ static void add_ffmpeg_audio( hb_title_t *title, hb_stream_t *stream, int id )
audio->config.in.bitrate = codec->bit_rate? codec->bit_rate : 1;
audio->config.in.samplerate = codec->sample_rate;
- audio->config.in.channel_layout = chan2layout[codec->channels & 7];
+ audio->config.in.channel_layout =
+ hb_ff_layout_xlat(codec->channel_layout, codec->channels);
}
set_audio_description( audio, lang_for_code2( st->language ) );
diff --git a/libhb/work.c b/libhb/work.c
index ac672f5f6..af4665bbc 100644
--- a/libhb/work.c
+++ b/libhb/work.c
@@ -546,7 +546,6 @@ static void do_job( hb_job_t * job, int cpu_count )
// So if the encoder is lame we need the output to be stereo (or multichannel
// matrixed into stereo like dpl). If the decoder is not AC3 or DCA the
// encoder has to handle the input format since we can't do a mixdown.
-#define CAN_MIXDOWN(a) ( a->config.in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA) )
#define STEREO_ONLY(a) ( a->config.out.codec & HB_ACODEC_LAME )
switch (audio->config.in.channel_layout & HB_INPUT_CH_LAYOUT_DISCRETE_NO_LFE_MASK)
@@ -566,16 +565,6 @@ static void do_job( hb_job_t * job, int cpu_count )
case HB_INPUT_CH_LAYOUT_MONO:
if ( STEREO_ONLY( audio ) )
{
- if ( !CAN_MIXDOWN( audio ) )
- {
- // XXX we're hosed - we can't mix up & lame can't handle
- // the input format. The user shouldn't be able to make
- // this choice. It's too late to do anything about it now
- // so complain in the log & let things abort in lame.
- hb_log( "ERROR - can't use lame mp3 audio output with "
- "mono audio stream %x - output will be messed up",
- audio->id );
- }
audio->config.out.mixdown = HB_AMIXDOWN_STEREO;
}
else
@@ -589,7 +578,7 @@ static void do_job( hb_job_t * job, int cpu_count )
// the A52 flags don't allow for a way to distinguish between DPL1 and
// DPL2 on a DVD so we always assume a DPL1 source for A52_DOLBY.
case HB_INPUT_CH_LAYOUT_DOLBY:
- if ( STEREO_ONLY( audio ) || !CAN_MIXDOWN( audio ) ||
+ if ( STEREO_ONLY( audio ) ||
audio->config.out.mixdown > HB_AMIXDOWN_DOLBY )
{
audio->config.out.mixdown = HB_AMIXDOWN_DOLBY;
@@ -599,57 +588,31 @@ static void do_job( hb_job_t * job, int cpu_count )
// 4 channel discrete
case HB_INPUT_CH_LAYOUT_2F2R:
case HB_INPUT_CH_LAYOUT_3F1R:
- if ( CAN_MIXDOWN( audio ) )
- {
- if ( STEREO_ONLY( audio ) ||
- audio->config.out.mixdown > HB_AMIXDOWN_DOLBY )
- {
- audio->config.out.mixdown = HB_AMIXDOWN_DOLBY;
- }
- }
- else
+ if ( STEREO_ONLY( audio ) ||
+ audio->config.out.mixdown > HB_AMIXDOWN_DOLBY )
{
- // XXX we can't mixdown & don't have any way to specify
- // 4 channel discrete output so we're hosed.
- hb_log( "ERROR - can't handle 4 channel discrete audio stream "
- "%x - output will be messed up", audio->id );
+ audio->config.out.mixdown = HB_AMIXDOWN_DOLBY;
}
break;
// 5 or 6 channel discrete
case HB_INPUT_CH_LAYOUT_3F2R:
- if ( CAN_MIXDOWN( audio ) )
+ if ( STEREO_ONLY( audio ) )
{
- if ( STEREO_ONLY( audio ) )
+ if ( audio->config.out.mixdown < HB_AMIXDOWN_STEREO )
{
- if ( audio->config.out.mixdown < HB_AMIXDOWN_STEREO )
- {
- audio->config.out.mixdown = HB_AMIXDOWN_STEREO;
- }
- else if ( audio->config.out.mixdown > HB_AMIXDOWN_DOLBYPLII )
- {
- audio->config.out.mixdown = HB_AMIXDOWN_DOLBYPLII;
- }
+ audio->config.out.mixdown = HB_AMIXDOWN_STEREO;
}
- else if ( ! ( audio->config.in.channel_layout &
- HB_INPUT_CH_LAYOUT_HAS_LFE ) )
+ else if ( audio->config.out.mixdown > HB_AMIXDOWN_DOLBYPLII )
{
- // we don't do 5 channel discrete so mixdown to DPLII
audio->config.out.mixdown = HB_AMIXDOWN_DOLBYPLII;
}
}
else if ( ! ( audio->config.in.channel_layout &
- HB_INPUT_CH_LAYOUT_HAS_LFE ) )
- {
- // XXX we can't mixdown & don't have any way to specify
- // 5 channel discrete output so we're hosed.
- hb_log( "ERROR - can't handle 5 channel discrete audio stream "
- "%x - output will be messed up", audio->id );
- }
- else
+ HB_INPUT_CH_LAYOUT_HAS_LFE ) )
{
- // we can't mixdown so force 6 channel discrete
- audio->config.out.mixdown = HB_AMIXDOWN_6CH;
+ // we don't do 5 channel discrete so mixdown to DPLII
+ audio->config.out.mixdown = HB_AMIXDOWN_DOLBYPLII;
}
break;
}