summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--contrib/faac/A00-bitrates.patch6
-rw-r--r--contrib/faac/A01-multichannel-improvements.patch752
-rw-r--r--contrib/faac/P00-cygwin.patch6
-rw-r--r--gtk/src/audiohandler.c6
-rw-r--r--gtk/src/audiohandler.h1
-rw-r--r--gtk/src/hb-backend.c89
-rw-r--r--gtk/src/presets.c39
-rw-r--r--libhb/audio_resample.c39
-rw-r--r--libhb/audio_resample.h3
-rw-r--r--libhb/common.c815
-rw-r--r--libhb/common.h12
-rw-r--r--libhb/encfaac.c67
-rw-r--r--libhb/encvorbis.c12
-rw-r--r--libhb/hb.c20
-rw-r--r--libhb/muxmp4.c6
-rw-r--r--libhb/work.c76
-rw-r--r--macosx/HBAudio.m20
-rw-r--r--macosx/HBAudioController.m12
-rw-r--r--test/test.c2
19 files changed, 1469 insertions, 514 deletions
diff --git a/contrib/faac/A00-bitrates.patch b/contrib/faac/A00-bitrates.patch
index 50b11ec78..49460768e 100644
--- a/contrib/faac/A00-bitrates.patch
+++ b/contrib/faac/A00-bitrates.patch
@@ -1,6 +1,6 @@
-diff -Naur faac-1.28/libfaac/frame.c ../build.debug/contrib/faac/faac-1.28/libfaac/frame.c
---- faac-1.28.orig/libfaac/frame.c 2004-11-17 06:26:06.000000000 -0800
-+++ faac-1.28/libfaac/frame.c 2010-04-10 12:26:28.200614437 -0700
+diff -Naur faac-1.28.old/libfaac/frame.c faac-1.28.new/libfaac/frame.c
+--- faac-1.28.old/libfaac/frame.c 2004-11-17 06:26:06.000000000 -0800
++++ faac-1.28.new/libfaac/frame.c 2010-04-10 12:26:28.200614437 -0700
@@ -196,6 +196,8 @@
{47000, 10000},
{64000, 16000},
diff --git a/contrib/faac/A01-multichannel-improvements.patch b/contrib/faac/A01-multichannel-improvements.patch
new file mode 100644
index 000000000..d0ec5ce3c
--- /dev/null
+++ b/contrib/faac/A01-multichannel-improvements.patch
@@ -0,0 +1,752 @@
+diff -Naur faac-1.28.old/frontend/main.c faac-1.28.new/frontend/main.c
+--- faac-1.28.old/frontend/main.c 2009-01-24 02:10:20.000000000 +0100
++++ faac-1.28.new/frontend/main.c 2012-08-06 21:15:34.000000000 +0200
+@@ -858,7 +858,7 @@
+ break;
+ }
+ if (infile->channels >= 6)
+- myFormat->useLfe = 1;
++ myFormat->numLFEChannels = 1;
+ myFormat->allowMidside = useMidSide;
+ if (bitRate)
+ myFormat->bitRate = bitRate / infile->channels;
+diff -Naur faac-1.28.old/include/faaccfg.h faac-1.28.new/include/faaccfg.h
+--- faac-1.28.old/include/faaccfg.h 2004-07-04 14:12:05.000000000 +0200
++++ faac-1.28.new/include/faaccfg.h 2012-08-06 21:15:34.000000000 +0200
+@@ -66,8 +66,14 @@
+ /* Allow mid/side coding */
+ unsigned int allowMidside;
+
+- /* Use one of the channels as LFE channel */
+- unsigned int useLfe;
++ /* Channel configuration */
++ unsigned int channelConfiguration;
++
++ /* Number of front, side, back & LFE channels */
++ unsigned int numFrontChannels;
++ unsigned int numSideChannels;
++ unsigned int numBackChannels;
++ unsigned int numLFEChannels;
+
+ /* Use Temporal Noise Shaping */
+ unsigned int useTns;
+diff -Naur faac-1.28.old/libfaac/bitstream.c faac-1.28.new/libfaac/bitstream.c
+--- faac-1.28.old/libfaac/bitstream.c 2007-06-05 20:59:47.000000000 +0200
++++ faac-1.28.new/libfaac/bitstream.c 2012-08-06 21:15:34.000000000 +0200
+@@ -1032,6 +1032,219 @@
+ return j;
+ }
+
++/* write a program_config_element() */
++int WritePCE(faacEncHandle hEncoder,
++ BitStream *bitStream,
++ int byte_alignment,
++ int instance_tag,
++ int writeFlag)
++{
++ int i;
++ int bits = 0;
++
++ /* we can have up to 29 full-bandwidth channels of each type:
++ * 4 bits -> 0 - 15 elements, 14 CPEs (28 channels) and 1 SCE (1 channel)
++ * we can have up to 3 LFE channels:
++ * 2 bits -> 0 - 3 elements, 3 LFEs (1 channel) */
++ if (hEncoder->config.numFrontChannels > 29) {
++ fprintf(stderr, "WritePCE: too many front channels (%u)\n",
++ hEncoder->config.numFrontChannels);
++ return 0;
++ }
++ if (hEncoder->config.numSideChannels > 29) {
++ fprintf(stderr, "WritePCE: too many side channels (%u)\n",
++ hEncoder->config.numSideChannels);
++ return 0;
++ }
++ if (hEncoder->config.numBackChannels > 29) {
++ fprintf(stderr, "WritePCE: too many back channels (%u)\n",
++ hEncoder->config.numBackChannels);
++ return 0;
++ }
++ if (hEncoder->config.numLFEChannels > 3) {
++ fprintf(stderr, "WritePCE: too many LFE channels (%u)\n",
++ hEncoder->config.numLFEChannels);
++ return 0;
++ }
++ /* program_config_element() shall be used only for the audio object types:
++ * AAC main, AAC SSR, AAC LC and AAC LTP */
++ if (hEncoder->config.aacObjectType > 4) {
++ fprintf(stderr, "WritePCE: unsupported AudioObjectType %u",
++ hEncoder->config.aacObjectType);
++ return 0;
++ }
++
++ /* Determine the channel configuration (see GetChannelInfo) */
++ int sceTag = 0;
++ int cpeTag = 0;
++ int lfeTag = 0;
++ int num_front_channel_elements = 0;
++ int front_element_is_cpe[15] = { 0 };
++ int front_element_tag_select[15] = { 0 };
++ int num_side_channel_elements = 0;
++ int side_element_is_cpe[15] = { 0 };
++ int side_element_tag_select[15] = { 0 };
++ int num_back_channel_elements = 0;
++ int back_element_is_cpe[15] = { 0 };
++ int back_element_tag_select[15] = { 0 };
++ int num_lfe_channel_elements = 0;
++ int lfe_element_tag_select[3] = { 0 };
++ // Front channels
++ i = hEncoder->config.numFrontChannels;
++ if (i % 2) {
++ front_element_is_cpe[num_front_channel_elements] = 0;
++ front_element_tag_select[num_front_channel_elements] = sceTag;
++ num_front_channel_elements++;
++ sceTag++;
++ i--;
++ }
++ while (i) {
++ front_element_is_cpe[num_front_channel_elements] = 1;
++ front_element_tag_select[num_front_channel_elements] = cpeTag;
++ num_front_channel_elements++;
++ cpeTag++;
++ i -= 2;
++ }
++ // Side channels
++ i = hEncoder->config.numSideChannels;
++ while (i > 1) {
++ side_element_is_cpe[num_side_channel_elements] = 1;
++ side_element_tag_select[num_side_channel_elements] = cpeTag;
++ num_side_channel_elements++;
++ cpeTag++;
++ i -= 2;
++ }
++ if (i) {
++ side_element_is_cpe[num_side_channel_elements] = 0;
++ side_element_tag_select[num_side_channel_elements] = sceTag;
++ num_side_channel_elements++;
++ sceTag++;
++ i--;
++ }
++ // Back channels
++ i = hEncoder->config.numBackChannels;
++ while (i > 1) {
++ back_element_is_cpe[num_back_channel_elements] = 1;
++ back_element_tag_select[num_back_channel_elements] = cpeTag;
++ num_back_channel_elements++;
++ cpeTag++;
++ i -= 2;
++ }
++ if (i) {
++ back_element_is_cpe[num_back_channel_elements] = 0;
++ back_element_tag_select[num_back_channel_elements] = sceTag;
++ num_back_channel_elements++;
++ sceTag++;
++ i--;
++ }
++ // LFE channels
++ i = hEncoder->config.numLFEChannels;
++ while (i) {
++ lfe_element_tag_select[num_lfe_channel_elements] = lfeTag;
++ num_lfe_channel_elements++;
++ lfeTag++;
++ i--;
++ }
++
++ /* element_instance_tag */
++ if (writeFlag)
++ PutBit(bitStream, instance_tag, 4);
++ bits =+ 4;
++
++ /* object_type */
++ if (writeFlag)
++ PutBit(bitStream, hEncoder->config.aacObjectType - 1, 2);
++ bits += 2;
++
++ /* sampling_frequency_index */
++ if (writeFlag)
++ PutBit(bitStream, hEncoder->sampleRateIdx, 4);
++ bits += 4;
++
++ /* num_front_channel_elements */
++ if (writeFlag)
++ PutBit(bitStream, num_front_channel_elements, 4);
++ bits += 4;
++
++ /* num_side_channel_elements */
++ if (writeFlag)
++ PutBit(bitStream, num_side_channel_elements, 4);
++ bits += 4;
++
++ /* num_back_channel_elements */
++ if (writeFlag)
++ PutBit(bitStream, num_back_channel_elements, 4);
++ bits += 4;
++
++ /* num_lfe_channel_elements */
++ if (writeFlag)
++ PutBit(bitStream, num_lfe_channel_elements, 2);
++ bits += 2;
++
++ /* num_assoc_data_elements */
++ if (writeFlag)
++ PutBit(bitStream, 0, 3);
++ bits += 3;
++
++ /* num_valid_cc_elements */
++ if (writeFlag)
++ PutBit(bitStream, 0, 4);
++ bits += 4;
++
++ /* mono_mixdown_present */
++ if (writeFlag)
++ PutBit(bitStream, 0, 1);
++ bits++;
++
++ /* stereo_mixdown_present */
++ if (writeFlag)
++ PutBit(bitStream, 0, 1);
++ bits++;
++
++ /* matrix_mixdown_idx_present */
++ if (writeFlag)
++ PutBit(bitStream, 0, 1);
++ bits++;
++
++ /* describe the channel configuration */
++ for (i = 0; i < num_front_channel_elements; i++) {
++ if (writeFlag) {
++ PutBit(bitStream, front_element_is_cpe[i], 1);
++ PutBit(bitStream, front_element_tag_select[i], 4);
++ }
++ bits += 5;
++ }
++ for (i = 0; i < num_side_channel_elements; i++) {
++ if (writeFlag) {
++ PutBit(bitStream, side_element_is_cpe[i], 1);
++ PutBit(bitStream, side_element_tag_select[i], 4);
++ }
++ bits += 5;
++ }
++ for (i = 0; i < num_back_channel_elements; i++) {
++ if (writeFlag) {
++ PutBit(bitStream, back_element_is_cpe[i], 1);
++ PutBit(bitStream, back_element_tag_select[i], 4);
++ }
++ bits += 5;
++ }
++ for (i = 0; i < num_lfe_channel_elements; i++) {
++ if (writeFlag)
++ PutBit(bitStream, lfe_element_tag_select[i], 4);
++ bits += 4;
++ }
++
++ /* byte_alignment() */
++ bits += ByteAlign(bitStream, writeFlag, bits + byte_alignment);
++
++ /* comment_field_bytes */
++ if (writeFlag)
++ PutBit(bitStream, 0, 8);
++ bits += 8;
++
++ return bits;
++}
++
+ #ifdef DRM
+ /*
+ ****************************************************************************
+diff -Naur faac-1.28.old/libfaac/bitstream.h faac-1.28.new/libfaac/bitstream.h
+--- faac-1.28.old/libfaac/bitstream.h 2004-07-04 14:10:52.000000000 +0200
++++ faac-1.28.new/libfaac/bitstream.h 2012-08-06 21:15:34.000000000 +0200
+@@ -164,6 +164,13 @@
+ unsigned long data,
+ int numBit);
+
++/* write a program_config_element() */
++int WritePCE(faacEncHandle hEncoder,
++ BitStream *bitStream,
++ int byte_alignment,
++ int instance_tag,
++ int writeFlag);
++
+ #ifdef __cplusplus
+ }
+ #endif /* __cplusplus */
+diff -Naur faac-1.28.old/libfaac/channels.c faac-1.28.new/libfaac/channels.c
+--- faac-1.28.old/libfaac/channels.c 2001-09-04 20:39:35.000000000 +0200
++++ faac-1.28.new/libfaac/channels.c 2012-08-06 21:15:34.000000000 +0200
+@@ -28,83 +28,112 @@
+ #include "coder.h"
+ #include "util.h"
+
+-/* If LFE present */
+-/* Num channels # of SCE's # of CPE's #of LFE's */
+-/* ============ ========== ========== ========= */
+-/* 1 1 0 0 */
+-/* 2 0 1 0 */
+-/* 3 1 1 0 */
+-/* 4 1 1 1 */
+-/* 5 1 2 0 */
+-/* For more than 5 channels, use the following elements: */
+-/* 2*N 1 2*(N-1) 1 */
+-/* 2*N+1 1 2*N 0 */
+-/* */
+-/* Else: */
+-/* */
+-/* Num channels # of SCE's # of CPE's #of LFE's */
+-/* ============ ========== ========== ========= */
+-/* 1 1 0 0 */
+-/* 2 0 1 0 */
+-/* 3 1 1 0 */
+-/* 4 2 1 0 */
+-/* 5 1 2 0 */
+-/* For more than 5 channels, use the following elements: */
+-/* 2*N 2 2*(N-1) 0 */
+-/* 2*N+1 1 2*N 0 */
+-
+-void GetChannelInfo(ChannelInfo *channelInfo, int numChannels, int useLfe)
+-{
+- int sceTag = 0;
+- int lfeTag = 0;
+- int cpeTag = 0;
+- int numChannelsLeft = numChannels;
++static void addSCE(ChannelInfo *channelInfo, int numChannels, int numChannelsLeft, int tag);
++static void addCPE(ChannelInfo *channelInfo, int numChannels, int numChannelsLeft, int tag);
++static void addLFE(ChannelInfo *channelInfo, int numChannels, int numChannelsLeft, int tag);
+
+
+- /* First element is sce, except for 2 channel case */
+- if (numChannelsLeft != 2) {
+- channelInfo[numChannels-numChannelsLeft].present = 1;
+- channelInfo[numChannels-numChannelsLeft].tag = sceTag++;
+- channelInfo[numChannels-numChannelsLeft].cpe = 0;
+- channelInfo[numChannels-numChannelsLeft].lfe = 0;
++void GetChannelInfo(ChannelInfo *channelInfo, int numFrontChannels, int numSideChannels, int numBackChannels, int numLFEChannels)
++{
++ int i;
++ int sceTag = 0;
++ int cpeTag = 0;
++ int lfeTag = 0;
++ int numChannels = (numFrontChannels +
++ numSideChannels +
++ numBackChannels +
++ numLFEChannels);
++ int numChannelsLeft = numChannels;
++
++ /* Front channels */
++ i = numFrontChannels;
++ if (i % 2) {
++ // Front Center
++ addSCE(channelInfo, numChannels, numChannelsLeft, sceTag);
+ numChannelsLeft--;
++ sceTag++;
++ i--;
++ }
++ while (i) {
++ // Front Left/Right, Front Left/Right of Center, ???
++ addCPE(channelInfo, numChannels, numChannelsLeft, cpeTag);
++ numChannelsLeft -= 2;
++ cpeTag++;
++ i -= 2;
+ }
+
+- /* Next elements are cpe's */
+- while (numChannelsLeft > 1) {
+- /* Left channel info */
+- channelInfo[numChannels-numChannelsLeft].present = 1;
+- channelInfo[numChannels-numChannelsLeft].tag = cpeTag++;
+- channelInfo[numChannels-numChannelsLeft].cpe = 1;
+- channelInfo[numChannels-numChannelsLeft].common_window = 0;
+- channelInfo[numChannels-numChannelsLeft].ch_is_left = 1;
+- channelInfo[numChannels-numChannelsLeft].paired_ch = numChannels-numChannelsLeft+1;
+- channelInfo[numChannels-numChannelsLeft].lfe = 0;
++ /* Side channels */
++ i = numSideChannels;
++ while (i > 1) {
++ // Surround Left/Right (if rear surrounds present), ???
++ addCPE(channelInfo, numChannels, numChannelsLeft, cpeTag);
++ numChannelsLeft -= 2;
++ cpeTag++;
++ i -= 2;
++ }
++ if (i) {
++ // ???
++ addSCE(channelInfo, numChannels, numChannelsLeft, sceTag);
+ numChannelsLeft--;
++ sceTag++;
++ i--;
++ }
+
+- /* Right channel info */
+- channelInfo[numChannels-numChannelsLeft].present = 1;
+- channelInfo[numChannels-numChannelsLeft].cpe = 1;
+- channelInfo[numChannels-numChannelsLeft].common_window = 0;
+- channelInfo[numChannels-numChannelsLeft].ch_is_left = 0;
+- channelInfo[numChannels-numChannelsLeft].paired_ch = numChannels-numChannelsLeft-1;
+- channelInfo[numChannels-numChannelsLeft].lfe = 0;
++ /* Back channels */
++ i = numBackChannels;
++ while (i > 1) {
++ // Surround Left/Right (if rear surrounds absent), Rear Surround Left/Right, ???
++ addCPE(channelInfo, numChannels, numChannelsLeft, cpeTag);
++ numChannelsLeft -= 2;
++ cpeTag++;
++ i -= 2;
++ }
++ if (i) {
++ // Surround Center
++ addSCE(channelInfo, numChannels, numChannelsLeft, sceTag);
+ numChannelsLeft--;
++ sceTag++;
++ i--;
+ }
+
+- /* Is there another channel left ? */
+- if (numChannelsLeft) {
+- if (useLfe) {
+- channelInfo[numChannels-numChannelsLeft].present = 1;
+- channelInfo[numChannels-numChannelsLeft].tag = lfeTag++;
+- channelInfo[numChannels-numChannelsLeft].cpe = 0;
+- channelInfo[numChannels-numChannelsLeft].lfe = 1;
+- } else {
+- channelInfo[numChannels-numChannelsLeft].present = 1;
+- channelInfo[numChannels-numChannelsLeft].tag = sceTag++;
+- channelInfo[numChannels-numChannelsLeft].cpe = 0;
+- channelInfo[numChannels-numChannelsLeft].lfe = 0;
+- }
++ /* LFE channel */
++ i = numLFEChannels;
++ while (i) {
++ addLFE(channelInfo, numChannels, numChannelsLeft, lfeTag);
+ numChannelsLeft--;
++ lfeTag++;
++ i--;
+ }
+ }
++
++static void addSCE(ChannelInfo *channelInfo, int numChannels, int numChannelsLeft, int tag) {
++ channelInfo[numChannels-numChannelsLeft].present = 1;
++ channelInfo[numChannels-numChannelsLeft].cpe = 0;
++ channelInfo[numChannels-numChannelsLeft].lfe = 0;
++ channelInfo[numChannels-numChannelsLeft].tag = tag;
++}
++
++static void addCPE(ChannelInfo *channelInfo, int numChannels, int numChannelsLeft, int tag) {
++ /* Left channel info */
++ channelInfo[numChannels-numChannelsLeft].present = 1;
++ channelInfo[numChannels-numChannelsLeft].cpe = 1;
++ channelInfo[numChannels-numChannelsLeft].lfe = 0;
++ channelInfo[numChannels-numChannelsLeft].tag = tag;
++ channelInfo[numChannels-numChannelsLeft].ch_is_left = 1;
++ channelInfo[numChannels-numChannelsLeft].common_window = 0;
++ channelInfo[numChannels-numChannelsLeft].paired_ch = numChannels-numChannelsLeft+1;
++ /* Right channel info */
++ channelInfo[numChannels-numChannelsLeft+1].present = 1;
++ channelInfo[numChannels-numChannelsLeft+1].cpe = 1;
++ channelInfo[numChannels-numChannelsLeft+1].lfe = 0;
++ channelInfo[numChannels-numChannelsLeft+1].ch_is_left = 0;
++ channelInfo[numChannels-numChannelsLeft+1].common_window = 0;
++ channelInfo[numChannels-numChannelsLeft+1].paired_ch = numChannels-numChannelsLeft;
++}
++
++static void addLFE(ChannelInfo *channelInfo, int numChannels, int numChannelsLeft, int tag) {
++ channelInfo[numChannels-numChannelsLeft].present = 1;
++ channelInfo[numChannels-numChannelsLeft].cpe = 0;
++ channelInfo[numChannels-numChannelsLeft].lfe = 1;
++ channelInfo[numChannels-numChannelsLeft].tag = tag;
++}
+diff -Naur faac-1.28.old/libfaac/channels.h faac-1.28.new/libfaac/channels.h
+--- faac-1.28.old/libfaac/channels.h 2003-06-26 21:19:41.000000000 +0200
++++ faac-1.28.new/libfaac/channels.h 2012-08-06 21:15:34.000000000 +0200
+@@ -45,7 +45,7 @@
+ MSInfo msInfo;
+ } ChannelInfo;
+
+-void GetChannelInfo(ChannelInfo *channelInfo, int numChannels, int useLfe);
++void GetChannelInfo(ChannelInfo *channelInfo, int numFrontChannels, int numSideChannels, int numBackChannels, int numLFEChannels);
+
+ #ifdef __cplusplus
+ }
+diff -Naur faac-1.28.old/libfaac/frame.c faac-1.28.new/libfaac/frame.c
+--- faac-1.28.old/libfaac/frame.c 2004-11-17 15:26:06.000000000 +0100
++++ faac-1.28.new/libfaac/frame.c 2012-08-06 21:15:34.000000000 +0200
+@@ -99,21 +99,47 @@
+ return -2; /* not supported */
+ }
+
+- *pSizeOfDecoderSpecificInfo = 2;
+- *ppBuffer = malloc(2);
++ if (hEncoder->config.channelConfiguration > 7) {
++ fprintf(stderr, "faacEncGetDecoderSpecificInfo: "
++ "invalid channel configuration %u\n",
++ hEncoder->config.channelConfiguration);
++ return -2;
++ } else if (hEncoder->config.channelConfiguration) {
++ // 16 bits
++ *pSizeOfDecoderSpecificInfo = 2;
++ } else {
++ // 16 bits + size of the program_config_element()
++ *pSizeOfDecoderSpecificInfo = 2 + (WritePCE(hEncoder, NULL, 0, 0, 0) / 8);
++ }
+
+- if(*ppBuffer != NULL){
++ *ppBuffer = malloc(*pSizeOfDecoderSpecificInfo);
+
++ if (*ppBuffer != NULL) {
+ memset(*ppBuffer,0,*pSizeOfDecoderSpecificInfo);
+ pBitStream = OpenBitStream(*pSizeOfDecoderSpecificInfo, *ppBuffer);
+ PutBit(pBitStream, hEncoder->config.aacObjectType, 5);
+ PutBit(pBitStream, hEncoder->sampleRateIdx, 4);
+- PutBit(pBitStream, hEncoder->numChannels, 4);
++ PutBit(pBitStream, hEncoder->config.channelConfiguration, 4);
++ PutBit(pBitStream, 0, 1); // frameLengthFlag
++ PutBit(pBitStream, 0, 1); // dependsOnCoreCoder
++ PutBit(pBitStream, 0, 1); // extensionFlag
++ if (!hEncoder->config.channelConfiguration) {
++ /* a program_config_element() must be written */
++ if (WritePCE(hEncoder, pBitStream, 0, 0, 1) <= 0) {
++ fprintf(stderr,
++ "faacEncGetDecoderSpecificInfo: WritePCE() failed!\n");
++ *pSizeOfDecoderSpecificInfo = 0;
++ CloseBitStream(pBitStream);
++ free(*ppBuffer);
++ *ppBuffer = NULL;
++ return -3;
++ }
++ }
+ CloseBitStream(pBitStream);
+-
+ return 0;
+ } else {
+- return -3;
++ *pSizeOfDecoderSpecificInfo = 0;
++ return -4;
+ }
+ }
+
+@@ -131,7 +157,6 @@
+ int i;
+
+ hEncoder->config.allowMidside = config->allowMidside;
+- hEncoder->config.useLfe = config->useLfe;
+ hEncoder->config.useTns = config->useTns;
+ hEncoder->config.aacObjectType = config->aacObjectType;
+ hEncoder->config.mpegVersion = config->mpegVersion;
+@@ -139,6 +164,77 @@
+ hEncoder->config.inputFormat = config->inputFormat;
+ hEncoder->config.shortctl = config->shortctl;
+
++ if (!config->channelConfiguration) {
++ if (hEncoder->numChannels != (config->numFrontChannels +
++ config->numSideChannels +
++ config->numBackChannels +
++ config->numLFEChannels)) {
++ fprintf(stderr, "faacEncSetConfiguration: "
++ "numChannels doesn't match the custom channel configuration\n");
++ return 0;
++ }
++ hEncoder->config.numFrontChannels = config->numFrontChannels;
++ hEncoder->config.numSideChannels = config->numSideChannels;
++ hEncoder->config.numBackChannels = config->numBackChannels;
++ hEncoder->config.numLFEChannels = config->numLFEChannels;
++ } else if (config->channelConfiguration > 7) {
++ fprintf(stderr, "faacEncSetConfiguration: "
++ "invalid channel configuration %u\n",
++ config->channelConfiguration);
++ return 0;
++ } else {
++ if ((config->channelConfiguration == 7 && hEncoder->numChannels != 8) ||
++ (config->channelConfiguration != 7 && hEncoder->numChannels != config->channelConfiguration)) {
++ fprintf(stderr, "faacEncSetConfiguration: "
++ "numChannels doesn't match the channel configuration\n");
++ return 0;
++ }
++ switch (config->channelConfiguration) {
++ case 7:
++ hEncoder->config.numFrontChannels = 5;
++ hEncoder->config.numSideChannels = 0;
++ hEncoder->config.numBackChannels = 2;
++ hEncoder->config.numLFEChannels = 1;
++ break;
++ case 6:
++ hEncoder->config.numFrontChannels = 3;
++ hEncoder->config.numSideChannels = 0;
++ hEncoder->config.numBackChannels = 2;
++ hEncoder->config.numLFEChannels = 1;
++ break;
++ case 5:
++ hEncoder->config.numFrontChannels = 3;
++ hEncoder->config.numSideChannels = 0;
++ hEncoder->config.numBackChannels = 2;
++ hEncoder->config.numLFEChannels = 0;
++ break;
++ case 4:
++ hEncoder->config.numFrontChannels = 3;
++ hEncoder->config.numSideChannels = 0;
++ hEncoder->config.numBackChannels = 1;
++ hEncoder->config.numLFEChannels = 0;
++ break;
++ case 3:
++ hEncoder->config.numFrontChannels = 3;
++ hEncoder->config.numSideChannels = 0;
++ hEncoder->config.numBackChannels = 0;
++ hEncoder->config.numLFEChannels = 0;
++ break;
++ case 2:
++ hEncoder->config.numFrontChannels = 2;
++ hEncoder->config.numSideChannels = 0;
++ hEncoder->config.numBackChannels = 0;
++ hEncoder->config.numLFEChannels = 0;
++ break;
++ case 1:
++ hEncoder->config.numFrontChannels = 1;
++ hEncoder->config.numSideChannels = 0;
++ hEncoder->config.numBackChannels = 0;
++ hEncoder->config.numLFEChannels = 0;
++ break;
++ }
++ }
++
+ assert((hEncoder->config.outputFormat == 0) || (hEncoder->config.outputFormat == 1));
+
+ switch( hEncoder->config.inputFormat )
+@@ -306,6 +402,12 @@
+ *maxOutputBytes += 1; /* for CRC */
+ #endif
+
++ if (!numChannels || numChannels > 64) {
++ fprintf(stderr, "faacEncOpen: invalid number of channels %u\n",
++ numChannels);
++ return NULL;
++ }
++
+ hEncoder = (faacEncStruct*)AllocMemory(sizeof(faacEncStruct));
+ SetMemory(hEncoder, 0, sizeof(faacEncStruct));
+
+@@ -324,7 +426,6 @@
+ hEncoder->config.mpegVersion = MPEG4;
+ hEncoder->config.aacObjectType = LTP;
+ hEncoder->config.allowMidside = 1;
+- hEncoder->config.useLfe = 1;
+ hEncoder->config.useTns = 0;
+ hEncoder->config.bitRate = 0; /* default bitrate / channel */
+ hEncoder->config.bandWidth = bwfac * hEncoder->sampleRate;
+@@ -340,6 +441,91 @@
+ /* default channel map is straight-through */
+ for( channel = 0; channel < 64; channel++ )
+ hEncoder->config.channel_map[channel] = channel;
++
++ /* Define a sensible default channel configuration */
++ if (numChannels <= 6 || numChannels == 8) {
++ switch (numChannels) {
++ case 8:
++ hEncoder->config.channelConfiguration = 7;
++ hEncoder->config.numFrontChannels = 5;
++ hEncoder->config.numSideChannels = 0;
++ hEncoder->config.numBackChannels = 2;
++ hEncoder->config.numLFEChannels = 1;
++ break;
++ case 6:
++ hEncoder->config.channelConfiguration = 6;
++ hEncoder->config.numFrontChannels = 3;
++ hEncoder->config.numSideChannels = 0;
++ hEncoder->config.numBackChannels = 2;
++ hEncoder->config.numLFEChannels = 1;
++ break;
++ case 5:
++ hEncoder->config.channelConfiguration = 5;
++ hEncoder->config.numFrontChannels = 3;
++ hEncoder->config.numSideChannels = 0;
++ hEncoder->config.numBackChannels = 2;
++ hEncoder->config.numLFEChannels = 0;
++ break;
++ case 4:
++ hEncoder->config.channelConfiguration = 4;
++ hEncoder->config.numFrontChannels = 3;
++ hEncoder->config.numSideChannels = 0;
++ hEncoder->config.numBackChannels = 1;
++ hEncoder->config.numLFEChannels = 0;
++ break;
++ case 3:
++ hEncoder->config.channelConfiguration = 3;
++ hEncoder->config.numFrontChannels = 3;
++ hEncoder->config.numSideChannels = 0;
++ hEncoder->config.numBackChannels = 0;
++ hEncoder->config.numLFEChannels = 0;
++ break;
++ case 2:
++ hEncoder->config.channelConfiguration = 2;
++ hEncoder->config.numFrontChannels = 2;
++ hEncoder->config.numSideChannels = 0;
++ hEncoder->config.numBackChannels = 0;
++ hEncoder->config.numLFEChannels = 0;
++ break;
++ case 1:
++ hEncoder->config.channelConfiguration = 1;
++ hEncoder->config.numFrontChannels = 1;
++ hEncoder->config.numSideChannels = 0;
++ hEncoder->config.numBackChannels = 0;
++ hEncoder->config.numLFEChannels = 0;
++ break;
++ }
++ } else {
++ hEncoder->config.channelConfiguration = 0;
++ hEncoder->config.numFrontChannels = 0;
++ hEncoder->config.numSideChannels = 0;
++ hEncoder->config.numBackChannels = 0;
++ hEncoder->config.numLFEChannels = 0;
++ for (channel = numChannels; channel > 0; channel--) {
++ // 7 channels: 7.0 (C L R Ls Rs Rls Rrs)
++ // 9 channels: 9.0 (Lc Rc L R Ls Rs Rls Rrs Cs)
++ // 10 channels: 10.0 (C Lc Rc L R Ls Rs Rls Rrs Cs)
++ // for more than 10 channels, use faacEncSetConfiguration()
++ if (hEncoder->config.numFrontChannels < 3) {
++ // C, L, R
++ hEncoder->config.numFrontChannels++;
++ } else if (hEncoder->config.numBackChannels < 2) {
++ // Ls or Rls, Rs or Rrs
++ hEncoder->config.numBackChannels++;
++ } else if (hEncoder->config.numSideChannels < 2) {
++ // Ls, Rs
++ hEncoder->config.numSideChannels++;
++ } else if (hEncoder->config.numBackChannels < 3) {
++ // Cs
++ hEncoder->config.numBackChannels++;
++ } else if (hEncoder->config.numFrontChannels < 5) {
++ // Lc, Rc
++ hEncoder->config.numFrontChannels++;
++ } else {
++ break;
++ }
++ }
++ }
+
+ /*
+ by default we have to be compatible with all previous software
+@@ -459,14 +645,13 @@
+ double fix;
+ #endif
+
+- /* local copy's of parameters */
++ /* local copies of parameters */
+ ChannelInfo *channelInfo = hEncoder->channelInfo;
+ CoderInfo *coderInfo = hEncoder->coderInfo;
+ unsigned int numChannels = hEncoder->numChannels;
+ unsigned int sampleRate = hEncoder->sampleRate;
+ unsigned int aacObjectType = hEncoder->config.aacObjectType;
+ unsigned int mpegVersion = hEncoder->config.mpegVersion;
+- unsigned int useLfe = hEncoder->config.useLfe;
+ unsigned int useTns = hEncoder->config.useTns;
+ unsigned int allowMidside = hEncoder->config.allowMidside;
+ unsigned int bandWidth = hEncoder->config.bandWidth;
+@@ -484,7 +669,11 @@
+ return 0;
+
+ /* Determine the channel configuration */
+- GetChannelInfo(channelInfo, numChannels, useLfe);
++ GetChannelInfo(channelInfo,
++ hEncoder->config.numFrontChannels,
++ hEncoder->config.numSideChannels,
++ hEncoder->config.numBackChannels,
++ hEncoder->config.numLFEChannels);
+
+ /* Update current sample buffers */
+ for (channel = 0; channel < numChannels; channel++)
diff --git a/contrib/faac/P00-cygwin.patch b/contrib/faac/P00-cygwin.patch
index a5da42d87..bef152139 100644
--- a/contrib/faac/P00-cygwin.patch
+++ b/contrib/faac/P00-cygwin.patch
@@ -1,6 +1,6 @@
-diff -Naur faac-1.28.orig/include/faac.h faac-1.28/include/faac.h
---- faac-1.28.orig/include/faac.h 2009-01-25 13:50:32.000000000 -0500
-+++ faac-1.28/include/faac.h 2009-03-20 03:31:46.000000000 -0400
+diff -Naur faac-1.28.old/include/faac.h faac-1.28.new/include/faac.h
+--- faac-1.28.old/include/faac.h 2009-01-25 13:50:32.000000000 -0500
++++ faac-1.28.new/include/faac.h 2009-03-20 03:31:46.000000000 -0400
@@ -50,7 +50,7 @@
typedef void *faacEncHandle;
diff --git a/gtk/src/audiohandler.c b/gtk/src/audiohandler.c
index f2940bb81..95b9ba166 100644
--- a/gtk/src/audiohandler.c
+++ b/gtk/src/audiohandler.c
@@ -56,7 +56,8 @@ check_list_full(signal_user_data_t *ud)
gint
ghb_select_audio_codec(gint mux, hb_audio_config_t *aconfig, gint acodec, gint fallback, gint copy_mask)
{
- guint32 in_codec = aconfig ? aconfig->in.codec : 0;
+ guint32 in_codec = aconfig != NULL ? aconfig->in.codec : 0;
+
if (acodec == HB_ACODEC_AUTO_PASS)
{
return hb_autopassthru_get_encoder(in_codec, copy_mask, fallback, mux);
@@ -119,7 +120,7 @@ int ghb_get_copy_mask(GValue *settings)
return mask;
}
-static int ghb_select_fallback( GValue *settings, int mux, int acodec )
+int ghb_select_fallback( GValue *settings, int mux, int acodec )
{
gint mask;
gint fallback = 0;
@@ -839,6 +840,7 @@ global_audio_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
ghb_check_dependency(ud, widget, NULL);
ghb_widget_to_setting(ud->settings, widget);
ghb_adjust_audio_rate_combos(ud);
+ ghb_grey_combo_options (ud);
ghb_audio_list_refresh_selected(ud);
ghb_live_reset(ud);
}
diff --git a/gtk/src/audiohandler.h b/gtk/src/audiohandler.h
index 0a3f98c3f..7bd300cc5 100644
--- a/gtk/src/audiohandler.h
+++ b/gtk/src/audiohandler.h
@@ -34,6 +34,7 @@ void ghb_set_audio(signal_user_data_t *ud, GValue *settings);
const gchar* ghb_get_user_audio_lang(GValue *settings, gint titleindex, gint track);
void ghb_audio_list_refresh_selected(signal_user_data_t *ud);
gint ghb_select_audio_codec(gint mux, hb_audio_config_t *aconfig, gint acodec, gint fallback_acodec, gint copy_mask);
+int ghb_select_fallback( GValue *settings, int mux, int acodec );
int ghb_get_copy_mask(GValue *settings);
void ghb_audio_list_refresh(signal_user_data_t *ud);
char * ghb_format_quality( const char *prefix, int codec, double quality );
diff --git a/gtk/src/hb-backend.c b/gtk/src/hb-backend.c
index f5746e9f9..f2638bf73 100644
--- a/gtk/src/hb-backend.c
+++ b/gtk/src/hb-backend.c
@@ -1590,6 +1590,21 @@ grey_combo_box_item(GtkBuilder *builder, const gchar *name, gint value, gboolean
}
}
+static void
+grey_mix_opts(signal_user_data_t *ud, gint acodec, gint64 layout)
+{
+ gint ii;
+
+ g_debug("grey_mix_opts()\n");
+ for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
+ {
+ grey_combo_box_item(ud->builder, "AudioMixdown",
+ hb_audio_mixdowns[ii].amixdown,
+ !hb_mixdown_is_supported(hb_audio_mixdowns[ii].amixdown,
+ acodec, layout));
+ }
+}
+
void
ghb_grey_combo_options(signal_user_data_t *ud)
{
@@ -1670,32 +1685,12 @@ ghb_grey_combo_options(signal_user_data_t *ud)
gval = ghb_widget_value(widget);
acodec = ghb_lookup_combo_int("AudioEncoder", gval);
ghb_value_free(gval);
- grey_combo_box_item(ud->builder, "AudioMixdown", 0, TRUE);
-
- gboolean allow_mono = TRUE;
- gboolean allow_stereo = TRUE;
- gboolean allow_dolby = TRUE;
- gboolean allow_dpl2 = TRUE;
- gboolean allow_6ch = TRUE;
- allow_6ch = acodec & ~HB_ACODEC_LAME;
- if (aconfig)
- {
- fallback = ghb_settings_combo_int(ud->settings, "AudioEncoderFallback");
- gint copy_mask = ghb_get_copy_mask(ud->settings);
- acodec = ghb_select_audio_codec(mux, aconfig, acodec, fallback, copy_mask);
- gint best = hb_get_best_mixdown(acodec, aconfig->in.channel_layout, HB_INVALID_AMIXDOWN);
-
- allow_stereo = best >= HB_AMIXDOWN_STEREO;
- allow_dolby = best >= HB_AMIXDOWN_DOLBY;
- allow_dpl2 = best >= HB_AMIXDOWN_DOLBYPLII;
- allow_6ch = best >= HB_AMIXDOWN_6CH;
- allow_mono = best >= HB_AMIXDOWN_MONO;
- }
- grey_combo_box_item(ud->builder, "AudioMixdown", HB_AMIXDOWN_MONO, !allow_mono);
- grey_combo_box_item(ud->builder, "AudioMixdown", HB_AMIXDOWN_STEREO, !allow_stereo);
- grey_combo_box_item(ud->builder, "AudioMixdown", HB_AMIXDOWN_DOLBY, !allow_dolby);
- grey_combo_box_item(ud->builder, "AudioMixdown", HB_AMIXDOWN_DOLBYPLII, !allow_dpl2);
- grey_combo_box_item(ud->builder, "AudioMixdown", HB_AMIXDOWN_6CH, !allow_6ch);
+
+ gint64 layout = aconfig != NULL ? aconfig->in.channel_layout : ~0;
+ fallback = ghb_select_fallback(ud->settings, mux, acodec);
+ gint copy_mask = ghb_get_copy_mask(ud->settings);
+ acodec = ghb_select_audio_codec(mux, aconfig, acodec, fallback, copy_mask);
+ grey_mix_opts(ud, acodec, layout);
}
gint
@@ -4472,40 +4467,20 @@ ghb_validate_audio(GValue *settings)
}
gint mix = ghb_settings_combo_int (asettings, "AudioMixdown");
- gboolean allow_mono = TRUE;
- gboolean allow_stereo = TRUE;
- gboolean allow_dolby = TRUE;
- gboolean allow_dpl2 = TRUE;
- gboolean allow_6ch = TRUE;
- allow_mono = TRUE;
-
- gint best = hb_get_best_mixdown(codec, aconfig->in.channel_layout, HB_INVALID_AMIXDOWN);
-
- allow_stereo = best >= HB_AMIXDOWN_STEREO;
- allow_dolby = best >= HB_AMIXDOWN_DOLBY;
- allow_dpl2 = best >= HB_AMIXDOWN_DOLBYPLII;
- allow_6ch = best >= HB_AMIXDOWN_6CH;
+ gint jj;
gchar *mix_unsup = NULL;
- if (mix == HB_AMIXDOWN_MONO && !allow_mono)
+ if (!hb_mixdown_is_supported(mix, codec, aconfig->in.channel_layout))
{
- mix_unsup = "mono";
- }
- if (mix == HB_AMIXDOWN_STEREO && !allow_stereo)
- {
- mix_unsup = "stereo";
- }
- if (mix == HB_AMIXDOWN_DOLBY && !allow_dolby)
- {
- mix_unsup = "Dolby";
- }
- if (mix == HB_AMIXDOWN_DOLBYPLII && !allow_dpl2)
- {
- mix_unsup = "Dolby Pro Logic II";
- }
- if (mix == HB_AMIXDOWN_6CH && !allow_6ch)
- {
- mix_unsup = "6 Channel";
+ for (jj = 0; jj < hb_audio_mixdowns_count; jj++)
+ {
+ if (mix == hb_audio_mixdowns[jj].amixdown)
+ {
+ {
+ mix_unsup = hb_audio_mixdowns[jj].human_readable_name;
+ }
+ }
+ }
}
if (mix_unsup)
{
diff --git a/gtk/src/presets.c b/gtk/src/presets.c
index 809ede24e..eeacbde04 100644
--- a/gtk/src/presets.c
+++ b/gtk/src/presets.c
@@ -2067,17 +2067,16 @@ value_map_t samplerate_xlat[] =
{NULL, NULL}
};
-value_map_t mix_xlat[] =
-{
- {"Mono", "mono"},
- {"Stereo", "stereo"},
- {"Dolby Surround", "dpl1"},
- {"Dolby Pro Logic II", "dpl2"},
- {"6-channel discrete", "6ch"},
- {"None", "none"},
- {"AC3 Passthru", "none"}, // Backwards compatibility with mac ui
- {"DTS Passthru", "none"}, // Backwards compatibility with mac ui
- {"DTS-HD Passthru", "none"}, // Backwards compatibility with mac ui
+// mix translation table filed in with hb_audio_mixdowns table contents
+value_map_t *mix_xlat;
+
+// Backwards compatibility mappings for audio mix
+value_map_t mix_xlat_compat[] =
+{
+ {"6-channel discrete", "5point1"},
+ {"AC3 Passthru", "none"},
+ {"DTS Passthru", "none"},
+ {"DTS-HD Passthru", "none"},
{NULL, NULL}
};
@@ -3130,6 +3129,24 @@ update_standard_presets(signal_user_data_t *ud)
void
ghb_presets_load(signal_user_data_t *ud)
{
+ int ii, jj;
+
+ // Create audio mixdown translation table
+ mix_xlat = malloc(sizeof(value_map_t) *
+ (hb_audio_mixdowns_count +
+ sizeof(mix_xlat_compat) / sizeof(value_map_t)));
+ for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
+ {
+ mix_xlat[ii].mac_val = hb_audio_mixdowns[ii].human_readable_name;
+ mix_xlat[ii].lin_val = hb_audio_mixdowns[ii].short_name;
+ }
+ for (jj = 0; mix_xlat_compat[jj].mac_val != NULL; jj++, ii++)
+ {
+ mix_xlat[ii] = mix_xlat_compat[jj];
+ }
+ mix_xlat[ii].mac_val = NULL;
+ mix_xlat[ii].lin_val = NULL;
+
presetsPlist = load_plist("presets");
if (presetsPlist == NULL)
{
diff --git a/libhb/audio_resample.c b/libhb/audio_resample.c
index 44f2a0144..ce80bc5fe 100644
--- a/libhb/audio_resample.c
+++ b/libhb/audio_resample.c
@@ -27,6 +27,21 @@ hb_audio_resample_t* hb_audio_resample_init(enum AVSampleFormat sample_fmt,
uint64_t channel_layout = hb_ff_mixdown_xlat(hb_amixdown, &matrix_encoding);
channels = av_get_channel_layout_nb_channels(channel_layout);
+ if (do_remix && (hb_amixdown == HB_AMIXDOWN_LEFT ||
+ hb_amixdown == HB_AMIXDOWN_RIGHT))
+ {
+ /* When downmixing, Dual Mono to Mono is a special case:
+ * the audio must remain 2-channel until all conversions are done. */
+ channels = 2;
+ channel_layout = AV_CH_LAYOUT_STEREO;
+ resample->dual_mono_downmix = 1;
+ resample->dual_mono_right_only = (hb_amixdown == HB_AMIXDOWN_RIGHT);
+ }
+ else
+ {
+ resample->dual_mono_downmix = 0;
+ }
+
// requested channel_layout
resample->out.channels = channels;
resample->out.channel_layout = channel_layout;
@@ -193,12 +208,12 @@ hb_buffer_t* hb_audio_resample(hb_audio_resample_t *resample,
return NULL;
}
- int out_size;
hb_buffer_t *out;
+ int out_size, out_samples;
if (resample->resample_needed)
{
- int in_linesize, out_linesize, out_samples;
+ int in_linesize, out_linesize;
// set in/out linesize and out_size
av_samples_get_buffer_size(&in_linesize,
resample->resample.channels, nsamples,
@@ -225,11 +240,29 @@ hb_buffer_t* hb_audio_resample(hb_audio_resample_t *resample,
}
else
{
- out_size = (nsamples *
+ out_samples = nsamples;
+ out_size = (out_samples *
resample->out.sample_size * resample->out.channels);
out = hb_buffer_init(out_size);
memcpy(out->data, samples, out_size);
}
+ /* Dual Mono to Mono.
+ *
+ * Copy all left or right samples to the first half of the buffer
+ * and halve the size */
+ if (resample->dual_mono_downmix)
+ {
+ int ii;
+ int jj = !!resample->dual_mono_right_only;
+ float *audio_samples = (float*)out->data;
+ for (ii = 0; ii < out_samples; ii++)
+ {
+ audio_samples[ii] = audio_samples[jj];
+ jj += 2;
+ }
+ out->size = out_samples * resample->out.sample_size;
+ }
+
return out;
}
diff --git a/libhb/audio_resample.h b/libhb/audio_resample.h
index 3a01d8696..baee471a6 100644
--- a/libhb/audio_resample.h
+++ b/libhb/audio_resample.h
@@ -28,6 +28,9 @@
typedef struct
{
int do_remix;
+ int dual_mono_downmix;
+ int dual_mono_right_only;
+
int resample_needed;
AVAudioResampleContext *avresample;
diff --git a/libhb/common.c b/libhb/common.c
index 6315498cc..821f17e76 100644
--- a/libhb/common.c
+++ b/libhb/common.c
@@ -20,93 +20,241 @@
* Global variables
*********************************************************************/
hb_rate_t hb_video_rates[] =
-{ { "5", 5400000 }, { "10", 2700000 }, { "12", 2250000 },
- { "15", 1800000 }, { "23.976", 1126125 }, { "24", 1125000 },
- { "25", 1080000 }, { "29.97", 900900 }, { "30", 900000 },
- { "50", 540000 }, { "59.94", 450450 }, { "60", 450000 } };
-int hb_video_rates_count = sizeof( hb_video_rates ) /
- sizeof( hb_rate_t );
+{
+ { "5", 5400000 },
+ { "10", 2700000 },
+ { "12", 2250000 },
+ { "15", 1800000 },
+ { "23.976", 1126125 },
+ { "24", 1125000 },
+ { "25", 1080000 },
+ { "29.97", 900900 },
+ { "30", 900000 },
+ { "50", 540000 },
+ { "59.94", 450450 },
+ { "60", 450000 },
+};
+int hb_video_rates_count = sizeof(hb_video_rates) / sizeof(hb_rate_t);
hb_rate_t hb_audio_rates[] =
-{ { "22.05", 22050 }, { "24", 24000 }, { "32", 32000 },
- { "44.1", 44100 }, { "48", 48000 } };
-int hb_audio_rates_count = sizeof( hb_audio_rates ) /
- sizeof( hb_rate_t );
-int hb_audio_rates_default = 3; /* 44100 Hz */
+{
+ { "8", 8000 },
+ { "11.025", 11025 },
+ { "12", 12000 },
+ { "16", 16000 },
+ { "22.05", 22050 },
+ { "24", 24000 },
+ { "32", 32000 },
+ { "44.1", 44100 },
+ { "48", 48000 },
+};
+int hb_audio_rates_count = sizeof(hb_audio_rates) / sizeof(hb_rate_t);
hb_rate_t hb_audio_bitrates[] =
-{ { "32", 32 }, { "40", 40 }, { "48", 48 }, { "56", 56 },
- { "64", 64 }, { "80", 80 }, { "96", 96 }, { "112", 112 },
- { "128", 128 }, { "160", 160 }, { "192", 192 }, { "224", 224 },
- { "256", 256 }, { "320", 320 }, { "384", 384 }, { "448", 448 },
- { "512", 512 }, { "576", 576 }, { "640", 640 }, { "768", 768 } };
-int hb_audio_bitrates_count = sizeof( hb_audio_bitrates ) /
- sizeof( hb_rate_t );
+{
+ // AC3-compatible bitrates
+ { "32", 32 },
+ { "40", 40 },
+ { "48", 48 },
+ { "56", 56 },
+ { "64", 64 },
+ { "80", 80 },
+ { "96", 96 },
+ { "112", 112 },
+ { "128", 128 },
+ { "160", 160 },
+ { "192", 192 },
+ { "224", 224 },
+ { "256", 256 },
+ { "320", 320 },
+ { "384", 384 },
+ { "448", 448 },
+ { "512", 512 },
+ { "576", 576 },
+ { "640", 640 },
+ // additional bitrates
+ { "768", 768 },
+ { "960", 960 },
+ { "1152", 1152 },
+ { "1344", 1344 },
+ { "1536", 1536 },
+};
+int hb_audio_bitrates_count = sizeof(hb_audio_bitrates) / sizeof(hb_rate_t);
static hb_error_handler_t *error_handler = NULL;
hb_mixdown_t hb_audio_mixdowns[] =
-{ { "None", "HB_AMIXDOWN_NONE", "none", HB_AMIXDOWN_NONE },
- { "Mono", "HB_AMIXDOWN_MONO", "mono", HB_AMIXDOWN_MONO },
- { "Stereo", "HB_AMIXDOWN_STEREO", "stereo", HB_AMIXDOWN_STEREO },
- { "Dolby Surround", "HB_AMIXDOWN_DOLBY", "dpl1", HB_AMIXDOWN_DOLBY },
- { "Dolby Pro Logic II", "HB_AMIXDOWN_DOLBYPLII", "dpl2", HB_AMIXDOWN_DOLBYPLII },
- { "6-channel discrete", "HB_AMIXDOWN_6CH", "6ch", HB_AMIXDOWN_6CH } };
-int hb_audio_mixdowns_count = sizeof( hb_audio_mixdowns ) /
- sizeof( hb_mixdown_t );
+{
+ { "None", "HB_AMIXDOWN_NONE", "none", HB_AMIXDOWN_NONE },
+ { "Mono", "HB_AMIXDOWN_MONO", "mono", HB_AMIXDOWN_MONO },
+ { "Mono (Left Only)", "HB_AMIXDOWN_LEFT", "left_only", HB_AMIXDOWN_LEFT },
+ { "Mono (Right Only)", "HB_AMIXDOWN_RIGHT", "right_only", HB_AMIXDOWN_RIGHT },
+ { "Stereo", "HB_AMIXDOWN_STEREO", "stereo", HB_AMIXDOWN_STEREO },
+ { "Dolby Surround", "HB_AMIXDOWN_DOLBY", "dpl1", HB_AMIXDOWN_DOLBY },
+ { "Dolby Pro Logic II", "HB_AMIXDOWN_DOLBYPLII", "dpl2", HB_AMIXDOWN_DOLBYPLII },
+ { "5.1 Channels", "HB_AMIXDOWN_5POINT1", "5point1", HB_AMIXDOWN_5POINT1 },
+ { "6.1 Channels", "HB_AMIXDOWN_6POINT1", "6point1", HB_AMIXDOWN_6POINT1 },
+ { "7.1 Channels", "HB_AMIXDOWN_7POINT1", "7point1", HB_AMIXDOWN_7POINT1 },
+ { "7.1 (5F/2R/LFE)", "HB_AMIXDOWN_5_2_LFE", "5_2_lfe", HB_AMIXDOWN_5_2_LFE },
+};
+int hb_audio_mixdowns_count = sizeof(hb_audio_mixdowns) / sizeof(hb_mixdown_t);
hb_encoder_t hb_video_encoders[] =
-{ { "H.264 (x264)", "x264", HB_VCODEC_X264, HB_MUX_MP4|HB_MUX_MKV },
- { "MPEG-4 (FFmpeg)", "ffmpeg4", HB_VCODEC_FFMPEG_MPEG4, HB_MUX_MP4|HB_MUX_MKV },
- { "MPEG-2 (FFmpeg)", "ffmpeg2", HB_VCODEC_FFMPEG_MPEG2, HB_MUX_MP4|HB_MUX_MKV },
- { "VP3 (Theora)", "theora", HB_VCODEC_THEORA, HB_MUX_MKV } };
-int hb_video_encoders_count = sizeof( hb_video_encoders ) /
- sizeof( hb_encoder_t );
+{
+ { "H.264 (x264)", "x264", HB_VCODEC_X264, HB_MUX_MP4|HB_MUX_MKV },
+ { "MPEG-4 (FFmpeg)", "ffmpeg4", HB_VCODEC_FFMPEG_MPEG4, HB_MUX_MP4|HB_MUX_MKV },
+ { "MPEG-2 (FFmpeg)", "ffmpeg2", HB_VCODEC_FFMPEG_MPEG2, HB_MUX_MP4|HB_MUX_MKV },
+ { "VP3 (Theora)", "theora", HB_VCODEC_THEORA, HB_MUX_MKV },
+};
+int hb_video_encoders_count = sizeof(hb_video_encoders) / sizeof(hb_encoder_t);
hb_encoder_t hb_audio_encoders[] =
{
#ifdef __APPLE__
- { "AAC (CoreAudio)", "ca_aac", HB_ACODEC_CA_AAC, HB_MUX_MP4|HB_MUX_MKV },
- { "HE-AAC (CoreAudio)", "ca_haac", HB_ACODEC_CA_HAAC, HB_MUX_MP4|HB_MUX_MKV },
+ { "AAC (CoreAudio)", "ca_aac", HB_ACODEC_CA_AAC, HB_MUX_MP4|HB_MUX_MKV },
+ { "HE-AAC (CoreAudio)", "ca_haac", HB_ACODEC_CA_HAAC, HB_MUX_MP4|HB_MUX_MKV },
#endif
- { "AAC (faac)", "faac", HB_ACODEC_FAAC, HB_MUX_MP4|HB_MUX_MKV },
- { "AAC (ffmpeg)", "ffaac", HB_ACODEC_FFAAC, HB_MUX_MP4|HB_MUX_MKV },
- { "AAC Passthru", "copy:aac", HB_ACODEC_AAC_PASS, HB_MUX_MP4|HB_MUX_MKV },
- { "AC3 (ffmpeg)", "ffac3", HB_ACODEC_AC3, HB_MUX_MP4|HB_MUX_MKV },
- { "AC3 Passthru", "copy:ac3", HB_ACODEC_AC3_PASS, HB_MUX_MP4|HB_MUX_MKV },
- { "DTS Passthru", "copy:dts", HB_ACODEC_DCA_PASS, HB_MUX_MP4|HB_MUX_MKV },
- { "DTS-HD Passthru", "copy:dtshd", HB_ACODEC_DCA_HD_PASS, HB_MUX_MP4|HB_MUX_MKV },
- { "MP3 (lame)", "lame", HB_ACODEC_LAME, HB_MUX_MP4|HB_MUX_MKV },
- { "MP3 Passthru", "copy:mp3", HB_ACODEC_MP3_PASS, HB_MUX_MP4|HB_MUX_MKV },
- { "Vorbis (vorbis)", "vorbis", HB_ACODEC_VORBIS, HB_MUX_MKV },
- { "FLAC (ffmpeg)", "ffflac", HB_ACODEC_FFFLAC, HB_MUX_MKV },
- { "Auto Passthru", "copy", HB_ACODEC_AUTO_PASS, HB_MUX_MP4|HB_MUX_MKV } };
-int hb_audio_encoders_count = sizeof( hb_audio_encoders ) /
- sizeof( hb_encoder_t );
+ { "AAC (faac)", "faac", HB_ACODEC_FAAC, HB_MUX_MP4|HB_MUX_MKV },
+ { "AAC (ffmpeg)", "ffaac", HB_ACODEC_FFAAC, HB_MUX_MP4|HB_MUX_MKV },
+ { "AAC Passthru", "copy:aac", HB_ACODEC_AAC_PASS, HB_MUX_MP4|HB_MUX_MKV },
+ { "AC3 (ffmpeg)", "ffac3", HB_ACODEC_AC3, HB_MUX_MP4|HB_MUX_MKV },
+ { "AC3 Passthru", "copy:ac3", HB_ACODEC_AC3_PASS, HB_MUX_MP4|HB_MUX_MKV },
+ { "DTS Passthru", "copy:dts", HB_ACODEC_DCA_PASS, HB_MUX_MP4|HB_MUX_MKV },
+ { "DTS-HD Passthru", "copy:dtshd", HB_ACODEC_DCA_HD_PASS, HB_MUX_MP4|HB_MUX_MKV },
+ { "MP3 (lame)", "lame", HB_ACODEC_LAME, HB_MUX_MP4|HB_MUX_MKV },
+ { "MP3 Passthru", "copy:mp3", HB_ACODEC_MP3_PASS, HB_MUX_MP4|HB_MUX_MKV },
+ { "Vorbis (vorbis)", "vorbis", HB_ACODEC_VORBIS, HB_MUX_MKV },
+ { "FLAC (ffmpeg)", "ffflac", HB_ACODEC_FFFLAC, HB_MUX_MKV },
+ { "Auto Passthru", "copy", HB_ACODEC_AUTO_PASS, HB_MUX_MP4|HB_MUX_MKV },
+};
+int hb_audio_encoders_count = sizeof(hb_audio_encoders) / sizeof(hb_encoder_t);
/* Expose values for PInvoke */
-hb_rate_t* hb_get_video_rates() { return hb_video_rates; }
-int hb_get_video_rates_count() { return hb_video_rates_count; }
-hb_rate_t* hb_get_audio_rates() { return hb_audio_rates; }
-int hb_get_audio_rates_count() { return hb_audio_rates_count; }
-int hb_get_audio_rates_default() { return hb_audio_rates_default; }
-hb_rate_t* hb_get_audio_bitrates() { return hb_audio_bitrates; }
-int hb_get_audio_bitrates_count() { return hb_audio_bitrates_count; }
-hb_mixdown_t* hb_get_audio_mixdowns() { return hb_audio_mixdowns; }
-int hb_get_audio_mixdowns_count() { return hb_audio_mixdowns_count; }
-hb_encoder_t* hb_get_video_encoders() { return hb_video_encoders; }
-int hb_get_video_encoders_count() { return hb_video_encoders_count; }
-hb_encoder_t* hb_get_audio_encoders() { return hb_audio_encoders; }
-int hb_get_audio_encoders_count() { return hb_audio_encoders_count; }
+hb_rate_t* hb_get_video_rates() { return hb_video_rates; }
+int hb_get_video_rates_count() { return hb_video_rates_count; }
+hb_rate_t* hb_get_audio_rates() { return hb_audio_rates; }
+int hb_get_audio_rates_count() { return hb_audio_rates_count; }
+hb_rate_t* hb_get_audio_bitrates() { return hb_audio_bitrates; }
+int hb_get_audio_bitrates_count() { return hb_audio_bitrates_count; }
+hb_mixdown_t* hb_get_audio_mixdowns() { return hb_audio_mixdowns; }
+int hb_get_audio_mixdowns_count() { return hb_audio_mixdowns_count; }
+hb_encoder_t* hb_get_video_encoders() { return hb_video_encoders; }
+int hb_get_video_encoders_count() { return hb_video_encoders_count; }
+hb_encoder_t* hb_get_audio_encoders() { return hb_audio_encoders; }
+int hb_get_audio_encoders_count() { return hb_audio_encoders_count; }
+
+int hb_mixdown_is_supported(int mixdown, uint32_t codec, uint64_t layout)
+{
+ return (hb_mixdown_has_codec_support(mixdown, codec) &&
+ hb_mixdown_has_remix_support(mixdown, layout));
+}
+
+int hb_mixdown_has_codec_support(int mixdown, uint32_t codec)
+{
+ // Passthru, only "None" mixdown is supported
+ if (codec & HB_ACODEC_PASS_FLAG)
+ return (mixdown == HB_AMIXDOWN_NONE);
+
+ // Not passthru, "None" mixdown never supported
+ if (mixdown == HB_AMIXDOWN_NONE)
+ return 0;
+
+ switch (codec)
+ {
+ case HB_ACODEC_FFFLAC:
+ case HB_ACODEC_VORBIS:
+ return (mixdown <= HB_AMIXDOWN_7POINT1);
+
+ case HB_ACODEC_LAME:
+ case HB_ACODEC_FFAAC:
+ return (mixdown <= HB_AMIXDOWN_DOLBYPLII);
+
+ case HB_ACODEC_FAAC:
+ case HB_ACODEC_CA_AAC:
+ case HB_ACODEC_CA_HAAC:
+ return ((mixdown <= HB_AMIXDOWN_5POINT1) ||
+ (mixdown == HB_AMIXDOWN_5_2_LFE));
+
+ default:
+ return (mixdown <= HB_AMIXDOWN_5POINT1);
+ }
+}
+
+int hb_mixdown_has_remix_support(int mixdown, uint64_t layout)
+{
+ switch (mixdown)
+ {
+ // stereo + front left/right of center
+ case HB_AMIXDOWN_5_2_LFE:
+ return ((layout & AV_CH_FRONT_LEFT_OF_CENTER) &&
+ (layout & AV_CH_FRONT_RIGHT_OF_CENTER) &&
+ (layout & AV_CH_LAYOUT_STEREO) == AV_CH_LAYOUT_STEREO);
+
+ // 7.0 or better
+ case HB_AMIXDOWN_7POINT1:
+ return ((layout & AV_CH_LAYOUT_7POINT0) == AV_CH_LAYOUT_7POINT0);
+
+ // 6.0 or better
+ case HB_AMIXDOWN_6POINT1:
+ return ((layout & AV_CH_LAYOUT_7POINT0) == AV_CH_LAYOUT_7POINT0 ||
+ (layout & AV_CH_LAYOUT_6POINT0) == AV_CH_LAYOUT_6POINT0 ||
+ (layout & AV_CH_LAYOUT_HEXAGONAL) == AV_CH_LAYOUT_HEXAGONAL);
+
+ // stereo + either of front center, side or back left/right, back center
+ case HB_AMIXDOWN_5POINT1:
+ return ((layout & AV_CH_LAYOUT_2_1) == AV_CH_LAYOUT_2_1 ||
+ (layout & AV_CH_LAYOUT_2_2) == AV_CH_LAYOUT_2_2 ||
+ (layout & AV_CH_LAYOUT_QUAD) == AV_CH_LAYOUT_QUAD ||
+ (layout & AV_CH_LAYOUT_SURROUND) == AV_CH_LAYOUT_SURROUND);
+
+ // stereo + either of side or back left/right, back center
+ // also, allow Dolby Surrounbd output if the input is already Dolby
+ case HB_AMIXDOWN_DOLBY:
+ case HB_AMIXDOWN_DOLBYPLII:
+ return ((layout & AV_CH_LAYOUT_2_1) == AV_CH_LAYOUT_2_1 ||
+ (layout & AV_CH_LAYOUT_2_2) == AV_CH_LAYOUT_2_2 ||
+ (layout & AV_CH_LAYOUT_QUAD) == AV_CH_LAYOUT_QUAD ||
+ (layout == AV_CH_LAYOUT_STEREO_DOWNMIX &&
+ mixdown == HB_AMIXDOWN_DOLBY));
+
+ // more than 1 channel
+ case HB_AMIXDOWN_STEREO:
+ return (av_get_channel_layout_nb_channels(layout) > 1);
+
+ // regular stereo (not Dolby)
+ case HB_AMIXDOWN_LEFT:
+ case HB_AMIXDOWN_RIGHT:
+ return (layout == AV_CH_LAYOUT_STEREO);
+
+ // mono remix always supported
+ // HB_AMIXDOWN_NONE always supported (for Passthru)
+ case HB_AMIXDOWN_MONO:
+ case HB_AMIXDOWN_NONE:
+ return 1;
+
+ // unknown mixdown, should never happen
+ default:
+ return 0;
+ }
+}
int hb_mixdown_get_discrete_channel_count(int amixdown)
{
switch (amixdown)
{
- case HB_AMIXDOWN_6CH:
+ case HB_AMIXDOWN_5_2_LFE:
+ case HB_AMIXDOWN_7POINT1:
+ return 8;
+
+ case HB_AMIXDOWN_6POINT1:
+ return 7;
+
+ case HB_AMIXDOWN_5POINT1:
return 6;
case HB_AMIXDOWN_MONO:
+ case HB_AMIXDOWN_LEFT:
+ case HB_AMIXDOWN_RIGHT:
return 1;
case HB_AMIXDOWN_NONE:
@@ -117,6 +265,21 @@ int hb_mixdown_get_discrete_channel_count(int amixdown)
}
}
+int hb_mixdown_get_low_freq_channel_count(int amixdown)
+{
+ switch (amixdown)
+ {
+ case HB_AMIXDOWN_5POINT1:
+ case HB_AMIXDOWN_6POINT1:
+ case HB_AMIXDOWN_7POINT1:
+ case HB_AMIXDOWN_5_2_LFE:
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
int hb_mixdown_get_mixdown_from_short_name(const char *short_name)
{
int i;
@@ -294,17 +457,15 @@ int hb_autopassthru_get_encoder( int in_codec, int copy_mask, int fallback, int
// Given an input bitrate, find closest match in the set of allowed bitrates
int hb_find_closest_audio_bitrate(int bitrate)
{
- int ii;
- int result;
-
// Check if bitrate mode was disabled
- if( bitrate <= 0 )
+ if (bitrate <= 0)
return bitrate;
+ int ii, result;
// result is highest rate if none found during search.
// rate returned will always be <= rate asked for.
result = hb_audio_bitrates[0].rate;
- for (ii = hb_audio_bitrates_count-1; ii >= 0; ii--)
+ for (ii = hb_audio_bitrates_count - 1; ii > 0; ii--)
{
if (bitrate >= hb_audio_bitrates[ii].rate)
{
@@ -315,259 +476,263 @@ int hb_find_closest_audio_bitrate(int bitrate)
return result;
}
-// Get the bitrate low and high limits for a codec/samplerate/mixdown triplet
-// The limits have been empirically determined through testing. Max bitrates
-// in table below. Numbers in parenthesis are the target bitrate chosen.
-/*
-Encoder 1 channel 2 channels 6 channels
-
-faac
-24kHz 86 (128) 173 (256) 460 (768)
-48kHz 152 (160) 304 (320) 759 (768)
+/* Get the bitrate low and high limits for a codec/samplerate/mixdown triplet.
-Vorbis
-24kHz 97 (80) 177 (160) 527 (512)
-48kHz 241 (224) 465 (448) 783 (768)
+Encoder 1.0 channel 2.0 channels 5.1 channels 6.1 channels 7.1 channels
+--------------------------------------------------------------------------------------
-Lame
-24kHz 146 (768) 138 (768)
-48kHz 318 (768) 318 (768)
+faac
+----
+supported samplerates: 8 - 48 kHz
+libfaac/util.c defines the bitrate limits:
+MinBitrate() -> 8000 bps (per channel, incl. LFE).
+MaxBitrate() -> (6144 * samplerate / 1024) bps (per channel, incl. LFE).
+But output bitrates don't go as high as the theoretical maximums:
+12 kHz 43 (72) 87 (144) 260 (432) 303 (504) 342 (576)
+24 kHz 87 (144) 174 (288) 514 (864) 595 (1008) 669 (1152)
+48 kHz 174 (288) 347 (576) 970 (1728) 1138 (2016) 1287 (2304)
+Also, faac isn't a great encoder, so you don't want to allow too low a bitrate.
+Limits: minimum of 32 Kbps per channel
+ maximum of 192 Kbps per channel at 32-48 kHz, adjusted for sr_shift
+
+
+ffaac
+-----
+supported samplerates: 8 - 48 kHz
+libavcodec/aacenc.c defines a maximum bitrate:
+-> 6144 * samplerate / 1024 bps (per channel, incl. LFE).
+But output bitrates don't go as high as the theoretical maximums:
+12 kHz 61 (72) 123 (144)
+24 kHz 121 (144) 242 (288)
+48 kHz 236 (288) 472 (576)
+Also, ffaac isn't a great encoder, so you don't want to allow too low a bitrate.
+Limits: minimum of 32 Kbps per channel
+ maximum of 192 Kbps per channel at 32 kHz, adjusted for sr_shift
+ maximum of 256 Kbps per channel at 44.1-48 kHz, adjusted for sr_shift
+
+vorbis
+------
+supported samplerates: 8 - 48 kHz
+lib/modes/setup_*.h provides a range of allowed bitrates for various configurations.
+for each samplerate, the highest minimums and lowest maximums are:
+ 8 kHz Minimum 8 Kbps, maximum 32 Kbps (per channel, incl. LFE).
+12 kHz Minimum 14 Kbps, maximum 44 Kbps (per channel, incl. LFE).
+16 kHz Minimum 16 Kbps, maximum 86 Kbps (per channel, incl. LFE).
+24 kHz Minimum 22 Kbps, maximum 86 Kbps (per channel, incl. LFE).
+32 kHz Minimum 26 Kbps, maximum 190 Kbps (per channel, incl. LFE).
+48 kHz Minimum 28 Kbps, maximum 240 Kbps (per channel, incl. LFE).
+Limits: minimum of 14/22/28 Kbps per channel (8-12, 16-24, 32-48 kHz)
+ maximum of 32/86/190/240 Kbps per channel (8-12, 16-24, 32, 44.1-48 kHz)
+
+lame
+----
+supported samplerates: 8 - 48 kHz
+lame_init_params() allows the following bitrates:
+12 kHz Minimum 8 Kbps, maximum 64 Kbps
+24 kHz Minimum 8 Kbps, maximum 160 Kbps
+48 kHz Minimum 32 Kbps, maximum 320 Kbps
+Limits: minimum of 8/8/32 Kbps (8-12, 16-24, 32-48 kHz)
+ maximum of 64/160/320 Kbps (8-12, 16-24, 32-48 kHz)
ffac3
-24kHz 318 (320) 318 (320) 318 (320)
-48kHz 636 (640) 636 (640) 636 (640)
-
-Core Audio AAC (core audio api provides range of allowed bitrates)
-24kHz 16-64 32-128 80-320
-32kHz 24-96 48-192 128-448
-48kHz 32-256 64-320 160-768
-
-Core Audio HE-AAC (core audio api provides range of allowed bitrates)
-32kHz 12-40 24-80 64-192
-48kHz 16-40 32-80 80-192
+-----
+supported samplerates: 32 - 48 kHz (< 32 kHz disabled for compatibility reasons)
+Dolby's encoder has a min. of 224 Kbps for 5 full-bandwidth channels (5.0, 5.1)
+The maximum AC3 bitrate is 640 Kbps
+Limits: minimum of 224/5 Kbps per full-bandwidth channel, maximum of 640 Kbps
+
+ca_aac
+------
+supported samplerates: 8 - 48 kHz
+Core Audio API provides a range of allowed bitrates:
+ 8 kHz 8 - 24 16 - 48 40 - 112 48 - 144 56 - 160
+12 kHz 12 - 32 24 - 64 64 - 160 72 - 192 96 - 224
+16 kHz 12 - 48 24 - 96 64 - 224 72 - 288 96 - 320
+24 kHz 16 - 64 32 - 128 80 - 320 96 - 384 112 - 448
+32 kHz 24 - 96 48 - 192 128 - 448 144 - 576 192 - 640
+48 kHz 32 - 256 64 - 320 160 - 768 192 - 960 224 - 960
+Limits:
+ 8 kHz -> minimum of 8 Kbps and maximum of 24 Kbps per full-bandwidth channel
+12 kHz -> minimum of 12 Kbps and maximum of 32 Kbps per full-bandwidth channel
+16 kHz -> minimum of 12 Kbps and maximum of 48 Kbps per full-bandwidth channel
+24 kHz -> minimum of 16 Kbps and maximum of 64 Kbps per full-bandwidth channel
+32 kHz -> minimum of 24 Kbps and maximum of 96 Kbps per full-bandwidth channel
+48 kHz -> minimum of 32 Kbps and maximum of 160 Kbps per full-bandwidth channel
+48 kHz -> maximum of +96 Kbps for Mono
+Note: encCoreAudioInit() will sanitize any mistake made here.
+
+ca_haac
+-------
+supported samplerates: 32 - 48 kHz
+Core Audio API provides a range of allowed bitrates:
+32 kHz 12 - 40 24 - 80 64 - 192 N/A 96 - 256
+48 kHz 16 - 40 32 - 80 80 - 192 N/A 112 - 256
+Limits: minimum of 12 (+ 4 if rate >= 44100) Kbps per full-bandwidth channel
+ maximum of 40 Kbps per full-bandwidth channel
+Note: encCoreAudioInit() will sanitize any mistake made here.
*/
-void hb_get_audio_bitrate_limits(uint32_t codec, int samplerate, int mixdown, int *low, int *high)
+void hb_get_audio_bitrate_limits(uint32_t codec, int samplerate, int mixdown,
+ int *low, int *high)
{
- int channels;
-
- channels = hb_mixdown_get_discrete_channel_count( mixdown );
- if( codec & HB_ACODEC_PASS_FLAG )
+ if (codec & HB_ACODEC_PASS_FLAG)
{
- // Bitrates don't apply to "lossless" audio (Passthru, FLAC), but may apply
- // if we fallback to an encoder when the source can't be passed through.
+ // Bitrates don't apply to passthrough audio, but may apply if we
+ // fallback to an encoder when the source can't be passed through.
*low = hb_audio_bitrates[0].rate;
*high = hb_audio_bitrates[hb_audio_bitrates_count-1].rate;
return;
}
- switch( codec )
+
+ /* samplerate, sr_shift */
+ int sr_shift;
+ samplerate = hb_get_best_samplerate(codec, samplerate, &sr_shift);
+
+ /* LFE, full-bandwidth channels */
+ int lfe_count, nchannels;
+ lfe_count = hb_mixdown_get_low_freq_channel_count(mixdown);
+ nchannels = hb_mixdown_get_discrete_channel_count(mixdown) - lfe_count;
+
+ switch (codec)
{
+ // Bitrates don't apply to "lossless" audio
case HB_ACODEC_FFFLAC:
- // Bitrates don't apply to "lossless" audio (Passthru, FLAC)
- *high = *low = -1;
- break;
+ *low = *high = -1;
+ return;
case HB_ACODEC_AC3:
- *low = 32 * channels;
- if (samplerate > 24000)
- {
- *high = 640;
- }
- else
- {
- *high = 320;
- }
+ *low = 224 * nchannels / 5;
+ *high = 640;
break;
case HB_ACODEC_CA_AAC:
- if (samplerate > 32000)
- {
- *low = channels * 32;
- if (channels == 1)
- *high = 256;
- if (channels == 2)
- *high = 320;
- if (channels == 6)
- {
- *low = 160;
- *high = 768;
- }
- }
- else if (samplerate > 24000)
- {
- *low = channels * 24;
- *high = channels * 96;
- if (channels == 6)
- {
- *low = 128;
- *high = 448;
- }
- }
- else
+ {
+ switch (samplerate)
{
- *low = channels * 16;
- *high = channels * 64;
- if (channels == 6)
- {
- *low = 80;
- *high = 320;
- }
+ case 8000:
+ *low = nchannels * 8;
+ *high = nchannels * 24;
+ break;
+ case 11025:
+ case 12000:
+ *low = nchannels * 12;
+ *high = nchannels * 32;
+ break;
+ case 16000:
+ *low = nchannels * 12;
+ *high = nchannels * 48;
+ break;
+ case 22050:
+ case 24000:
+ *low = nchannels * 16;
+ *high = nchannels * 64;
+ break;
+ case 32000:
+ *low = nchannels * 24;
+ *high = nchannels * 96;
+ break;
+ case 44100:
+ case 48000:
+ default:
+ *low = nchannels * 32;
+ *high = nchannels * (160 + (96 * (nchannels == 1)));
+ break;
}
- break;
+ } break;
case HB_ACODEC_CA_HAAC:
- if (samplerate > 32000)
- {
- *low = channels * 16;
- *high = channels * 40;
- if (channels == 6)
- {
- *low = 80;
- *high = 192;
- }
- }
- else
- {
- *low = channels * 12;
- *high = channels * 40;
- if (channels == 6)
- {
- *low = 64;
- *high = 192;
- }
- }
+ *low = nchannels * (12 + (4 * (samplerate >= 44100)));
+ *high = nchannels * 40;
break;
case HB_ACODEC_FAAC:
- *low = 32 * channels;
- if (samplerate > 24000)
- {
- *high = 160 * channels;
- if (*high > 768)
- *high = 768;
- }
- else
- {
- *high = 96 * channels;
- if (*high > 480)
- *high = 480;
- }
+ *low = (nchannels + lfe_count) * 32;
+ *high = (nchannels + lfe_count) * (192 >> sr_shift);
break;
case HB_ACODEC_FFAAC:
- *low = 32 * channels;
- if (samplerate > 24000)
- {
- *high = 160 * channels;
- if (*high > 768)
- *high = 768;
- }
- else
- {
- *high = 96 * channels;
- if (*high > 480)
- *high = 480;
- }
+ *low = ((nchannels + lfe_count) * 32);
+ *high = ((nchannels + lfe_count) *
+ ((192 + (64 * ((samplerate << sr_shift) >= 44100)))
+ >> sr_shift));
break;
- case HB_ACODEC_VORBIS:
- *high = channels * 80;
- if (samplerate > 24000)
- {
- if (channels > 2)
- {
- // Vorbis minimum is around 30kbps/ch for 6ch
- // at rates > 24k (32k/44.1k/48k)
- *low = 32 * channels;
- *high = 128 * channels;
- }
- else
- {
- // Allow 24kbps mono and 48kbps stereo at rates > 24k
- // (32k/44.1k/48k)
- *low = 24 * channels;
- if (samplerate > 32000)
- *high = channels * 224;
- else
- *high = channels * 160;
- }
- }
- else
- {
- *low = channels * 16;
- *high = 80 * channels;
- }
+ case HB_ACODEC_LAME:
+ *low = 8 + (24 * (sr_shift < 1));
+ *high = 64 + (96 * (sr_shift < 2)) + (160 * (sr_shift < 1));
break;
- case HB_ACODEC_LAME:
- *low = hb_audio_bitrates[0].rate;
- if (samplerate > 24000)
- *high = 320;
- else
- *high = 160;
+ case HB_ACODEC_VORBIS:
+ *low = (nchannels + lfe_count) * (14 +
+ (8 * (sr_shift < 2)) +
+ (6 * (sr_shift < 1)));
+ *high = (nchannels + lfe_count) * (32 +
+ ( 54 * (sr_shift < 2)) +
+ (104 * (sr_shift < 1)) +
+ ( 50 * (samplerate >= 44100)));
break;
-
+
default:
- *low = hb_audio_bitrates[0].rate;
+ *low = hb_audio_bitrates[0].rate;
*high = hb_audio_bitrates[hb_audio_bitrates_count-1].rate;
break;
}
+ // sanitize max. bitrate
+ if (*high < hb_audio_bitrates[0].rate)
+ *high = hb_audio_bitrates[0].rate;
+ if (*high > hb_audio_bitrates[hb_audio_bitrates_count-1].rate)
+ *high = hb_audio_bitrates[hb_audio_bitrates_count-1].rate;
}
-// Given an input bitrate, sanitize it. Check low and high limits and
-// make sure it is in the set of allowed bitrates.
-int hb_get_best_audio_bitrate( uint32_t codec, int bitrate, int samplerate, int mixdown)
+// Given an input bitrate, sanitize it.
+// Check low and high limits and make sure it is in the set of allowed bitrates.
+int hb_get_best_audio_bitrate(uint32_t codec, int bitrate, int samplerate,
+ int mixdown)
{
int low, high;
-
hb_get_audio_bitrate_limits(codec, samplerate, mixdown, &low, &high);
if (bitrate > high)
bitrate = high;
if (bitrate < low)
bitrate = low;
- bitrate = hb_find_closest_audio_bitrate(bitrate);
- return bitrate;
+ return hb_find_closest_audio_bitrate(bitrate);
}
// Get the default bitrate for a given codec/samplerate/mixdown triplet.
-int hb_get_default_audio_bitrate( uint32_t codec, int samplerate, int mixdown )
+int hb_get_default_audio_bitrate(uint32_t codec, int samplerate, int mixdown)
{
- int bitrate, channels;
- int sr_shift;
-
- if( codec & HB_ACODEC_PASS_FLAG )
+ if (codec & HB_ACODEC_PASS_FLAG)
+ {
return -1;
+ }
- channels = hb_mixdown_get_discrete_channel_count( mixdown );
-
- // Min bitrate is established such that we get good quality
- // audio as a minimum.
- sr_shift = (samplerate <= 24000) ? 1 : 0;
+ int bitrate, nchannels, sr_shift;
+ /* full-bandwidth channels, sr_shift */
+ nchannels = (hb_mixdown_get_discrete_channel_count(mixdown) -
+ hb_mixdown_get_low_freq_channel_count(mixdown));
+ hb_get_best_samplerate(codec, samplerate, &sr_shift);
- switch ( codec )
+ switch (codec)
{
case HB_ACODEC_FFFLAC:
- bitrate = -1;
- sr_shift = 0;
- break;
+ return -1;
+
+ // 96, 224, 640 Kbps
case HB_ACODEC_AC3:
- if (channels == 1)
- bitrate = 96;
- else if (channels <= 2)
- bitrate = 224;
- else
- bitrate = 640;
+ bitrate = (nchannels * 128) - (32 * (nchannels < 5));
break;
+
case HB_ACODEC_CA_HAAC:
- bitrate = channels * 32;
+ bitrate = nchannels * 32;
break;
+
default:
- bitrate = channels * 80;
+ bitrate = nchannels * 80;
break;
}
+ // sample_rate adjustment
bitrate >>= sr_shift;
- bitrate = hb_get_best_audio_bitrate( codec, bitrate, samplerate, mixdown );
- return bitrate;
+ return hb_get_best_audio_bitrate(codec, bitrate, samplerate, mixdown);
}
// Get limits and hints for the UIs.
@@ -577,9 +742,10 @@ int hb_get_default_audio_bitrate( uint32_t codec, int samplerate, int mixdown )
//
// direction says whether 'low' limit is highest or lowest
// quality (direction 0 == lowest value is worst quality)
-void hb_get_audio_quality_limits(uint32_t codec, float *low, float *high, float *granularity, int *direction)
+void hb_get_audio_quality_limits(uint32_t codec, float *low, float *high,
+ float *granularity, int *direction)
{
- switch( codec )
+ switch (codec)
{
case HB_ACODEC_LAME:
*direction = 1;
@@ -610,11 +776,10 @@ void hb_get_audio_quality_limits(uint32_t codec, float *low, float *high, float
}
}
-float hb_get_best_audio_quality( uint32_t codec, float quality)
+float hb_get_best_audio_quality(uint32_t codec, float quality)
{
float low, high, granularity;
int direction;
-
hb_get_audio_quality_limits(codec, &low, &high, &granularity, &direction);
if (quality > high)
quality = high;
@@ -654,9 +819,10 @@ float hb_get_default_audio_quality( uint32_t codec )
//
// direction says whether 'low' limit is highest or lowest
// compression level (direction 0 == lowest value is worst compression level)
-void hb_get_audio_compression_limits(uint32_t codec, float *low, float *high, float *granularity, int *direction)
+void hb_get_audio_compression_limits(uint32_t codec, float *low, float *high,
+ float *granularity, int *direction)
{
- switch( codec )
+ switch (codec)
{
case HB_ACODEC_FFFLAC:
*direction = 0;
@@ -680,12 +846,11 @@ void hb_get_audio_compression_limits(uint32_t codec, float *low, float *high, fl
}
}
-float hb_get_best_audio_compression( uint32_t codec, float compression)
+float hb_get_best_audio_compression(uint32_t codec, float compression)
{
float low, high, granularity;
int direction;
-
- hb_get_audio_compression_limits( codec, &low, &high, &granularity, &direction );
+ hb_get_audio_compression_limits(codec, &low, &high, &granularity, &direction);
if( compression > high )
compression = high;
if( compression < low )
@@ -693,72 +858,39 @@ float hb_get_best_audio_compression( uint32_t codec, float compression)
return compression;
}
-float hb_get_default_audio_compression( uint32_t codec )
+float hb_get_default_audio_compression(uint32_t codec)
{
- float compression;
- switch( codec )
+ switch (codec)
{
case HB_ACODEC_FFFLAC:
- compression = 5;
- break;
+ return 5.;
case HB_ACODEC_LAME:
- compression = 2;
- break;
+ return 2.;
default:
- compression = -1;
- break;
+ return -1.;
}
- return compression;
}
int hb_get_best_mixdown(uint32_t codec, uint64_t layout, int mixdown)
{
- int best_mixdown;
-
+ // Passthru, only "None" mixdown is supported
if (codec & HB_ACODEC_PASS_FLAG)
- {
- // Audio passthrough, no mixdown
return HB_AMIXDOWN_NONE;
- }
- else if ((layout & AV_CH_LAYOUT_2_1) == AV_CH_LAYOUT_2_1 ||
- (layout & AV_CH_LAYOUT_2_2) == AV_CH_LAYOUT_2_2 ||
- (layout & AV_CH_LAYOUT_QUAD) == AV_CH_LAYOUT_QUAD)
- {
- // at least 2 front channels and one back or side channel
- // allow downmixing or upmixing to 5.1 (yes, we can)
- if (codec != HB_ACODEC_LAME && codec != HB_ACODEC_FFAAC)
- {
- best_mixdown = HB_AMIXDOWN_6CH;
- }
- else
- {
- best_mixdown = HB_AMIXDOWN_DOLBYPLII;
- }
- }
- else if (layout == AV_CH_LAYOUT_STEREO_DOWNMIX)
- {
- // Dolby in, allow Dolby out
- best_mixdown = HB_AMIXDOWN_DOLBY;
- }
- else if (av_get_channel_layout_nb_channels(layout) > 1)
- {
- // more than one channel, allow Stereo downmix
- best_mixdown = HB_AMIXDOWN_STEREO;
- }
- else
- {
- // only one channel, not much point in upmixing
- best_mixdown = HB_AMIXDOWN_MONO;
- }
- // return the best that is not greater than the requested mixdown
- // HB_INVALID_AMIXDOWN means the caller requested the best available mixdown
- if (best_mixdown > mixdown && mixdown != HB_INVALID_AMIXDOWN)
- best_mixdown = mixdown;
+ // caller requested the best available mixdown
+ if (mixdown == HB_INVALID_AMIXDOWN)
+ mixdown = hb_audio_mixdowns[hb_audio_mixdowns_count].amixdown;
- return best_mixdown;
+ int ii;
+ // test all mixdowns until an authorized, supported mixdown is found
+ // stop before we reach the "worst" non-None mixdown (index == 1)
+ for (ii = hb_audio_mixdowns_count; ii > 1; ii--)
+ if (hb_audio_mixdowns[ii].amixdown <= mixdown &&
+ hb_mixdown_is_supported(hb_audio_mixdowns[ii].amixdown, codec, layout))
+ break;
+ return hb_audio_mixdowns[ii].amixdown;
}
int hb_get_default_mixdown(uint32_t codec, uint64_t layout)
@@ -766,10 +898,13 @@ int hb_get_default_mixdown(uint32_t codec, uint64_t layout)
int mixdown;
switch (codec)
{
- // the FLAC and AC3 encoders default to the best mixdown up to 6-channel
+ // the FLAC encoder defaults to the best mixdown up to 7.1
case HB_ACODEC_FFFLAC:
+ mixdown = HB_AMIXDOWN_7POINT1;
+ break;
+ // the AC3 encoder defaults to the best mixdown up to 5.1
case HB_ACODEC_AC3:
- mixdown = HB_AMIXDOWN_6CH;
+ mixdown = HB_AMIXDOWN_5POINT1;
break;
// other encoders default to the best mixdown up to DPLII
default:
@@ -780,6 +915,52 @@ int hb_get_default_mixdown(uint32_t codec, uint64_t layout)
return hb_get_best_mixdown(codec, layout, mixdown);
}
+int hb_get_best_samplerate(uint32_t codec, int samplerate, int *sr_shift)
+{
+ int ii, best_samplerate, samplerate_shift;
+ if ((samplerate < 32000) &&
+ (codec == HB_ACODEC_CA_HAAC || codec == HB_ACODEC_AC3))
+ {
+ // ca_haac can't do samplerates < 32 kHz
+ // AC-3 < 32 kHz suffers from poor hardware compatibility
+ best_samplerate = 32000;
+ samplerate_shift = 0;
+ }
+ else
+ {
+ best_samplerate = samplerate;
+ for (ii = hb_audio_rates_count - 1; ii >= 0; ii--)
+ {
+ // valid samplerate
+ if (best_samplerate == hb_audio_rates[ii].rate)
+ break;
+
+ // samplerate is higher than the next valid samplerate,
+ // or lower than the lowest valid samplerate
+ if (best_samplerate > hb_audio_rates[ii].rate || ii == 0)
+ {
+ best_samplerate = hb_audio_rates[ii].rate;
+ break;
+ }
+ }
+ /* sr_shift: 0 -> 48000, 44100, 32000 Hz
+ * 1 -> 24000, 22050, 16000 Hz
+ * 2 -> 12000, 11025, 8000 Hz
+ *
+ * also, since samplerates are sanitized downwards:
+ *
+ * (samplerate < 32000) implies (samplerate <= 24000)
+ */
+ samplerate_shift = ((best_samplerate < 16000) ? 2 :
+ (best_samplerate < 32000) ? 1 : 0);
+ }
+ if (sr_shift != NULL)
+ {
+ *sr_shift = samplerate_shift;
+ }
+ return best_samplerate;
+}
+
/**********************************************************************
* hb_reduce
**********************************************************************
diff --git a/libhb/common.h b/libhb/common.h
index 1650f8002..77898cef3 100644
--- a/libhb/common.h
+++ b/libhb/common.h
@@ -197,7 +197,11 @@ int hb_get_video_encoders_count();
hb_encoder_t* hb_get_audio_encoders();
int hb_get_audio_encoders_count();
+int hb_mixdown_is_supported(int mixdown, uint32_t codec, uint64_t layout);
+int hb_mixdown_has_codec_support(int mixdown, uint32_t codec);
+int hb_mixdown_has_remix_support(int mixdown, uint64_t layout);
int hb_mixdown_get_discrete_channel_count(int amixdown);
+int hb_mixdown_get_low_freq_channel_count(int amixdown);
int hb_mixdown_get_mixdown_from_short_name(const char *short_name);
const char* hb_mixdown_get_short_name_from_mixdown(int amixdown);
@@ -206,6 +210,7 @@ void hb_autopassthru_print_settings( hb_job_t * job );
int hb_autopassthru_get_encoder( int in_codec, int copy_mask, int fallback, int muxer );
int hb_get_best_mixdown(uint32_t codec, uint64_t layout, int mixdown);
int hb_get_default_mixdown(uint32_t codec, uint64_t layout);
+int hb_get_best_samplerate(uint32_t codec, int samplerate, int *sr_shift);
int hb_find_closest_audio_bitrate(int bitrate);
void hb_get_audio_bitrate_limits(uint32_t codec, int samplerate, int mixdown, int *low, int *high);
int hb_get_best_audio_bitrate( uint32_t codec, int bitrate, int samplerate, int mixdown);
@@ -438,10 +443,15 @@ struct hb_audio_config_s
HB_INVALID_AMIXDOWN = -1,
HB_AMIXDOWN_NONE = 0,
HB_AMIXDOWN_MONO,
+ HB_AMIXDOWN_LEFT,
+ HB_AMIXDOWN_RIGHT,
HB_AMIXDOWN_STEREO,
HB_AMIXDOWN_DOLBY,
HB_AMIXDOWN_DOLBYPLII,
- HB_AMIXDOWN_6CH,
+ HB_AMIXDOWN_5POINT1,
+ HB_AMIXDOWN_6POINT1,
+ HB_AMIXDOWN_7POINT1,
+ HB_AMIXDOWN_5_2_LFE,
} mixdown; /* Audio mixdown */
int track; /* Output track number */
uint32_t codec; /* Output audio codec */
diff --git a/libhb/encfaac.c b/libhb/encfaac.c
index 675881e8e..c6a3f8a16 100644
--- a/libhb/encfaac.c
+++ b/libhb/encfaac.c
@@ -40,21 +40,6 @@ hb_work_object_t hb_encfaac =
encfaacClose
};
-static const int valid_rates[] =
-{
- 22050, 24000, 32000, 44100, 48000, 0
-};
-
-static int find_samplerate( int rate )
-{
- int i;
-
- for ( i = 0; valid_rates[i] && rate > valid_rates[i]; ++i )
- {
- }
- return i;
-}
-
/***********************************************************************
* hb_work_encfaac_init
***********************************************************************
@@ -75,28 +60,6 @@ int encfaacInit( hb_work_object_t * w, hb_job_t * 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);
- /* 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. */
- int rate_index = find_samplerate(audio->config.out.samplerate);
- if ( audio->config.out.samplerate != valid_rates[rate_index] )
- {
- int rate = valid_rates[valid_rates[rate_index]? rate_index : rate_index - 1];
- hb_log( "encfaac changing output samplerate from %d to %d",
- audio->config.out.samplerate, rate );
- audio->config.out.samplerate = rate;
-
- /* if the new rate is over the max bandwidth per channel limit */
- /* lower the bandwidth. */
- double bw = audio->config.out.bitrate * 1000 / pv->out_discrete_channels;
- if ( bw > (double)rate * (6144./1024.) )
- {
- int newbr = (double)rate * (6.144/1024.) * pv->out_discrete_channels;
- hb_log( "encfaac changing output bitrate from %d to %d",
- audio->config.out.bitrate, newbr );
- audio->config.out.bitrate = newbr;
- }
- }
-
pv->faac = faacEncOpen( audio->config.out.samplerate, pv->out_discrete_channels,
&pv->input_samples, &pv->output_bytes );
pv->buf = malloc( pv->input_samples * sizeof( float ) );
@@ -110,7 +73,7 @@ int encfaacInit( hb_work_object_t * w, hb_job_t * job )
cfg->aacObjectType = LOW;
cfg->allowMidside = 1;
- // channel remapping, LFE
+ /* channel configuration & remapping */
uint64_t layout;
int *remap_table;
layout = hb_ff_mixdown_xlat(audio->config.out.mixdown, NULL);
@@ -123,7 +86,33 @@ int encfaacInit( hb_work_object_t * w, hb_job_t * job )
pv->out_discrete_channels * sizeof(int));
free(remap_table);
}
- cfg->useLfe = !!(layout & AV_CH_LOW_FREQUENCY);
+ switch (audio->config.out.mixdown)
+ {
+ case HB_AMIXDOWN_7POINT1:
+ cfg->channelConfiguration = 0;
+ cfg->numFrontChannels = 3;
+ cfg->numSideChannels = 2;
+ cfg->numBackChannels = 2;
+ cfg->numLFEChannels = 1;
+ break;
+
+ case HB_AMIXDOWN_6POINT1:
+ cfg->channelConfiguration = 0;
+ cfg->numFrontChannels = 3;
+ cfg->numSideChannels = 0;
+ cfg->numBackChannels = 3;
+ cfg->numLFEChannels = 1;
+ break;
+
+ case HB_AMIXDOWN_5_2_LFE:
+ cfg->channelConfiguration = 7;
+ break;
+
+ default:
+ cfg->channelConfiguration =
+ hb_mixdown_get_discrete_channel_count(audio->config.out.mixdown);
+ break;
+ }
cfg->useTns = 0;
cfg->bitRate = audio->config.out.bitrate * 1000 / pv->out_discrete_channels; /* Per channel */
diff --git a/libhb/encvorbis.c b/libhb/encvorbis.c
index a5325ef6d..4bd36b43a 100644
--- a/libhb/encvorbis.c
+++ b/libhb/encvorbis.c
@@ -72,18 +72,6 @@ int encvorbisInit(hb_work_object_t *w, hb_job_t *job)
if (audio->config.out.bitrate > 0)
{
- /* 28kbps/channel seems to be the minimum for 6ch vorbis. */
- int min_bitrate = 28 * pv->out_discrete_channels;
- if (pv->out_discrete_channels > 2 &&
- audio->config.out.bitrate < min_bitrate)
- {
- hb_log("encvorbis: Selected bitrate (%d kbps) too low for %d channel audio",
- audio->config.out.bitrate, pv->out_discrete_channels);
- hb_log("encvorbis: Resetting bitrate to %d kbps", min_bitrate);
- /* Naughty! We shouldn't modify the audio from here. */
- audio->config.out.bitrate = min_bitrate;
- }
-
if (vorbis_encode_setup_managed(&pv->vi, pv->out_discrete_channels,
audio->config.out.samplerate, -1,
audio->config.out.bitrate * 1000, -1))
diff --git a/libhb/hb.c b/libhb/hb.c
index ed074f93d..12377a8b5 100644
--- a/libhb/hb.c
+++ b/libhb/hb.c
@@ -221,6 +221,8 @@ uint64_t hb_ff_mixdown_xlat(int hb_mixdown, int *downmix_mode)
break;
case HB_AMIXDOWN_MONO:
+ case HB_AMIXDOWN_LEFT:
+ case HB_AMIXDOWN_RIGHT:
ff_layout = AV_CH_LAYOUT_MONO;
break;
@@ -238,13 +240,27 @@ uint64_t hb_ff_mixdown_xlat(int hb_mixdown, int *downmix_mode)
ff_layout = AV_CH_LAYOUT_STEREO;
break;
- case HB_AMIXDOWN_6CH:
+ case HB_AMIXDOWN_5POINT1:
ff_layout = AV_CH_LAYOUT_5POINT1;
break;
+ case HB_AMIXDOWN_6POINT1:
+ ff_layout = AV_CH_LAYOUT_6POINT1;
+ break;
+
+ case HB_AMIXDOWN_7POINT1:
+ ff_layout = AV_CH_LAYOUT_7POINT1;
+ break;
+
+ case HB_AMIXDOWN_5_2_LFE:
+ ff_layout = (AV_CH_LAYOUT_5POINT1_BACK|
+ AV_CH_FRONT_LEFT_OF_CENTER|
+ AV_CH_FRONT_RIGHT_OF_CENTER);
+ break;
+
default:
ff_layout = AV_CH_LAYOUT_STEREO;
- hb_log("unrecognized channel layout");
+ hb_log("hb_ff_mixdown_xlat: unsupported mixdown %d", hb_mixdown);
break;
}
if (downmix_mode != NULL)
diff --git a/libhb/muxmp4.c b/libhb/muxmp4.c
index 2203193a1..d21e4b767 100644
--- a/libhb/muxmp4.c
+++ b/libhb/muxmp4.c
@@ -295,7 +295,7 @@ static int MP4Init( hb_mux_object_t * m )
bsmod = 0;
freq = audio->config.out.samplerate;
bitrate = audio->config.out.bitrate * 1000;
- switch( audio->config.out.mixdown )
+ switch (audio->config.out.mixdown)
{
case HB_AMIXDOWN_MONO:
acmod = 1;
@@ -309,13 +309,13 @@ static int MP4Init( hb_mux_object_t * m )
lfeon = 0;
break;
- case HB_AMIXDOWN_6CH:
+ case HB_AMIXDOWN_5POINT1:
acmod = 7;
lfeon = 1;
break;
default:
- hb_log(" MP4Init: bad mixdown" );
+ hb_log("MP4Init: bad mixdown");
acmod = 2;
lfeon = 0;
break;
diff --git a/libhb/work.c b/libhb/work.c
index 141ec4b3b..9dffb5f46 100644
--- a/libhb/work.c
+++ b/libhb/work.c
@@ -405,14 +405,14 @@ void hb_display_job_info( hb_job_t * job )
else if( subtitle->source == SRTSUB )
{
/* For SRT, print offset and charset too */
- hb_log( " * subtitle track %i, %s (track %d, id 0x%x) Text [SRT] -> Passthrough%s, offset: %"PRId64", charset: %s",
+ hb_log( " * subtitle track %d, %s (track %d, id 0x%x) Text [SRT] -> Passthrough%s, offset: %"PRId64", charset: %s",
subtitle->out_track, subtitle->lang, subtitle->track, subtitle->id,
subtitle->config.default_track ? ", Default" : "",
subtitle->config.offset, subtitle->config.src_codeset );
}
else
{
- hb_log( " * subtitle track %i, %s (track %d, id 0x%x) %s [%s] -> %s%s%s",
+ hb_log( " * subtitle track %d, %s (track %d, id 0x%x) %s [%s] -> %s%s%s",
subtitle->out_track, subtitle->lang, subtitle->track, subtitle->id,
subtitle->format == PICTURESUB ? "Picture" : "Text",
hb_subsource_name( subtitle->source ),
@@ -782,36 +782,15 @@ static void do_job( hb_job_t * job )
free(audio);
continue;
}
- if (!(audio->config.out.codec & HB_ACODEC_PASS_FLAG))
- {
- if (audio->config.out.samplerate < 0)
- {
- // if not specified, set to same as input
- audio->config.out.samplerate = audio->config.in.samplerate;
- }
- if (audio->config.out.samplerate > 48000)
- {
- hb_log("Sample rate %d not supported. Downsampling to 48kHz for track %d",
- audio->config.out.samplerate, audio->config.out.track);
- audio->config.out.samplerate = 48000;
- }
- else if (audio->config.out.samplerate < 32000 &&
- audio->config.out.codec == HB_ACODEC_CA_HAAC)
- {
- // Core Audio HE-AAC doesn't support samplerates < 32 kHz
- hb_log("Sample rate %d not supported (ca_haac). Using 32kHz for track %d",
- audio->config.out.samplerate, audio->config.out.track);
- audio->config.out.samplerate = 32000;
- }
- }
/* Adjust output track number, in case we removed one.
* Output tracks sadly still need to be in sequential order.
* Note: out.track starts at 1, i starts at 0 */
audio->config.out.track = ++i;
}
- int best_mixdown = 0;
- int best_bitrate = 0;
+ int best_mixdown = 0;
+ int best_bitrate = 0;
+ int best_samplerate = 0;
for (i = 0; i < hb_list_count(title->list_audio); i++)
{
@@ -831,6 +810,31 @@ static void do_job( hb_job_t * job )
if (audio->config.out.codec == HB_ACODEC_VORBIS)
audio->priv.config.vorbis.language = audio->config.lang.simple;
+ /* sense-check the requested samplerate */
+ if (audio->config.out.samplerate < 0)
+ {
+ // if not specified, set to same as input
+ audio->config.out.samplerate = audio->config.in.samplerate;
+ }
+ best_samplerate =
+ hb_get_best_samplerate(audio->config.out.codec,
+ audio->config.out.samplerate, NULL);
+ if (best_samplerate != audio->config.out.samplerate)
+ {
+ int ii;
+ for (ii = 0; ii < hb_audio_rates_count; ii++)
+ {
+ if (best_samplerate == hb_audio_rates[ii].rate)
+ {
+ hb_log("work: sanitizing track %d unsupported samplerate %d Hz to %s kHz",
+ audio->config.out.track, audio->config.out.samplerate,
+ hb_audio_rates[ii].string);
+ break;
+ }
+ }
+ audio->config.out.samplerate = best_samplerate;
+ }
+
/* sense-check the requested mixdown */
if (audio->config.out.mixdown <= HB_AMIXDOWN_NONE)
{
@@ -842,7 +846,7 @@ static void do_job( hb_job_t * job )
{
if (hb_audio_mixdowns[j].amixdown == audio->config.out.mixdown)
{
- hb_log("work: mixdown not specified, track %i setting mixdown %s",
+ hb_log("work: mixdown not specified, track %d setting mixdown %s",
audio->config.out.track,
hb_audio_mixdowns[j].human_readable_name);
break;
@@ -851,10 +855,10 @@ static void do_job( hb_job_t * job )
}
else
{
- best_mixdown = hb_get_best_mixdown(audio->config.out.codec,
- audio->config.in.channel_layout,
- audio->config.out.mixdown);
-
+ best_mixdown =
+ hb_get_best_mixdown(audio->config.out.codec,
+ audio->config.in.channel_layout,
+ audio->config.out.mixdown);
if (audio->config.out.mixdown != best_mixdown)
{
int prev_mix_idx = 0, best_mix_idx = 0;
@@ -870,7 +874,7 @@ static void do_job( hb_job_t * job )
}
}
/* log the output mixdown */
- hb_log("work: sanitizing track %i mixdown %s to %s",
+ hb_log("work: sanitizing track %d mixdown %s to %s",
audio->config.out.track,
hb_audio_mixdowns[prev_mix_idx].human_readable_name,
hb_audio_mixdowns[best_mix_idx].human_readable_name);
@@ -942,14 +946,13 @@ static void do_job( hb_job_t * job )
if (audio->config.out.bitrate <= 0)
{
/* Bitrate not specified, set the default bitrate */
- audio->config.out.bitrate =
+ audio->config.out.bitrate =
hb_get_default_audio_bitrate(audio->config.out.codec,
audio->config.out.samplerate,
audio->config.out.mixdown);
-
if (audio->config.out.bitrate > 0)
{
- hb_log("work: bitrate not specified, track %d setting bitrate %d",
+ hb_log("work: bitrate not specified, track %d setting bitrate %d Kbps",
audio->config.out.track,
audio->config.out.bitrate);
}
@@ -961,12 +964,11 @@ static void do_job( hb_job_t * job )
audio->config.out.bitrate,
audio->config.out.samplerate,
audio->config.out.mixdown);
-
if (best_bitrate > 0 &&
best_bitrate != audio->config.out.bitrate)
{
/* log the output bitrate */
- hb_log("work: sanitizing track %d bitrate %d to %d",
+ hb_log("work: sanitizing track %d bitrate %d to %d Kbps",
audio->config.out.track,
audio->config.out.bitrate, best_bitrate);
}
diff --git a/macosx/HBAudio.m b/macosx/HBAudio.m
index 8a5f06291..fdd7b5462 100644
--- a/macosx/HBAudio.m
+++ b/macosx/HBAudio.m
@@ -224,37 +224,19 @@ static NSMutableArray *masterBitRateArray = nil;
{
NSMutableArray *permittedMixdowns = [NSMutableArray array];
NSDictionary *dict;
- BOOL shouldAdd;
int currentMixdown;
unsigned long long channelLayout = [[track objectForKey: keyAudioInputChannelLayout] unsignedLongLongValue];
unsigned int count = [masterMixdownArray count];
int codecCodec = [[codec objectForKey: keyAudioCodec] intValue];
int theDefaultMixdown = hb_get_default_mixdown(codecCodec, channelLayout);
- int theBestMixdown = hb_get_best_mixdown(codecCodec, channelLayout, HB_INVALID_AMIXDOWN);
for (unsigned int i = 0; i < count; i++)
{
dict = [masterMixdownArray objectAtIndex: i];
currentMixdown = [[dict objectForKey: keyAudioMixdown] intValue];
- // Basically with the way the mixdowns are stored, the assumption from the libhb point of view
- // currently is that all mixdowns from the best down to mono are supported.
- if ((currentMixdown != HB_AMIXDOWN_NONE) && (currentMixdown <= theBestMixdown))
- {
- shouldAdd = YES;
- }
- else if ((currentMixdown == HB_AMIXDOWN_NONE) && (codecCodec & HB_ACODEC_PASS_FLAG))
- {
- // "None" mixdown (passthru)
- shouldAdd = YES;
- }
- else
- {
- shouldAdd = NO;
- }
-
- if (shouldAdd)
+ if (hb_mixdown_is_supported(currentMixdown, codecCodec, channelLayout))
{
[permittedMixdowns addObject: dict];
}
diff --git a/macosx/HBAudioController.m b/macosx/HBAudioController.m
index 235e39f43..b9b80bd53 100644
--- a/macosx/HBAudioController.m
+++ b/macosx/HBAudioController.m
@@ -90,9 +90,9 @@ NSString *HBMixdownChangedNotification = @"HBMixdownChangedNotification";
if ([anAudio enabled])
{
NSString *prefix = [NSString stringWithFormat: @"Audio%d", counter + 1];
- NSNumber *sampleRateToUse = (0 == [[[anAudio sampleRate] objectForKey: keyAudioSamplerate] intValue]) ?
- [[anAudio track] objectForKey: keyAudioInputSampleRate] :
- [[anAudio sampleRate] objectForKey: keyAudioSamplerate];
+ NSNumber *sampleRateToUse = ([[[anAudio sampleRate] objectForKey: keyAudioSamplerate] intValue] == 0 ?
+ [[anAudio track] objectForKey: keyAudioInputSampleRate] :
+ [[anAudio sampleRate] objectForKey: keyAudioSamplerate]);
[aDict setObject: [[anAudio track] objectForKey: keyAudioTrackIndex] forKey: [prefix stringByAppendingString: @"Track"]];
[aDict setObject: [[anAudio track] objectForKey: keyAudioTrackName] forKey: [prefix stringByAppendingString: @"TrackDescription"]];
@@ -345,7 +345,7 @@ NSString *HBMixdownChangedNotification = @"HBMixdownChangedNotification";
[dict setObject:[NSNumber numberWithFloat:0.0] forKey:@"AudioTrackGainSlider"];
}
- // map legacy passthru mixdowns
+ // map legacy mixdowns
key = [dict objectForKey: @"AudioMixdown"];
if ([key isEqualToString: @"AC3 Passthru"] ||
[key isEqualToString: @"DTS Passthru"] ||
@@ -353,6 +353,10 @@ NSString *HBMixdownChangedNotification = @"HBMixdownChangedNotification";
{
[dict setObject: @"None" forKey: @"AudioMixdown"];
}
+ else if ([key isEqualToString: @"6-channel discrete"])
+ {
+ [dict setObject: @"5.1 Channels" forKey: @"AudioMixdown"];
+ }
// If our preset wants us to support a codec that the track does not support, instead
// of changing the codec we remove the audio instead.
diff --git a/test/test.c b/test/test.c
index ec16e700d..a82327990 100644
--- a/test/test.c
+++ b/test/test.c
@@ -2925,7 +2925,7 @@ static void ShowHelp()
fprintf(out,
" Separated by commas for more than one audio track.\n"
" Default: up to %s for ffac3 and ffflac,\n",
- hb_mixdown_get_short_name_from_mixdown(HB_AMIXDOWN_6CH));
+ hb_mixdown_get_short_name_from_mixdown(HB_AMIXDOWN_5POINT1));
fprintf(out,
" up to %s for other encoders).\n",
hb_mixdown_get_short_name_from_mixdown(HB_AMIXDOWN_DOLBYPLII));