2001-08-03 14:18:08 +02:00
|
|
|
/*
|
|
|
|
* decode.c
|
|
|
|
*
|
|
|
|
* Copyright (C) Aaron Holtzman - May 1999
|
|
|
|
*
|
|
|
|
* This file is part of ac3dec, a free Dolby AC-3 stream decoder.
|
|
|
|
*
|
|
|
|
* ac3dec is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
|
|
* any later version.
|
|
|
|
*
|
|
|
|
* ac3dec is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with GNU Make; see the file COPYING. If not, write to
|
|
|
|
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
*
|
2001-08-09 11:41:39 +02:00
|
|
|
*------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* Thomas Mirlacher <dent@cosy.sbg.ac.at>
|
|
|
|
* added OMS support
|
|
|
|
* 11 Jan 2001
|
|
|
|
* Thomas Mirlacher <dent@cosy.sbg.ac.at>
|
|
|
|
* faster error response using jmp functions
|
|
|
|
*
|
|
|
|
* 9 Aug 2001
|
|
|
|
* Matjaz Thaler <matjaz.thaler@rd.iskraemeco.si>
|
|
|
|
* Added support for DVB-s PCI card
|
2001-08-03 14:18:08 +02:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/time.h>
|
2001-08-09 11:41:39 +02:00
|
|
|
|
|
|
|
#ifdef __OMS__
|
|
|
|
#include <oms/oms.h>
|
|
|
|
#include <oms/plugin/output_audio.h>
|
|
|
|
#endif
|
2001-08-03 14:18:08 +02:00
|
|
|
|
|
|
|
#include "ac3.h"
|
|
|
|
#include "ac3_internal.h"
|
|
|
|
#include "bitstream.h"
|
2001-08-09 11:41:39 +02:00
|
|
|
#include "downmix.h"
|
|
|
|
#include "srfft.h"
|
2001-08-03 14:18:08 +02:00
|
|
|
#include "imdct.h"
|
|
|
|
#include "exponent.h"
|
|
|
|
#include "coeff.h"
|
|
|
|
#include "bit_allocate.h"
|
|
|
|
#include "parse.h"
|
|
|
|
#include "crc.h"
|
|
|
|
#include "stats.h"
|
|
|
|
#include "rematrix.h"
|
|
|
|
#include "sanity_check.h"
|
|
|
|
#include "debug.h"
|
2001-08-09 11:41:39 +02:00
|
|
|
#ifndef __OMS__
|
|
|
|
//#include "audio_out.h"
|
|
|
|
#endif
|
2001-08-03 14:18:08 +02:00
|
|
|
//our global config structure
|
|
|
|
ac3_config_t ac3_config;
|
|
|
|
|
|
|
|
static audblk_t audblk;
|
|
|
|
static bsi_t bsi;
|
|
|
|
static syncinfo_t syncinfo;
|
2001-08-09 11:41:39 +02:00
|
|
|
#ifndef __OMS__
|
|
|
|
static uint32_t done_banner;
|
|
|
|
#endif
|
|
|
|
static uint32_t is_output_initialized = 0;
|
2001-08-03 14:18:08 +02:00
|
|
|
|
|
|
|
//the floating point samples for one audblk
|
|
|
|
static stream_samples_t samples;
|
|
|
|
|
|
|
|
//the integer samples for the entire frame (with enough space for 2 ch out)
|
|
|
|
//if this size change, be sure to change the size when muting
|
2001-08-09 11:41:39 +02:00
|
|
|
static int16_t s16_samples[2 * 6 * 256] __attribute__ ((aligned(16)));
|
2001-08-03 14:18:08 +02:00
|
|
|
|
2001-08-09 11:41:39 +02:00
|
|
|
// downmix stuff
|
|
|
|
static float cmixlev_lut[4] = { 0.707, 0.595, 0.500, 0.707 };
|
|
|
|
static float smixlev_lut[4] = { 0.707, 0.500, 0.0 , 0.500 };
|
|
|
|
static dm_par_t dm_par;
|
|
|
|
|
2001-08-03 14:18:08 +02:00
|
|
|
//Storage for the syncframe
|
2001-08-09 11:41:39 +02:00
|
|
|
#define BUFFER_MAX_SIZE 4096
|
|
|
|
static uint8_t buffer[BUFFER_MAX_SIZE];
|
|
|
|
static uint32_t buffer_size = 0;;
|
|
|
|
// for error handling
|
|
|
|
jmp_buf error_jmp_mark;
|
2001-08-03 14:18:08 +02:00
|
|
|
|
2001-08-09 11:41:39 +02:00
|
|
|
static uint32_t decode_buffer_syncframe (syncinfo_t *syncinfo, uint8_t **start, uint8_t *end)
|
2001-08-03 14:18:08 +02:00
|
|
|
{
|
2001-08-09 11:41:39 +02:00
|
|
|
uint8_t *cur = *start;
|
|
|
|
uint16_t syncword = syncinfo->syncword;
|
|
|
|
uint32_t ret = 0;
|
2001-08-03 14:18:08 +02:00
|
|
|
|
|
|
|
// Find an ac3 sync frame.
|
2001-08-09 11:41:39 +02:00
|
|
|
while (syncword != 0x0b77) {
|
|
|
|
if (cur >= end)
|
2001-08-03 14:18:08 +02:00
|
|
|
goto done;
|
|
|
|
syncword = (syncword << 8) + *cur++;
|
|
|
|
}
|
|
|
|
|
|
|
|
//need the next 3 bytes to decide how big the frame is
|
2001-08-09 11:41:39 +02:00
|
|
|
while (buffer_size < 3) {
|
2001-08-03 14:18:08 +02:00
|
|
|
if(cur >= end)
|
|
|
|
goto done;
|
|
|
|
|
2001-08-09 11:41:39 +02:00
|
|
|
buffer[buffer_size++] = *cur++;
|
2001-08-03 14:18:08 +02:00
|
|
|
}
|
|
|
|
|
2001-08-09 11:41:39 +02:00
|
|
|
parse_syncinfo (syncinfo,buffer);
|
|
|
|
stats_print_syncinfo (syncinfo);
|
2001-08-03 14:18:08 +02:00
|
|
|
|
2001-08-09 11:41:39 +02:00
|
|
|
while (buffer_size < syncinfo->frame_size * 2 - 2) {
|
2001-08-03 14:18:08 +02:00
|
|
|
if(cur >= end)
|
|
|
|
goto done;
|
|
|
|
|
2001-08-09 11:41:39 +02:00
|
|
|
buffer[buffer_size++] = *cur++;
|
2001-08-03 14:18:08 +02:00
|
|
|
}
|
2001-08-09 11:41:39 +02:00
|
|
|
|
|
|
|
#if 0
|
2001-08-03 14:18:08 +02:00
|
|
|
// Check the crc over the entire frame
|
|
|
|
crc_init();
|
2001-08-09 11:41:39 +02:00
|
|
|
crc_process_frame (buffer, syncinfo->frame_size * 2 - 2);
|
2001-08-03 14:18:08 +02:00
|
|
|
|
2001-08-09 11:41:39 +02:00
|
|
|
if (!crc_validate()) {
|
2001-08-03 14:18:08 +02:00
|
|
|
fprintf(stderr,"** CRC failed - skipping frame **\n");
|
2001-08-09 11:41:39 +02:00
|
|
|
goto done;
|
2001-08-03 14:18:08 +02:00
|
|
|
}
|
2001-08-09 11:41:39 +02:00
|
|
|
#endif
|
|
|
|
|
2001-08-03 14:18:08 +02:00
|
|
|
//if we got to this point, we found a valid ac3 frame to decode
|
|
|
|
|
2001-08-09 11:41:39 +02:00
|
|
|
bitstream_init (buffer);
|
2001-08-03 14:18:08 +02:00
|
|
|
//get rid of the syncinfo struct as we already parsed it
|
2001-08-09 11:41:39 +02:00
|
|
|
bitstream_get (24);
|
2001-08-03 14:18:08 +02:00
|
|
|
|
|
|
|
//reset the syncword for next time
|
|
|
|
syncword = 0xffff;
|
2001-08-09 11:41:39 +02:00
|
|
|
buffer_size = 0;
|
2001-08-03 14:18:08 +02:00
|
|
|
ret = 1;
|
|
|
|
|
|
|
|
done:
|
|
|
|
syncinfo->syncword = syncword;
|
|
|
|
*start = cur;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2001-08-09 11:41:39 +02:00
|
|
|
|
|
|
|
void inline decode_mute (void)
|
2001-08-03 14:18:08 +02:00
|
|
|
{
|
|
|
|
//mute the frame
|
2001-08-09 11:41:39 +02:00
|
|
|
memset (s16_samples, 0, sizeof(int16_t) * 256 * 2 * 6);
|
2001-08-03 14:18:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-08-09 11:41:39 +02:00
|
|
|
void ac3dec_init (void)
|
2001-08-03 14:18:08 +02:00
|
|
|
{
|
2001-08-09 11:41:39 +02:00
|
|
|
// FIXME - don't do that statically here
|
|
|
|
ac3_config.num_output_ch = 2;
|
|
|
|
ac3_config.flags = 0;
|
|
|
|
|
|
|
|
imdct_init ();
|
|
|
|
downmix_init ();
|
|
|
|
memset (&syncinfo, 0, sizeof (syncinfo));
|
|
|
|
memset (&bsi, 0, sizeof (bsi));
|
|
|
|
memset (&audblk, 0, sizeof (audblk));
|
|
|
|
sanity_check_init (&syncinfo,&bsi,&audblk);
|
2001-08-03 14:18:08 +02:00
|
|
|
}
|
|
|
|
|
2001-08-09 11:41:39 +02:00
|
|
|
#ifdef __OMS__
|
|
|
|
size_t ac3dec_decode_data (plugin_output_audio_t *output, uint8_t *data_start, uint8_t *data_end)
|
|
|
|
#else
|
|
|
|
size_t ac3dec_decode_data (uint8_t *data_start ,uint8_t *data_end, int ac3reset, int *input_pointer, int *output_pointer, char *ac3_data)
|
|
|
|
#endif
|
2001-08-03 14:18:08 +02:00
|
|
|
{
|
2001-08-09 11:41:39 +02:00
|
|
|
uint32_t i;
|
2001-08-03 14:18:08 +02:00
|
|
|
int datasize;
|
|
|
|
char *data;
|
|
|
|
|
2001-08-09 11:41:39 +02:00
|
|
|
|
2001-08-03 14:18:08 +02:00
|
|
|
if(ac3reset != 0){
|
|
|
|
syncinfo.syncword = 0xffff;
|
2001-08-09 11:41:39 +02:00
|
|
|
buffer_size = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (setjmp (error_jmp_mark) < 0) {
|
|
|
|
ac3dec_init ();
|
|
|
|
return 0;
|
2001-08-03 14:18:08 +02:00
|
|
|
}
|
|
|
|
|
2001-08-09 11:41:39 +02:00
|
|
|
while (decode_buffer_syncframe (&syncinfo, &data_start, data_end)) {
|
|
|
|
parse_bsi (&bsi);
|
|
|
|
|
|
|
|
#ifndef __OMS__
|
|
|
|
if(!done_banner) {
|
|
|
|
// stats_print_banner(&syncinfo,&bsi);
|
|
|
|
done_banner = 1;
|
2001-08-03 14:18:08 +02:00
|
|
|
}
|
2001-08-09 11:41:39 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
// compute downmix parameters
|
|
|
|
// downmix to tow channels for now
|
|
|
|
dm_par.clev = 0.0; dm_par.slev = 0.0; dm_par.unit = 1.0;
|
|
|
|
if (bsi.acmod & 0x1) // have center
|
|
|
|
dm_par.clev = cmixlev_lut[bsi.cmixlev];
|
|
|
|
|
|
|
|
if (bsi.acmod & 0x4) // have surround channels
|
|
|
|
dm_par.slev = smixlev_lut[bsi.surmixlev];
|
2001-08-03 14:18:08 +02:00
|
|
|
|
2001-08-09 11:41:39 +02:00
|
|
|
dm_par.unit /= 1.0 + dm_par.clev + dm_par.slev;
|
|
|
|
dm_par.clev *= dm_par.unit;
|
|
|
|
dm_par.slev *= dm_par.unit;
|
2001-08-03 14:18:08 +02:00
|
|
|
|
2001-08-09 11:41:39 +02:00
|
|
|
for(i=0; i < 6; i++) {
|
2001-08-03 14:18:08 +02:00
|
|
|
//Initialize freq/time sample storage
|
2001-08-09 11:41:39 +02:00
|
|
|
memset (samples, 0, sizeof(float) * 256 * (bsi.nfchans + bsi.lfeon));
|
2001-08-03 14:18:08 +02:00
|
|
|
|
|
|
|
// Extract most of the audblk info from the bitstream
|
|
|
|
// (minus the mantissas
|
2001-08-09 11:41:39 +02:00
|
|
|
parse_audblk (&bsi,&audblk);
|
2001-08-03 14:18:08 +02:00
|
|
|
|
|
|
|
// Take the differential exponent data and turn it into
|
|
|
|
// absolute exponents
|
2001-08-09 11:41:39 +02:00
|
|
|
exponent_unpack (&bsi,&audblk);
|
2001-08-03 14:18:08 +02:00
|
|
|
|
|
|
|
// Figure out how many bits per mantissa
|
2001-08-09 11:41:39 +02:00
|
|
|
bit_allocate (syncinfo.fscod,&bsi,&audblk);
|
2001-08-03 14:18:08 +02:00
|
|
|
|
|
|
|
// Extract the mantissas from the stream and
|
|
|
|
// generate floating point frequency coefficients
|
2001-08-09 11:41:39 +02:00
|
|
|
coeff_unpack (&bsi,&audblk,samples);
|
2001-08-03 14:18:08 +02:00
|
|
|
|
2001-08-09 11:41:39 +02:00
|
|
|
if (bsi.acmod == 0x2)
|
|
|
|
rematrix (&audblk,samples);
|
2001-08-03 14:18:08 +02:00
|
|
|
|
|
|
|
// Convert the frequency samples into time samples
|
2001-08-09 11:41:39 +02:00
|
|
|
imdct (&bsi,&audblk,samples, &s16_samples[i * 2 * 256], &dm_par);
|
2001-08-03 14:18:08 +02:00
|
|
|
|
|
|
|
// Downmix into the requested number of channels
|
2001-08-09 11:41:39 +02:00
|
|
|
// and convert floating point to int16_t
|
|
|
|
// downmix(&bsi,samples,&s16_samples[i * 2 * 256]);
|
2001-08-03 14:18:08 +02:00
|
|
|
|
2001-08-09 11:41:39 +02:00
|
|
|
if (sanity_check(&syncinfo,&bsi,&audblk) < 0) {
|
|
|
|
HANDLE_ERROR ();
|
|
|
|
return 0;
|
|
|
|
}
|
2001-08-03 14:18:08 +02:00
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2001-08-09 11:41:39 +02:00
|
|
|
if (!is_output_initialized) {
|
|
|
|
#ifdef __OMS__
|
|
|
|
plugin_output_audio_attr_t attr;
|
|
|
|
#ifdef __sun__
|
|
|
|
attr.format = 16;
|
|
|
|
#else
|
|
|
|
attr.format = AFMT_S16_NE;
|
|
|
|
#endif
|
|
|
|
attr.speed = syncinfo.sampling_rate;
|
|
|
|
attr.channels = 2;
|
|
|
|
|
|
|
|
// output->setup (&attr);
|
|
|
|
#else
|
|
|
|
// ao_functions->open (16, syncinfo.sampling_rate, 2);
|
|
|
|
#endif
|
2001-08-03 14:18:08 +02:00
|
|
|
is_output_initialized = 1;
|
|
|
|
}
|
2001-08-09 11:41:39 +02:00
|
|
|
|
|
|
|
#ifdef __OMS__
|
|
|
|
output->write (s16_samples, 256 * 6 * 2 * 2);
|
|
|
|
#else
|
|
|
|
// ao_functions->play(s16_samples, 256 * 6 * 2);
|
2001-08-03 14:18:08 +02:00
|
|
|
data = (char *)s16_samples;
|
|
|
|
datasize = 0;
|
|
|
|
while(datasize < 6144){
|
|
|
|
if(((*input_pointer+1) % AC3_BUFFER_SIZE) != *output_pointer){ // There is room in the sync_buffer
|
|
|
|
ac3_data[*input_pointer]=data[datasize];
|
|
|
|
datasize++;
|
|
|
|
*input_pointer = (*input_pointer+1) % AC3_BUFFER_SIZE;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
*input_pointer = *output_pointer = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-08-09 11:41:39 +02:00
|
|
|
#endif
|
2001-08-03 14:18:08 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2001-08-09 11:41:39 +02:00
|
|
|
decode_mute ();
|
|
|
|
|
2001-08-03 14:18:08 +02:00
|
|
|
return 0;
|
|
|
|
}
|