summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjstebbins <[email protected]>2010-04-05 18:50:29 +0000
committerjstebbins <[email protected]>2010-04-05 18:50:29 +0000
commitd7dc1c11f93fe701893899471a5d729869d8f5c6 (patch)
tree5d087d19b5092465f471e1ef76138b5f42396c97
parent453a109aae42e4ce540b16977c4ffe3631b7dce3 (diff)
generalize audio channel map reordering
this allows remapping any channel order to any other channel order with the appropriate map definitions. channel maps currently supplied are smpte (used by ffmpeg), qt (our standard channel order), and ac3 (as delivered by a52dec). remapping can also be applied to the downmixer with the function hb_downmix_set_chan_map(hb_chan_map_t * map_in, hb_chan_map_t * map_out). this allows downmixing and channel reordering in a single step. there is no additional cost to reordering since the matrix multiply used to do the downmix simultaneously reorders. git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@3201 b64f7644-9d1e-0410-96f1-a4d463321fa5
-rw-r--r--libhb/decavcodec.c10
-rw-r--r--libhb/downmix.c482
-rw-r--r--libhb/downmix.h31
3 files changed, 404 insertions, 119 deletions
diff --git a/libhb/decavcodec.c b/libhb/decavcodec.c
index 9f3196a85..17d320657 100644
--- a/libhb/decavcodec.c
+++ b/libhb/decavcodec.c
@@ -209,6 +209,7 @@ static int decavcodecInit( hb_work_object_t * w, hb_job_t * job )
{
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_qt_chan_map );
}
return 0;
@@ -1081,6 +1082,7 @@ static int decavcodecviInit( hb_work_object_t * w, hb_job_t * job )
{
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_qt_chan_map );
}
return 0;
@@ -1228,9 +1230,6 @@ static void decodeAudio( hb_audio_t * audio, hb_work_private_t *pv, uint8_t *dat
}
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) );
@@ -1247,8 +1246,9 @@ static void decodeAudio( hb_audio_t * audio, hb_work_private_t *pv, uint8_t *dat
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 );
+ hb_layout_remap( &hb_smpte_chan_map, &hb_qt_chan_map,
+ audio->config.in.channel_layout,
+ fl32, n_ch_samples );
}
double pts = pv->pts_next;
diff --git a/libhb/downmix.c b/libhb/downmix.c
index 0ab9b90f3..2b57324c1 100644
--- a/libhb/downmix.c
+++ b/libhb/downmix.c
@@ -888,6 +888,7 @@ int hb_mixdown_to_mode(uint32_t mixdown)
}
}
+
// 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
@@ -924,47 +925,232 @@ int hb_mixdown_to_mode(uint32_t mixdown)
// 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] =
+#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 =
+{
{
-// 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
+ {{ 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
+}
};
-int hb_smpte_chan_map[10][2][8] =
+hb_chan_map_t hb_ac3_chan_map =
{
-// 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
+{
+ {{ 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( int (*layouts)[2][8], hb_sample_t * samples, int layout, int nsamples )
+void hb_layout_remap(
+ hb_chan_map_t * map_in,
+ hb_chan_map_t * map_out,
+ int 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[6];
@@ -972,7 +1158,8 @@ void hb_layout_remap( int (*layouts)[2][8], hb_sample_t * samples, int layout, i
lfe = ((mode & DOWNMIX_LFE_FLAG) != 0);
mode = mode & DOWNMIX_CHANNEL_MASK;
nchans = nchans_tbl[mode] + lfe;
- map = layouts[mode][lfe];
+ inv_map = map_in->inv_chan_map[mode][lfe];
+ map = map_out->chan_map[mode][lfe];
for (ii = 0; ii < nsamples; ii++)
{
@@ -982,7 +1169,8 @@ void hb_layout_remap( int (*layouts)[2][8], hb_sample_t * samples, int layout, i
}
for (jj = 0; jj < nchans; jj++)
{
- samples[jj] = tmp[map[jj]];
+ int ord = map[jj];
+ samples[jj] = tmp[inv_map[ord]];
}
samples += nchans;
}
@@ -1016,43 +1204,36 @@ static void matrix_mul(
}
}
-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)
+static void set_level( hb_downmix_t * downmix )
{
int ii, jj;
- int spos;
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++)
{
- matrix[ii][jj] *= level;
+ downmix->matrix[ii][jj] *= downmix->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_in & HB_CH_FRONT_CENTER)
{
if (!(layout_out & HB_CH_FRONT_CENTER))
{
for (jj = 0; jj < 8; jj++)
{
- matrix[0][jj] *= clev;
+ downmix->matrix[downmix->center][jj] *= downmix->clev;
}
}
}
@@ -1064,29 +1245,16 @@ static void set_level(
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++)
{
- 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;
- }
+ 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;
}
}
@@ -1101,9 +1269,8 @@ static void set_level(
// 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 level = downmix->level;
hb_sample_t clev = downmix->clev;
hb_sample_t slev = downmix->slev;
@@ -1218,27 +1385,41 @@ void hb_downmix_adjust_level( hb_downmix_t * downmix )
level /= 1 + LVL_3DB + 2 * LVL_SQRT_1_3 + 2 * LVL_SQRT_2_3;
}
+ 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] *= level;
+ downmix->matrix[ii][jj] = matrix[ii][jj];
}
}
}
-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;
@@ -1254,53 +1435,121 @@ int hb_downmix_set_mode( hb_downmix_t * downmix, int layout, int mixdown )
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;
+
+ 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 )
{
- 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;
+ downmix->clev = clev;
+ downmix->slev = slev;
+ downmix->level = level;
+ downmix->matrix_initialized = 0;
+}
- if (mode_in >= DOWNMIX_NUM_MODES || mode_out >= DOWNMIX_NUM_MODES)
- return;
+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];
- matrix = downmix_matrix[mode_in][mode_out];
+ // Copy the matrix
+ for ( ii = 0; ii < 8; ii++ )
+ {
+ for ( jj = 0; jj < 8; jj++ )
+ {
+ matrix[ii][jj] = downmix->matrix[ii][jj];
+ }
+ }
- for (ii = 0; ii < 8; ii++)
+ // 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++ )
{
- for (jj = 0; jj < 8; jj++)
+ int ord = map[ii];
+ int row = inv_map[ord];
+ switch (ord)
{
- downmix->matrix[ii][jj] = matrix[ii][jj];
+ 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];
}
}
- downmix->clev = clev;
- downmix->slev = slev;
- downmix->level = level;
- set_level(downmix->matrix, clev, slev, level, mode_in, mode_out);
+
+ // 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)
@@ -1315,12 +1564,11 @@ hb_downmix_t * hb_downmix_init(int layout, int mixdown)
return NULL;
}
// Set some good default values
- downmix->clev = LVL_3DB;
- downmix->slev = LVL_3DB;
- downmix->level = 1.0;
+ hb_downmix_set_level( downmix, LVL_3DB, LVL_3DB, 1.0 );
downmix->bias = 0.0;
- set_level(downmix->matrix, LVL_3DB, LVL_3DB, 1.0,
- downmix->mode_in, downmix->mode_out);
+ 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;
}
@@ -1331,10 +1579,22 @@ void hb_downmix_close( hb_downmix_t **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)
{
- matrix_mul(dst, src, downmix->nchans_out, downmix->nchans_in,
- nsamples, downmix->matrix, downmix->bias);
+ 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 )
diff --git a/libhb/downmix.h b/libhb/downmix.h
index f9710488b..5a6ec0bf5 100644
--- a/libhb/downmix.h
+++ b/libhb/downmix.h
@@ -11,22 +11,38 @@ 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 int hb_smpte_chan_map[10][2][8];
-extern int hb_ac3_chan_map[10][2][8];
+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 );
@@ -34,8 +50,17 @@ 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( int (*layouts)[2][8], hb_sample_t * samples, int layout, int nsamples );
+void hb_layout_remap(
+ hb_chan_map_t * map_in,
+ hb_chan_map_t * map_out,
+ int layout,
+ hb_sample_t * samples,
+ int nsamples );
int hb_need_downmix( int layout, int mixdown );
#endif /* DOWNMIX_H */