/* XMPS - X MPEG Player System * Copyright (C) 1999 Damien Chavarria * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public Licensse as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * * ac3_codec.c * * AC3 Video Codec. * @Author Chavarria Damien. * Copyright 1999-2000 */ /********************************************************************* * INCLUDES * *********************************************************************/ #include "ac3_codec.h" #define BUFFER_MAX_SIZE 4096 typedef struct { xmps_audio_info_t *info; int channels; int format; int bit_count; int sample_size; int frequency; int block_align; int avg_bytes_per_sec; int data_offset; int data_length; xmps_system_plugin_t *system; int stream_id; audblk_t audblk; bsi_t bsi; syncinfo_t syncinfo; stream_samples_t samples; unsigned short s16_samples[2 * 6 * 256] __attribute__ ((aligned(16))); float cmixlev_lut[4]; float smixlev_lut[4]; dm_par_t dm_par; char buffer[BUFFER_MAX_SIZE]; unsigned int buffer_size; } ac3_t; int ac3_error; /* * get_audio_codec_info : MANDATORY * * Used by scanplugins to get a pointer to the codec. * */ xmps_audio_decoder_plugin_t *get_audio_decoder_info(void) { xmps_audio_decoder_plugin_t *audio_decoder; audio_decoder = (xmps_audio_decoder_plugin_t *) malloc(sizeof(xmps_audio_decoder_plugin_t)); audio_decoder->name = "AC3"; audio_decoder->data = malloc(sizeof(ac3_t)); audio_decoder->open = ac3_open; audio_decoder->get = ac3_get; audio_decoder->set = ac3_set; audio_decoder->decompress = ac3_decompress; audio_decoder->close = ac3_close; ((ac3_t *) audio_decoder->data)->info = (xmps_audio_info_t *) malloc(sizeof(xmps_audio_info_t)); ((ac3_t *) audio_decoder->data)->cmixlev_lut[0] = 0.707; ((ac3_t *) audio_decoder->data)->cmixlev_lut[1] = 0.595; ((ac3_t *) audio_decoder->data)->cmixlev_lut[2] = 0.500; ((ac3_t *) audio_decoder->data)->cmixlev_lut[3] = 0.707; ((ac3_t *) audio_decoder->data)->smixlev_lut[0] = 0.707; ((ac3_t *) audio_decoder->data)->smixlev_lut[1] = 0.595; ((ac3_t *) audio_decoder->data)->smixlev_lut[2] = 0.0; ((ac3_t *) audio_decoder->data)->smixlev_lut[3] = 0.500; ac3_error = 0; return audio_decoder; } /********************************************************************* * FUNCTIONS * *********************************************************************/ unsigned int ac3_open(xmps_audio_decoder_plugin_t *audio_decoder) { if(audio_decoder == NULL) { return 0; } return 1; } void decompress_ac3(ac3_t *data) { int i; unsigned short syncword = 0xFFFF; unsigned char dummy; data->buffer_size = 0; /* * we need to find the * beginning of the frame; */ while (syncword != 0x0b77) { data->system->read(data->system, data->stream_id, &dummy, 1); syncword = (syncword << 8) + dummy; } data->buffer_size = 0; while (data->buffer_size < 3) { data->system->read(data->system, data->stream_id, &data->buffer[data->buffer_size++], 1); } parse_syncinfo (&data->syncinfo, data->buffer); /* * now we can read * the entire frame */ /* while (data->buffer_size < data->syncinfo.frame_size * 2 - 2) { data->system->read(data->system, data->stream_id, &data->buffer[data->buffer_size++], 1); } */ data->system->read(data->system, data->stream_id, data->buffer + data->buffer_size, (data->syncinfo.frame_size * 2) - 5); data->buffer_size = (data->syncinfo.frame_size * 2) - 2; /* * and initialize the bitstream */ bitstream_init(data->buffer); bitstream_get(24); /* * now we can start decoding */ parse_bsi(&data->bsi); /* * compute downmix parameters * downmix to tow channels for now */ data->dm_par.clev = 0.0; data->dm_par.slev = 0.0; data->dm_par.unit = 1.0; if (data->bsi.acmod & 0x1) // have center data->dm_par.clev = data->cmixlev_lut[data->bsi.cmixlev]; if (data->bsi.acmod & 0x4) // have surround channels data->dm_par.slev = data->smixlev_lut[data->bsi.surmixlev]; data->dm_par.unit /= 1.0 + data->dm_par.clev + data->dm_par.slev; data->dm_par.clev *= data->dm_par.unit; data->dm_par.slev *= data->dm_par.unit; for(i=0; i < 6; i++) { //Initialize freq/time sample storage memset (data->samples, 0, sizeof(float) * 256 * (data->bsi.nfchans + data->bsi.lfeon)); // Extract most of the audblk info from the bitstream // (minus the mantissas parse_audblk(&data->bsi, &data->audblk); // Take the differential exponent data and turn it into // absolute exponents exponent_unpack(&data->bsi, &data->audblk); if(ac3_error) goto error; // Figure out how many bits per mantissa bit_allocate(data->syncinfo.fscod, &data->bsi, &data->audblk); // Extract the mantissas from the stream and // generate floating point frequency coefficients coeff_unpack (&data->bsi, &data->audblk, data->samples); if(ac3_error) goto error; if(data->bsi.acmod == 0x2) rematrix (&data->audblk, data->samples); // Convert the frequency samples into time samples imdct (&data->bsi, &data->audblk, data->samples, &data->s16_samples[i * 2 * 256], &data->dm_par); continue; } ring_write((char *) data->s16_samples, 256*2*2*6); return; error: memset(data->s16_samples, 0, 256*2*2*6); ring_write((char *) data->s16_samples, 256*2*2*6); ac3_error = 0; } void* ac3_get(xmps_audio_decoder_plugin_t *audio_decoder, unsigned int flag, void *arg) { ac3_t *data; if(audio_decoder == NULL) { return NULL; } data = (ac3_t *) audio_decoder->data; if(data == NULL) { return NULL; } switch(flag) { case XMPS_FLAG_AUDIO_FORMAT_LIST: { GList *list = NULL; switch(data->bit_count) { case 8: data->info->format.type = XMPS_AUDIO_FORMAT_U8; break; case 16: default: data->info->format.type = XMPS_AUDIO_FORMAT_S16; break; } data->info->format.bit_count = data->bit_count; list = g_list_prepend(list, (void *) &data->info->format); return (void *) list; } break; case XMPS_FLAG_AUDIO_INFO: { data->info->channels = 2; if(data->info->channels > 2) data->info->channels = 2; data->info->frequency = 48000; data->info->format.type = XMPS_AUDIO_FORMAT_S16; data->info->format.bit_count = 16; data->info->sample_size = 4; return data->info; } break; default: break; } return NULL; } unsigned int ac3_set(xmps_audio_decoder_plugin_t *audio_decoder, unsigned int flag, void *arg) { ac3_t *data; if(audio_decoder == NULL) { return 0; } data = (ac3_t *) audio_decoder->data; if(data == NULL) { return 0; } switch(flag) { case XMPS_FLAG_INPUT: { xmps_data_t *data_stream; data_stream = (xmps_data_t *) arg; if(data_stream == NULL) { return 0; } XMPS_DEBUG("trying to open data stream!"); if(data_stream->type == XMPS_DATA_AUDIO_COMP && data_stream->plugin_type == XMPS_PLUGIN_SYSTEM) { if(strstr(data_stream->audio_compression, "MPG3") != NULL) { unsigned int i; unsigned short syncword; unsigned char dummy; xmps_system_plugin_t *system; /* * check for frame header * */ system = (xmps_system_plugin_t *) data_stream->plugin; i = 0; syncword = 0xFFFF; while (syncword != 0x0b77 && i < 2048) { system->read(system, data_stream->id, &dummy, 1); syncword = (syncword << 8) + dummy; i++; } if( syncword == 0x0b77) { system->seek(system, data_stream->id, 0, XMPS_SEEK_SET); ring_init(); imdct_init(); data->system = system; data->stream_id = data_stream->id; while(!ring_full(256*6*2*2)) { XMPS_DEBUG("buffering (1 AC3 frame)"); decompress_ac3(data); } return 1; } else { system->seek(system, data_stream->id, 0, XMPS_SEEK_SET); return 0; } } } } break; case XMPS_FLAG_EMPTY_BUFFERS: ring_init(); break; default: break; } return 0; } unsigned int ac3_decompress(xmps_audio_decoder_plugin_t *audio_decoder, void *in_buffer, void *out_buffer, unsigned int size) { ac3_t *data; if(audio_decoder == NULL) { return 0; } data = (ac3_t *) audio_decoder->data; if(data == NULL) { return 0; } while(!ring_full(256*6*2*2)) { decompress_ac3(data); } ring_read(out_buffer, size); return size; } unsigned int ac3_close(xmps_audio_decoder_plugin_t *audio_decoder) { ac3_t *data; if(audio_decoder == NULL) { return 0; } data = (ac3_t *) audio_decoder->data; if(data == NULL) { return 0; } return 1; }