]> granicus.if.org Git - handbrake/commitdiff
Audio improvements.
authorRodeo <tdskywalker@gmail.com>
Mon, 3 Sep 2012 12:37:16 +0000 (12:37 +0000)
committerRodeo <tdskywalker@gmail.com>
Mon, 3 Sep 2012 12:37:16 +0000 (12:37 +0000)
New supported samplerates: 8, 11.025, 12, 16 kHz.
Now 8, 11.025, 12, 16, 22.05, 24, 42, 44.1, 48 Khz are supported.
Unsupported samplerates are sanitized to the closest samplerate for all encoders.

Samplerates < 32 kHz are now forbidden for AC3 encoding (sanitized to 32 kHz). Most AC3 decoders don't support such samplerates.

New upmixing: 3.0 (Front Left, Right & Center) can now be upmixed to 5.1 to preserve the center channel.

New mixdowns:

6.1 (Front Left, Right & Center, Surround Left, Right & Center, LFE)
7.1 (Front Left, Right & Center, Surround Left & Right, Rear Left & Right, LFE)
-> available to Vorbis & FLAC encoders for compatible input channel layouts
7.1 (Front Left, Right & Center, Front Left & Right of Center, Surround Left & Right, LFE)
-> available to AAC encoders (ca_aac, ca_haac, faac) for compatible input channel layouts

Mono (Left  Only): Stereo to Mono by discarding the Right channel
Mono (Right Only): Stereo to Mono by discarding the Left  channel
-> available to all encoders for non-Dolby Stereo input

The "6-channel discrete" mixdown becomes "5.1 Channels".

New bitrates: 960 - 1536 Kbps.
This lets users work around poor audio quality in crappy encoders by throwing more bits at them.

Bitrate limits have been re-worked and re-tested for all encoders.

git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@4930 b64f7644-9d1e-0410-96f1-a4d463321fa5

19 files changed:
contrib/faac/A00-bitrates.patch
contrib/faac/A01-multichannel-improvements.patch [new file with mode: 0644]
contrib/faac/P00-cygwin.patch
gtk/src/audiohandler.c
gtk/src/audiohandler.h
gtk/src/hb-backend.c
gtk/src/presets.c
libhb/audio_resample.c
libhb/audio_resample.h
libhb/common.c
libhb/common.h
libhb/encfaac.c
libhb/encvorbis.c
libhb/hb.c
libhb/muxmp4.c
libhb/work.c
macosx/HBAudio.m
macosx/HBAudioController.m
test/test.c

index 50b11ec78ea67f7be94027de6779d50d7f6cebbd..49460768ebf565b558ea3cefbdffe7bc25771b0a 100644 (file)
@@ -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 (file)
index 0000000..d0ec5ce
--- /dev/null
@@ -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++) 
index a5da42d879543aacc9ddc1a3ef24ed1010205dc5..bef1521398f25d74060b73e51825a4fdbde69010 100644 (file)
@@ -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;
  
index f2940bb815ec269bd9f36c5745584eeb687c1f76..95b9ba166a55590aaae2976c52a01cd312c8c1b1 100644 (file)
@@ -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);
 }
index 0a3f98c3f0bd4cf3bdd01fb1c20a65d6b53776fd..7bd300cc5f0f9c935b580a11d79fafb474deeeec 100644 (file)
@@ -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 );
index f5746e9f92d32b3cfb1c324b419c7a1e68c6dd9c..f2638bf73c70f6cdd4823c3991f3ed59abb1e53f 100644 (file)
@@ -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)
                {
index 809ede24e864ab7dd67f151c511b4ec2daf604d3..eeacbde044408a894593225c12fdefbc08fb8e34 100644 (file)
@@ -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)
        {
index 44f2a0144d89cbc52dc7121db883253ed3ae2702..ce80bc5fe1d8be192d519af61b9de94facdbeeb2 100644 (file)
@@ -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;
 }
index 3a01d8696dc23eaf09127db953bd3d0b99549a41..baee471a62b701382d43ccb315d4a9187c2a9e9d 100644 (file)
@@ -28,6 +28,9 @@
 typedef struct
 {
     int do_remix;
+    int dual_mono_downmix;
+    int dual_mono_right_only;
+
     int resample_needed;
     AVAudioResampleContext *avresample;
 
index 6315498cc5bb73871ee46212660c00949266730b..821f17e76cb90df1452d3dbf7d98c40df94af95d 100644 (file)
  * 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
  **********************************************************************
index 1650f8002a96b9dd6f854b3f9609de22c7343964..77898cef3673687013bdd6d196d732f5141938ff 100644 (file)
@@ -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 */
index 675881e8e70b45c854cc6dcdb682884c45f225b9..c6a3f8a16bf1cb9b5e5d30814dded784d591d0c2 100644 (file)
@@ -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 */
index a5325ef6d3ff8f84a1a6f9f13ab30d06a75a0038..4bd36b43aedac387cc39796d4e2de9597ea2d6c1 100644 (file)
@@ -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))
index ed074f93d806c8f7a52060cf48b4c40113f50531..12377a8b584cdd1fd576a14761d0dc057cbb2384 100644 (file)
@@ -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)
index 2203193a1c27eb495199be2c32a0bec29f953525..d21e4b7678c650302238068a40cf1c9d74436ac4 100644 (file)
@@ -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;
index 141ec4b3bae8a53749c426e45b23c4dcdd6b798c..9dffb5f4646e530a4ce441d8183e47bc24a40b26 100644 (file)
@@ -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);
                     }
index 8a5f06291d8001fda047b22b5a4df3834c98ddf6..fdd7b546296f724ecbfdf2aa5b6ff2d669a7d588 100644 (file)
@@ -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];
         }
index 235e39f438a5bc732be4206ab09a4570b7d1fb73..b9b80bd53b399851f1832f40600b4ace825604ea 100644 (file)
@@ -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.
index ec16e700d7e77dab3ab0a649f8bbdfcb10fe1c6f..a8232799004952fb200a0f63f9b75d8a2dd3cd92 100644 (file)
@@ -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));