Index: libhb/declpcm.c===================================================================--- libhb/declpcm.c (revision 1353)+++ 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/scan.c===================================================================--- libhb/scan.c (revision 1353)+++ libhb/scan.c (working copy)@@ -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->codec == HB_ACODEC_MPGA ) { audio->input_channel_layout = HB_INPUT_CH_LAYOUT_STEREO; }@@ -562,9 +562,11 @@ for( i = 0; i < hb_list_count( title->list_audio ); i++ ) { 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 ) &&- audio->id == b->id )+ /* check if we have an AC3, DCA or LPCM which we recognise */+ if ( audio->id == b->id &&+ ( audio->codec == HB_ACODEC_AC3 ||+ audio->codec == HB_ACODEC_DCA ||+ audio->codec == HB_ACODEC_LPCM ) ) { break; }@@ -745,6 +747,83 @@ break; } }+ else if ( i == 0 && audio->codec == HB_ACODEC_LPCM )+ {+ // 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.+ switch( ( b->data[4] >> 4 ) & 0x3 )+ {+ case 0:+ rate = 48000;+ break;+ case 1:+ rate = 96000;+ break;+ case 2:+ rate = 44100;+ break;+ case 3:+ rate = 32000;+ break;+ }+ switch( b->data[4] >> 6 )+ {+ case 0:+ // 16 bit samples+ bitrate = rate * 16;+ break;+ case 1:+ // 20 bit samples (5 bytes for 2 samples = 2.5/sample)+ bitrate = rate * 20;+ break;+ case 2:+ bitrate = rate * 24;+ break;+ default:+ hb_log( "scan: illegal bits per sample in lpcm header" );+ bitrate = 0;+ break;+ }+ hb_log( "scan: LPCM, rate=%dHz, bitrate=%d", rate, bitrate );+ audio->rate = rate;+ audio->bitrate = bitrate;++ // bottom 3 bits of byte 4 are #channels - 1+ // standard allows for up to 8 channels but Handbrake only+ // has mappings for up to 6.+ switch( b->data[4] & 7 )+ {+ case 0:+ audio->input_channel_layout = HB_INPUT_CH_LAYOUT_MONO;+ break;+ case 1:+ audio->input_channel_layout = HB_INPUT_CH_LAYOUT_STEREO;+ break;+ case 2:+ audio->input_channel_layout = HB_INPUT_CH_LAYOUT_2F1R;+ break;+ case 3:+ audio->input_channel_layout = HB_INPUT_CH_LAYOUT_2F2R;+ break;+ case 4:+ audio->input_channel_layout = HB_INPUT_CH_LAYOUT_3F2R;+ break;+ case 5:+ audio->input_channel_layout = HB_INPUT_CH_LAYOUT_4F2R;+ break;+ default:+ audio->input_channel_layout = HB_INPUT_CH_LAYOUT_STEREO;+ break;+ }+ sprintf( audio->lang + strlen( audio->lang ),+ " (%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));+ break;+ } } }