Mercurial > mplayer.hg
changeset 10012:f8f3f8b4e0d7
DTS support by Peter Schuller <peterschueller@telemed.de> (revised by arpi)
author | alex |
---|---|
date | Mon, 28 Apr 2003 16:17:26 +0000 |
parents | 736ca83d609f |
children | 1dfffdd245dc |
files | libmpcodecs/ad_hwac3.c |
diffstat | 1 files changed, 318 insertions(+), 53 deletions(-) [+] |
line wrap: on
line diff
--- a/libmpcodecs/ad_hwac3.c Mon Apr 28 16:11:42 2003 +0000 +++ b/libmpcodecs/ad_hwac3.c Mon Apr 28 16:17:26 2003 +0000 @@ -1,6 +1,10 @@ // Reference: DOCS/tech/hwac3.txt !!!!! +/* DTS code based on "ac3/decode_dts.c" and "ac3/conversion.c" from "ogle 0.9" + (see http://www.dtek.chalmers.se/~dvd/) +*/ + #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -16,52 +20,109 @@ #include "../liba52/a52.h" -extern int a52_fillbuff(sh_audio_t *sh_audio); + +static int isdts = -1; static ad_info_t info = { - "AC3 pass-through SP/DIF", - "hwac3", - "Nick Kurshev", - "???", - "" + "AC3/DTS pass-through SP/DIF", + "hwac3", + "Nick Kurshev/Peter Schüller", + "???", + "" }; LIBAD_EXTERN(hwac3) + +static int dts_syncinfo(uint8_t *indata_ptr, int *flags, int *sample_rate, int *bit_rate); +static int decode_audio_dts(unsigned char *indata_ptr, int len, unsigned char *buf); + + +static int ac3dts_fillbuff(sh_audio_t *sh_audio) +{ + int length = 0; + int flags = 0; + int sample_rate = 0; + int bit_rate = 0; + + sh_audio->a_in_buffer_len = 0; + /* sync frame:*/ + while(1) + { + // DTS has a 10 byte header + while(sh_audio->a_in_buffer_len < 10) + { + int c = demux_getc(sh_audio->ds); + if(c<0) + return -1; /* EOF*/ + sh_audio->a_in_buffer[sh_audio->a_in_buffer_len++] = c; + } + + length = dts_syncinfo(sh_audio->a_in_buffer, &flags, &sample_rate, &bit_rate); + if(length >= 10) + { + if(isdts != 1) + { + mp_msg(MSGT_DECAUDIO, MSGL_STATUS, "hwac3: switched to DTS, %d bps, %d Hz\n", bit_rate, sample_rate); + isdts = 1; + } + break; + } + length = a52_syncinfo(sh_audio->a_in_buffer, &flags, &sample_rate, &bit_rate); + if(length >= 7 && length <= 3840) + { + if(isdts != 0) + { + mp_msg(MSGT_DECAUDIO, MSGL_STATUS, "hwac3: switched to AC3, %d bps, %d Hz\n", bit_rate, sample_rate); + isdts = 0; + } + break; /* we're done.*/ + } + /* bad file => resync*/ + memcpy(sh_audio->a_in_buffer, sh_audio->a_in_buffer + 1, 9); + --sh_audio->a_in_buffer_len; + } + mp_msg(MSGT_DECAUDIO, MSGL_DBG2, "ac3dts: %s len=%d flags=0x%X %d Hz %d bit/s\n", isdts == 1 ? "DTS" : isdts == 0 ? "AC3" : "unknown", length, flags, sample_rate, bit_rate); + + sh_audio->samplerate = sample_rate; + sh_audio->i_bps = bit_rate / 8; + demux_read_data(sh_audio->ds, sh_audio->a_in_buffer + 10, length - 10); + sh_audio->a_in_buffer_len = length; + + // TODO: is DTS also checksummed? + if(isdts == 0 && crc16_block(sh_audio->a_in_buffer + 2, length - 2) != 0) + mp_msg(MSGT_DECAUDIO, MSGL_STATUS, "a52: CRC check failed! \n"); + + return length; +} + + static int preinit(sh_audio_t *sh) { /* Dolby AC3 audio: */ - sh->audio_out_minsize=4*256*6; - sh->audio_in_minsize=3840; - sh->channels=2; - sh->sample_format=AFMT_AC3; + sh->audio_out_minsize = 128 * 32 * 2 * 2; // DTS seems to need more than AC3 + sh->audio_in_minsize = 8192; + sh->channels = 2; + sh->samplesize = 2; + sh->sample_format = AFMT_AC3; return 1; } static int init(sh_audio_t *sh_audio) { /* Dolby AC3 passthrough:*/ - sample_t *a52_samples=a52_init(0); - if (a52_samples == NULL) { - mp_msg(MSGT_DECAUDIO,MSGL_ERR,"A52 init failed\n"); - return 0; - } - if(a52_fillbuff(sh_audio)<0) { - mp_msg(MSGT_DECAUDIO,MSGL_ERR,"A52 sync failed\n"); - return 0; + sample_t *a52_samples = a52_init(0); + if(a52_samples == NULL) + { + mp_msg(MSGT_DECAUDIO, MSGL_ERR, "A52 init failed\n"); + return 0; } - /* - sh_audio->samplerate=ai.samplerate; // SET by a52_fillbuff() - sh_audio->samplesize=ai.framesize; - sh_audio->i_bps=ai.bitrate*(1000/8); // SET by a52_fillbuff() - sh_audio->ac3_frame=malloc(6144); - sh_audio->o_bps=sh_audio->i_bps; // XXX FIXME!!! XXX - - o_bps is calculated from samplesize*channels*samplerate - a single ac3 frame is always translated to 6144 byte packet. (zero padding)*/ - sh_audio->channels=2; - sh_audio->samplesize=2; /* 2*2*(6*256) = 6144 (very TRICKY!)*/ + if(ac3dts_fillbuff(sh_audio) < 0) + { + mp_msg(MSGT_DECAUDIO, MSGL_ERR, "AC3/DTS sync failed\n"); + return 0; + } return 1; } @@ -71,37 +132,241 @@ static int control(sh_audio_t *sh,int cmd,void* arg, ...) { - switch(cmd) - { - case ADCTRL_SKIP_FRAME: - a52_fillbuff(sh); break; // skip AC3 frame - return CONTROL_TRUE; - } + switch(cmd) + { + case ADCTRL_SKIP_FRAME: + ac3dts_fillbuff(sh); break; // skip AC3 frame + return CONTROL_TRUE; + } return CONTROL_UNKNOWN; } + static int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen) { - int len=sh_audio->a_in_buffer_len; - if(len<=0) - if((len=a52_fillbuff(sh_audio))<=0) return len; /*EOF*/ - sh_audio->a_in_buffer_len=0; + int len = sh_audio->a_in_buffer_len; + + if(len <= 0) + if((len = ac3dts_fillbuff(sh_audio)) <= 0) + return len; /*EOF*/ + sh_audio->a_in_buffer_len = 0; + + if(isdts == 1) + { + return decode_audio_dts(sh_audio->a_in_buffer, len, buf); + } + else if(isdts == 0) + { + buf[0] = 0x72; + buf[1] = 0xF8; + buf[2] = 0x1F; + buf[3] = 0x4E; + buf[4] = 0x01; //(length) ? data_type : 0; /* & 0x1F; */ + buf[5] = 0x00; + buf[6] = (len << 3) & 0xFF; + buf[7] = (len >> 5) & 0xFF; +#ifdef WORDS_BIGENDIAN + memcpy(buf + 8, sh_audio->a_in_buffer, len); // untested +#else + swab(sh_audio->a_in_buffer, buf + 8, len); +#endif + memset(buf + 8 + len, 0, 6144 - 8 - len); + + return 6144; + } + else + return -1; +} + + +static int DTS_SAMPLEFREQS[16] = +{ + 0, + 8000, + 16000, + 32000, + 64000, + 128000, + 11025, + 22050, + 44100, + 88200, + 176400, + 12000, + 24000, + 48000, + 96000, + 192000 +}; -// int ac3_iec958_build_burst(int length, int data_type, int big_endian, unsigned char * data, unsigned char * out) -// len = ac3_iec958_build_burst(len, 0x01, 1, sh_audio->a_in_buffer, buf); +static int DTS_BITRATES[30] = +{ + 32000, + 56000, + 64000, + 96000, + 112000, + 128000, + 192000, + 224000, + 256000, + 320000, + 384000, + 448000, + 512000, + 576000, + 640000, + 768000, + 896000, + 1024000, + 1152000, + 1280000, + 1344000, + 1408000, + 1411200, + 1472000, + 1536000, + 1920000, + 2048000, + 3072000, + 3840000, + 4096000 +}; + +static int dts_decode_header(uint8_t *indata_ptr, int *rate, int *nblks, int *sfreq) +{ + int ftype; + int surp; + int unknown_bit; + int fsize; + int amode; + + if(((indata_ptr[0] << 24) | (indata_ptr[1] << 16) | (indata_ptr[2] << 8) + | (indata_ptr[3])) != 0x7ffe8001) + return -1; + + ftype = indata_ptr[4] >> 7; + + surp = (indata_ptr[4] >> 2) & 0x1f; + surp = (surp + 1) % 32; + + unknown_bit = (indata_ptr[4] >> 1) & 0x01; + + *nblks = (indata_ptr[4] & 0x01) << 6 | (indata_ptr[5] >> 2); + *nblks = *nblks + 1; - buf[0] = 0x72; - buf[1] = 0xF8; - buf[2] = 0x1F; - buf[3] = 0x4E; - buf[4] = 0x01; //(length) ? data_type : 0; /* & 0x1F; */ - buf[5] = 0x00; - buf[6] = (len << 3) & 0xFF; - buf[7] = (len >> 5) & 0xFF; - swab(sh_audio->a_in_buffer, buf + 8, len); - //memcpy(buf + 8, sh_audio->a_in_buffer, len); - memset(buf + 8 + len, 0, 6144 - 8 - len); + fsize = (indata_ptr[5] & 0x03) << 12 | (indata_ptr[6] << 4) | (indata_ptr[7] >> 4); + fsize = fsize + 1; + + amode = (indata_ptr[7] & 0x0f) << 2 | (indata_ptr[8] >> 6); + *sfreq = (indata_ptr[8] >> 2) & 0x0f; + *rate = (indata_ptr[8] & 0x03) << 3 | ((indata_ptr[9] >> 5) & 0x07); + + if(ftype != 1) + { + mp_msg(MSGT_DECAUDIO, MSGL_ERR, "DTS: Termination frames not handled, REPORT BUG\n"); + return -1; + } + + if(*sfreq != 13) + { + mp_msg(MSGT_DECAUDIO, MSGL_ERR, "DTS: Only 48kHz supported, REPORT BUG\n"); + return -1; + } + + if((fsize > 8192) || (fsize < 96)) + { + mp_msg(MSGT_DECAUDIO, MSGL_ERR, "DTS: fsize: %d invalid, REPORT BUG\n", fsize); + return -1; + } + + if(*nblks != 8 && + *nblks != 16 && + *nblks != 32 && + *nblks != 64 && + *nblks != 128 && + ftype == 1) + { + mp_msg(MSGT_DECAUDIO, MSGL_ERR, "DTS: nblks %d not valid for normal frame, REPORT BUG\n", nblks); + return -1; + } + + return fsize; +} - return 6144; +static int dts_syncinfo(uint8_t *indata_ptr, int *flags, int *sample_rate, int *bit_rate) +{ + int nblks; + int fsize; + int rate; + int sfreq; + + fsize = dts_decode_header(indata_ptr, &rate, &nblks, &sfreq); + if(fsize >= 0) + { + if(rate >= 0 && rate <= 29) + *bit_rate = DTS_BITRATES[rate]; + else + *bit_rate = 0; + if(sfreq >= 1 && sfreq <= 15) + *sample_rate = DTS_SAMPLEFREQS[sfreq]; + else + *sample_rate = 0; + } + return fsize; +} + + +static int decode_audio_dts(unsigned char *indata_ptr, int len, unsigned char *buf) +{ + int nblks; + int fsize; + int rate; + int sfreq; + int burst_len; + int nr_samples; + + fsize = dts_decode_header(indata_ptr, &rate, &nblks, &sfreq); + if(fsize < 0) + return -1; + + burst_len = fsize * 8; + nr_samples = nblks * 32; + + buf[0] = 0x72; buf[1] = 0xf8; /* iec 61937 */ + buf[2] = 0x1f; buf[3] = 0x4e; /* syncword */ + switch(nr_samples) + { + case 512: + buf[4] = 0x0b; /* DTS-1 (512-sample bursts) */ + break; + case 1024: + buf[4] = 0x0c; /* DTS-2 (1024-sample bursts) */ + break; + case 2048: + buf[4] = 0x0d; /* DTS-3 (2048-sample bursts) */ + break; + default: + mp_msg(MSGT_DECAUDIO, MSGL_ERR, "DTS: %d-sample bursts not supported\n", nr_samples); + buf[4] = 0x00; + break; + } + buf[5] = 0; /* ?? */ + buf[6] = (burst_len) & 0xff; + buf[7] = (burst_len >> 8) & 0xff; + + if(fsize + 8 > nr_samples * 2 * 2) + { + mp_msg(MSGT_DECAUDIO, MSGL_ERR, "DTS: more data than fits\n"); + } +#ifdef WORDS_BIGENDIAN + memcpy(&buf[8], indata_ptr, fsize); // untested +#else + //TODO if fzise is odd, swab doesn't copy the last byte + swab(indata_ptr, &buf[8], fsize); +#endif + memset(&buf[fsize + 8], 0, nr_samples * 2 * 2 - (fsize + 8)); + + return nr_samples * 2 * 2; } #endif