summaryrefslogtreecommitdiffstats
path: root/libmpcodecs/ad_hwac3.c
diff options
context:
space:
mode:
authoralex <alex@b3059339-0415-0410-9bf9-f77b7e298cf2>2003-04-28 16:17:26 +0000
committeralex <alex@b3059339-0415-0410-9bf9-f77b7e298cf2>2003-04-28 16:17:26 +0000
commit489e551f54e50c4f45aa60a9675774cd881f5163 (patch)
tree4054bd26b8a58ced9224c9006563706d69be3aa3 /libmpcodecs/ad_hwac3.c
parent7e677ff7cfa8f11888303d78cb342add509c4ff7 (diff)
downloadmpv-489e551f54e50c4f45aa60a9675774cd881f5163.tar.bz2
mpv-489e551f54e50c4f45aa60a9675774cd881f5163.tar.xz
DTS support by Peter Schuller <peterschueller@telemed.de> (revised by arpi)
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@10013 b3059339-0415-0410-9bf9-f77b7e298cf2
Diffstat (limited to 'libmpcodecs/ad_hwac3.c')
-rw-r--r--libmpcodecs/ad_hwac3.c375
1 files changed, 320 insertions, 55 deletions
diff --git a/libmpcodecs/ad_hwac3.c b/libmpcodecs/ad_hwac3.c
index 59f4533270..22e35df303 100644
--- a/libmpcodecs/ad_hwac3.c
+++ b/libmpcodecs/ad_hwac3.c
@@ -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;
+ 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;
+ if(ac3dts_fillbuff(sh_audio) < 0)
+ {
+ mp_msg(MSGT_DECAUDIO, MSGL_ERR, "AC3/DTS sync 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!)*/
return 1;
}
@@ -71,37 +132,241 @@ static void uninit(sh_audio_t *sh)
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 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);
-
- 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);
-
- return 6144;
+ 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
+};
+
+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;
+
+ 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;
+}
+
+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