summaryrefslogtreecommitdiffstats
path: root/libhb
diff options
context:
space:
mode:
Diffstat (limited to 'libhb')
-rw-r--r--libhb/declpcm.c150
1 files changed, 109 insertions, 41 deletions
diff --git a/libhb/declpcm.c b/libhb/declpcm.c
index 62eb563e8..a47e0974c 100644
--- a/libhb/declpcm.c
+++ b/libhb/declpcm.c
@@ -11,7 +11,8 @@ 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 chunks; /* number of samples pairs if paired */
+ uint32_t samples; /* frame size in samples */
uint32_t pos; /* buffer offset for next input data */
int64_t next_pts; /* pts for next output frame */
@@ -98,6 +99,23 @@ static void lpcmInfo( hb_work_object_t *w, hb_buffer_t *in )
pv->nchannels = ( in->data[4] & 7 ) + 1;
pv->sample_size = hdr2samplesize[in->data[4] >> 6];
+ // 20 and 24 bit lpcm is always encoded in sample pairs. So take this
+ // into account when computing sizes.
+ int chunk_size = pv->sample_size / 8;
+ int samples_per_chunk = 1;
+
+ switch( pv->sample_size )
+ {
+ case 20:
+ chunk_size = 5;
+ samples_per_chunk = 2;
+ break;
+ case 24:
+ chunk_size = 6;
+ samples_per_chunk = 2;
+ break;
+ }
+
/*
* PCM frames have a constant duration (150 90KHz ticks).
* We need to convert that to the amount of data expected. It's the
@@ -107,9 +125,23 @@ static void lpcmInfo( hb_work_object_t *w, hb_buffer_t *in )
* 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;
+ /*
+ * Don't trust the number of frames given in the header. We've seen
+ * streams for which this is incorrect, and it can be computed.
+ * pv->duration = in->data[0] * 150;
+ */
+ int chunks = ( in->size - pv->offset ) / chunk_size;
+ int samples = chunks * samples_per_chunk;
+
+ // Calculate number of frames that start in this packet
+ int frames = ( 90000 * samples / ( pv->samplerate * pv->nchannels ) +
+ 149 ) / 150;
+
+ pv->duration = frames * 150;
+ pv->chunks = ( pv->duration * pv->nchannels * pv->samplerate +
+ samples_per_chunk - 1 ) / ( 90000 * samples_per_chunk );
+ pv->samples = ( pv->duration * pv->nchannels * pv->samplerate ) / 90000;
+ pv->size = pv->chunks * chunk_size;
pv->next_pts = in->start;
}
@@ -181,63 +213,99 @@ static hb_buffer_t *Decode( hb_work_object_t *w )
hb_work_private_t *pv = w->private_data;
hb_buffer_t *out;
- if (pv->count == 0)
+ if (pv->samples == 0)
return NULL;
- out = hb_buffer_init( pv->count * sizeof( float ) );
+ out = hb_buffer_init( pv->samples * sizeof( float ) );
out->start = pv->next_pts;
pv->next_pts += pv->duration;
out->stop = pv->next_pts;
- uint8_t *frm = pv->frame;
float *odat = (float *)out->data;
- int count = pv->count;
+ int count = pv->chunks / pv->nchannels;
switch( pv->sample_size )
{
case 16: // 2 byte, big endian, signed (the right shift sign extends)
- while ( --count >= 0 )
+ {
+ uint8_t *frm = pv->frame;
+ while ( count-- )
{
- *odat++ = (float)(( (int)( frm[0] << 24 ) >> 16 ) | frm[1]) / 32768.0;
- frm += 2;
+ int cc;
+ for( cc = 0; cc < pv->nchannels; cc++ )
+ {
+ // Shifts below result in sign extension which gives
+ // us proper signed values. The final division adjusts
+ // the range to [-1.0 ... 1.0]
+ *odat++ = (float)( ( (int)( frm[0] << 24 ) >> 16 ) |
+ frm[1] ) / 32768.0;
+ frm += 2;
+ }
}
- break;
+ } 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 )
+ {
+ // There will always be 2 groups of samples. A group is
+ // a collection of samples that spans all channels.
+ // The data for the samples is split. The first 2 msb
+ // bytes for all samples is encoded first, then the remaining
+ // lsb bits are encoded.
+ uint8_t *frm = pv->frame;
+ while ( count-- )
{
- *odat++ = (float)( ( (int)( frm[0] << 24 ) >> 12 ) |
- ( frm[1] << 4 ) | ( frm[2] >> 4 ) ) / (16. * 32768.0);
- *odat++ = (float)( ( (int)( frm[2] << 28 ) >> 16 ) |
- ( frm[3] << 8 ) | frm[4] ) / (16. * 32768.0);
- frm += 5;
+ int gg, cc;
+ int shift = 4;
+ uint8_t *lsb = frm + 4 * pv->nchannels;
+ for( gg = 0; gg < 2; gg++ )
+ {
+ for( cc = 0; cc < pv->nchannels; cc++ )
+ {
+ // Shifts below result in sign extension which gives
+ // us proper signed values. The final division adjusts
+ // the range to [-1.0 ... 1.0]
+ *odat = (float)( ( (int)( frm[0] << 24 ) >> 12 ) |
+ ( frm[1] << 4 ) |
+ ( ( ( lsb[0] >> shift ) & 0x0f ) ) ) /
+ (16. * 32768.0);
+ odat++;
+ lsb += !shift;
+ shift ^= 4;
+ frm += 2;
+ }
+ }
+ frm = lsb;
}
- break;
+ } 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 )
+ {
+ // There will always be 2 groups of samples. A group is
+ // a collection of samples that spans all channels.
+ // The data for the samples is split. The first 2 msb
+ // bytes for all samples is encoded first, then the remaining
+ // lsb bits are encoded.
+ uint8_t *frm = pv->frame;
+ while ( count-- )
{
- *odat++ = (float)( ( (int)( frm[0] << 24 ) >> 8 ) |
- ( frm[1] << 8 ) | frm[8] ) / (256. * 32768.0);
- *odat++ = (float)( ( (int)( frm[2] << 24 ) >> 8 ) |
- ( frm[3] << 8 ) | frm[9] ) / (256. * 32768.0);
- *odat++ = (float)( ( (int)( frm[4] << 24 ) >> 8 ) |
- ( frm[5] << 8 ) | frm[10] ) / (256. * 32768.0);
- *odat++ = (float)( ( (int)( frm[6] << 24 ) >> 8 ) |
- ( frm[7] << 8 ) | frm[11] ) / (256. * 32768.0);
- frm += 12;
+ int gg, cc;
+ uint8_t *lsb = frm + 4 * pv->nchannels;
+ for( gg = 0; gg < 2; gg++ )
+ {
+ for( cc = 0; cc < pv->nchannels; cc++ )
+ {
+ // Shifts below result in sign extension which gives
+ // us proper signed values. The final division adjusts
+ // the range to [-1.0 ... 1.0]
+ *odat++ = (float)( ( (int)( frm[0] << 24 ) >> 8 ) |
+ ( frm[1] << 8 ) | lsb[0] ) /
+ (256. * 32768.0);
+ frm += 2;
+ lsb++;
+ }
+ }
+ frm = lsb;
}
- break;
+ } break;
}
return out;
}