diff options
-rw-r--r-- | contrib/faac/A00-bitrates.patch | 6 | ||||
-rw-r--r-- | contrib/faac/A01-multichannel-improvements.patch | 752 | ||||
-rw-r--r-- | contrib/faac/P00-cygwin.patch | 6 | ||||
-rw-r--r-- | gtk/src/audiohandler.c | 6 | ||||
-rw-r--r-- | gtk/src/audiohandler.h | 1 | ||||
-rw-r--r-- | gtk/src/hb-backend.c | 89 | ||||
-rw-r--r-- | gtk/src/presets.c | 39 | ||||
-rw-r--r-- | libhb/audio_resample.c | 39 | ||||
-rw-r--r-- | libhb/audio_resample.h | 3 | ||||
-rw-r--r-- | libhb/common.c | 815 | ||||
-rw-r--r-- | libhb/common.h | 12 | ||||
-rw-r--r-- | libhb/encfaac.c | 67 | ||||
-rw-r--r-- | libhb/encvorbis.c | 12 | ||||
-rw-r--r-- | libhb/hb.c | 20 | ||||
-rw-r--r-- | libhb/muxmp4.c | 6 | ||||
-rw-r--r-- | libhb/work.c | 76 | ||||
-rw-r--r-- | macosx/HBAudio.m | 20 | ||||
-rw-r--r-- | macosx/HBAudioController.m | 12 | ||||
-rw-r--r-- | test/test.c | 2 |
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)); |