All pastes #967566 Raw Edit

someone

public diff v1 · immutable
·published 2008-04-02 14:43 UTC
rendered paste body
Index: libhb/decmpeg2.c===================================================================--- libhb/decmpeg2.c	(revision 1368)+++ libhb/decmpeg2.c	(working copy)@@ -100,28 +100,18 @@                 m->width  = m->info->sequence->width;                 m->height = m->info->sequence->height;                 m->rate   = m->info->sequence->frame_period;-            }-            if ( m->aspect_ratio <= 0 )-            {-              // We can parse out the aspect ratio from the Sequence Start Header data in buf_es->data--              // Make sure we have the correct data in the buffer-              if ((buf_es->data[0] == 0x00) && (buf_es->data[1] == 0x00) && (buf_es->data[2] == 0x01) && (buf_es->data[3] == 0xb3))-              {-                unsigned char ar_fr = buf_es->data[7];    // Top 4 bits == aspect ratio flag  - bottom 4 bits == rate flags-                switch ((ar_fr & 0xf0) >> 4)+                if ( m->aspect_ratio <= 0 && m->height &&+                     m->info->sequence->pixel_height )                 {-                  case 2:-                    m->aspect_ratio = HB_ASPECT_BASE * 4 / 3;   // 4:3-                    break;-                  case 3:-                    m->aspect_ratio = HB_ASPECT_BASE * 16 / 9;  // 16:9-                    break;-                  default:-                    hb_log("hb_libmpeg2_decode - STATE_SEQUENCE unexpected aspect ratio/frame rate 0x%x\n", ar_fr);-                    break;+                    /* mpeg2_parse doesn't store the aspect ratio. Instead+                     * it keeps the pixel width & height that would cause+                     * the storage width & height to come out in the correct+                     * aspect ratio. Convert these back to aspect ratio.+                     */+                    m->aspect_ratio = ( m->width * m->info->sequence->pixel_width *+                                       HB_ASPECT_BASE ) / m->height /+                                       m->info->sequence->pixel_height;                 }-              }             }         }         else if( state == STATE_GOP && m->look_for_break == 2)Index: libhb/stream.c===================================================================--- libhb/stream.c	(revision 1368)+++ libhb/stream.c	(working copy)@@ -756,6 +756,26 @@   return 1; } +static void set_audio_description( hb_audio_t *audio, iso639_lang_t *lang )+{+    /* XXX+     * This is a duplicate of code in dvd.c - it should get factored out+     * into a common routine. We probably should only be putting the lang+     * code or a lang pointer into the audio config & let the common description+     * formatting routine in scan.c do all the stuff below.+     */+    snprintf( audio->config.lang.description,+              sizeof( audio->config.lang.description ), "%s (%s)",+              strlen(lang->native_name) ? lang->native_name : lang->eng_name,+              audio->config.in.codec == HB_ACODEC_AC3 ? "AC3" :+                  audio->config.in.codec == HB_ACODEC_DCA ? "DTS" :+                      audio->config.in.codec == HB_ACODEC_MPGA ? "MPEG" : "LPCM" );+    snprintf( audio->config.lang.simple, sizeof( audio->config.lang.simple ), "%s",+              strlen(lang->native_name) ? lang->native_name : lang->eng_name );+    snprintf( audio->config.lang.iso639_2, sizeof( audio->config.lang.iso639_2 ),+              "%s", lang->iso639_2);+}+ static hb_audio_t *hb_ts_stream_set_audio_id_and_codec(hb_stream_t *stream,                                                        int aud_pid_index) {@@ -794,8 +814,13 @@         }     }     fseeko(stream->file_handle, cur_pos, SEEK_SET);-    if (! audio->config.in.codec)+    if ( audio->config.in.codec )     {+		set_audio_description( audio,+                  lang_for_code( stream->a52_info[aud_pid_index].lang_code ) );+    }+    else+    {         hb_log("transport stream pid 0x%x (type 0x%x) isn't audio",                 stream->ts_audio_pids[aud_pid_index],                 stream->ts_audio_stream_type[1 + aud_pid_index]);@@ -832,6 +857,7 @@             return;      }+    set_audio_description( audio, lang_for_code( 0 ) );     hb_list_add( title->list_audio, audio ); } @@ -884,121 +910,6 @@ }  /***********************************************************************- * hb_stream_update_audio- ***********************************************************************- *- **********************************************************************/-void hb_stream_update_audio(hb_stream_t *stream, hb_audio_t *audio)-{-	iso639_lang_t *lang;--    if (stream->stream_type == hb_stream_type_transport)-	{-        // Find the audio stream info for this PID. The stream index is-        // the subchannel id which is in the bottom four bits for MPEG audio-        // and the bottom four bits of the upper byte for everything else.-        int i = ( audio->id >= 0xd0 ? audio->id >> 8 : audio->id ) & 0xf;-        if (i >= stream->ts_number_audio_pids)-		{-            hb_log("hb_stream_update_audio: no PID for audio stream 0x%x",-                    audio->id);-			return;-		}-        if (audio->id < 0xd0)-        {-            /* XXX fake mpeg audio sample rate & bps */-            stream->a52_info[i].flags = A52_STEREO;-            stream->a52_info[i].rate = 48000 /*Hz*/;-            stream->a52_info[i].bitrate = 384000 /*Bps*/;-        }--		lang = lang_for_code(stream->a52_info[i].lang_code);-        if (!audio->config.in.samplerate)-            audio->config.in.samplerate = stream->a52_info[i].rate;-        if (!audio->config.in.bitrate)-            audio->config.in.bitrate = stream->a52_info[i].bitrate;-        if (!audio->priv.config.a52.ac3flags)-            audio->priv.config.a52.ac3flags = audio->config.flags.ac3 = stream->a52_info[i].flags;--	}-    else-    {-        // XXX should try to get language code from the AC3 bitstream-        lang = lang_for_code(0x0000);-    }--	if (!audio->config.in.channel_layout)-	{-		switch( audio->config.flags.ac3 & A52_CHANNEL_MASK )-		{-			/* mono sources */-			case A52_MONO:-			case A52_CHANNEL1:-			case A52_CHANNEL2:-				audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_MONO;-				break;-			/* stereo input */-			case A52_CHANNEL:-			case A52_STEREO:-				audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_STEREO;-				break;-			/* dolby (DPL1 aka Dolby Surround = 4.0 matrix-encoded) input */-			case A52_DOLBY:-				audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_DOLBY;-				break;-			/* 3F/2R input */-			case A52_3F2R:-				audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_3F2R;-				break;-			/* 3F/1R input */-			case A52_3F1R:-				audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_3F1R;-				break;-			/* other inputs */-			case A52_3F:-				audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_3F;-				break;-			case A52_2F1R:-				audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_2F1R;-				break;-			case A52_2F2R:-				audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_2F2R;-				break;-			/* unknown */-			default:-				audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_STEREO;-		}--		/* add in our own LFE flag if the source has LFE */-		if (audio->config.flags.ac3 & A52_LFE)-		{-			audio->config.in.channel_layout = audio->config.in.channel_layout | HB_INPUT_CH_LAYOUT_HAS_LFE;-		}-	}--    snprintf( audio->config.lang.description, sizeof( audio->config.lang.description ), "%s (%s)", strlen(lang->native_name) ? lang->native_name : lang->eng_name,-	  audio->config.in.codec == HB_ACODEC_AC3 ? "AC3" : ( audio->config.in.codec == HB_ACODEC_MPGA ? "MPEG" : ( audio->config.in.codec == HB_ACODEC_DCA ? "DTS" : "LPCM" ) ) );-	snprintf( audio->config.lang.simple, sizeof( audio->config.lang.simple ), "%s", strlen(lang->native_name) ? lang->native_name : lang->eng_name );-	snprintf( audio->config.lang.iso639_2, sizeof( audio->config.lang.iso639_2 ), "%s", lang->iso639_2);--	if ( (audio->config.flags.ac3 & A52_CHANNEL_MASK) == A52_DOLBY ) {-        sprintf( audio->config.lang.description + strlen( audio->config.lang.description ),-			 " (Dolby Surround)" );-	} else {-        sprintf( audio->config.lang.description + strlen( audio->config.lang.description ),-			 " (%d.%d ch)",-			HB_INPUT_CH_LAYOUT_GET_DISCRETE_FRONT_COUNT(audio->config.in.channel_layout) +-			HB_INPUT_CH_LAYOUT_GET_DISCRETE_REAR_COUNT(audio->config.in.channel_layout),-			HB_INPUT_CH_LAYOUT_GET_DISCRETE_LFE_COUNT(audio->config.in.channel_layout));-	}--	hb_log( "stream: audio %x: lang %s, rate %d, bitrate %d, "-            "flags = 0x%x", audio->id, audio->config.lang.description, audio->config.in.samplerate,-            audio->config.in.bitrate, audio->config.flags.ac3 );--}--/***********************************************************************  * hb_ts_stream_init  ***********************************************************************  *Index: libhb/declpcm.c===================================================================--- libhb/declpcm.c	(revision 1368)+++ libhb/declpcm.c	(working copy)@@ -6,6 +6,27 @@  #include "hb.h" +struct hb_work_private_s+{+    hb_job_t    *job;+    uint32_t    size;       /* frame size in bytes */+    uint32_t    count;      /* frame size in samples */+    uint32_t    pos;        /* buffer offset for next input data */++    int64_t     next_pts;   /* pts for next output frame */+    int64_t     sequence;++    /* the following is frame info for the frame we're currently accumulating */+    uint64_t    duration;   /* frame duratin (in 90KHz ticks) */+    uint32_t    offset;     /* where in buf frame starts */+    uint32_t    samplerate; /* sample rate in bits/sec */+    uint8_t     nchannels;+    uint8_t     sample_size; /* bits per sample */++    uint8_t     frame[HB_DVD_READ_BUFFER_SIZE*2];+};++static hb_buffer_t * Decode( hb_work_object_t * w ); int  declpcmInit( hb_work_object_t *, hb_job_t * ); int  declpcmWork( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** ); void declpcmClose( hb_work_object_t * );@@ -19,72 +40,196 @@     declpcmClose }; +static const int hdr2samplerate[] = { 48000, 96000, 44100, 32000 };+static const int hdr2samplesize[] = { 16, 20, 24, 16 };++static void lpcmInfo( hb_work_object_t *w, hb_buffer_t *in )+{+    hb_work_private_t * pv = w->private_data;++    /*+     * LPCM packets have a 7 byte header (the substream id is stripped off+     * before we get here so it's numbered -1 below)::+     * byte -1  Substream id+     * byte 0   Number of frames that begin in this packet+     *          (last frame may finish in next packet)+     * byte 1,2 offset to first frame that begins in this packet (not including hdr)+     * byte 3:+     *   bits 0-4  continuity counter (increments modulo 20)+     *   bit   5   reserved+     *   bit   6   audio mute on/off+     *   bit   7   audio emphasis on/off+     * byte 4:+     *   bits 0-2  #channels - 1 (e.g., stereo = 1)+     *   bit   3   reserved+     *   bits 4-5  sample rate (0=48K,1=96K,2=44.1K,3=32K)+     *   bits 6-7  bits per sample (0=16 bit, 1=20 bit, 2=24 bit)+     * byte 5   Dynamic range control (0x80 = off)+     *+     * The audio is viewed as "frames" of 150 90KHz ticks each (80 samples @ 48KHz).+     * The frames are laid down continuously without regard to MPEG packet+     * boundaries. E.g., for 48KHz stereo, the first packet will contain 6+     * frames plus the start of the 7th, the second packet will contain the+     * end of the 7th, 8-13 & the start of 14, etc. The frame structure is+     * important because the PTS on the packet gives the time of the first+     * frame that starts in the packet *NOT* the time of the first sample +     * in the packet. Also samples get split across packet boundaries+     * so we can't assume that we can consume all the data in one packet+     * on every call to the work routine.+     */+    pv->offset = ( ( in->data[1] << 8 ) | in->data[2] ) + 2;+    if ( pv->offset >= HB_DVD_READ_BUFFER_SIZE )+    {+        hb_log( "declpcm: illegal frame offset %d", pv->offset );+        pv->offset = 2; /*XXX*/+    }+    pv->samplerate = hdr2samplerate[ ( in->data[4] >> 4 ) & 0x3 ];+    pv->nchannels  = ( in->data[4] & 7 ) + 1;+    pv->sample_size = hdr2samplesize[in->data[4] >> 6];++    /*+     * PCM frames have a constant duration (150 90KHz ticks).+     * We need to convert that to the amount of data expected.  It's the+     * duration divided by the sample rate (to get #samples) times the number+     * of channels times the bits per sample divided by 8 to get bytes.+     * (we have to compute in bits because 20 bit samples are not an integral+     * number of bytes). We do all the multiplies first then the divides to+     * avoid truncation errors. +     */+    pv->duration = in->data[0] * 150;+    pv->count = ( pv->duration * pv->nchannels * pv->samplerate ) / 90000;+    pv->size = ( pv->count * pv->sample_size ) / 8;++    pv->next_pts = in->start;+}+ int declpcmInit( hb_work_object_t * w, hb_job_t * job ) {+    hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );+    w->private_data = pv;+    pv->job   = job;     return 0; } +/* + * Convert DVD encapsulated LPCM to floating point PCM audio buffers.+ * The amount of audio in a PCM frame is always <= the amount that will fit+ * in a DVD block (2048 bytes) but the standard doesn't require that the audio+ * frames line up with the DVD frames. Since audio frame boundaries are unrelated+ * to DVD PES boundaries, this routine has to reconstruct then extract the audio+ * frames. Because of the arbitrary alignment, it can output zero, one or two buf's.+ */ int declpcmWork( hb_work_object_t * w, hb_buffer_t ** buf_in,                  hb_buffer_t ** buf_out ) {-    hb_buffer_t * in = *buf_in, * out;-    int samplerate = 0;-    int count;-    uint8_t * samples_u8;-    float   * samples_fl32;-    int i;-    uint64_t duration;+    hb_work_private_t * pv = w->private_data;+    hb_buffer_t *in;+    hb_buffer_t *buf = NULL; -    *buf_out = NULL;--    if( in->data[5] != 0x80 )+    /* need an input buffer to do anything */+    if( ! buf_in || ! ( in = *buf_in ) )     {-        hb_log( "no LPCM frame sync (%02x)", in->data[5] );+        *buf_out = buf;         return HB_WORK_OK;     } -    switch( ( in->data[4] >> 4 ) & 0x3 )+    pv->sequence = in->sequence;++    /* if we have a frame to finish, add enough data from this buf to finish it */+    if ( pv->size )     {-        case 0:-            samplerate = 48000;-            break;-        case 1:-            samplerate = 96000;//32000; /* FIXME vlc says it is 96000 */-            break;-        case 2:-            samplerate = 44100;-            break;-        case 3:-            samplerate = 32000;-            break;+        memcpy( pv->frame + pv->pos, in->data + 6, pv->size - pv->pos );+        buf = Decode( w );     }+    *buf_out = buf; -    count       = ( in->size - 6 ) / 2;-    out         = hb_buffer_init( count * sizeof( float ) );-    duration    = count * 90000 / samplerate / 2;-    out->start  = in->start;-    out->stop   = out->start + duration;+    /* save the (rest of) data from this buf in our frame buffer */+    lpcmInfo( w, in );+    int off = pv->offset;+    int amt = in->size - off;+    pv->pos = amt;+    memcpy( pv->frame, in->data + off, amt );+    if ( amt >= pv->size )+    {+        if ( buf )+        {+            buf->next = Decode( w );+        }+        else+        {+            *buf_out = Decode( w );+        }+        pv->size = 0;+    }+    return HB_WORK_OK;+} -    samples_u8   = in->data + 6;-    samples_fl32 = (float *) out->data;+static hb_buffer_t *Decode( hb_work_object_t *w )+{+    hb_work_private_t *pv = w->private_data;+    hb_buffer_t *out = hb_buffer_init( pv->count * sizeof( float ) );+ +    out->start  = pv->next_pts;+    pv->next_pts += pv->duration;+    out->stop = pv->next_pts; -    /* Big endian int16 -> float conversion */-    for( i = 0; i < count; i++ )+    uint8_t *frm = pv->frame;+    float *odat = (float *)out->data;+    int count = pv->count;++    switch( pv->sample_size )     {-#ifdef WORDS_BIGENDIAN-        samples_fl32[0] = *( (int16_t *) samples_u8 );-#else-        samples_fl32[0] = (int16_t) ( ( samples_u8[0] << 8 ) | samples_u8[1] );-#endif-        samples_u8   += 2;-        samples_fl32 += 1;+        case 16: // 2 byte, big endian, signed (the right shift sign extends)+            while ( --count >= 0 )+            {+                *odat++ = ( (int)( frm[0] << 24 ) >> 16 ) | frm[1];+                frm += 2;+            }+            break;+        case 20:+            // 20 bit big endian signed (5 bytes for 2 samples = 2.5 bytes/sample+            // so we do two samples per iteration).+            count /= 2;+            while ( --count >= 0 )+            {+                *odat++ = (float)( ( (int)( frm[0] << 24 ) >> 12 ) |+                                   ( frm[1] << 4 ) | ( frm[2] >> 4 ) ) / 16.;+                *odat++ = (float)( ( (int)( frm[2] << 28 ) >> 16 ) |+                                   ( frm[3] << 8 ) | frm[4] ) / 16.;+                frm += 5;+            }+            break;+        case 24:+            // This format is bizarre. It's 24 bit samples but some confused+            // individual apparently thought they would be easier to interpret+            // as 16 bits if they were scrambled in the following way:+            // Things are stored in 4 sample (12 byte) chunks. Each chunk has+            // 4 samples containing the two top bytes of the actual samples in+            // 16 bit big-endian order followed by the four least significant bytes+            // of each sample.+            count /= 4; // the loop has to work in 4 sample chunks+            while ( --count >= 0 )+            {+                *odat++ = (float)( ( (int)( frm[0] << 24 ) >> 8 ) |+                            ( frm[1] << 8 ) | frm[8] ) / 256.;+                *odat++ = (float)( ( (int)( frm[2] << 24 ) >> 8 ) |+                            ( frm[3] << 8 ) | frm[9] ) / 256.;+                *odat++ = (float)( ( (int)( frm[4] << 24 ) >> 8 ) |+                            ( frm[5] << 8 ) | frm[10] ) / 256.;+                *odat++ = (float)( ( (int)( frm[6] << 24 ) >> 8 ) |+                            ( frm[7] << 8 ) | frm[11] ) / 256.;+                frm += 12;+            }+            break;     }--    *buf_out = out;--    return HB_WORK_OK;+    return out; }  void declpcmClose( hb_work_object_t * w ) {+    if ( w->private_data )+    {+        free( w->private_data );+        w->private_data = 0;+    } }Index: libhb/internal.h===================================================================--- libhb/internal.h	(revision 1368)+++ libhb/internal.h	(working copy)@@ -141,7 +141,6 @@ hb_title_t * hb_stream_title_scan( hb_stream_t *); int          hb_stream_read( hb_stream_t *, hb_buffer_t *); int          hb_stream_seek( hb_stream_t *, float );-void		 hb_stream_update_audio( hb_stream_t *, hb_audio_t *);  /***********************************************************************  * Work objectsIndex: libhb/scan.c===================================================================--- libhb/scan.c	(revision 1368)+++ libhb/scan.c	(working copy)@@ -23,8 +23,8 @@  static void ScanFunc( void * ); static int  DecodePreviews( hb_scan_t *, hb_title_t * title );-static void LookForAC3AndDCA( hb_title_t * title, hb_buffer_t * b );-static int  AllAC3AndDCAOK( hb_title_t * title );+static void LookForAudio( hb_title_t * title, hb_buffer_t * b );+static int  AllAudioOK( hb_title_t * title );  hb_thread_t * hb_scan_init( hb_handle_t * handle, const char * path,                             int title_index, hb_list_t * list_title )@@ -132,41 +132,14 @@             continue;         } -		if (data->stream)-		{-			// Stream based processing uses PID's to handle the different audio options for a given title-			for( j = 0; j < hb_list_count( title->list_audio ); j++ )-			{-				audio = hb_list_item( title->list_audio, j );-				hb_stream_update_audio(data->stream, audio);-			}-		}-		else if (data->dvd)-		{-			/* Make sure we found AC3 rates and bitrates */-			for( j = 0; j < hb_list_count( title->list_audio ); )-			{-				audio = hb_list_item( title->list_audio, j );-				if( audio->config.in.codec == HB_ACODEC_AC3 &&-                    !audio->config.in.bitrate )-				{-					hb_list_rem( title->list_audio, audio );-					free( audio );-					continue;-				}-				j++;-			}-		}--        /* Make sure we found AC3 / DCA rates and bitrates */+        /* Make sure we found audio rates and bitrates */         for( j = 0; j < hb_list_count( title->list_audio ); )         {             audio = hb_list_item( title->list_audio, j );-            if( ( audio->config.in.codec == HB_ACODEC_AC3 || audio->config.in.codec == HB_ACODEC_DCA ) &&-                !audio->config.in.bitrate )+            if( !audio->config.in.bitrate )             {-                hb_log( "scan: removing audio with codec of 0x%x because of no bitrate",-                        audio->config.in.codec );+                hb_log( "scan: removing audio 0x%x because no bitrate found",+                        audio->id );                 hb_list_rem( title->list_audio, audio );                 free( audio );                 continue;@@ -174,7 +147,7 @@             j++;         } -        /* Do we still have audio */+        /* If we don't have any audio streams left, remove the title */         if( !hb_list_count( title->list_audio ) )         {             hb_list_rem( data->list_title, title );@@ -182,18 +155,6 @@             continue;         } -        /* set a default input channel layout of stereo for LPCM or MPEG2 audio */-        /* AC3 and DCA will already have had their layout set via DecodePreviews above, */-        /* which calls LookForAC3AndDCA */-        for( j = 0; j < hb_list_count( title->list_audio ); j++ )-        {-            audio = hb_list_item( title->list_audio, j );-            if( audio->config.in.codec == HB_ACODEC_LPCM || audio->config.in.codec == HB_ACODEC_MPGA )-            {-                audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_STEREO;-            }-        }-         i++;     } @@ -227,7 +188,6 @@         }          job->width = title->width - job->crop[2] - job->crop[3];-//        job->height = title->height - job->crop[0] - job->crop[1];         hb_fix_aspect( job, HB_KEEP_WIDTH );         if( job->height > title->height - job->crop[0] - job->crop[1] )         {@@ -235,8 +195,8 @@             hb_fix_aspect( job, HB_KEEP_HEIGHT );         } -    hb_log( "scan: title (%d) job->width:%d, job->height:%d",-            i,job->width, job->height );+        hb_log( "scan: title (%d) job->width:%d, job->height:%d",+                i, job->width, job->height );          job->keep_ratio = 1; @@ -311,7 +271,10 @@         }         else if (data->stream)         {-          if (!hb_stream_seek(data->stream, (float) ( i + 1 ) / 11.0 ) )+          /* we start reading streams at zero rather than 1/11 because+           * short streams may have only one sequence header in the entire+           * file and we need it to decode any previews. */+          if (!hb_stream_seek(data->stream, (float) i / 11.0 ) )           {             goto error;           }@@ -354,22 +317,20 @@                             ++ar4_count : ++ar16_count ;                     }                 }-                else if( !i )+                else if( ! AllAudioOK( title ) )                 {-                    LookForAC3AndDCA( title, buf_es );+                    LookForAudio( title, buf_es );                 }                 hb_buffer_close( &buf_es ); -                if( hb_list_count( list_raw ) &&-                    ( i || AllAC3AndDCAOK( title ) ) )+                if( hb_list_count( list_raw ) && AllAudioOK( title ) )                 {                     /* We got a picture */                     break;                 }             } -            if( hb_list_count( list_raw ) &&-                ( i || AllAC3AndDCAOK( title ) ) )+            if( hb_list_count( list_raw ) && AllAudioOK( title ) )             {                 break;             }@@ -378,7 +339,7 @@         if( !hb_list_count( list_raw ) )         {             hb_log( "scan: could not get a decoded picture" );-            goto error;+            continue;         }          /* Get size and rate infos */@@ -564,206 +525,292 @@     return npreviews; } -static void LookForAC3AndDCA( hb_title_t * title, hb_buffer_t * b )+static void update_audio_description( const char *codec, hb_audio_t *audio,+                                      int is_dolby ) {-    int i;-    int flags;-    int rate;-    int bitrate;-    int frame_length;-    dca_state_t * state;+    hb_log( "scan: %s, rate=%dHz, bitrate=%d", codec, audio->config.in.samplerate,+            audio->config.in.bitrate ); -    /* Figure out if this is a AC3 or DCA buffer for a known track */-    hb_audio_t * audio = NULL;-    for( i = 0; i < hb_list_count( title->list_audio ); i++ )+    /* XXX */+    if ( is_dolby )     {-        audio = hb_list_item( title->list_audio, i );-        /* check if we have an AC3 or DCA which we recognise */-        if( ( audio->config.in.codec == HB_ACODEC_AC3 || audio->config.in.codec == HB_ACODEC_DCA ) &&-            audio->id    == b->id )+        strcat( audio->config.lang.description, " (Dolby Surround)" );+        return;+    }++    char *desc = audio->config.lang.description ++                    strlen( audio->config.lang.description );+    sprintf( desc, " (%d.%d ch)",+       HB_INPUT_CH_LAYOUT_GET_DISCRETE_FRONT_COUNT(audio->config.in.channel_layout) ++       HB_INPUT_CH_LAYOUT_GET_DISCRETE_REAR_COUNT(audio->config.in.channel_layout),+       HB_INPUT_CH_LAYOUT_GET_DISCRETE_LFE_COUNT(audio->config.in.channel_layout));+}++static int hb_setup_a52_audio( hb_audio_t *audio, hb_buffer_t *b )+{+    int i, rate, bitrate, flags;++    /* since AC3 frames don't line up with MPEG ES frames scan the+     * entire frame for an AC3 sync pattern.  */+    for ( i = 0; i < b->size - 7; ++i )+    {+        if( a52_syncinfo( &b->data[i], &flags, &rate, &bitrate ) != 0 )         {             break;         }-        else+    }+    if ( i >= b->size - 7 )+    {+        /* didn't find AC3 sync */+        return 0;+    }++    audio->config.in.samplerate = rate;+    audio->config.in.bitrate = bitrate;++    switch( flags & A52_CHANNEL_MASK )+    {+        /* mono sources */+        case A52_MONO:+        case A52_CHANNEL1:+        case A52_CHANNEL2:+            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_MONO;+            break;+        /* stereo input */+        case A52_CHANNEL:+        case A52_STEREO:+            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_STEREO;+            break;+        /* dolby (DPL1 aka Dolby Surround = 4.0 matrix-encoded) input */+        case A52_DOLBY:+            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_DOLBY;+            break;+        /* 3F/2R input */+        case A52_3F2R:+            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_3F2R;+            break;+        /* 3F/1R input */+        case A52_3F1R:+            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_3F1R;+            break;+        /* other inputs */+        case A52_3F:+            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_3F;+            break;+        case A52_2F1R:+            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_2F1R;+            break;+        case A52_2F2R:+            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_2F2R;+            break;+        /* unknown */+        default:+            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_STEREO;+    }++    if (flags & A52_LFE)+    {+        audio->config.in.channel_layout |= HB_INPUT_CH_LAYOUT_HAS_LFE;+    }++    /* store the AC3 flags for future reference+     * This enables us to find out if we had a stereo or Dolby source later on+     * Store the ac3 flags in the public ac3flags property too, so we can access+     * it from the GUI+     */+    audio->config.flags.ac3 = audio->priv.config.a52.ac3flags = flags;+    update_audio_description( "AC3", audio, (flags & A52_CHANNEL_MASK) == A52_DOLBY );+    return 1;+}++static int hb_setup_dca_audio( hb_audio_t *audio, hb_buffer_t *b )+{+    int i, flags, rate, bitrate, frame_length;+    dca_state_t * state = dca_init( 0 );++    /* since DCA frames don't line up with MPEG ES frames scan the+     * entire frame for an DCA sync pattern.  */+    for ( i = 0; i < b->size - 7; ++i )+    {+        if( dca_syncinfo( state, &b->data[i], &flags, &rate, &bitrate,+                          &frame_length ) )         {-            audio = NULL;+            break;         }     }-    if( !audio )+    if ( i >= b->size - 7 )     {-        return;+        /* didn't find DCA sync */+        return 0;     } -    if( audio->config.in.bitrate )+    audio->config.in.samplerate = rate;+    audio->config.in.bitrate = bitrate;+    switch( flags & DCA_CHANNEL_MASK )     {-        /* Already done for this track */-        return;+        /* mono sources */+        case DCA_MONO:+            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_MONO;+            break;+        /* stereo input */+        case DCA_CHANNEL:+        case DCA_STEREO:+        case DCA_STEREO_SUMDIFF:+        case DCA_STEREO_TOTAL:+            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_STEREO;+            break;+        /* 3F/2R input */+        case DCA_3F2R:+            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_3F2R;+            break;+        /* 3F/1R input */+        case DCA_3F1R:+            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_3F1R;+            break;+        /* other inputs */+        case DCA_3F:+            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_3F;+            break;+        case DCA_2F1R:+            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_2F1R;+            break;+        case DCA_2F2R:+            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_2F2R;+            break;+        case DCA_4F2R:+            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_4F2R;+            break;+        /* unknown */+        default:+            audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_STEREO;     } -    for( i = 0; i < b->size - 7; i++ )+    if (flags & DCA_LFE)     {+        audio->config.in.channel_layout |= HB_INPUT_CH_LAYOUT_HAS_LFE;+    } -        if ( audio->config.in.codec == HB_ACODEC_AC3 )-        {+    /* store the DCA flags for future reference+     * This enables us to find out if we had a stereo or Dolby source later on+     * store the dca flags in the public dcaflags property too, so we can access+     * it from the GUI+     */+    audio->config.flags.dca = audio->priv.config.dca.dcaflags = flags;+    update_audio_description( "DCA", audio, (flags & DCA_CHANNEL_MASK) == DCA_DOLBY );+    return 1;+} -            /* check for a52 */-            if( a52_syncinfo( &b->data[i], &flags, &rate, &bitrate ) )-            {-                hb_log( "scan: AC3, rate=%dHz, bitrate=%d", rate, bitrate );-                audio->config.in.samplerate = rate;-                audio->config.in.bitrate = bitrate;-                switch( flags & A52_CHANNEL_MASK )-                {-                    /* mono sources */-                    case A52_MONO:-                    case A52_CHANNEL1:-                    case A52_CHANNEL2:-                        audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_MONO;-                        break;-                    /* stereo input */-                    case A52_CHANNEL:-                    case A52_STEREO:-                        audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_STEREO;-                        break;-                    /* dolby (DPL1 aka Dolby Surround = 4.0 matrix-encoded) input */-                    case A52_DOLBY:-                        audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_DOLBY;-                        break;-                    /* 3F/2R input */-                    case A52_3F2R:-                        audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_3F2R;-                        break;-                    /* 3F/1R input */-                    case A52_3F1R:-                        audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_3F1R;-                        break;-                    /* other inputs */-                    case A52_3F:-                        audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_3F;-                        break;-                    case A52_2F1R:-                        audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_2F1R;-                        break;-                    case A52_2F2R:-                        audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_2F2R;-                        break;-                    /* unknown */-                    default:-                        audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_STEREO;-                }+static int hb_setup_pcm_audio( hb_audio_t *audio, hb_buffer_t *b )+{+    // LPCM doesn't have a sync pattern like AC3 or DCA but every+    // LPCM elementary stream packet starts with a 7 byte header+    // giving the characteristics of the stream.+    // See libhb/declpcm.c for a description of the LPCM header. -                /* add in our own LFE flag if the source has LFE */-                if (flags & A52_LFE)-                {-                    audio->config.in.channel_layout = audio->config.in.channel_layout | HB_INPUT_CH_LAYOUT_HAS_LFE;-                }+    static const int hdr2samplerate[] = { 48000, 96000, 44100, 32000 };+    static const int hdr2samplesize[] = { 16, 20, 24, 16 };+    static const int hdr2layout[] = {+            HB_INPUT_CH_LAYOUT_MONO,   HB_INPUT_CH_LAYOUT_STEREO,+            HB_INPUT_CH_LAYOUT_2F1R,   HB_INPUT_CH_LAYOUT_2F2R,+            HB_INPUT_CH_LAYOUT_3F2R,   HB_INPUT_CH_LAYOUT_4F2R,+            HB_INPUT_CH_LAYOUT_STEREO, HB_INPUT_CH_LAYOUT_STEREO,+    }; -                /* store the AC3 flags for future reference-                 * This enables us to find out if we had a stereo or Dolby source later on-                 * Store the ac3 flags in the public ac3flags property too, so we can access it from the GUI-                 */-                audio->config.flags.ac3 = audio->priv.config.a52.ac3flags = flags;+    int nchannels  = ( b->data[4] & 7 ) + 1;+    int sample_size = hdr2samplesize[b->data[4] >> 6]; -                /* XXX */-                if ( (flags & A52_CHANNEL_MASK) == A52_DOLBY ) {-                    sprintf( audio->config.lang.description + strlen( audio->config.lang.description ),-                         " (Dolby Surround)" );-                } else {-                    sprintf( audio->config.lang.description + strlen( audio->config.lang.description ),-                         " (%d.%d ch)",-                        HB_INPUT_CH_LAYOUT_GET_DISCRETE_FRONT_COUNT(audio->config.in.channel_layout) +-                        HB_INPUT_CH_LAYOUT_GET_DISCRETE_REAR_COUNT(audio->config.in.channel_layout),-                        HB_INPUT_CH_LAYOUT_GET_DISCRETE_LFE_COUNT(audio->config.in.channel_layout));-                }+    int rate = hdr2samplerate[ ( b->data[4] >> 4 ) & 0x3 ];+    int bitrate = rate * sample_size * nchannels; -                break;+    audio->config.in.samplerate = rate;+    audio->config.in.bitrate = bitrate;+    audio->config.in.channel_layout = hdr2layout[nchannels - 1];+    update_audio_description( "LPCM", audio, 0 );+    return 1;+} -            }+static int hb_setup_mpg_audio( hb_audio_t *audio, hb_buffer_t *b )+{+    /* XXX+     * This is a placeholder to get the audio sample rate set.+     * It should be replaced by something that extracts the correct info from+     * the mpeg audio bitstream.+     */+    audio->config.in.samplerate = 48000;+    audio->config.in.bitrate = 384000;+    audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_STEREO;+    update_audio_description( "MPGA", audio, 0 );+    return 1;+} +/*+ * This routine is called for every frame from a non-video elementary stream.+ * These are a mix of audio & subtitle streams, some of which we want & some+ * we're ignoring. This routine checks the frame against all our audio streams+ * to see if it's one we want and haven't identified yet. If yes, it passes the+ * frame to a codec-specific id routine which is responsible for filling in+ * the sample rate, bit rate, channels & other audio parameters.+ *+ * Since a sample rate is essential for further audio processing, any audio+ * stream which isn't successfully id'd by is deleted at the end of the scan.+ * This is necessary to avoid ambiguities where things that might be audio+ * aren't (e.g., some European DVD Teletext streams use the same IDs as US ATSC+ * AC-3 audio).+ */+static void LookForAudio( hb_title_t * title, hb_buffer_t * b )+{+    int i;++    hb_audio_t * audio = NULL;+    for( i = 0; i < hb_list_count( title->list_audio ); i++ )+    {+        audio = hb_list_item( title->list_audio, i );+        /* check if this elementary stream is one we want */+        if ( audio->id == b->id )+        {+            break;         }-        else if ( audio->config.in.codec == HB_ACODEC_DCA )+        else         {+            audio = NULL;+        }+    }+    if( !audio || audio->config.in.bitrate != 0 )+    {+        /* not found or already done */+        return;+    } -            hb_log( "scan: checking for DCA syncinfo" );+    switch ( audio->config.in.codec )+    {+        case HB_ACODEC_AC3:+            hb_setup_a52_audio( audio, b );+            break; -            /* check for dca */-            state = dca_init( 0 );-            if( dca_syncinfo( state, &b->data[i], &flags, &rate, &bitrate, &frame_length ) )-            {-                hb_log( "scan: DCA, rate=%dHz, bitrate=%d", rate, bitrate );-                audio->config.in.samplerate    = rate;-                audio->config.in.bitrate = bitrate;-                switch( flags & DCA_CHANNEL_MASK )-                {-                    /* mono sources */-                    case DCA_MONO:-                        audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_MONO;-                        break;-                    /* stereo input */-                    case DCA_CHANNEL:-                    case DCA_STEREO:-                    case DCA_STEREO_SUMDIFF:-                    case DCA_STEREO_TOTAL:-                        audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_STEREO;-                        break;-                    /* 3F/2R input */-                    case DCA_3F2R:-                        audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_3F2R;-                        break;-                    /* 3F/1R input */-                    case DCA_3F1R:-                        audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_3F1R;-                        break;-                    /* other inputs */-                    case DCA_3F:-                        audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_3F;-                        break;-                    case DCA_2F1R:-                        audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_2F1R;-                        break;-                    case DCA_2F2R:-                        audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_2F2R;-                        break;-                    case DCA_4F2R:-                        audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_4F2R;-                        break;-                    /* unknown */-                    default:-                        audio->config.in.channel_layout = HB_INPUT_CH_LAYOUT_STEREO;-                }+        case HB_ACODEC_DCA:+            hb_setup_dca_audio( audio, b );+            break; -                /* add in our own LFE flag if the source has LFE */-                if (flags & DCA_LFE)-                {-                    audio->config.in.channel_layout = audio->config.in.channel_layout | HB_INPUT_CH_LAYOUT_HAS_LFE;-                }+        case HB_ACODEC_LPCM:+            hb_setup_pcm_audio( audio, b );+            break; -                /* store the DCA flags for future reference-                 * This enables us to find out if we had a stereo or Dolby source later on-                 * store the dca flags in the public dcaflags property too, so we can access it from the GUI-                 */-                audio->config.flags.dca = audio->priv.config.dca.dcaflags = flags;+        case HB_ACODEC_MPGA:+            hb_setup_mpg_audio( audio, b );+            break; -                /* XXX */-                if ( (flags & DCA_CHANNEL_MASK) == DCA_DOLBY ) {-                    sprintf( audio->config.lang.description + strlen( audio->config.lang.description ),-                         " (Dolby Surround)" );-                } else {-                    sprintf( audio->config.lang.description + strlen( audio->config.lang.description ),-                         " (%d.%d ch)",-                        HB_INPUT_CH_LAYOUT_GET_DISCRETE_FRONT_COUNT(audio->config.in.channel_layout) +-                        HB_INPUT_CH_LAYOUT_GET_DISCRETE_REAR_COUNT(audio->config.in.channel_layout),-                        HB_INPUT_CH_LAYOUT_GET_DISCRETE_LFE_COUNT(audio->config.in.channel_layout));-                }--                break;-            }-        }+        default:+            hb_log( "Internal error in scan: unhandled audio type %d for 0x%x",+                    audio->config.in.codec, audio->id );+            break;     }- } -static int  AllAC3AndDCAOK( hb_title_t * title )+/*+ * This routine checks to see if we've ID'd all the audio streams associated+ * with a title. It returns 0 if there are more to ID & 1 if all are done.+ */+static int  AllAudioOK( hb_title_t * title ) {     int i;     hb_audio_t * audio;@@ -771,12 +818,10 @@     for( i = 0; i < hb_list_count( title->list_audio ); i++ )     {         audio = hb_list_item( title->list_audio, i );-        if( ( audio->config.in.codec == HB_ACODEC_AC3 || audio->config.in.codec == HB_ACODEC_DCA ) &&-            !audio->config.in.bitrate )+        if( audio->config.in.bitrate == 0 )         {             return 0;         }     }-     return 1; }