diff options
Diffstat (limited to 'src/audio_dec')
-rw-r--r-- | src/audio_dec/xine_lpcm_decoder.c | 128 |
1 files changed, 104 insertions, 24 deletions
diff --git a/src/audio_dec/xine_lpcm_decoder.c b/src/audio_dec/xine_lpcm_decoder.c index f5e2aeb6d..ca7802b07 100644 --- a/src/audio_dec/xine_lpcm_decoder.c +++ b/src/audio_dec/xine_lpcm_decoder.c @@ -67,22 +67,34 @@ typedef struct lpcm_decoder_s { uint32_t ao_cap_mode; int output_open; - int cpu_be; /**< TRUE, if we're a Big endian CPU */ + int cpu_be; /* TRUE, if we're a Big endian CPU */ + + int64_t pts; + + uint8_t *buf; + size_t buffered_bytes; + size_t buf_size; + } lpcm_decoder_t; static void lpcm_reset (audio_decoder_t *this_gen) { - /* lpcm_decoder_t *this = (lpcm_decoder_t *) this_gen; */ + lpcm_decoder_t *this = (lpcm_decoder_t *) this_gen; + free (this->buf); + this->buf = NULL; } static void lpcm_discontinuity (audio_decoder_t *this_gen) { + + lpcm_reset(this_gen); } static void lpcm_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { lpcm_decoder_t *this = (lpcm_decoder_t *) this_gen; int16_t *sample_buffer=(int16_t *)buf->content; + int buf_size = buf->size; int stream_be; audio_buffer_t *audio_buffer; int format_changed = 0; @@ -98,17 +110,54 @@ static void lpcm_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { unsigned int sample_rate = 0; unsigned int num_channels; - num_channels = (buf->decoder_info[2] & 0x7) + 1; - switch ((buf->decoder_info[2]>>4) & 3) { - case 0: sample_rate = 48000; break; - case 1: sample_rate = 96000; break; - case 2: sample_rate = 44100; break; - case 3: sample_rate = 32000; break; - } - switch ((buf->decoder_info[2]>>6) & 3) { - case 0: bits_per_sample = 16; break; - case 1: bits_per_sample = 20; break; - case 2: bits_per_sample = 24; break; + lprintf("lpcm_decoder: config data 0x%x\n", buf->decoder_info[2]); + + /* BluRay PCM header is 4 bytes */ + if (buf->decoder_info[2] & 0xffffff00) { + static const uint8_t channels[16] = {0, 1, 0, 2, 3, 3, 4, 4, 5, 6, 7, 8, 0, 0, 0, 0}; + + num_channels = channels[(buf->decoder_info[2] >> (16+4)) & 0x0f]; + switch ((buf->decoder_info[2] >> (24+6)) & 0x03) { + case 1: bits_per_sample = 16; break; + case 2: bits_per_sample = 20; break; + case 3: bits_per_sample = 24; break; + default: bits_per_sample = 0; break; + } + switch ((buf->decoder_info[2] >> 16) & 0x0f) { + case 1: sample_rate = 48000; break; + case 4: sample_rate = 96000; break; + case 5: sample_rate = 192000; break; + default: sample_rate = 0; break; + } + + if (!num_channels || !sample_rate || !bits_per_sample) + xine_log (this->stream->xine, XINE_LOG_MSG, + "lpcm_decoder: unsupported BluRay PCM format: 0x%08x\n", buf->decoder_info[2]); + + if (this->buffered_bytes) + xine_log (this->stream->xine, XINE_LOG_MSG, "lpcm_decoder: %zd bytes lost !\n", this->buffered_bytes); + + if (!this->buf) { + this->buffered_bytes = 0; + this->buf_size = 8128; + this->buf = malloc(this->buf_size); + } + + } else { + + /* MPEG2/DVD PCM header is one byte */ + num_channels = (buf->decoder_info[2] & 0x7) + 1; + switch ((buf->decoder_info[2]>>4) & 3) { + case 0: sample_rate = 48000; break; + case 1: sample_rate = 96000; break; + case 2: sample_rate = 44100; break; + case 3: sample_rate = 32000; break; + } + switch ((buf->decoder_info[2]>>6) & 3) { + case 0: bits_per_sample = 16; break; + case 1: bits_per_sample = 20; break; + case 2: bits_per_sample = 24; break; + } } if( this->bits_per_sample != bits_per_sample || @@ -119,13 +168,17 @@ static void lpcm_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { this->number_of_channels = num_channels; this->rate = sample_rate; format_changed++; + + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "lpcm_decoder: format changed to %d channels, %d bits per sample, %d Hz, %d kbit/s\n", + num_channels, bits_per_sample, sample_rate, (num_channels * sample_rate * bits_per_sample)/1024); } } if( buf->decoder_flags & BUF_FLAG_STDHEADER ) { this->rate=buf->decoder_info[1]; - this->bits_per_sample=buf->decoder_info[2] ; - this->number_of_channels=buf->decoder_info[3] ; + this->bits_per_sample=buf->decoder_info[2]; + this->number_of_channels=buf->decoder_info[3]; format_changed++; } @@ -159,6 +212,30 @@ static void lpcm_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { if (!this->output_open || (buf->decoder_flags & BUF_FLAG_HEADER) ) return; + if (buf->pts && !this->pts) + this->pts = buf->pts; + + /* data accumulation */ + if (this->buf) { + int frame_end = buf->decoder_flags & BUF_FLAG_FRAME_END; + if (this->buffered_bytes || !frame_end) { + if (this->buf_size < this->buffered_bytes + buf->size) { + this->buf_size *= 2; + this->buf = realloc(this->buf, this->buf_size); + } + + memcpy(this->buf + this->buffered_bytes, buf->content, buf->size); + this->buffered_bytes += buf->size; + + if (!frame_end) + return; + + sample_buffer = (int16_t*)this->buf; + buf_size = this->buffered_bytes; + this->buffered_bytes = 0; + } + } + audio_buffer = this->stream->audio_out->get_buffer (this->stream->audio_out); /* Swap LPCM samples into native byte order, if necessary */ @@ -167,14 +244,14 @@ static void lpcm_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { if( this->bits_per_sample == 16 ){ if (stream_be != this->cpu_be) - swab (sample_buffer, audio_buffer->mem, buf->size); + swab (sample_buffer, audio_buffer->mem, buf_size); else - memcpy (audio_buffer->mem, sample_buffer, buf->size); + memcpy (audio_buffer->mem, sample_buffer, buf_size); } else if( this->bits_per_sample == 20 ) { uint8_t *s = (uint8_t *)sample_buffer; uint8_t *d = (uint8_t *)audio_buffer->mem; - int n = buf->size; + int n = buf_size; if (stream_be != this->cpu_be) { while( n >= 0 ) { @@ -194,7 +271,7 @@ static void lpcm_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { } else if( this->bits_per_sample == 24 ) { uint8_t *s = (uint8_t *)sample_buffer; uint8_t *d = (uint8_t *)audio_buffer->mem; - int n = buf->size; + int n = buf_size; while (n >= 3) { if ( stream_be ) { @@ -221,18 +298,19 @@ static void lpcm_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { n -= 3; } - if ( (d - (uint8_t*)audio_buffer->mem)/2*3 < buf->size ) - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "lpcm_decoder: lost %i bytes\n", (int)(buf->size - (d - (uint8_t*)audio_buffer->mem))/2*3); + if ( (d - (uint8_t*)audio_buffer->mem)/2*3 < buf_size ) + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "lpcm_decoder: lost %i bytes\n", (int)(buf_size - (d - (uint8_t*)audio_buffer->mem))/2*3); } else { - memcpy (audio_buffer->mem, sample_buffer, buf->size); + memcpy (audio_buffer->mem, sample_buffer, buf_size); } - audio_buffer->vpts = buf->pts; - audio_buffer->num_frames = (((buf->size*8)/this->number_of_channels)/this->bits_per_sample); + audio_buffer->vpts = this->pts; + audio_buffer->num_frames = (((buf_size*8)/this->number_of_channels)/this->bits_per_sample); this->stream->audio_out->put_buffer (this->stream->audio_out, audio_buffer, this->stream); + this->pts = 0; } static void lpcm_dispose (audio_decoder_t *this_gen) { @@ -242,6 +320,8 @@ static void lpcm_dispose (audio_decoder_t *this_gen) { this->stream->audio_out->close (this->stream->audio_out, this->stream); this->output_open = 0; + free (this->buf); + free (this_gen); } |