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; }