All pastes #955308 Raw Edit

saintdev audio patch to svn 1318

public diff v1 · immutable
#955308 ·published 2008-03-24 15:14 UTC
rendered paste body
Index: test/test.c===================================================================--- test/test.c	(revision 1318)+++ test/test.c	(working copy)@@ -37,22 +37,27 @@ static int    vcodec      = HB_VCODEC_FFMPEG; static int    h264_13     = 0; static int    h264_30     = 0;-static char * audios      = NULL;-static int    audio_mixdown = HB_AMIXDOWN_DOLBYPLII;-static float  dynamic_range_compression = 0;+static hb_list_t * audios = NULL;+static hb_audio_t * audio = NULL;+static int    num_audio_tracks = 0;+static char * mixdowns    = NULL;+static char * dynamic_range_compression = NULL;+static char * arates      = NULL;+static char * abitrates   = NULL;+static char * acodecs     = NULL;+static int    default_acodec = HB_ACODEC_FAAC;+static int    default_arate = 44100;+static int    default_abitrate = 128; static int    sub         = 0; static int    width       = 0; static int    height      = 0; static int    crop[4]     = { -1,-1,-1,-1 }; static int    cpu         = 0; static int    vrate       = 0;-static int    arate       = 0; static float  vquality    = -1.0; static int    vbitrate    = 0; static int    size        = 0;-static int    abitrate    = 0; static int    mux         = 0;-static int    acodec      = 0; static int    pixelratio  = 0; static int    loosePixelratio = 0; static int    modulus       = 0;@@ -87,6 +92,9 @@ static int  CheckOptions( int argc, char ** argv ); static int  HandleEvents( hb_handle_t * h ); +static int get_acodec_for_string( char *codec );+static int is_sample_rate_valid(int rate);+ /* Only print the "Muxing..." message once */ static int show_mux_warning = 1; @@ -107,6 +115,8 @@     int           build;     char        * version; +    audios = hb_list_init();+     /* Parse command line */     if( ParseOptions( argc, argv ) ||         CheckOptions( argc, argv ) )@@ -230,7 +240,20 @@     if( input )  free( input );     if( output ) free( output );     if( format ) free( format );-    if( audios ) free( audios );+    if( audios )+    {+        while( ( audio = hb_list_item( audios, 0 ) ) )+        {+            hb_list_rem( audios, audio );+            free( audio );+        }+        hb_list_close( &audios );+    }+    if( mixdowns ) free( mixdowns );+    if( dynamic_range_compression ) free( dynamic_range_compression );+    if( arates ) free( arates );+    if( abitrates ) free( abitrates );+    if( acodecs ) free( acodecs );     if (native_language ) free (native_language ); 	if( x264opts ) free (x264opts ); 	if( x264opts2 ) free (x264opts2 );@@ -283,14 +306,14 @@     for( i = 0; i < hb_list_count( title->list_audio ); i++ )     {         audio = hb_list_item( title->list_audio, i );-        if( ( audio->codec & HB_ACODEC_AC3 ) || ( audio->codec & HB_ACODEC_DCA) )+        if( ( audio->in.codec == HB_ACODEC_AC3 ) || ( audio->in.codec == HB_ACODEC_DCA) )         {             fprintf( stderr, "    + %d, %s, %dHz, %dbps\n", i + 1,-                     audio->lang, audio->rate, audio->bitrate );+                     audio->lang.description, audio->in.samplerate, audio->in.bitrate );         }         else         {-            fprintf( stderr, "    + %d, %s\n", i + 1, audio->lang );+            fprintf( stderr, "    + %d, %s\n", i + 1, audio->lang.description );         }     }     fprintf( stderr, "  + subtitle tracks:\n" );@@ -327,7 +350,16 @@             hb_list_t  * list;             hb_title_t * title;             hb_job_t   * job;+            int i; +            /* Audio argument string parsing variables */+            int acodec = 0;+            int abitrate = 0;+            int arate = 0;+            int mixdown = HB_AMIXDOWN_DOLBYPLII;+            double d_r_c = 0;+            /* Audio argument string parsing variables */+             list = hb_get_titles( h );              if( !hb_list_count( list ) )@@ -412,9 +444,9 @@                     mux = HB_MUX_MKV;                     vcodec = HB_VCODEC_X264;                     job->vbitrate = 1000;-                    job->abitrate = 160;-                    job->arate = 48000;-                    acodec = HB_ACODEC_FAAC;+                    default_abitrate = 160;+                    default_arate = 48000;+                    default_acodec = HB_ACODEC_FAAC;                     x264opts = strdup("ref=5:mixed-refs:bframes=6:bime:weightb:b-rdo:direct=auto:b-pyramid:me=umh:subme=5:analyse=all:8x8dct:trellis=1:nr=150:no-fast-pskip:filter=2,2");                     deinterlace = 1;                     deinterlace_opt = "0";@@ -426,15 +458,26 @@                  if (!strcmp(preset_name, "AppleTV"))                 {+                    if (hb_list_count(audios) == 0)+                    {+                        audio = hb_audio_new();+                        audio->in.track = audio->out.track = 0;+                        hb_list_add(audios, audio);++                        audio = hb_audio_new();+                        audio->in.track = 0;+                        audio->out.track = 1;+                        hb_list_add(audios, audio);+                        if (acodecs) free(acodecs);+                        acodecs = strdup("faac,ac3");+                    }                     mux = HB_MUX_MP4;                     job->largeFileSize = 1;                     vcodec = HB_VCODEC_X264;                     job->vbitrate = 2500;-                    job->abitrate = 160;-                    job->arate = 48000;-                    acodec = HB_ACODEC_FAAC;-                    audio_mixdown = HB_AMIXDOWN_DOLBYPLII_AC3;-                    arate = 48000;+                    default_abitrate = 160;+                    default_arate = 48000;+                    default_acodec = HB_ACODEC_FAAC;                     x264opts = strdup("bframes=3:ref=1:subme=5:me=umh:no-fast-pskip=1:trellis=1:cabac=0");                     job->chapter_markers = 1;                     pixelratio = 1;@@ -445,7 +488,7 @@                     mux = HB_MUX_MKV;                     vcodec = HB_VCODEC_X264;                     job->vbitrate = 1800;-                    acodec = HB_ACODEC_AC3;+                    default_acodec = HB_ACODEC_AC3;                     x264opts = strdup("ref=16:mixed-refs:bframes=16:bime:weightb:b-rdo:direct=auto:b-pyramid:me=esa:subme=7:me-range=64:analyse=all:8x8dct:trellis=1:no-fast-pskip:no-dct-decimate:filter=-2,-1");                     job->chapter_markers = 1;                     pixelratio = 1;@@ -457,9 +500,9 @@                 {                     mux = HB_MUX_MP4;                     job->vbitrate = 512;-                    job->abitrate = 128;-                    job->arate = 48000;-                    acodec = HB_ACODEC_FAAC;+                    default_abitrate = 128;+                    default_arate = 48000;+                    default_acodec = HB_ACODEC_FAAC;                     job->width = 512;                     job->chapter_markers = 1;                 }@@ -469,9 +512,9 @@                     mux = HB_MUX_MP4;                     vcodec = HB_VCODEC_X264;                     size = 695;-                    job->abitrate = 128;-                    job->arate = 48000;-                    acodec = HB_ACODEC_FAAC;+                    default_abitrate = 128;+                    default_arate = 48000;+                    default_acodec = HB_ACODEC_FAAC;                     job->width = 640;                     x264opts = strdup("ref=3:mixed-refs:bframes=16:bime:weightb:b-rdo:b-pyramid:direct=auto:me=umh:subme=6:trellis=1:analyse=all:8x8dct:no-fast-pskip");                     job->chapter_markers = 1;@@ -483,9 +526,9 @@                 {                     mux = HB_MUX_MP4;                     job->vbitrate = 1000;-                    job->abitrate = 160;-                    job->arate = 48000;-                    acodec = HB_ACODEC_FAAC;+                    default_abitrate = 160;+                    default_arate = 48000;+                    default_acodec = HB_ACODEC_FAAC;                 }                  if (!strcmp(preset_name, "Constant Quality Rate"))@@ -494,7 +537,7 @@                     vcodec = HB_VCODEC_X264;                     job->vquality = 0.64709997177124023;                     job->crf = 1;-                    acodec = HB_ACODEC_AC3;+                    default_acodec = HB_ACODEC_AC3;                     x264opts = strdup("ref=3:mixed-refs:bframes=3:b-pyramid:b-rdo:bime:weightb:filter=-2,-1:subme=6:trellis=1:analyse=all:8x8dct:me=umh");                     job->chapter_markers = 1;                     pixelratio = 1;@@ -505,7 +548,7 @@                     mux = HB_MUX_MKV;                     vcodec = HB_VCODEC_X264;                     job->vbitrate = 1600;-                    acodec = HB_ACODEC_AC3;+                    default_acodec = HB_ACODEC_AC3;                     x264opts = strdup("ref=5:mixed-refs:bframes=3:bime:weightb:b-rdo:b-pyramid:me=umh:subme=7:trellis=1:analyse=all:8x8dct:no-fast-pskip");                     job->chapter_markers = 1;                     pixelratio = 1;@@ -518,7 +561,7 @@                     mux = HB_MUX_MKV;                     vcodec = HB_VCODEC_X264;                     job->vbitrate = 1800;-                    acodec = HB_ACODEC_AC3;+                    default_acodec = HB_ACODEC_AC3;                     x264opts = strdup("ref=3:mixed-refs:bframes=6:bime:weightb:b-rdo:direct=auto:b-pyramid:me=umh:subme=7:analyse=all:8x8dct:trellis=1:no-fast-pskip");                     job->chapter_markers = 1;                     pixelratio = 1;@@ -532,9 +575,9 @@                     job->ipod_atom = 1;                     vcodec = HB_VCODEC_X264;                     job->vbitrate = 960;-                    job->abitrate = 128;-                    job->arate = 48000;-                    acodec = HB_ACODEC_FAAC;+                    default_abitrate = 128;+                    default_arate = 48000;+                    default_acodec = HB_ACODEC_FAAC;                     job->width = 480;                     x264opts = strdup("level=30:cabac=0:ref=1:analyse=all:me=umh:subme=6:no-fast-pskip=1:trellis=1");                     job->chapter_markers = 1;@@ -546,9 +589,9 @@                     job->ipod_atom = 1;                     vcodec = HB_VCODEC_X264;                     job->vbitrate = 1500;-                    job->abitrate = 160;-                    job->arate = 48000;-                    acodec = HB_ACODEC_FAAC;+                    default_abitrate = 160;+                    default_arate = 48000;+                    default_acodec = HB_ACODEC_FAAC;                     job->width = 640;                     x264opts = strdup("level=30:bframes=0:cabac=0:ref=1:vbv-maxrate=1500:vbv-bufsize=2000:analyse=all:me=umh:subme=6:no-fast-pskip=1");                     job->chapter_markers = 1;@@ -560,9 +603,9 @@                     job->ipod_atom = 1;                     vcodec = HB_VCODEC_X264;                     job->vbitrate = 700;-                    job->abitrate = 160;-                    job->arate = 48000;-                    acodec = HB_ACODEC_FAAC;+                    default_abitrate = 160;+                    default_arate = 48000;+                    default_acodec = HB_ACODEC_FAAC;                     job->width = 320;                     x264opts = strdup("level=30:bframes=0:cabac=0:ref=1:vbv-maxrate=768:vbv-bufsize=2000:analyse=all:me=umh:subme=6:no-fast-pskip=1");                     job->chapter_markers = 1;@@ -573,9 +616,9 @@                     mux = HB_MUX_MP4;                     vcodec = HB_VCODEC_X264;                     job->vbitrate = 1500;-                    job->abitrate = 160;-                    job->arate = 48000;-                    acodec = HB_ACODEC_FAAC;+                    default_abitrate = 160;+                    default_arate = 48000;+                    default_acodec = HB_ACODEC_FAAC;                     x264opts = strdup("ref=2:bframes=2:subme=5:me=umh");                     job->chapter_markers = 1;                     pixelratio = 1;@@ -588,9 +631,9 @@                     mux = HB_MUX_MP4;                     vcodec = HB_VCODEC_X264;                     job->vbitrate = 2500;-                    job->abitrate = 160;-                    job->arate = 48000;-                    acodec = HB_ACODEC_FAAC;+                    default_abitrate = 160;+                    default_arate = 48000;+                    default_acodec = HB_ACODEC_FAAC;                     x264opts = strdup("level=41:subme=5:me=umh");                     pixelratio = 1;                 }@@ -599,9 +642,9 @@                 {                     mux = HB_MUX_MP4;                     job->vbitrate = 1024;-                    job->abitrate = 128;-                    job->arate = 48000;-                    acodec = HB_ACODEC_FAAC;+                    default_abitrate = 128;+                    default_arate = 48000;+                    default_acodec = HB_ACODEC_FAAC;                     job->width = 368;                     job->height = 208;                     job->chapter_markers = 1;@@ -612,9 +655,9 @@                     mux = HB_MUX_MP4;                     vcodec = HB_VCODEC_X264;                     job->vbitrate = 2000;-                    job->abitrate = 160;-                    job->arate = 48000;-                    acodec = HB_ACODEC_FAAC;+                    default_abitrate = 160;+                    default_arate = 48000;+                    default_acodec = HB_ACODEC_FAAC;                     x264opts = strdup("ref=3:mixed-refs:bframes=3:bime:weightb:b-rdo:direct=auto:me=umh:subme=5:analyse=all:trellis=1:no-fast-pskip");                     job->chapter_markers = 1;                     pixelratio = 1;@@ -627,9 +670,9 @@                     mux = HB_MUX_MKV;                     vcodec = HB_VCODEC_X264;                     job->vbitrate = 1300;-                    job->abitrate = 160;-                    job->arate = 48000;-                    acodec = HB_ACODEC_FAAC;+                    default_abitrate = 160;+                    default_arate = 48000;+                    default_acodec = HB_ACODEC_FAAC;                     x264opts = strdup("ref=3:mixed-refs:bframes=6:bime:weightb:direct=auto:b-pyramid:me=umh:subme=6:analyse=all:8x8dct:trellis=1:nr=150:no-fast-pskip");                     deinterlace = 1;                     deinterlace_opt = "0";@@ -645,9 +688,9 @@                     mux = HB_MUX_MP4;                     vcodec = HB_VCODEC_X264;                     job->vbitrate = 2000;-                    job->abitrate = 160;-                    job->arate = 48000;-                    acodec = HB_ACODEC_FAAC;+                    default_abitrate = 160;+                    default_arate = 48000;+                    default_acodec = HB_ACODEC_FAAC;                     x264opts = strdup("level=40:ref=2:mixed-refs:bframes=3:bime:weightb:b-rdo:direct=auto:b-pyramid:me=umh:subme=5:analyse=all:no-fast-pskip:filter=-2,-1");                     pixelratio = 1;                 }@@ -802,74 +845,230 @@                 job->vrate = 27000000;                 job->vrate_base = vrate;             }-            if( arate )++            /* Parse audio tracks */+            /* First audio struct is already on the list */+            audio = hb_list_item(job->list_audio, 0);+            if( hb_list_count(audios) == 0 )             {-                job->arate = arate;+                /* Add it to our audios */+                hb_list_add(audios, audio);             }+            /* Get rid of it! */+            hb_list_rem(job->list_audio, audio);+            num_audio_tracks = hb_list_count(audios); -            if( audios )+            for (i = 0; i < num_audio_tracks; i++)             {-                if( strcasecmp( audios, "none" ) )+                audio = hb_list_item(audios, i);+                if ( (audio->in.track == -1) || (audio->out.track == -1) ||+                     (audio->out.codec == HB_ACODEC_NONE) )                 {-                    int    audio_count = 0;-                    char * tmp         = audios;-                    while( *tmp )+                    num_audio_tracks--;+                    hb_list_rem(audios, audio);+                    free(audio);+                    continue;+                }+                hb_list_add(job->list_audio, hb_audio_copy( hb_list_item( title->list_audio, audio->in.track ) ) );+            }+            /* Audio Tracks */++            /* Audio Codecs */+            i = 0;+            if( acodecs )+            {+                char * token = strtok(acodecs, ",");+                if (token == NULL)+                    token = acodecs;+                while ( token != NULL )+                {+                    if ((acodec = get_acodec_for_string(token)) == -1)                     {-                        if( *tmp < '0' || *tmp > '9' )+                        fprintf(stderr, "Invalid codec %s, using default for container.\n", token);+                        acodec = default_acodec;+                    }+                    audio = hb_list_item(job->list_audio, i);+                    audio->out.codec = acodec;+                    if( (++i) >= num_audio_tracks )+                        break;  /* We have more inputs than audio tracks, oops */+                    token = strtok(NULL, ",");+                }+            }+            if (i < num_audio_tracks)+            {+                /* We have fewer inputs than audio tracks, use the default codec for+                 * this container for the remaining tracks. Unless we only have one input+                 * then use that codec instead.+                 */+                if (i != 1)+                    acodec = default_acodec;+                for ( ; i < num_audio_tracks; i++)+                {+                    audio = hb_list_item(job->list_audio, i);+                    audio->out.codec = acodec;+                }+            }+            /* Audio Codecs */++            /* Sample Rate */+            i = 0;+            if( arates )+            {+                char * token = strtok(arates, ",");+                if (token == NULL)+                    token = arates;+                while ( token != NULL )+                {+                    arate = atoi(token);+                    audio = hb_list_item(job->list_audio, i);+                    if (audio->out.codec == HB_ACODEC_AC3 || audio->out.codec == HB_ACODEC_DCA)+                    {+                        /* Would probably be better to have this handled in libhb. */+                        audio->out.samplerate = audio->in.samplerate;+                    }+                    else+                    {+                        if (!is_sample_rate_valid(arate))                         {-                            /* Skip non numeric char */-                            tmp++;-                            continue;+                            fprintf(stderr, "Invalid sample rate %d, using default\n", arate);+                            arate = default_arate;                         }-						job->audio_mixdowns[audio_count] = audio_mixdown;-                        job->audios[audio_count++] =-                            strtol( tmp, &tmp, 0 ) - 1;+                        audio->out.samplerate = arate;                     }-                    job->audios[audio_count] = -1;+                    if( (++i) >= num_audio_tracks )+                        break;  /* We have more inputs than audio tracks, oops */+                    token = strtok(NULL, ",");                 }-                else+            }+            if (i < num_audio_tracks)+            {+                /* We have fewer inputs than audio tracks, use default sample rate.+                 * Unless we only have one input, then use that for all tracks.+                 */+                if (i != 1)+                    arate = default_arate;+                for ( ; i < num_audio_tracks; i++)                 {-                    job->audios[0] = -1;+                    audio = hb_list_item(job->list_audio, i);+                    if (audio->out.codec == HB_ACODEC_AC3 || audio->out.codec == HB_ACODEC_DCA)+                    {+                        audio->out.samplerate = audio->in.samplerate;+                        continue;+                    }+                    audio->out.samplerate = arate;                 }             }-			else-			{-			    /* default to the first audio track if none has been specified */-			    job->audios[0] = 0;-			    job->audio_mixdowns[0] = audio_mixdown;-			}+            /* Sample Rate */ -			if( audio_mixdown == HB_AMIXDOWN_DOLBYPLII_AC3)-			{-               int i;-               for( i = 3 ; i > 0; i--)-               {-                   job->audios[i*2+1] = job->audios[i];-                   job->audios[i*2] = job->audios[i];-                   if(job->audios[i] != -1  )-                   {-                       job->audio_mixdowns[i*2+1] = HB_AMIXDOWN_AC3;-                       job->audio_mixdowns[i*2] = HB_AMIXDOWN_DOLBYPLII;-                   }-               }--               job->audios[1] = job->audios[0];-               job->audio_mixdowns[1] = HB_AMIXDOWN_AC3;-               job->audio_mixdowns[0] = HB_AMIXDOWN_DOLBYPLII;+            /* Audio Bitrate */+            i = 0;+            if( abitrates )+            {+                char * token = strtok(abitrates, ",");+                if (token == NULL)+                    token = abitrates;+                while ( token != NULL )+                {+                    abitrate = atoi(token);+                    audio = hb_list_item(job->list_audio, i);+                    if (audio->out.codec == HB_ACODEC_AC3 || audio->out.codec == HB_ACODEC_DCA)+                    {+                        audio->out.bitrate = audio->in.bitrate;   /* See note above about arate. */+                    }+                    else+                    {+                        audio->out.bitrate = abitrate;+                    }+                    if( (++i) >= num_audio_tracks )+                        break;  /* We have more inputs than audio tracks, oops */+                    token = strtok(NULL, ",");+                }             }+            if (i < num_audio_tracks)+            {+                /* We have fewer inputs than audio tracks, use the default bitrate+                 * for the remaining tracks. Unless we only have one input, then use+                 * that for all tracks.+                 */+                if (i != 1)+                    abitrate = default_abitrate;+                for (; i < num_audio_tracks; i++)+                {+                    audio = hb_list_item(job->list_audio, i);+                    if (audio->out.codec == HB_ACODEC_AC3 || audio->out.codec == HB_ACODEC_DCA)+                    {+                        audio->out.bitrate = audio->in.bitrate;+                        continue;+                    }+                    audio->out.bitrate = abitrate;+                }+            }+            /* Audio Bitrate */ -            if( abitrate )+            /* Audio DRC */+            i = 0;+            if ( dynamic_range_compression )             {-                job->abitrate = abitrate;+                char * token = strtok(dynamic_range_compression, ",");+                if (token == NULL)+                    token = dynamic_range_compression;+                while ( token != NULL )+                {+                    d_r_c = atof(token);+                    audio = hb_list_item(job->list_audio, i);+                    audio->out.dynamic_range_compression = d_r_c;+                    if( (++i) >= num_audio_tracks )+                        break;  /* We have more inputs than audio tracks, oops */+                    token = strtok(NULL, ",");+                }             }-            if( acodec )+            if (i < num_audio_tracks)             {-                job->acodec = acodec;+                /* We have fewer inputs than audio tracks, use no DRC for the remaining+                 * tracks. Unless we only have one input, then use the same DRC for all+                 * tracks.+                 */+                if (i != 1)+                    d_r_c = 0;+                for (; i < num_audio_tracks; i++)+                {+                    audio = hb_list_item(job->list_audio, i);+                    audio->out.dynamic_range_compression = d_r_c;+                }             }-            if ( dynamic_range_compression )+            /* Audio DRC */++            /* Audio Mixdown */+            i = 0;+            if ( mixdowns )             {-                job->dynamic_range_compression = dynamic_range_compression;+                char * token = strtok(mixdowns, ",");+                if (token == NULL)+                    token = mixdowns;+                while ( token != NULL )+                {+                    mixdown = hb_mixdown_get_mixdown_from_short_name(token);+                    audio = hb_list_item(job->list_audio, i);+                    audio->out.mixdown = mixdown;+                    if( (++i) >= num_audio_tracks )+                        break;  /* We have more inputs than audio tracks, oops */+                    token = strtok(NULL, ",");+                }             }+            if (i < num_audio_tracks)+            {+                /* We have fewer inputs than audio tracks, use DPLII for the rest. Unless+                 * we only have one input, then use that.+                 */+                if (i != 1)+                    mixdown = HB_AMIXDOWN_DOLBYPLII;+                for (; i < num_audio_tracks; i++)+                {+                   audio = hb_list_item(job->list_audio, i);+                   audio->out.mixdown = mixdown;+                }+            }+            /* Audio Mixdown */              if( size )             {@@ -1216,18 +1415,21 @@   	"### Audio Options-----------------------------------------------------------\n\n"-	"    -E, --aencoder <string> Audio encoder (faac/lame/vorbis/ac3/aac+ac3) \n"-	"                            ac3 meaning passthrough, aac+ac3 meaning an\n"-	"                            aac dpl2 mixdown paired with ac3 pass-thru\n"+	"    -a, --audio <string>    Select audio channel(s), separated by commas\n"+    "                            More than one output track can be used for one\n"+    "                            input.\n"+    "                            (\"none\" for no audio, \"1,2,3\" for multiple\n"+    "                             tracks, default: first one)\n"+    "    -E, --aencoder <string> Audio encoder(s) (faac/lame/vorbis/ac3) \n"+	"                            ac3 meaning passthrough\n"+	"                            Seperated by commas for more than one audio track.\n" 	"                            (default: guessed)\n"-	"    -B, --ab <kb/s>         Set audio bitrate (default: 128)\n"-	"    -a, --audio <string>    Select audio channel(s), separated by commas\n"-	"                            (\"none\" for no audio, \"1,2,3\" for multiple\n"-	"                             tracks, default: first one,\n"-	"                             max 8 normally, max 4 with aac+ac3)\n"-    "    -6, --mixdown <string>  Format for surround sound downmixing\n"+	"    -B, --ab <kb/s>         Set audio bitrate(s)  (default: 128)\n"+    "                            Seperated by commas for more than one audio track.\n"+	"    -6, --mixdown <string>  Format(s) for surround sound downmixing\n"+    "                            Seperated by commas for more than one audio track.\n"     "                            (mono/stereo/dpl1/dpl2/6ch, default: dpl2)\n"-    "    -R, --arate             Set audio samplerate (" );+    "    -R, --arate             Set audio samplerate(s) (" );     for( i = 0; i < hb_audio_rates_count; i++ )     {         fprintf( stderr, hb_audio_rates[i].string );@@ -1235,9 +1437,11 @@             fprintf( stderr, "/" );     }     fprintf( stderr, " kHz)\n"+    "                            Seperated by commas for more than one audio track.\n"     "    -D, --drc <float>       Apply extra dynamic range compression to the audio,\n"     "                            making soft sounds louder. Range is 1.0 to 4.0\n"     "                            (too loud), with 1.5 - 2.5 being a useful range.\n"+    "                            Seperated by commas for more than one audio track.\n"   	"\n"@@ -1450,33 +1654,64 @@                 chapter_markers = 1;                 break;             case 'a':-                audios = strdup( optarg );+            {+                char * token = strtok(optarg, ",");+                if (token == NULL)+                    token = optarg;+                int track_start, track_end;+                while( token != NULL )+                {+                    audio = hb_audio_new();+                    if (strlen(token) >= 3)+                    {+                        if (sscanf(token, "%d-%d", &track_start, &track_end) == 2)+                        {+                            int i;+                            for (i = track_start - 1; i < track_end; i++)+                            {+                                if (i != track_start - 1)+                                    audio = hb_audio_new();+                                audio->in.track = i;+                                audio->out.track = num_audio_tracks++;+                                hb_list_add(audios, audio);+                            }+                        }+                        else if( !strcasecmp(token, "none" ) )+                        {+                            audio->in.track = audio->out.track = -1;+                            audio->out.codec = HB_ACODEC_NONE;+                            hb_list_add(audios, audio);+                            break;+                        }+                        else+                        {+                            fprintf(stderr, "ERROR: Unable to parse audio input \"%s\", skipping.",+                                    token);+                            free(audio);+                        }+                    }+                    else+                    {+                        audio->in.track = atoi(token) - 1;+                        audio->out.track = num_audio_tracks++;+                        hb_list_add(audios, audio);+                    }+                    token = strtok(NULL, ",");+                }                 break;+            }             case '6':-                if( !strcasecmp( optarg, "mono" ) )+                if( optarg != NULL )                 {-                    audio_mixdown = HB_AMIXDOWN_MONO;+                    mixdowns = strdup( optarg );                 }-                else if( !strcasecmp( optarg, "stereo" ) )+                break;+            case 'D':+                if( optarg != NULL )                 {-                    audio_mixdown = HB_AMIXDOWN_STEREO;+                    dynamic_range_compression = strdup( optarg );                 }-                else if( !strcasecmp( optarg, "dpl1" ) )-                {-                    audio_mixdown = HB_AMIXDOWN_DOLBY;-                }-                else if( !strcasecmp( optarg, "dpl2" ) )-                {-                    audio_mixdown = HB_AMIXDOWN_DOLBYPLII;-                }-                else if( !strcasecmp( optarg, "6ch" ) )-                {-                    audio_mixdown = HB_AMIXDOWN_6CH;-                }                 break;-            case 'D':-                dynamic_range_compression = atof( optarg );-                break;             case 's':                 sub = atoi( optarg );                 break;@@ -1593,28 +1828,10 @@                 }                 break;             case 'E':-                if( !strcasecmp( optarg, "ac3" ) )+                if( optarg != NULL )                 {-                    acodec = HB_ACODEC_AC3;+                    acodecs = strdup( optarg );                 }-                else if( !strcasecmp( optarg, "lame" ) )-                {-                    acodec = HB_ACODEC_LAME;-                }-                else if( !strcasecmp( optarg, "faac" ) )-                {-                    acodec = HB_ACODEC_FAAC;-                }-                else if( !strcasecmp( optarg, "vorbis") )-                {-                    acodec = HB_ACODEC_VORBIS;-                }-                else if( !strcasecmp( optarg, "aac+ac3") )-                {-                    acodec = HB_ACODEC_FAAC;-                    audio_mixdown = HB_AMIXDOWN_DOLBYPLII_AC3;-                    arate = 48000;-                }                 break;             case 'w':                 width = atoi( optarg );@@ -1654,23 +1871,11 @@                 break;             }             case 'R':-            {-                int i;-                arate = 0;-                for( i = 0; i < hb_audio_rates_count; i++ )+                if( optarg != NULL )                 {-                    if( !strcmp( optarg, hb_audio_rates[i].string ) )-                    {-                        arate = hb_audio_rates[i].rate;-                        break;-                    }+                    arates = strdup( optarg );                 }-                if( !arate )-                {-                    fprintf( stderr, "invalid framerate %s\n", optarg );-                }                 break;-            }             case 'b':                 vbitrate = atoi( optarg );                 break;@@ -1681,7 +1886,10 @@                 size = atoi( optarg );                 break;             case 'B':-                abitrate = atoi( optarg );+                if( optarg != NULL )+                {+                    abitrates = strdup( optarg );+                }                 break;             case 'Q':                 crf = 0;@@ -1795,23 +2003,23 @@             return 1;         } -        if( !acodec )+        if( !acodecs )         {             if( mux == HB_MUX_MP4 || mux == HB_MUX_IPOD )             {-                acodec = HB_ACODEC_FAAC;+                default_acodec = HB_ACODEC_FAAC;             }             else if( mux == HB_MUX_AVI )             {-                acodec = HB_ACODEC_LAME;+                default_acodec = HB_ACODEC_LAME;             }             else if( mux == HB_MUX_OGM )             {-                acodec = HB_ACODEC_VORBIS;+                default_acodec = HB_ACODEC_VORBIS;             }             else if( mux == HB_MUX_MKV )             {-                acodec = HB_ACODEC_AC3;+                default_acodec = HB_ACODEC_AC3;             }         } @@ -1819,3 +2027,42 @@      return 0; }++static int get_acodec_for_string( char *codec )+{+    if( !strcasecmp( codec, "ac3" ) )+    {+        return HB_ACODEC_AC3;+    }+    else if( !strcasecmp( codec, "dts" ) || !strcasecmp( codec, "dca" ) )+    {+        return HB_ACODEC_DCA;+    }+    else if( !strcasecmp( codec, "lame" ) )+    {+        return HB_ACODEC_LAME;+    }+    else if( !strcasecmp( codec, "faac" ) )+    {+        return HB_ACODEC_FAAC;+    }+    else if( !strcasecmp( codec, "vorbis") )+    {+        return HB_ACODEC_VORBIS;+    }+    else+    {+        return -1;+    }+}++static int is_sample_rate_valid(int rate)+{+    int i;+    for( i = 0; i < hb_audio_rates_count; i++ )+    {+            if (rate == hb_audio_rates[i].rate)+                return 1;+    }+    return 0;+}Index: libhb/deca52.c===================================================================--- libhb/deca52.c	(revision 1318)+++ libhb/deca52.c	(working copy)@@ -88,6 +88,7 @@ int deca52Init( hb_work_object_t * w, hb_job_t * job ) {     hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );+    hb_audio_t * audio = w->audio;     w->private_data = pv;      pv->job   = job;@@ -98,14 +99,14 @@ 	/* Decide what format we want out of a52dec 	work.c has already done some of this deduction for us in do_job() */ -	pv->flags_out = HB_AMIXDOWN_GET_A52_FORMAT(w->amixdown);+	pv->flags_out = HB_AMIXDOWN_GET_A52_FORMAT(audio->out.mixdown);  	/* pass the number of channels used into the private work data */ 	/* will only be actually used if we're not doing AC3 passthru */-	pv->out_discrete_channels = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(w->amixdown);+    pv->out_discrete_channels = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->out.mixdown);      pv->level     = 32768.0;-    pv->dynamic_range_compression = job->dynamic_range_compression;+    pv->dynamic_range_compression = audio->out.dynamic_range_compression;      pv->next_expected_pts = 0;     pv->sequence = 0;@@ -168,6 +169,7 @@ {     hb_work_private_t * pv = w->private_data;     hb_buffer_t * buf;+    hb_audio_t  * audio = w->audio;     int           i, j, k;     uint64_t      pts, pos; @@ -215,8 +217,7 @@     hb_list_getbytes( pv->list, pv->frame, pv->size, &pts, &pos );      /* AC3 passthrough: don't decode the AC3 frame */-    if( pv->job->acodec & HB_ACODEC_AC3 ||-        w->amixdown == HB_AMIXDOWN_AC3 )+    if( audio->out.codec == HB_ACODEC_AC3 )     {         buf = hb_buffer_init( pv->size );         memcpy( buf->data, pv->frame, pv->size );Index: libhb/enclame.c===================================================================--- libhb/enclame.c	(revision 1318)+++ libhb/enclame.c	(working copy)@@ -39,6 +39,7 @@ int enclameInit( hb_work_object_t * w, hb_job_t * job ) {     hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );+    hb_audio_t * audio = w->audio;     w->private_data = pv;      pv->job   = job;@@ -46,9 +47,9 @@     hb_log( "enclame: opening libmp3lame" );      pv->lame = lame_init();-    lame_set_brate( pv->lame, job->abitrate );-    lame_set_in_samplerate( pv->lame, job->arate );-    lame_set_out_samplerate( pv->lame, job->arate );+    lame_set_brate( pv->lame, audio->out.bitrate );+    lame_set_in_samplerate( pv->lame, audio->out.samplerate );+    lame_set_out_samplerate( pv->lame, audio->out.samplerate );     lame_init_params( pv->lame );      pv->input_samples = 1152 * 2;@@ -85,6 +86,7 @@ static hb_buffer_t * Encode( hb_work_object_t * w ) {     hb_work_private_t * pv = w->private_data;+    hb_audio_t * audio = w->audio;     hb_buffer_t * buf;     int16_t samples_s16[1152 * 2];     uint64_t pts, pos;@@ -104,8 +106,8 @@     }      buf        = hb_buffer_init( pv->output_bytes );-    buf->start = pts + 90000 * pos / 2 / sizeof( float ) / pv->job->arate;-    buf->stop  = buf->start + 90000 * 1152 / pv->job->arate;+    buf->start = pts + 90000 * pos / 2 / sizeof( float ) / audio->out.samplerate;+    buf->stop  = buf->start + 90000 * 1152 / audio->out.samplerate;     buf->size  = lame_encode_buffer_interleaved( pv->lame, samples_s16,             1152, buf->data, LAME_MAXMP3BUFFER );     buf->frametype   = HB_FRAME_AUDIO;Index: libhb/muxavi.c===================================================================--- libhb/muxavi.c	(revision 1318)+++ libhb/muxavi.c	(working copy)@@ -281,7 +281,7 @@     hb_mux_data_t * mux_data;      int audio_count = hb_list_count( title->list_audio );-    int is_ac3      = ( job->acodec & HB_ACODEC_AC3 );+    int is_ac3      = 0;     int hdrl_bytes;     int i; @@ -346,6 +346,8 @@     {         audio = hb_list_item( title->list_audio, i ); +        is_ac3 = (audio->out.codec == HB_ACODEC_AC3);+         mux_data = calloc( sizeof( hb_mux_data_t ), 1 );         audio->mux_data = mux_data; @@ -358,8 +360,8 @@         h.Type          = FOURCC( "auds" );         h.InitialFrames = 1;         h.Scale         = 1;-        h.Rate          = is_ac3 ? ( audio->bitrate / 8 ) :-                                   ( job->abitrate * 1000 / 8 );+        h.Rate          = is_ac3 ? ( audio->in.bitrate / 8 ) :+                                   ( audio->out.bitrate * 1000 / 8 );         h.Quality       = 0xFFFFFFFF;         h.SampleSize    = 1; @@ -370,15 +372,15 @@             f.BytesCount     = sizeof( hb_wave_formatex_t ) - 8;             f.FormatTag      = 0x2000;             f.Channels       = HB_INPUT_CH_LAYOUT_GET_DISCRETE_COUNT(audio->input_channel_layout);-            f.SamplesPerSec  = audio->rate;+            f.SamplesPerSec  = audio->in.samplerate;         }         else         {             f.BytesCount     = sizeof( hb_wave_formatex_t ) +                                sizeof( hb_wave_mp3_t ) - 8;             f.FormatTag      = 0x55;-            f.Channels       = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(job->audio_mixdowns[i]);-            f.SamplesPerSec  = job->arate;+            f.Channels       = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->out.mixdown);+            f.SamplesPerSec  = audio->out.samplerate;         }         f.AvgBytesPerSec = h.Rate;         f.BlockAlign     = 1;@@ -391,7 +393,7 @@             f.Size           = sizeof( hb_wave_mp3_t );             m.Id             = 1;             m.Flags          = 2;-            m.BlockSize      = 1152 * f.AvgBytesPerSec / job->arate;+            m.BlockSize      = 1152 * f.AvgBytesPerSec / audio->out.samplerate;             m.FramesPerBlock = 1;             m.CodecDelay     = 1393;         }@@ -513,7 +515,7 @@     {         audio = hb_list_item( title->list_audio, i );         fseek( m->file, 264 + i *-               ( 102 + ( ( job->acodec & HB_ACODEC_AC3 ) ? 0 :+               ( 102 + ( ( audio->out.codec == HB_ACODEC_AC3 ) ? 0 :                  sizeof( hb_wave_mp3_t ) ) ), SEEK_SET );         WriteInt32( m->file, audio->mux_data->header.Length );     }Index: libhb/dvd.c===================================================================--- libhb/dvd.c	(revision 1318)+++ libhb/dvd.c	(working copy)@@ -251,28 +251,28 @@         {             case 0x00:                 audio->id    = ( ( 0x80 + position ) << 8 ) | 0xbd;-                audio->codec = HB_ACODEC_AC3;+                audio->in.codec = HB_ACODEC_AC3;                 break;              case 0x02:             case 0x03:                 audio->id    = 0xc0 + position;-                audio->codec = HB_ACODEC_MPGA;+                audio->in.codec = HB_ACODEC_MPGA;                 break;              case 0x04:                 audio->id    = ( ( 0xa0 + position ) << 8 ) | 0xbd;-                audio->codec = HB_ACODEC_LPCM;+                audio->in.codec = HB_ACODEC_LPCM;                 break;              case 0x06:                 audio->id    = ( ( 0x88 + position ) << 8 ) | 0xbd;-                audio->codec = HB_ACODEC_DCA;+                audio->in.codec = HB_ACODEC_DCA;                 break;              default:                 audio->id    = 0;-                audio->codec = 0;+                audio->in.codec = HB_ACODEC_NONE;                 hb_log( "scan: unknown audio codec (%x)",                         audio_format );                 break;@@ -302,18 +302,18 @@          lang = lang_for_code( vts->vtsi_mat->vts_audio_attr[i].lang_code ); -        snprintf( audio->lang, sizeof( audio->lang ), "%s (%s)",+        snprintf( audio->lang.description, sizeof( audio->lang.description ), "%s (%s)",             strlen(lang->native_name) ? lang->native_name : lang->eng_name,-            audio->codec == HB_ACODEC_AC3 ? "AC3" : ( audio->codec ==-                HB_ACODEC_DCA ? "DTS" : ( audio->codec ==+            audio->in.codec == HB_ACODEC_AC3 ? "AC3" : ( audio->in.codec ==+                HB_ACODEC_DCA ? "DTS" : ( audio->in.codec ==                 HB_ACODEC_MPGA ? "MPEG" : "LPCM" ) ) );-        snprintf( audio->lang_simple, sizeof( audio->lang_simple ), "%s",+        snprintf( audio->lang.simple, sizeof( audio->lang.simple ), "%s",                   strlen(lang->native_name) ? lang->native_name : lang->eng_name );-        snprintf( audio->iso639_2, sizeof( audio->iso639_2 ), "%s",+        snprintf( audio->lang.iso639_2, sizeof( audio->lang.iso639_2 ), "%s",                   lang->iso639_2);          hb_log( "scan: id=%x, lang=%s, 3cc=%s", audio->id,-                audio->lang, audio->iso639_2 );+                audio->lang.description, audio->lang.iso639_2 );          hb_list_add( title->list_audio, audio );     }Index: libhb/hb.c===================================================================--- libhb/hb.c	(revision 1318)+++ libhb/hb.c	(working copy)@@ -722,7 +722,7 @@     hb_job_t      * job_copy;     hb_title_t    * title,    * title_copy;     hb_chapter_t  * chapter,  * chapter_copy;-    hb_audio_t    * audio,    * audio_copy;+    hb_audio_t    * audio;     hb_subtitle_t * subtitle, * subtitle_copy;     int             i;     char            audio_lang[4];@@ -747,18 +747,12 @@     /* Do nothing about audio during first pass */     if( job->pass == 0 || job->pass == 2 )     {-        for( i = 0; i < 8; i++ )+        for( i = 0; i < hb_list_count(job->list_audio); i++ )         {-            if( job->audios[i] < 0 )+            if( ( audio = hb_list_item( job->list_audio, i ) ) )             {-                break;+                hb_list_add( title_copy->list_audio, hb_audio_copy(audio) );             }-            if( ( audio = hb_list_item( title->list_audio, job->audios[i] ) ) )-            {-                audio_copy = malloc( sizeof( hb_audio_t ) );-                memcpy( audio_copy, audio, sizeof( hb_audio_t ) );-                hb_list_add( title_copy->list_audio, audio_copy );-            }         }     } @@ -788,17 +782,13 @@         /*          * Find the first audio language that is being encoded          */-        for( i = 0; i < 8; i++ )+        for( i = 0; i < hb_list_count(job->list_audio); i++ )         {-            if( job->audios[i] < 0 )+            if( ( audio = hb_list_item( job->list_audio, i ) ) )             {+                strncpy(audio_lang, audio->lang.iso639_2, sizeof(audio_lang));                 break;             }-            if( ( audio = hb_list_item( title->list_audio, job->audios[i] ) ) )-            {-                strncpy(audio_lang, audio->iso639_2, sizeof(audio_lang));-                break;-            }         }          /*@@ -923,6 +913,7 @@     memcpy( job_copy, job, sizeof( hb_job_t ) );     title_copy->job = job_copy;     job_copy->title = title_copy;+    job_copy->list_audio = title_copy->list_audio;     job_copy->file  = strdup( job->file );     job_copy->h     = h;     job_copy->pause = h->pause_lock;Index: libhb/muxmp4.c===================================================================--- libhb/muxmp4.c	(revision 1318)+++ libhb/muxmp4.c	(working copy)@@ -27,6 +27,11 @@     MP4TrackId chapter_track;     int current_chapter;     uint64_t chapter_duration;++    /* Sample rate of the first audio track.+     * Used for the timescale+     */+    int samplerate; };  struct hb_mux_data_s@@ -137,6 +142,10 @@     /* Flags for enabling/disabling tracks in an MP4. */     typedef enum { TRACK_DISABLED = 0x0, TRACK_ENABLED = 0x1, TRACK_IN_MOVIE = 0x2, TRACK_IN_PREVIEW = 0x4, TRACK_IN_POSTER = 0x8}  track_header_flags; +    /* Need the sample rate of the first audio track to use as the timescale. */+    audio = hb_list_item(title->list_audio, 0);+    m->samplerate = audio->out.samplerate;+    audio = NULL;      /* Create an empty mp4 file */     if (job->largeFileSize)@@ -166,7 +175,7 @@        synchronization issues (audio not playing at the correct speed).        To workaround this, we use the audio samplerate as the        timescale */-    if (!(MP4SetTimeScale( m->file, job->arate )))+    if (!(MP4SetTimeScale( m->file, m->samplerate )))     {         hb_error("muxmp4.c: MP4SetTimeScale failed!");         *job->die = 1;@@ -183,7 +192,7 @@             return 0;         } -		mux_data->track = MP4AddH264VideoTrack( m->file, job->arate,+		mux_data->track = MP4AddH264VideoTrack( m->file, m->samplerate, 		        MP4_INVALID_DURATION, job->width, job->height, 		        job->config.h264.sps[1], /* AVCProfileIndication */ 		        job->config.h264.sps[2], /* profile_compat */@@ -211,7 +220,7 @@             *job->die = 1;             return 0;         }-        mux_data->track = MP4AddVideoTrack( m->file, job->arate,+        mux_data->track = MP4AddVideoTrack( m->file, m->samplerate,                 MP4_INVALID_DURATION, job->width, job->height,                 MP4_MPEG4_VIDEO_TYPE );         if (mux_data->track == MP4_INVALID_TRACK_ID)@@ -263,12 +272,11 @@         mux_data = malloc( sizeof( hb_mux_data_t ) );         audio->mux_data = mux_data; -        if( job->acodec & HB_ACODEC_AC3 ||-            job->audio_mixdowns[i] == HB_AMIXDOWN_AC3 )+        if( audio->out.codec == HB_ACODEC_AC3 )         {             mux_data->track = MP4AddAC3AudioTrack(                 m->file,-                job->arate, 1536, MP4_MPEG4_AUDIO_TYPE );+                m->samplerate, 1536, MP4_MPEG4_AUDIO_TYPE );             MP4SetTrackBytesProperty(                 m->file, mux_data->track,                 "udta.name.value",@@ -276,7 +284,7 @@         } else {             mux_data->track = MP4AddAudioTrack(                 m->file,-                job->arate, 1024, MP4_MPEG4_AUDIO_TYPE );+                m->samplerate, 1024, MP4_MPEG4_AUDIO_TYPE );             MP4SetTrackBytesProperty(                 m->file, mux_data->track,                 "udta.name.value",@@ -288,15 +296,15 @@                 audio->config.aac.bytes, audio->config.aac.length );              /* Set the correct number of channels for this track */-            reserved2[9] = (u_int8_t)HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->amixdown);+            reserved2[9] = (u_int8_t)HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->out.mixdown);             MP4SetTrackBytesProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.mp4a.reserved2", reserved2, sizeof(reserved2));          }         /* Set the language for this track */         /* The language is stored as 5-bit text - 0x60 */-        language_code = audio->iso639_2[0] - 0x60;   language_code <<= 5;-        language_code |= audio->iso639_2[1] - 0x60;  language_code <<= 5;-        language_code |= audio->iso639_2[2] - 0x60;+        language_code = audio->lang.iso639_2[0] - 0x60;   language_code <<= 5;+        language_code |= audio->lang.iso639_2[1] - 0x60;  language_code <<= 5;+        language_code |= audio->lang.iso639_2[2] - 0x60;         MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.mdhd.language", language_code);  @@ -372,7 +380,7 @@              if ( job->areBframes )             {-                duration += buf->renderOffset * job->arate / 90000;+                duration += buf->renderOffset * m->samplerate / 90000;             }              sample = MP4GenerateChapterSample( m, duration );@@ -396,8 +404,8 @@         /* Because we use the audio samplerate as the timescale,            we have to use potentially variable durations so the video            doesn't go out of sync */-        int64_t bias = ( buf->start * job->arate / 90000 ) - m->sum_dur;-        duration = ( buf->stop - buf->start ) * job->arate / 90000 + bias;+        int64_t bias = ( buf->start * m->samplerate / 90000 ) - m->sum_dur;+        duration = ( buf->stop - buf->start ) * m->samplerate / 90000 + bias;         if ( duration <= 0 )         {             /* We got an illegal mp4/h264 duration. This shouldn't@@ -406,14 +414,14 @@                try to fix the error so that the file will still be playable. */             hb_log("MP4Mux: illegal duration %lld, bias %lld, start %lld (%lld),"                    "stop %lld (%lld), sum_dur %lld",-                   duration, bias, buf->start * job->arate / 90000, buf->start,-                   buf->stop * job->arate / 90000, buf->stop, m->sum_dur );+                   duration, bias, buf->start * m->samplerate / 90000, buf->start,+                   buf->stop * m->samplerate / 90000, buf->stop, m->sum_dur );             /* we don't know when the next frame starts so we can't pick a                valid duration for this one so we pick something "short"                (roughly 1/3 of an NTSC frame time) and rely on the bias calc                for the next frame to correct things (a duration underestimate                just results in a large bias on the next frame). */-            duration = 1000 * job->arate / 90000;+            duration = 1000 * m->samplerate / 90000;         }         m->sum_dur += duration;     }@@ -436,7 +444,7 @@                          duration,                          ((mux_data->track != 1) ||                           (job->areBframes==0) ||-                          (job->vcodec != HB_VCODEC_X264)) ? 0 : (  buf->renderOffset * job->arate / 90000),+                          (job->vcodec != HB_VCODEC_X264)) ? 0 : (  buf->renderOffset * m->samplerate / 90000),                          ((buf->frametype & HB_FRAME_KEY) != 0) ) )     {         hb_error("Failed to write to output file, disk full?");Index: libhb/stream.c===================================================================--- libhb/stream.c	(revision 1318)+++ libhb/stream.c	(working copy)@@ -333,7 +333,7 @@         for (i=0; i < stream->ts_number_audio_pids; i++)         {             hb_audio_t *audio = hb_ts_stream_set_audio_id_and_codec(stream, i);-            if (audio->codec)+            if (audio->in.codec)                 hb_list_add( aTitle->list_audio, audio );             else             {@@ -732,7 +732,7 @@         if (buf[3] == 0xbd)         {             audio->id = 0x80bd | (aud_pid_index << 8);-            audio->codec = HB_ACODEC_AC3;+            audio->in.codec = HB_ACODEC_AC3;             hb_log("transport stream pid 0x%x (type 0x%x) is AC-3 audio id 0x%x",                    stream->ts_audio_pids[aud_pid_index],                    stream->ts_audio_stream_type[aud_pid_index],@@ -743,7 +743,7 @@         else if ((buf[3] & 0xe0) == 0xc0)         {             audio->id = buf[3] | aud_pid_index;-            audio->codec = HB_ACODEC_MPGA;+            audio->in.codec = HB_ACODEC_MPGA;             hb_log("transport stream pid 0x%x (type 0x%x) is MPEG audio id 0x%x",                    stream->ts_audio_pids[aud_pid_index],                    stream->ts_audio_stream_type[aud_pid_index],@@ -753,7 +753,7 @@         }     }     fseeko(stream->file_handle, cur_pos, SEEK_SET);-    if (! audio->codec)+    if (! audio->in.codec)     {         hb_log("transport stream pid 0x%x (type 0x%x) isn't audio",                 stream->ts_audio_pids[aud_pid_index],@@ -770,7 +770,7 @@     switch ( id >> 12 )     {         case 0x0:-            audio->codec = HB_ACODEC_MPGA;+            audio->in.codec = HB_ACODEC_MPGA;             hb_log("add_audio_to_title: added MPEG audio stream 0x%x", id);             break;         case 0x2:@@ -778,11 +778,11 @@             free( audio );             return;         case 0x8:-            audio->codec = HB_ACODEC_AC3;+            audio->in.codec = HB_ACODEC_AC3;             hb_log("add_audio_to_title: added AC3 audio stream 0x%x", id);             break;         case 0xa:-            audio->codec = HB_ACODEC_LPCM;+            audio->in.codec = HB_ACODEC_LPCM;             hb_log("add_audio_to_title: added LPCM audio stream 0x%x", id);             break;         default:@@ -872,12 +872,12 @@         }  		lang = lang_for_code(stream->a52_info[i].lang_code);-		if (!audio->rate)-			audio->rate = stream->a52_info[i].rate;-		if (!audio->bitrate)-			audio->bitrate = stream->a52_info[i].bitrate;-		if (!audio->config.a52.ac3flags)-			audio->config.a52.ac3flags = audio->ac3flags = stream->a52_info[i].flags;+        if (!audio->in.samplerate)+            audio->in.samplerate = stream->a52_info[i].rate;+        if (!audio->in.bitrate)+            audio->in.bitrate = stream->a52_info[i].bitrate;+        if (!audio->config.a52.ac3flags)+            audio->config.a52.ac3flags = audio->flags.ac3 = stream->a52_info[i].flags;  	}     else@@ -888,7 +888,7 @@  	if (!audio->input_channel_layout) 	{-		switch( audio->ac3flags & A52_CHANNEL_MASK )+		switch( audio->flags.ac3 & A52_CHANNEL_MASK ) 		{ 			/* mono sources */ 			case A52_MONO:@@ -929,29 +929,29 @@ 		}  		/* add in our own LFE flag if the source has LFE */-		if (audio->ac3flags & A52_LFE)+		if (audio->flags.ac3 & A52_LFE) 		{ 			audio->input_channel_layout = audio->input_channel_layout | HB_INPUT_CH_LAYOUT_HAS_LFE; 		} 	} -	snprintf( audio->lang, sizeof( audio->lang ), "%s (%s)", strlen(lang->native_name) ? lang->native_name : lang->eng_name,-	  audio->codec == HB_ACODEC_AC3 ? "AC3" : ( audio->codec == HB_ACODEC_MPGA ? "MPEG" : ( audio->codec == HB_ACODEC_DCA ? "DTS" : "LPCM" ) ) );-	snprintf( audio->lang_simple, sizeof( audio->lang_simple ), "%s", strlen(lang->native_name) ? lang->native_name : lang->eng_name );-	snprintf( audio->iso639_2, sizeof( audio->iso639_2 ), "%s", lang->iso639_2);+    snprintf( audio->lang.description, sizeof( audio->lang.description ), "%s (%s)", strlen(lang->native_name) ? lang->native_name : lang->eng_name,+	  audio->in.codec == HB_ACODEC_AC3 ? "AC3" : ( audio->in.codec == HB_ACODEC_MPGA ? "MPEG" : ( audio->in.codec == HB_ACODEC_DCA ? "DTS" : "LPCM" ) ) );+	snprintf( audio->lang.simple, sizeof( audio->lang.simple ), "%s", strlen(lang->native_name) ? lang->native_name : lang->eng_name );+	snprintf( audio->lang.iso639_2, sizeof( audio->lang.iso639_2 ), "%s", lang->iso639_2); -	if ( (audio->ac3flags & A52_CHANNEL_MASK) == A52_DOLBY ) {-		sprintf( audio->lang + strlen( audio->lang ),+	if ( (audio->flags.ac3 & A52_CHANNEL_MASK) == A52_DOLBY ) {+        sprintf( audio->lang.description + strlen( audio->lang.description ), 			 " (Dolby Surround)" ); 	} else {-		sprintf( audio->lang + strlen( audio->lang ),+        sprintf( audio->lang.description + strlen( audio->lang.description ), 			 " (%d.%d ch)", 			HB_INPUT_CH_LAYOUT_GET_DISCRETE_FRONT_COUNT(audio->input_channel_layout) + 			HB_INPUT_CH_LAYOUT_GET_DISCRETE_REAR_COUNT(audio->input_channel_layout), 			HB_INPUT_CH_LAYOUT_GET_DISCRETE_LFE_COUNT(audio->input_channel_layout)); 	} -	hb_log( "hb_stream_update_audio: id=%x, lang=%s, 3cc=%s, rate = %d, bitrate = %d, flags = 0x%x (%d)", audio->id, audio->lang, audio->iso639_2, audio->rate, audio->bitrate, audio->ac3flags, audio->ac3flags );+    hb_log( "hb_stream_update_audio: id=%x, lang=%s, 3cc=%s, rate = %d, bitrate = %d, flags = 0x%x (%d)", audio->id, audio->lang.description, audio->lang.iso639_2, audio->in.samplerate, audio->in.bitrate, audio->flags.ac3, audio->flags.ac3 );  } Index: libhb/decdca.c===================================================================--- libhb/decdca.c	(revision 1318)+++ libhb/decdca.c	(working copy)@@ -61,6 +61,7 @@ int decdcaInit( hb_work_object_t * w, hb_job_t * job ) {     hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );+    hb_audio_t * audio = w->audio;     w->private_data = pv;      pv->job   = job;@@ -71,11 +72,11 @@ 	/* Decide what format we want out of libdca 	work.c has already done some of this deduction for us in do_job() */ -	pv->flags_out = HB_AMIXDOWN_GET_DCA_FORMAT(w->amixdown);+	pv->flags_out = HB_AMIXDOWN_GET_DCA_FORMAT(audio->out.mixdown);  	/* pass the number of channels used into the private work data */ 	/* will only be actually used if we're not doing AC3 passthru */-	pv->out_discrete_channels = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(w->amixdown);+    pv->out_discrete_channels = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->out.mixdown);      pv->level     = 32768.0; Index: libhb/muxogm.c===================================================================--- libhb/muxogm.c	(revision 1318)+++ libhb/muxogm.c	(working copy)@@ -135,7 +135,7 @@     {         audio                 = hb_list_item( title->list_audio, i );         mux_data              = malloc( sizeof( hb_mux_data_t ) );-        mux_data->codec       = job->acodec;+        mux_data->codec       = audio->out.codec;         mux_data->i_packet_no = 0;         audio->mux_data       = mux_data;         ogg_stream_init( &mux_data->os, i + 1 );@@ -185,7 +185,7 @@         audio   = hb_list_item( title->list_audio, i );         mux_data = audio->mux_data;         memset( &h, 0, sizeof( ogg_stream_header_t ) );-        switch( job->acodec )+        switch( audio->out.codec )         {             case HB_ACODEC_LAME:             {@@ -195,7 +195,7 @@                  SetDWLE( &h.i_size, sizeof( ogg_stream_header_t ) - 1);                 SetQWLE( &h.i_time_unit, 0 );-                SetQWLE( &h.i_samples_per_unit, job->arate );+                SetQWLE( &h.i_samples_per_unit, audio->out.samplerate );                 SetDWLE( &h.i_default_len, 1 );                 SetDWLE( &h.i_buffer_size, 30 * 1024 );                 SetWLE ( &h.i_bits_per_sample, 0 );@@ -203,7 +203,7 @@                 SetDWLE( &h.header.audio.i_channels, 2 );                 SetDWLE( &h.header.audio.i_block_align, 0 );                 SetDWLE( &h.header.audio.i_avgbytespersec,-                         job->abitrate / 8 );+                         audio->out.bitrate / 8 );                  op.packet   = (unsigned char*) &h;                 op.bytes    = sizeof( ogg_stream_header_t );@@ -234,7 +234,7 @@     for( i = 0; i < hb_list_count( title->list_audio ); i++ )     {         audio = hb_list_item( title->list_audio, i );-        if( job->acodec == HB_ACODEC_VORBIS )+        if( audio->out.codec == HB_ACODEC_VORBIS )         {             int       j;             mux_data = audio->mux_data;@@ -259,44 +259,48 @@ static int OGMMux( hb_mux_object_t * m, hb_mux_data_t * mux_data,                    hb_buffer_t * buf ) {+    hb_job_t * job = m->job;     ogg_packet   op; -    switch( mux_data->codec )+    if( mux_data == job->mux_data )     {-        case HB_VCODEC_FFMPEG:-        case HB_VCODEC_XVID:-        case HB_VCODEC_X264:-            op.bytes  = buf->size + 1;-            op.packet = malloc( op.bytes );-            op.packet[0] = (buf->frametype & HB_FRAME_KEY) ? 0x08 : 0x00;-            memcpy( &op.packet[1], buf->data, buf->size );-            op.b_o_s       = 0;-            op.e_o_s       = 0;-            op.granulepos  = mux_data->i_packet_no;-            op.packetno    = mux_data->i_packet_no++;-            break;-        case HB_ACODEC_LAME:-            op.bytes  = buf->size + 1;-            op.packet = malloc( op.bytes );-            op.packet[0] = 0x08;-            memcpy( &op.packet[1], buf->data, buf->size );-            op.b_o_s       = 0;-            op.e_o_s       = 0;-            op.granulepos  = mux_data->i_packet_no * 1152;-            op.packetno    = mux_data->i_packet_no++;-            break;-        case HB_ACODEC_VORBIS:-            memcpy( &op, buf->data, sizeof( ogg_packet ) );-            op.packet = malloc( op.bytes );-            memcpy( op.packet, buf->data + sizeof( ogg_packet ), op.bytes );-            break;--        default:-            hb_log( "muxogm: unhandled codec" );-            op.bytes = 0;-            op.packet = NULL;-            break;+        /* Video */+        op.bytes  = buf->size + 1;+        op.packet = malloc( op.bytes );+        op.packet[0] = (buf->frametype & HB_FRAME_KEY) ? 0x08 : 0x00;+        memcpy( &op.packet[1], buf->data, buf->size );+        op.b_o_s       = 0;+        op.e_o_s       = 0;+        op.granulepos  = mux_data->i_packet_no;+        op.packetno    = mux_data->i_packet_no++;     }+    else+    {+        /* Audio */+        switch( mux_data->codec )+        {+            case HB_ACODEC_LAME:+                op.bytes  = buf->size + 1;+                op.packet = malloc( op.bytes );+                op.packet[0] = 0x08;+                memcpy( &op.packet[1], buf->data, buf->size );+                op.b_o_s       = 0;+                op.e_o_s       = 0;+                op.granulepos  = mux_data->i_packet_no * 1152;+                op.packetno    = mux_data->i_packet_no++;+                break;+            case HB_ACODEC_VORBIS:+                memcpy( &op, buf->data, sizeof( ogg_packet ) );+                op.packet = malloc( op.bytes );+                memcpy( op.packet, buf->data + sizeof( ogg_packet ), op.bytes );+                break;+            default:+                hb_log( "muxogm: unhandled codec" );+                op.bytes = 0;+                op.packet = NULL;+                break;+        }+    }      if( op.packet )     {Index: libhb/sync.c===================================================================--- libhb/sync.c	(revision 1318)+++ libhb/sync.c	(working copy)@@ -137,6 +137,7 @@     hb_work_private_t * pv = w->private_data;     hb_job_t          * job   = pv->job;     hb_title_t        * title = job->title;+    hb_audio_t        * audio = NULL;      int i; @@ -144,8 +145,8 @@      for( i = 0; i < hb_list_count( title->list_audio ); i++ )     {-        if( job->acodec & HB_ACODEC_AC3 ||-            job->audio_mixdowns[i] == HB_AMIXDOWN_AC3 )+        audio = hb_list_item( title->list_audio, i );+        if( audio->out.codec == HB_ACODEC_AC3 )         {             free( pv->sync_audio[i].ac3_buf );         }@@ -207,8 +208,7 @@     sync        = &pv->sync_audio[i];     sync->audio = hb_list_item( title->list_audio, i ); -    if( job->acodec & HB_ACODEC_AC3 ||-        job->audio_mixdowns[i] == HB_AMIXDOWN_AC3 )+    if( sync->audio->out.codec == HB_ACODEC_AC3 )     {         /* Have a silent AC-3 frame ready in case we have to fill a            gap */@@ -219,9 +219,9 @@         codec = avcodec_find_encoder( CODEC_ID_AC3 );         c     = avcodec_alloc_context(); -        c->bit_rate    = sync->audio->bitrate;-        c->sample_rate = sync->audio->rate;-        c->channels    = 2;+        c->bit_rate    = sync->audio->in.bitrate;+        c->sample_rate = sync->audio->in.samplerate;+        c->channels    = HB_INPUT_CH_LAYOUT_GET_DISCRETE_COUNT( sync->audio->input_channel_layout );          if( avcodec_open( c, codec ) < 0 )         {@@ -231,8 +231,8 @@          zeros          = calloc( AC3_SAMPLES_PER_FRAME *                                  sizeof( short ) * c->channels, 1 );-        sync->ac3_size = sync->audio->bitrate * AC3_SAMPLES_PER_FRAME /-                             sync->audio->rate / 8;+        sync->ac3_size = sync->audio->in.bitrate * AC3_SAMPLES_PER_FRAME /+                             sync->audio->in.samplerate / 8;         sync->ac3_buf  = malloc( sync->ac3_size );          if( avcodec_encode_audio( c, sync->ac3_buf, sync->ac3_size,@@ -249,7 +249,7 @@     {         /* Initialize libsamplerate */         int error;-        sync->state             = src_new( SRC_LINEAR, HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(sync->audio->amixdown), &error );+        sync->state             = src_new( SRC_LINEAR, HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(sync->audio->out.mixdown), &error );         sync->data.end_of_input = 0;     } }@@ -659,16 +659,15 @@     sync   = &pv->sync_audio[i];     audio  = sync->audio; -    if( job->acodec & HB_ACODEC_AC3 ||-        job->audio_mixdowns[i] == HB_AMIXDOWN_AC3 )+    if( audio->out.codec == HB_ACODEC_AC3 )     {         fifo = audio->fifo_out;-        rate = audio->rate;+        rate = audio->in.samplerate;     }     else     {         fifo = audio->fifo_sync;-        rate = job->arate;+        rate = audio->out.samplerate;     }      while( !hb_fifo_is_full( fifo ) &&@@ -822,8 +821,7 @@             }         } -        if( job->acodec & HB_ACODEC_AC3 ||-            job->audio_mixdowns[i] == HB_AMIXDOWN_AC3 )+        if( audio->out.codec == HB_ACODEC_AC3 )         {             buf        = hb_fifo_get( audio->fifo_raw );             buf->start = start;@@ -837,8 +835,8 @@              int count_in, count_out; -            count_in  = buf_raw->size / HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->amixdown) / sizeof( float );-            count_out = ( buf_raw->stop - buf_raw->start ) * job->arate / 90000;+            count_in  = buf_raw->size / HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->out.mixdown) / sizeof( float );+            count_out = ( buf_raw->stop - buf_raw->start ) * audio->out.samplerate / 90000;             if( buf->start < pts_expected - 1500 )                 count_out--;             else if( buf->start > pts_expected + 1500 )@@ -851,7 +849,7 @@             sync->data.src_ratio = (double) sync->data.output_frames /                                    (double) sync->data.input_frames; -            buf = hb_buffer_init( sync->data.output_frames * HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->amixdown) *+            buf = hb_buffer_init( sync->data.output_frames * HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->out.mixdown) *                                   sizeof( float ) );             sync->data.data_out = (float *) buf->data;             if( src_process( sync->state, &sync->data ) )@@ -861,12 +859,12 @@             }             hb_buffer_close( &buf_raw ); -            buf->size = sync->data.output_frames_gen * HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->amixdown) * sizeof( float );+            buf->size = sync->data.output_frames_gen * HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->out.mixdown) * sizeof( float );              /* Set dates for resampled data */             buf->start = start;             buf->stop  = start + sync->data.output_frames_gen *-                            90000 / job->arate;+                            90000 / audio->out.samplerate;              sync->count_frames += sync->data.output_frames_gen;         }@@ -939,13 +937,12 @@     job    = pv->job;     sync   = &pv->sync_audio[i]; -    if( job->acodec & HB_ACODEC_AC3 ||-        job->audio_mixdowns[i] == HB_AMIXDOWN_AC3 )+    if( sync->audio->out.codec == HB_ACODEC_AC3 )     {         buf        = hb_buffer_init( sync->ac3_size );-        buf->start = sync->count_frames * 90000 / sync->audio->rate;+        buf->start = sync->count_frames * 90000 / sync->audio->in.samplerate;         buf->stop  = buf->start + 90000 * AC3_SAMPLES_PER_FRAME /-                     sync->audio->rate;+                     sync->audio->in.samplerate;         memcpy( buf->data, sync->ac3_buf, buf->size );          hb_log( "sync: adding a silent AC-3 frame for track %x",@@ -957,15 +954,15 @@     }     else     {-        buf        = hb_buffer_init( HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(sync->audio->amixdown) * job->arate / 20 *+        buf        = hb_buffer_init( HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(sync->audio->out.mixdown) * sync->audio->out.samplerate / 20 *                                      sizeof( float ) );-        buf->start = sync->count_frames * 90000 / job->arate;+        buf->start = sync->count_frames * 90000 / sync->audio->out.samplerate;         buf->stop  = buf->start + 90000 / 20;         memset( buf->data, 0, buf->size );          hb_fifo_push( sync->audio->fifo_sync, buf ); -        sync->count_frames += job->arate / 20;+        sync->count_frames += sync->audio->out.samplerate / 20;     } } Index: libhb/encfaac.c===================================================================--- libhb/encfaac.c	(revision 1318)+++ libhb/encfaac.c	(working copy)@@ -45,6 +45,7 @@ int encfaacInit( hb_work_object_t * w, hb_job_t * job ) {     hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );+    hb_audio_t * audio = w->audio;     faacEncConfigurationPtr cfg;     uint8_t * bytes;     unsigned long length;@@ -54,9 +55,9 @@     pv->job   = job;  	/* pass the number of channels used into the private work data */-	pv->out_discrete_channels = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(w->amixdown);+    pv->out_discrete_channels = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->out.mixdown); -    pv->faac = faacEncOpen( job->arate, pv->out_discrete_channels, &pv->input_samples,+    pv->faac = faacEncOpen( audio->out.samplerate, pv->out_discrete_channels, &pv->input_samples,                            &pv->output_bytes );     pv->buf  = malloc( pv->input_samples * sizeof( float ) ); @@ -74,12 +75,12 @@ 	}      cfg->useTns        = 0;-    cfg->bitRate       = job->abitrate * 1000 / pv->out_discrete_channels; /* Per channel */+    cfg->bitRate       = audio->out.bitrate * 1000 / pv->out_discrete_channels; /* Per channel */     cfg->bandWidth     = 0;     cfg->outputFormat  = 0;     cfg->inputFormat   =  FAAC_INPUT_FLOAT; -	if (w->amixdown == HB_AMIXDOWN_6CH && w->source_acodec == HB_ACODEC_AC3)+    if (audio->out.mixdown == HB_AMIXDOWN_6CH && audio->in.codec == HB_ACODEC_AC3)     {         /* we are preserving 5.1 AC-3 audio into 6-channel AAC, and need to         re-map the output of deca52 into our own mapping - the mapping@@ -140,6 +141,7 @@ static hb_buffer_t * Encode( hb_work_object_t * w ) {     hb_work_private_t * pv = w->private_data;+    hb_audio_t * audio = w->audio;     hb_buffer_t * buf;     uint64_t      pts, pos; @@ -153,8 +155,8 @@                       &pts, &pos );      buf        = hb_buffer_init( pv->output_bytes );-    buf->start = pts + 90000 * pos / pv->out_discrete_channels / sizeof( float ) / pv->job->arate;-    buf->stop  = buf->start + 90000 * pv->input_samples / pv->job->arate / pv->out_discrete_channels;+    buf->start = pts + 90000 * pos / pv->out_discrete_channels / sizeof( float ) / audio->out.samplerate;+    buf->stop  = buf->start + 90000 * pv->input_samples / audio->out.samplerate / pv->out_discrete_channels;     buf->size  = faacEncEncode( pv->faac, (int32_t *) pv->buf,             pv->input_samples, buf->data, pv->output_bytes );     buf->frametype   = HB_FRAME_AUDIO;Index: libhb/muxcommon.c===================================================================--- libhb/muxcommon.c	(revision 1318)+++ libhb/muxcommon.c	(working copy)@@ -82,6 +82,12 @@                 break;             case HB_MUX_MKV:                 m = hb_mux_mkv_init( job );+                break;+            case HB_MUX_NONE:+            default:+                m = NULL;+                hb_error("Invalid muxer: %d", job->mux);+                *job->die = 1;         }     } @@ -116,7 +122,8 @@     /* Create file, write headers */     if( job->pass == 0 || job->pass == 2 )     {-        m->init( m );+        if( m )+            m->init( m );     }      /* Build list of fifos we're interested in */@@ -170,7 +177,8 @@ 		p.progress = 0;         hb_set_state( job->h, &state ); #undef p-        m->end( m );+        if( m )+            m->end( m );          if( !stat( job->file, &sb ) )         {@@ -204,7 +212,7 @@         }     } -    free( m );+    if( m ) free( m );      for( i = 0; i < hb_list_count( list ); i++ )     {@@ -217,7 +225,7 @@     }     hb_list_close( &list ); -    free( mux );+    if( mux ) free( mux ); }  hb_thread_t * hb_muxer_init( hb_job_t * job )Index: libhb/work.c===================================================================--- libhb/work.c	(revision 1318)+++ libhb/work.c	(working copy)@@ -264,6 +264,12 @@                 hb_log( "   + x264 options: %s", job->x264opts);             w = getWork( WORK_ENCX264 );             break;+        case HB_VCODEC_NONE:+        default:+            hb_error("Invalid video codec: %d", job->vcodec);+            w = NULL;+            *job->die = 1;+            goto cleanup;     }     w->fifo_in  = job->fifo_render;     w->fifo_out = job->fifo_mpeg4;@@ -333,57 +339,53 @@         }     } -    if( job->audio_mixdowns[0] == HB_AMIXDOWN_AC3 || job->audio_mixdowns[1] == HB_AMIXDOWN_AC3 )-    {-        /* Hard set correct sample rate for AC3 when libhb-           mistakenly thinks the audio codec is AAC */-        job->arate = 48000;-    }--    if( job->acodec & HB_ACODEC_AC3 )-    {-        hb_log( " + audio AC3 passthrough" );--        /* Hard set correct sample rate for AC3 */-        job->arate = 48000;-    }-    else-    {-        hb_log( " + audio %d kbps, %d Hz", job->abitrate, job->arate );-        hb_log( " + encoder %s", ( job->acodec & HB_ACODEC_FAAC ) ?-                "faac" : ( ( job->acodec & HB_ACODEC_LAME ) ? "lame" :-                "vorbis" ) );-    }--    if ( job->dynamic_range_compression > 1 )-        hb_log(" + dynamic range compression: %f", job->dynamic_range_compression);--    /* if we are doing AC3 passthru (at the codec level, not pass-through),-     * then remove any non-AC3 audios from the job */+    /* if we are doing passthru, and the input codec is not the same as the output+     * codec, then remove this audio from the job */     /* otherwise, Bad Things will happen */     for( i = 0; i < hb_list_count( title->list_audio ); )     {         audio = hb_list_item( title->list_audio, i );-        if( ( job->acodec & HB_ACODEC_AC3 ) && ( audio->codec != HB_ACODEC_AC3 ) )+        if( ( ( audio->out.codec == HB_ACODEC_AC3 ) && ( audio->in.codec != HB_ACODEC_AC3 ) ) ||+            ( ( audio->out.codec == HB_ACODEC_DCA ) && ( audio->in.codec != HB_ACODEC_DCA ) ) )         {+            hb_log( "Passthru requested and input codec is not the same as output codec for track %d", audio->out.track );             hb_list_rem( title->list_audio, audio );             free( audio );             continue;         }-        i++;+        /* Adjust output track number, in case we removed one.+         * Output tracks sadly still need to be in sequential order.+         */+        audio->out.track = i++;     }      for( i = 0; i < hb_list_count( title->list_audio ); i++ )     {         audio = hb_list_item( title->list_audio, i );-        hb_log( "   + %x, %s", audio->id, audio->lang );+        hb_log( " + audio track %d", audio->out.track );+        if( (audio->out.codec == HB_ACODEC_AC3) || (audio->out.codec == HB_ACODEC_DCA) )+        {+            hb_log( "   + %s passthrough", (audio->out.codec == HB_ACODEC_AC3) ?+                "AC3" : "DCA" );+        }+        else+        {+            hb_log( "   + audio %d kbps, %d Hz", audio->out.bitrate, audio->out.samplerate );+            hb_log( "   + encoder %s", ( audio->out.codec == HB_ACODEC_FAAC ) ?+            "faac" : ( ( audio->out.codec == HB_ACODEC_LAME ) ? "lame" :+            "vorbis" ) );+            if ( audio->out.dynamic_range_compression > 1 )+                hb_log("   + dynamic range compression: %f", audio->out.dynamic_range_compression);+        } +        hb_log( "     + %x, %s", audio->id, audio->lang.description );+ 		/* sense-check the current mixdown options */  		/* log the requested mixdown */ 		for (j = 0; j < hb_audio_mixdowns_count; j++) {-			if (hb_audio_mixdowns[j].amixdown == job->audio_mixdowns[i]) {-				hb_log( "     + Requested mixdown: %s (%s)", hb_audio_mixdowns[j].human_readable_name, hb_audio_mixdowns[j].internal_name );+			if (hb_audio_mixdowns[j].amixdown == audio->out.mixdown) {+				hb_log( "       + Requested mixdown: %s (%s)", hb_audio_mixdowns[j].human_readable_name, hb_audio_mixdowns[j].internal_name ); 				break; 			} 		}@@ -392,22 +394,11 @@          /* audioCodecsSupportMono and audioCodecsSupport6Ch are the same for now,            but this may change in the future, so they are separated for flexibility */-        int audioCodecsSupportMono = ((audio->codec == HB_ACODEC_AC3 ||-            audio->codec == HB_ACODEC_DCA) && (job->acodec == HB_ACODEC_FAAC || job->acodec == HB_ACODEC_VORBIS));-        int audioCodecsSupport6Ch =  ((audio->codec == HB_ACODEC_AC3 ||-            audio->codec == HB_ACODEC_DCA) && (job->acodec == HB_ACODEC_FAAC || job->acodec == HB_ACODEC_VORBIS));+        int audioCodecsSupportMono = ( (audio->in.codec == HB_ACODEC_AC3 || audio->in.codec == HB_ACODEC_DCA) &&+            (audio->out.codec == HB_ACODEC_FAAC || audio->out.codec == HB_ACODEC_VORBIS) );+        int audioCodecsSupport6Ch =  ( (audio->in.codec == HB_ACODEC_AC3 || audio->in.codec == HB_ACODEC_DCA) &&+            (audio->out.codec == HB_ACODEC_FAAC || audio->out.codec == HB_ACODEC_VORBIS)); -        if( audio->codec != HB_ACODEC_AC3 && job->audio_mixdowns[i] == HB_AMIXDOWN_AC3 )-        {-            /*-             * Sanity check that we haven't asked for AC3 from a non AC3 track - drop this track-             * to stereo to avoid a crash later.-             */-            job->audio_mixdowns[i] = HB_AMIXDOWN_STEREO;-        }--        if( job->audio_mixdowns[i] != HB_AMIXDOWN_AC3 )-        {         /* find out what the format of our source audio is */         switch (audio->input_channel_layout & HB_INPUT_CH_LAYOUT_DISCRETE_NO_LFE_MASK) { @@ -415,10 +406,10 @@             case HB_INPUT_CH_LAYOUT_MONO:                 /* regardless of what stereo mixdown we've requested, a mono source always get mixed down                 to mono if we can, and mixed up to stereo if we can't */-                if (job->audio_mixdowns[i] == HB_AMIXDOWN_MONO && audioCodecsSupportMono == 1) {-                    job->audio_mixdowns[i] = HB_AMIXDOWN_MONO;+                if (audio->out.mixdown == HB_AMIXDOWN_MONO && audioCodecsSupportMono == 1) {+                    audio->out.mixdown = HB_AMIXDOWN_MONO;                 } else {-                    job->audio_mixdowns[i] = HB_AMIXDOWN_STEREO;+                    audio->out.mixdown = HB_AMIXDOWN_STEREO;                 }                 break; @@ -426,11 +417,11 @@             case HB_INPUT_CH_LAYOUT_STEREO:                 /* if we've requested a mono mixdown, and it is supported, then do the mix */                 /* use stereo if not supported */-                if (job->audio_mixdowns[i] == HB_AMIXDOWN_MONO && audioCodecsSupportMono == 0) {-                    job->audio_mixdowns[i] = HB_AMIXDOWN_STEREO;+                if (audio->out.mixdown == HB_AMIXDOWN_MONO && audioCodecsSupportMono == 0) {+                    audio->out.mixdown = HB_AMIXDOWN_STEREO;                 /* otherwise, preserve stereo regardless of if we requested something higher */-                } else if (job->audio_mixdowns[i] > HB_AMIXDOWN_STEREO) {-                    job->audio_mixdowns[i] = HB_AMIXDOWN_STEREO;+                } else if (audio->out.mixdown > HB_AMIXDOWN_STEREO) {+                    audio->out.mixdown = HB_AMIXDOWN_STEREO;                 }                 break; @@ -440,12 +431,12 @@             case HB_INPUT_CH_LAYOUT_DOLBY:                 /* if we've requested a mono mixdown, and it is supported, then do the mix */                 /* preserve dolby if not supported */-                if (job->audio_mixdowns[i] == HB_AMIXDOWN_MONO && audioCodecsSupportMono == 0) {-                    job->audio_mixdowns[i] = HB_AMIXDOWN_DOLBY;+                if (audio->out.mixdown == HB_AMIXDOWN_MONO && audioCodecsSupportMono == 0) {+                    audio->out.mixdown = HB_AMIXDOWN_DOLBY;                 /* otherwise, preserve dolby even if we requested something higher */                 /* a stereo mixdown will still be honoured here */-                } else if (job->audio_mixdowns[i] > HB_AMIXDOWN_DOLBY) {-                    job->audio_mixdowns[i] = HB_AMIXDOWN_DOLBY;+                } else if (audio->out.mixdown > HB_AMIXDOWN_DOLBY) {+                    audio->out.mixdown = HB_AMIXDOWN_DOLBY;                 }                 break; @@ -453,21 +444,21 @@             case HB_INPUT_CH_LAYOUT_3F2R:                 /* if we've requested a mono mixdown, and it is supported, then do the mix */                 /* use dpl2 if not supported */-                if (job->audio_mixdowns[i] == HB_AMIXDOWN_MONO && audioCodecsSupportMono == 0) {-                    job->audio_mixdowns[i] = HB_AMIXDOWN_DOLBYPLII;+                if (audio->out.mixdown == HB_AMIXDOWN_MONO && audioCodecsSupportMono == 0) {+                    audio->out.mixdown = HB_AMIXDOWN_DOLBYPLII;                 } else {                     /* check if we have 3F2R input and also have an LFE - i.e. we have a 5.1 source) */                     if (audio->input_channel_layout & HB_INPUT_CH_LAYOUT_HAS_LFE) {                         /* we have a 5.1 source */                         /* if we requested 6ch, but our audio format doesn't support it, then mix to DPLII instead */-                        if (job->audio_mixdowns[i] == HB_AMIXDOWN_6CH && audioCodecsSupport6Ch == 0) {-                            job->audio_mixdowns[i] = HB_AMIXDOWN_DOLBYPLII;+                        if (audio->out.mixdown == HB_AMIXDOWN_6CH && audioCodecsSupport6Ch == 0) {+                            audio->out.mixdown = HB_AMIXDOWN_DOLBYPLII;                         }                     } else {                         /* we have a 5.0 source, so we can't do 6ch conversion                         default to DPL II instead */-                        if (job->audio_mixdowns[i] > HB_AMIXDOWN_DOLBYPLII) {-                            job->audio_mixdowns[i] = HB_AMIXDOWN_DOLBYPLII;+                        if (audio->out.mixdown > HB_AMIXDOWN_DOLBYPLII) {+                            audio->out.mixdown = HB_AMIXDOWN_DOLBYPLII;                         }                     }                 }@@ -478,13 +469,13 @@             case HB_INPUT_CH_LAYOUT_3F1R:                 /* if we've requested a mono mixdown, and it is supported, then do the mix */                 /* use dpl1 if not supported */-                if (job->audio_mixdowns[i] == HB_AMIXDOWN_MONO && audioCodecsSupportMono == 0) {-                    job->audio_mixdowns[i] = HB_AMIXDOWN_DOLBY;+                if (audio->out.mixdown == HB_AMIXDOWN_MONO && audioCodecsSupportMono == 0) {+                    audio->out.mixdown = HB_AMIXDOWN_DOLBY;                 } else {                     /* we have a 4.0 or 4.1 source, so we can't do DPLII or 6ch conversion                     default to DPL I instead */-                    if (job->audio_mixdowns[i] > HB_AMIXDOWN_DOLBY) {-                        job->audio_mixdowns[i] = HB_AMIXDOWN_DOLBY;+                    if (audio->out.mixdown > HB_AMIXDOWN_DOLBY) {+                        audio->out.mixdown = HB_AMIXDOWN_DOLBY;                     }                 }                 /* all other mixdowns will have been preserved here */@@ -492,30 +483,26 @@              default:                 /* if we've requested a mono mixdown, and it is supported, then do the mix */-                if (job->audio_mixdowns[i] == HB_AMIXDOWN_MONO && audioCodecsSupportMono == 1) {-                    job->audio_mixdowns[i] = HB_AMIXDOWN_MONO;+                if (audio->out.mixdown == HB_AMIXDOWN_MONO && audioCodecsSupportMono == 1) {+                    audio->out.mixdown = HB_AMIXDOWN_MONO;                 /* mix everything else down to stereo */                 } else {-                    job->audio_mixdowns[i] = HB_AMIXDOWN_STEREO;+                    audio->out.mixdown = HB_AMIXDOWN_STEREO;                 }          }-        }  		/* log the output mixdown */ 		for (j = 0; j < hb_audio_mixdowns_count; j++) {-			if (hb_audio_mixdowns[j].amixdown == job->audio_mixdowns[i]) {-				hb_log( "     + Actual mixdown: %s (%s)", hb_audio_mixdowns[j].human_readable_name, hb_audio_mixdowns[j].internal_name );+			if (hb_audio_mixdowns[j].amixdown == audio->out.mixdown) {+				hb_log( "       + Actual mixdown: %s (%s)", hb_audio_mixdowns[j].human_readable_name, hb_audio_mixdowns[j].internal_name ); 				break; 			} 		} -		/* we now know we have a valid mixdown for the input source and the audio output format */-		/* remember the mixdown for this track */-		audio->amixdown = job->audio_mixdowns[i];+        if (audio->out.codec == HB_ACODEC_VORBIS)+            audio->config.vorbis.language = audio->lang.simple; -        audio->config.vorbis.language = audio->lang_simple;-         /* set up the audio work structures */         audio->fifo_in   = hb_fifo_init( 2048 );         audio->fifo_raw  = hb_fifo_init( FIFO_CPU_MULT * cpu_count );@@ -526,7 +513,7 @@         /*          * Audio Decoder Thread          */-        switch( audio->codec )+        switch( audio->in.codec )         {             case HB_ACODEC_AC3:                 w = getWork( WORK_DECA52 );@@ -540,12 +527,16 @@             case HB_ACODEC_LPCM:                 w = getWork( WORK_DECLPCM );                 break;+            default:+                /* Invalid input codec */+                hb_error("Invalid input codec: %d", audio->in.codec);+                *job->die = 1;+                goto cleanup;         }         w->fifo_in       = audio->fifo_in;         w->fifo_out      = audio->fifo_raw;         w->config        = &audio->config;-        w->amixdown      = audio->amixdown;-        w->source_acodec = audio->codec;+        w->audio         = audio;          /* FIXME: This feels really hackish, anything better? */         audio_w = calloc( sizeof( hb_work_object_t ), 1 );@@ -556,10 +547,8 @@         /*          * Audio Encoder Thread          */-        if( job->audio_mixdowns[i] != HB_AMIXDOWN_AC3 )+        switch( audio->out.codec )         {-            switch( job->acodec )-            {             case HB_ACODEC_FAAC:                 w = getWork( WORK_ENCFAAC );                 break;@@ -569,11 +558,17 @@             case HB_ACODEC_VORBIS:                 w = getWork( WORK_ENCVORBIS );                 break;-            }+            case HB_ACODEC_AC3:+                break;+            case HB_ACODEC_DCA:    /* These are all invalid output codecs. */+            default:+                hb_error("Invalid audio codec: %d", audio->out.codec);+                w = NULL;+                *job->die = 1;+                goto cleanup;         } -        if( job->acodec != HB_ACODEC_AC3 &&-            job->audio_mixdowns[i] != HB_AMIXDOWN_AC3)+        if( audio->out.codec != HB_ACODEC_AC3 )         {             /*              * Add the encoder thread if not doing AC-3 pass through@@ -581,8 +576,7 @@             w->fifo_in       = audio->fifo_sync;             w->fifo_out      = audio->fifo_out;             w->config        = &audio->config;-            w->amixdown      = audio->amixdown;-            w->source_acodec = audio->codec;+            w->audio         = audio;              /* FIXME: This feels really hackish, anything better? */             audio_w = calloc( sizeof( hb_work_object_t ), 1 );@@ -636,12 +630,16 @@     w->close( w );     job->done = 1; +cleanup:     /* Close work objects */     while( ( w = hb_list_item( job->list_work, 0 ) ) )     {         hb_list_rem( job->list_work, w );-        hb_thread_close( &w->thread );-        w->close( w );+        if( w && w->thread )+        {+            hb_thread_close( &w->thread );+            w->close( w );+        }          /* FIXME: This feels really hackish, anything better? */         if ( w->id == WORK_DECA52 ||@@ -659,8 +657,10 @@     hb_list_close( &job->list_work );      /* Stop read & write threads */-    hb_thread_close( &job->reader );-    hb_thread_close( &job->muxer );+    if( job->reader )+        hb_thread_close( &job->reader );+    if( job->muxer )+        hb_thread_close( &job->muxer );      /* Close fifos */     hb_fifo_close( &job->fifo_mpeg2 );@@ -680,10 +680,14 @@     for( i = 0; i < hb_list_count( title->list_audio ); i++ )     {         audio = hb_list_item( title->list_audio, i );-        hb_fifo_close( &audio->fifo_in );-        hb_fifo_close( &audio->fifo_raw );-        hb_fifo_close( &audio->fifo_sync );-        hb_fifo_close( &audio->fifo_out );+        if( audio->fifo_in )+            hb_fifo_close( &audio->fifo_in );+        if( audio->fifo_raw )+            hb_fifo_close( &audio->fifo_raw );+        if( audio->fifo_sync )+            hb_fifo_close( &audio->fifo_sync );+        if( audio->fifo_out )+            hb_fifo_close( &audio->fifo_out );     }      if( job->indepth_scan )Index: libhb/scan.c===================================================================--- libhb/scan.c	(revision 1318)+++ libhb/scan.c	(working copy)@@ -147,8 +147,8 @@ 			for( j = 0; j < hb_list_count( title->list_audio ); ) 			{ 				audio = hb_list_item( title->list_audio, j );-				if( audio->codec == HB_ACODEC_AC3 &&-					!audio->bitrate )+				if( audio->in.codec == HB_ACODEC_AC3 &&+					!audio->in.bitrate ) 				{ 					hb_list_rem( title->list_audio, audio ); 					free( audio );@@ -162,11 +162,11 @@         for( j = 0; j < hb_list_count( title->list_audio ); )         {             audio = hb_list_item( title->list_audio, j );-            if( ( audio->codec == HB_ACODEC_AC3 || audio->codec == HB_ACODEC_DCA ) &&-                !audio->bitrate )+            if( ( audio->in.codec == HB_ACODEC_AC3 || audio->in.codec == HB_ACODEC_DCA ) &&+                !audio->in.bitrate )             {                 hb_log( "scan: removing audio with codec of 0x%x because of no bitrate",-                    audio->codec );+                    audio->in.codec );                 hb_list_rem( title->list_audio, audio );                 free( audio );                 continue;@@ -188,7 +188,7 @@         for( j = 0; j < hb_list_count( title->list_audio ); j++ )         {             audio = hb_list_item( title->list_audio, j );-            if( audio->codec == HB_ACODEC_LPCM || audio->codec == HB_ACODEC_MPGA )+            if( audio->in.codec == HB_ACODEC_LPCM || audio->in.codec == HB_ACODEC_MPGA )             {                 audio->input_channel_layout = HB_INPUT_CH_LAYOUT_STEREO;             }@@ -201,6 +201,7 @@     for( i = 0; i < hb_list_count( data->list_title ); i++ )     {         hb_job_t * job;+        hb_audio_t * audio;          title      = hb_list_item( data->list_title, i );         job        = calloc( sizeof( hb_job_t ), 1 );@@ -247,13 +248,15 @@         job->vrate      = title->rate;         job->vrate_base = title->rate_base; -        job->audios[0] = 0;-        job->audios[1] = -1;+        audio = hb_audio_copy(hb_list_item(title->list_audio, 0));+        audio->in.track = 0;+        audio->out.track = 0;+        audio->out.codec = HB_ACODEC_FAAC;+        audio->out.bitrate = 128;+        audio->out.samplerate = 44100;+        job->list_audio = hb_list_init();+        hb_list_add(job->list_audio, audio); -        job->acodec   = HB_ACODEC_FAAC;-        job->abitrate = 128;-        job->arate    = 44100;-         job->subtitle = -1;          job->mux = HB_MUX_MP4;@@ -553,7 +556,7 @@     {         audio = hb_list_item( title->list_audio, i );         /* check if we have an AC3 or DCA which we recognise */-        if( ( audio->codec == HB_ACODEC_AC3 || audio->codec == HB_ACODEC_DCA ) &&+        if( ( audio->in.codec == HB_ACODEC_AC3 || audio->in.codec == HB_ACODEC_DCA ) &&             audio->id    == b->id )         {             break;@@ -568,7 +571,7 @@         return;     } -    if( audio->bitrate )+    if( audio->in.bitrate )     {         /* Already done for this track */         return;@@ -577,15 +580,15 @@     for( i = 0; i < b->size - 7; i++ )     { -        if ( audio->codec == HB_ACODEC_AC3 )+        if ( audio->in.codec == HB_ACODEC_AC3 )         {              /* check for a52 */             if( a52_syncinfo( &b->data[i], &flags, &rate, &bitrate ) )             {                 hb_log( "scan: AC3, rate=%dHz, bitrate=%d", rate, bitrate );-                audio->rate    = rate;-                audio->bitrate = bitrate;+                audio->in.samplerate = rate;+                audio->in.bitrate = bitrate;                 switch( flags & A52_CHANNEL_MASK )                 {                     /* mono sources */@@ -637,14 +640,14 @@                 audio->config.a52.ac3flags = flags;                  /* store the ac3 flags in the public ac3flags property too, so we can access it from the GUI */-                audio->ac3flags = audio->config.a52.ac3flags;+                audio->flags.ac3 = audio->config.a52.ac3flags;                  /* XXX */                 if ( (flags & A52_CHANNEL_MASK) == A52_DOLBY ) {-                    sprintf( audio->lang + strlen( audio->lang ),+                    sprintf( audio->lang.description + strlen( audio->lang.description ),                          " (Dolby Surround)" );                 } else {-                    sprintf( audio->lang + strlen( audio->lang ),+                    sprintf( audio->lang.description + strlen( audio->lang.description ),                          " (%d.%d ch)",                         HB_INPUT_CH_LAYOUT_GET_DISCRETE_FRONT_COUNT(audio->input_channel_layout) +                         HB_INPUT_CH_LAYOUT_GET_DISCRETE_REAR_COUNT(audio->input_channel_layout),@@ -656,7 +659,7 @@             }          }-        else if ( audio->codec == HB_ACODEC_DCA )+        else if ( audio->in.codec == HB_ACODEC_DCA )         {              hb_log( "scan: checking for DCA syncinfo" );@@ -666,8 +669,8 @@             if( dca_syncinfo( state, &b->data[i], &flags, &rate, &bitrate, &frame_length ) )             {                 hb_log( "scan: DCA, rate=%dHz, bitrate=%d", rate, bitrate );-                audio->rate    = rate;-                audio->bitrate = bitrate;+                audio->in.samplerate    = rate;+                audio->in.bitrate = bitrate;                 switch( flags & DCA_CHANNEL_MASK )                 {                     /* mono sources */@@ -718,14 +721,14 @@                 audio->config.dca.dcaflags = flags;                  /* store the dca flags in the public dcaflags property too, so we can access it from the GUI */-                audio->dcaflags = audio->config.dca.dcaflags;+                audio->flags.dca = audio->config.dca.dcaflags;                  /* XXX */                 if ( (flags & DCA_CHANNEL_MASK) == DCA_DOLBY ) {-                    sprintf( audio->lang + strlen( audio->lang ),+                    sprintf( audio->lang.description + strlen( audio->lang.description ),                          " (Dolby Surround)" );                 } else {-                    sprintf( audio->lang + strlen( audio->lang ),+                    sprintf( audio->lang.description + strlen( audio->lang.description ),                          " (%d.%d ch)",                         HB_INPUT_CH_LAYOUT_GET_DISCRETE_FRONT_COUNT(audio->input_channel_layout) +                         HB_INPUT_CH_LAYOUT_GET_DISCRETE_REAR_COUNT(audio->input_channel_layout),@@ -747,8 +750,8 @@     for( i = 0; i < hb_list_count( title->list_audio ); i++ )     {         audio = hb_list_item( title->list_audio, i );-        if( ( audio->codec == HB_ACODEC_AC3 || audio->codec == HB_ACODEC_DCA ) &&-            !audio->bitrate )+        if( ( audio->in.codec == HB_ACODEC_AC3 || audio->in.codec == HB_ACODEC_DCA ) &&+            !audio->in.bitrate )         {             return 0;         }Index: libhb/muxmkv.c===================================================================--- libhb/muxmkv.c	(revision 1318)+++ libhb/muxmkv.c	(working copy)@@ -29,6 +29,7 @@     mk_Track  * track;     uint64_t  prev_chapter_tc;     uint16_t  current_chapter;+    int       codec; };  /**********************************************************************@@ -138,7 +139,9 @@         mux_data = malloc( sizeof( hb_mux_data_t ) );         audio->mux_data = mux_data; -        switch (job->acodec)+        mux_data->codec = audio->out.codec;++        switch (audio->out.codec)         {             case HB_ACODEC_AC3:                 track->codecPrivate = NULL;@@ -173,22 +176,13 @@                 }                 break;             case HB_ACODEC_FAAC:-                if( job->audio_mixdowns[i] == HB_AMIXDOWN_AC3 )-                {-                    track->codecPrivate = NULL;-                    track->codecPrivateSize = 0;-                    track->codecID = MK_ACODEC_AC3; -                }-                else-                {-                    track->codecPrivate = audio->config.aac.bytes;-                    track->codecPrivateSize = audio->config.aac.length;-                    track->codecID = MK_ACODEC_AAC;-                }+                track->codecPrivate = audio->config.aac.bytes;+                track->codecPrivateSize = audio->config.aac.length;+                track->codecID = MK_ACODEC_AAC;                 break;             default:                 *job->die = 1;-                hb_error("muxmkv: Unknown audio codec: %x", job->acodec);+                hb_error("muxmkv: Unknown audio codec: %x", audio->out.codec);                 return 0;         } @@ -199,12 +193,12 @@         }         track->flagEnabled = 1;         track->trackType = MK_TRACK_AUDIO;-        track->language = audio->iso639_2;-        track->extra.audio.samplingFreq = (float)job->arate;-        track->extra.audio.channels = (job->acodec == HB_ACODEC_AC3 || job->audio_mixdowns[i] == HB_AMIXDOWN_AC3  ) ? HB_INPUT_CH_LAYOUT_GET_DISCRETE_COUNT(audio->input_channel_layout) : HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->amixdown);+        track->language = audio->lang.iso639_2;+        track->extra.audio.samplingFreq = (float)audio->out.samplerate;+        track->extra.audio.channels = (audio->out.codec == HB_ACODEC_AC3 ) ? HB_INPUT_CH_LAYOUT_GET_DISCRETE_COUNT(audio->input_channel_layout) : HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->out.mixdown); //        track->defaultDuration = job->arate * 1000;         mux_data->track = mk_createTrack(m->file, track);-        if (job->acodec == HB_ACODEC_VORBIS && track->codecPrivate != NULL)+        if (audio->out.codec == HB_ACODEC_VORBIS && track->codecPrivate != NULL)           free(track->codecPrivate);     } @@ -269,7 +263,7 @@     {         /* Audio */         timecode = buf->start * TIMECODE_SCALE;-        if (job->acodec == HB_ACODEC_VORBIS)+        if (mux_data->codec == HB_ACODEC_VORBIS)         {             /* ughhh, vorbis is a pain :( */             ogg_packet  *op;Index: libhb/common.c===================================================================--- libhb/common.c	(revision 1318)+++ libhb/common.c	(working copy)@@ -43,9 +43,7 @@   { "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       },-  { "AC-3 Pass-through",  "HB_AMIXDOWN_AC3",       "ac-3",   HB_AMIXDOWN_AC3       },-  { "Dolby Pro Logic II + AC-3",  "HB_AMIXDOWN_DOLBYPLII_AC3", "dpl2+ac3", HB_AMIXDOWN_DOLBYPLII_AC3 },+  { "6-channel discrete", "HB_AMIXDOWN_6CH",       "6ch",    HB_AMIXDOWN_6CH       } }; int hb_audio_mixdowns_count = sizeof( hb_audio_mixdowns ) /                               sizeof( hb_mixdown_t );@@ -193,23 +191,6 @@             return 0;     } -    /* How many audio samples we put in each frame */-    switch( job->acodec )-    {-        case HB_ACODEC_FAAC:-        case HB_ACODEC_VORBIS:-            samples_per_frame = 1024;-            break;-        case HB_ACODEC_LAME:-            samples_per_frame = 1152;-            break;-        case HB_ACODEC_AC3:-            samples_per_frame = 1536;-            break;-        default:-            return 0;-    }-     /* Get the duration in seconds */     length = 0;     for( i = job->chapter_start; i <= job->chapter_end; i++ )@@ -223,19 +204,37 @@     /* Video overhead */     avail -= length * job->vrate * overhead / job->vrate_base; -    for( i = 0; job->audios[i] >= 0; i++ )+    for( i = 0; i < hb_list_count(job->list_audio); i++ )     {         /* Audio data */         int abitrate;-        if( job->acodec & HB_ACODEC_AC3 ||-            job->audio_mixdowns[i] == HB_AMIXDOWN_AC3)+        audio = hb_list_item( job->list_audio, i);++        /* How many audio samples we put in each frame */+        switch( audio->out.codec )         {+            case HB_ACODEC_FAAC:+            case HB_ACODEC_VORBIS:+                samples_per_frame = 1024;+                break;+            case HB_ACODEC_LAME:+                samples_per_frame = 1152;+                break;+            case HB_ACODEC_AC3:+                samples_per_frame = 1536;+                break;+            default:+                return 0;+        }++        if( audio->out.codec == HB_ACODEC_AC3 ||+            audio->out.codec == HB_ACODEC_DCA)+        {             /*-             * For AC-3 we take the bitrate from the input audio+             * For pass through we take the bitrate from the input audio              * bitrate as we are simply passing it through.              */-            audio = hb_list_item( title->list_audio, job->audios[i] );-            abitrate = audio->bitrate / 8;+            abitrate = audio->in.bitrate / 8;         }         else         {@@ -243,12 +242,12 @@              * Where we are transcoding the audio we use the destination              * bitrate.              */-            abitrate = job->abitrate * 1000 / 8;+            abitrate = audio->out.bitrate * 1000 / 8;         }         avail -= length * abitrate;          /* Audio overhead */-        avail -= length * job->arate * overhead / samples_per_frame;+        avail -= length * audio->out.samplerate * overhead / samples_per_frame;     }      if( avail < 0 )@@ -645,3 +644,33 @@     *_f = NULL; } +/**********************************************************************+ * hb_audio_copy+ **********************************************************************+ *+ *********************************************************************/+hb_audio_t *hb_audio_copy(const hb_audio_t *src)+{+    hb_audio_t *audio = hb_audio_new();+    memcpy(audio, src, sizeof(*audio));+    return audio;+}++/**********************************************************************+ * hb_audio_new+ **********************************************************************+ *+ *********************************************************************/+hb_audio_t *hb_audio_new(void)+{+    hb_audio_t *audio = calloc(1, sizeof(*audio));+    /* Initalize some sensable defaults */+    audio->in.codec = HB_ACODEC_NONE;+    audio->out.codec = HB_ACODEC_FAAC;+    audio->out.bitrate = 128;+    audio->out.samplerate = 44100;+    audio->out.mixdown = HB_AMIXDOWN_DOLBYPLII;+    audio->out.dynamic_range_compression = 0;++    return audio;+}Index: libhb/encvorbis.c===================================================================--- libhb/encvorbis.c	(revision 1318)+++ libhb/encvorbis.c	(working copy)@@ -44,13 +44,14 @@  int encvorbisInit( hb_work_object_t * w, hb_job_t * job ) {+    hb_audio_t * audio = w->audio;     int i;     ogg_packet header[3];     struct ovectl_ratemanage2_arg  ctl_rate_arg;      hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );     w->private_data = pv;-    pv->out_discrete_channels = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(w->amixdown);+    pv->out_discrete_channels = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->out.mixdown);      pv->job   = job; @@ -58,17 +59,18 @@      /* 28kbps/channel seems to be the minimum for 6ch vorbis. */     int min_bitrate = 28 * pv->out_discrete_channels;-    if (pv->out_discrete_channels > 2 && job->abitrate < min_bitrate)+    if (pv->out_discrete_channels > 2 && audio->out.bitrate < min_bitrate)     {-        hb_log( "encvorbis: Selected bitrate (%d kbps) too low for %d channel audio.", job->abitrate, pv->out_discrete_channels);+        hb_log( "encvorbis: Selected bitrate (%d kbps) too low for %d channel audio.", audio->out.bitrate, pv->out_discrete_channels);         hb_log( "encvorbis: Resetting bitrate to %d kbps", min_bitrate);-        job->abitrate = min_bitrate;+        /* Naughty! We shouldn't modify the audio from here. */+        audio->out.bitrate = min_bitrate;     }      /* init */     vorbis_info_init( &pv->vi );     if( vorbis_encode_setup_managed( &pv->vi, pv->out_discrete_channels,-          job->arate, -1, 1000 * job->abitrate, -1 ) )+          audio->out.samplerate, -1, 1000 * audio->out.bitrate, -1 ) )     {         hb_error( "encvorbis: vorbis_encode_setup_managed failed.\n" );         *job->die = 1;@@ -80,7 +82,7 @@         hb_log( "encvorbis: vorbis_encode_ctl( ratemanage2_get ) failed" );     } -    ctl_rate_arg.bitrate_average_kbps = job->abitrate;+    ctl_rate_arg.bitrate_average_kbps = audio->out.bitrate;     ctl_rate_arg.management_active = 1;      if( vorbis_encode_ctl( &pv->vi, OV_ECTL_RATEMANAGE2_SET, &ctl_rate_arg ) ||Index: libhb/common.h===================================================================--- libhb/common.h	(revision 1318)+++ libhb/common.h	(working copy)@@ -70,6 +70,41 @@  int hb_calc_bitrate( hb_job_t *, int size ); +hb_audio_t *hb_audio_copy(const hb_audio_t *src);+hb_audio_t *hb_audio_new();++/* Video codecs */+typedef enum {+    HB_VCODEC_NONE,+    HB_VCODEC_FFMPEG,+    HB_VCODEC_XVID,+    HB_VCODEC_X264+} hb_vcodec_t;++/* Muxers */+typedef enum {+    HB_MUX_NONE,+    HB_MUX_MP4,+    HB_MUX_PSP,+    HB_MUX_AVI,+    HB_MUX_OGM,+    HB_MUX_IPOD,+    HB_MUX_MKV+} hb_format_t;++/* Audio codecs */+typedef enum+{+    HB_ACODEC_NONE,+    HB_ACODEC_FAAC,+    HB_ACODEC_LAME,+    HB_ACODEC_VORBIS,+    HB_ACODEC_AC3,+    HB_ACODEC_MPGA,+    HB_ACODEC_LPCM,+    HB_ACODEC_DCA+} hb_acodec_t;+ struct hb_rate_s {     char * string;@@ -156,12 +191,7 @@          crf:               boolean for whether to use constant rate factor with x264          x264opts:          string of extra x264 options          areBframes:        boolean to note if b-frames are included in x264opts */-#define HB_VCODEC_MASK   0x0000FF-#define HB_VCODEC_FFMPEG 0x000001-#define HB_VCODEC_XVID   0x000002-#define HB_VCODEC_X264   0x000004--    int             vcodec;+    hb_vcodec_t     vcodec;     float           vquality;     int             vbitrate;     int             vrate;@@ -174,77 +204,9 @@     int             areBframes;     int             vfr; -    /* Audio tracks:-         audios:          Indexes in hb_title_t's audios list, starting from 0.-                          -1 indicates the end of the list-        audio_mixdowns:  The mixdown to be used for each audio track in audios[] */+    /* List of audio settings. */+    hb_list_t     * list_audio; -/* define some masks, used to extract the various information from the HB_AMIXDOWN_XXXX values */-#define HB_AMIXDOWN_DCA_FORMAT_MASK             0x00FFF000-#define HB_AMIXDOWN_A52_FORMAT_MASK             0x00000FF0-#define HB_AMIXDOWN_DISCRETE_CHANNEL_COUNT_MASK 0x0000000F--/* define the HB_AMIXDOWN_XXXX values */--#define HB_AMIXDOWN_MONO                        0x01000001-// DCA_FORMAT of DCA_MONO                  = 0    = 0x000-// A52_FORMAT of A52_MONO                  = 1    = 0x01-// discrete channel count of 1--#define HB_AMIXDOWN_STEREO                      0x02002022-// DCA_FORMAT of DCA_STEREO                = 2    = 0x002-// A52_FORMAT of A52_STEREO                = 2    = 0x02-// discrete channel count of 2--#define HB_AMIXDOWN_DOLBY                       0x042070A2-// DCA_FORMAT of DCA_3F1R | DCA_OUT_DPLI   = 519  = 0x207-// A52_FORMAT of A52_DOLBY                 = 10   = 0x0A-// discrete channel count of 2--#define HB_AMIXDOWN_DOLBYPLII                   0x084094A2-// DCA_FORMAT of DCA_3F2R | DCA_OUT_DPLII  = 1033 = 0x409-// A52_FORMAT of A52_DOLBY | A52_USE_DPLII = 74   = 0x4A-// discrete channel count of 2--#define HB_AMIXDOWN_6CH                         0x10089176-// DCA_FORMAT of DCA_3F2R | DCA_LFE        = 137  = 0x089-// A52_FORMAT of A52_3F2R | A52_LFE        = 23   = 0x17-// discrete channel count of 6--#define HB_AMIXDOWN_AC3                         0x20000000--#define HB_AMIXDOWN_DOLBYPLII_AC3               0x404094A2-// DCA_FORMAT of DCA_3F2R | DCA_OUT_DPLII  = 1033 = 0x409-// A52_FORMAT of A52_DOLBY | A52_USE_DPLII = 74   = 0x4A-// discrete channel count of 2--/* define some macros to extract the various information from the HB_AMIXDOWN_XXXX values */-#define HB_AMIXDOWN_GET_DCA_FORMAT( a ) ( ( a & HB_AMIXDOWN_DCA_FORMAT_MASK ) >> 12 )-#define HB_AMIXDOWN_GET_A52_FORMAT( a ) ( ( a & HB_AMIXDOWN_A52_FORMAT_MASK ) >> 4 )-#define HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT( a ) ( ( a & HB_AMIXDOWN_DISCRETE_CHANNEL_COUNT_MASK ) )--    int             audios[8];-	int             audio_mixdowns[8];--    /* Audio settings:-         acodec:   output codec-         abitrate: output bitrate (kbps)-         arate:    output samplerate (Hz)-       HB_ACODEC_AC3 means pass-through, then abitrate and arate are-       ignored */-#define HB_ACODEC_MASK   0x00FF00-#define HB_ACODEC_FAAC   0x000100-#define HB_ACODEC_LAME   0x000200-#define HB_ACODEC_VORBIS 0x000400-#define HB_ACODEC_AC3    0x000800-#define HB_ACODEC_MPGA   0x001000-#define HB_ACODEC_LPCM   0x002000-#define HB_ACODEC_DCA    0x004000-    int             acodec;-    int             abitrate;-    int             arate;-    float           dynamic_range_compression;-     /* Subtitle settings:          subtitle: index in hb_title_t's subtitles list, starting          from 0. -1 means no subtitle */@@ -254,15 +216,7 @@     /* Muxer settings          mux:  output file format          file: file path */-#define HB_MUX_MASK 0xFF0000-#define HB_MUX_MP4  0x010000-#define HB_MUX_PSP  0x020000-#define HB_MUX_AVI  0x040000-#define HB_MUX_OGM  0x080000-#define HB_MUX_IPOD 0x100000-#define HB_MUX_MKV  0x200000--    int             mux;+    hb_format_t      mux;     const char          * file;      /* Allow MP4 files > 4 gigs */@@ -299,22 +253,38 @@ #endif }; -struct hb_audio_s-{-    int  id;-    char lang[1024];-    char lang_simple[1024];-    char iso639_2[4];-    int  codec;-    int  rate;-    int  bitrate;+/* Audio Mixdown */+/* define some masks, used to extract the various information from the HB_AMIXDOWN_XXXX values */+#define HB_AMIXDOWN_DCA_FORMAT_MASK             0x00FFF000+#define HB_AMIXDOWN_A52_FORMAT_MASK             0x00000FF0+#define HB_AMIXDOWN_DISCRETE_CHANNEL_COUNT_MASK 0x0000000F+/* define the HB_AMIXDOWN_XXXX values */+#define HB_AMIXDOWN_MONO                        0x01000001+// DCA_FORMAT of DCA_MONO                  = 0    = 0x000+// A52_FORMAT of A52_MONO                  = 1    = 0x01+// discrete channel count of 1+#define HB_AMIXDOWN_STEREO                      0x02002022+// DCA_FORMAT of DCA_STEREO                = 2    = 0x002+// A52_FORMAT of A52_STEREO                = 2    = 0x02+// discrete channel count of 2+#define HB_AMIXDOWN_DOLBY                       0x042070A2+// DCA_FORMAT of DCA_3F1R | DCA_OUT_DPLI   = 519  = 0x207+// A52_FORMAT of A52_DOLBY                 = 10   = 0x0A+// discrete channel count of 2+#define HB_AMIXDOWN_DOLBYPLII                   0x084094A2+// DCA_FORMAT of DCA_3F2R | DCA_OUT_DPLII  = 1033 = 0x409+// A52_FORMAT of A52_DOLBY | A52_USE_DPLII = 74   = 0x4A+// discrete channel count of 2+#define HB_AMIXDOWN_6CH                         0x10089176+// DCA_FORMAT of DCA_3F2R | DCA_LFE        = 137  = 0x089+// A52_FORMAT of A52_3F2R | A52_LFE        = 23   = 0x17+// discrete channel count of 6+/* define some macros to extract the various information from the HB_AMIXDOWN_XXXX values */+#define HB_AMIXDOWN_GET_DCA_FORMAT( a ) ( ( a & HB_AMIXDOWN_DCA_FORMAT_MASK ) >> 12 )+#define HB_AMIXDOWN_GET_A52_FORMAT( a ) ( ( a & HB_AMIXDOWN_A52_FORMAT_MASK ) >> 4 )+#define HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT( a ) ( ( a & HB_AMIXDOWN_DISCRETE_CHANNEL_COUNT_MASK ) ) -    /* ac3flags is only set when the source audio format is HB_ACODEC_AC3 */-    int ac3flags;--    /* dcaflags is only set when the source audio format is HB_ACODEC_DCA */-    int dcaflags;-+/* Input Channel Layout */ /* define some masks, used to extract the various information from the HB_AMIXDOWN_XXXX values */ #define HB_INPUT_CH_LAYOUT_DISCRETE_FRONT_MASK  0x00F0000 #define HB_INPUT_CH_LAYOUT_DISCRETE_REAR_MASK   0x000F000@@ -322,7 +292,6 @@ #define HB_INPUT_CH_LAYOUT_DISCRETE_NO_LFE_MASK 0xFFFF0FF #define HB_INPUT_CH_LAYOUT_ENCODED_FRONT_MASK   0x00000F0 #define HB_INPUT_CH_LAYOUT_ENCODED_REAR_MASK    0x000000F- /* define the input channel layouts used to describe the channel layout of this audio */ #define HB_INPUT_CH_LAYOUT_MONO    0x0110010 #define HB_INPUT_CH_LAYOUT_STEREO  0x0220020@@ -334,7 +303,6 @@ #define HB_INPUT_CH_LAYOUT_3F2R    0x0832032 #define HB_INPUT_CH_LAYOUT_4F2R    0x0942042 #define HB_INPUT_CH_LAYOUT_HAS_LFE 0x0000100- /* define some macros to extract the various information from the HB_AMIXDOWN_XXXX values */ #define HB_INPUT_CH_LAYOUT_GET_DISCRETE_FRONT_COUNT( a ) ( ( a & HB_INPUT_CH_LAYOUT_DISCRETE_FRONT_MASK ) >> 16 ) #define HB_INPUT_CH_LAYOUT_GET_DISCRETE_REAR_COUNT( a )  ( ( a & HB_INPUT_CH_LAYOUT_DISCRETE_REAR_MASK ) >> 12 )@@ -343,12 +311,55 @@ #define HB_INPUT_CH_LAYOUT_GET_ENCODED_FRONT_COUNT( a )   ( ( a & HB_INPUT_CH_LAYOUT_ENCODED_FRONT_MASK ) >> 4 ) #define HB_INPUT_CH_LAYOUT_GET_ENCODED_REAR_COUNT( a )   ( ( a & HB_INPUT_CH_LAYOUT_ENCODED_REAR_MASK ) ) -	/* input_channel_layout is the channel layout of this audio */-	/* this is used to provide a common way of describing the source audio */-	int input_channel_layout;+struct hb_audio_s+{+    /* Input */+    struct+    {+        int track;      /* Input track number */+        hb_acodec_t codec;      /* Input audio codec */+        int samplerate; /* Input sample rate (Hz) */+        int bitrate;    /* Input bitrate (kbps) */+    } in; +    /* Output */+    struct+    {+        int track;      /* Output track number */+        hb_acodec_t codec;  /* Output audio codec.+                             * HB_ACODEC_AC3 means pass-through, then bitrate and samplerate+                             * are ignored.+                             */+        int samplerate; /* Output sample rate (Hz) */+        int bitrate;    /* Output bitrate (kbps) */+        int mixdown;    /* The mixdown format to be used for this audio track (see HB_AMIXDOWN_*) */+        double dynamic_range_compression; /* Amount of DRC that gets applied to this track */+    } out;++    /* Misc. */+    union+    {+        int ac3;    /* flags.ac3 is only set when the source audio format is HB_ACODEC_AC3 */+        int dca;    /* flags.dca is only set when the source audio format is HB_ACODEC_DCA */+    } flags;++    struct+    {+        char description[1024];+        char simple[1024];+        char iso639_2[4];+    } lang;+ #ifdef __LIBHB__     /* Internal data */+    /* Input */+    int  id;+    /* input_channel_layout is the channel layout of this audio+     * this is used to provide a common way of describing the source audio+     */+    int input_channel_layout;++    /* Misc. */     hb_fifo_t * fifo_in;   /* AC3/MPEG/LPCM ES */     hb_fifo_t * fifo_raw;  /* Raw audio */     hb_fifo_t * fifo_sync; /* Resampled, synced raw audio */@@ -356,9 +367,6 @@      hb_esconfig_t config;     hb_mux_data_t * mux_data;--	/* amixdown is the mixdown format to be used for this audio track */-   	int amixdown; #endif }; @@ -477,7 +485,9 @@             /* HB_STATE_WORKDONE */ #define HB_ERROR_NONE     0 #define HB_ERROR_CANCELED 1-#define HB_ERROR_UNKNOWN  2+#define HB_ERROR_INVALID_VCODEC 0x02+#define HB_ERROR_INVALID_ACODEC 0x04+#define HB_ERROR_UNKNOWN        0x08             int error;         } workdone; @@ -504,10 +514,8 @@     hb_fifo_t         * fifo_out;     hb_esconfig_t     * config; -	/* amixdown is the mixdown format to be used if the work object is an audio track */-   	int               amixdown;-    /* source_acodec is the source audio codec if the work object is an audio track */-    int               source_acodec;+    /* Pointer hb_audio_t so we have access to the info in the audio worker threads. */+    hb_audio_t *audio;      hb_work_private_t * private_data;