# HG changeset patch # User bellard # Date 1043659290 0 # Node ID c7922c5becf60392cb0846ab6bdc5ce6f0af7bc4 # Parent 9fbad5cf7e9e3ed58b4f058a8b05f44955718ab5 DV audio decoder by Roman Shaposhnick diff -r 9fbad5cf7e9e -r c7922c5becf6 allcodecs.c --- a/allcodecs.c Sun Jan 26 23:11:08 2003 +0000 +++ b/allcodecs.c Mon Jan 27 09:21:30 2003 +0000 @@ -72,7 +72,7 @@ register_avcodec(&rv10_decoder); register_avcodec(&svq1_decoder); register_avcodec(&dvvideo_decoder); - // register_avcodec(&dvaudio_decoder); + register_avcodec(&dvaudio_decoder); register_avcodec(&mjpeg_decoder); register_avcodec(&mjpegb_decoder); register_avcodec(&mp2_decoder); diff -r 9fbad5cf7e9e -r c7922c5becf6 dv.c --- a/dv.c Sun Jan 26 23:11:08 2003 +0000 +++ b/dv.c Mon Jan 27 09:21:30 2003 +0000 @@ -634,7 +634,6 @@ typedef struct DVAudioDecodeContext { AVCodecContext *avctx; GetBitContext gb; - } DVAudioDecodeContext; static int dvaudio_decode_init(AVCodecContext *avctx) @@ -643,13 +642,126 @@ return 0; } +static UINT16 dv_audio_12to16(UINT16 sample) +{ + UINT16 shift, result; + + sample = (sample < 0x800) ? sample : sample | 0xf000; + shift = (sample & 0xf00) >> 8; + + if (shift < 0x2 || shift > 0xd) { + result = sample; + } else if (shift < 0x8) { + shift--; + result = (sample - (256 * shift)) << shift; + } else { + shift = 0xe - shift; + result = ((sample + ((256 * shift) + 1)) << shift) - 1; + } + + return result; +} + /* NOTE: exactly one frame must be given (120000 bytes for NTSC, - 144000 bytes for PAL) */ + 144000 bytes for PAL) + + There's a couple of assumptions being made here: + 1. We don't do any kind of audio error correction. It means, + that erroneous samples 0x8000 are being passed upwards. + Do we need to silence erroneous samples ? Average them ? + 2. We don't do software emphasis. + 3. We are not checking for 'speed' argument being valid. + 4. Audio is always returned as 16bit linear samples: 12bit + nonlinear samples are converted into 16bit linear ones. +*/ static int dvaudio_decode_frame(AVCodecContext *avctx, void *data, int *data_size, UINT8 *buf, int buf_size) { - // DVAudioDecodeContext *s = avctx->priv_data; + DVVideoDecodeContext *s = avctx->priv_data; + const UINT16 (*unshuffle)[9]; + int smpls, freq, quant, sys, stride, difseg, ad, dp, nb_dif_segs, i; + UINT16 lc, rc; + UINT8 *buf_ptr; + + /* parse id */ + init_get_bits(&s->gb, &buf[AAUX_OFFSET], 5*8); + i = get_bits(&s->gb, 8); + if (i != 0x50) { /* No audio ? */ + *data_size = 0; + return buf_size; + } + + get_bits(&s->gb, 1); /* 0 - locked audio, 1 - unlocked audio */ + skip_bits(&s->gb, 1); + smpls = get_bits(&s->gb, 6); /* samples in this frame - min. samples */ + + skip_bits(&s->gb, 8); + + skip_bits(&s->gb, 2); + sys = get_bits(&s->gb, 1); /* 0 - 60 fields, 1 = 50 fields */ + skip_bits(&s->gb, 5); + + get_bits(&s->gb, 1); /* 0 - emphasis on, 1 - emphasis off */ + get_bits(&s->gb, 1); /* 0 - reserved, 1 - emphasis time constant 50/15us */ + freq = get_bits(&s->gb, 3); /* 0 - 48KHz, 1 - 44,1kHz, 2 - 32 kHz */ + quant = get_bits(&s->gb, 3); /* 0 - 16bit linear, 1 - 12bit nonlinear */ + + if (quant > 1) + return -1; /* Unsupported quantization */ + + avctx->sample_rate = dv_audio_frequency[freq]; + // What about: + // avctx->bit_rate = + // avctx->frame_size = + + *data_size = (dv_audio_min_samples[sys][freq] + smpls) * + avctx->channels * 2; + + if (sys) { + nb_dif_segs = 12; + stride = 108; + unshuffle = dv_place_audio50; + } else { + nb_dif_segs = 10; + stride = 90; + unshuffle = dv_place_audio60; + } + + /* for each DIF segment */ + buf_ptr = buf; + for (difseg = 0; difseg < nb_dif_segs; difseg++) { + buf_ptr += 6 * 80; /* skip DIF segment header */ + for (ad = 0; ad < 9; ad++) { + + for (dp = 8; dp < 80; dp+=2) { + if (quant == 0) { /* 16bit quantization */ + i = unshuffle[difseg][ad] + (dp - 8)/2 * stride; + ((short *)data)[i] = (buf_ptr[dp] << 8) | buf_ptr[dp+1]; + } else { /* 12bit quantization */ + if (difseg >= nb_dif_segs/2) + goto out; /* We're not doing 4ch at this time */ + + lc = ((UINT16)buf_ptr[dp] << 4) | + ((UINT16)buf_ptr[dp+2] >> 4); + rc = ((UINT16)buf_ptr[dp+1] << 4) | + ((UINT16)buf_ptr[dp+2] & 0x0f); + lc = dv_audio_12to16(lc); + rc = dv_audio_12to16(rc); + + i = unshuffle[difseg][ad] + (dp - 8)/3 * stride; + ((short *)data)[i] = lc; + i = unshuffle[difseg+nb_dif_segs/2][ad] + (dp - 8)/3 * stride; + ((short *)data)[i] = rc; + ++dp; + } + } + + buf_ptr += 16 * 80; /* 15 Video DIFs + 1 Audio DIF */ + } + } + +out: return buf_size; } diff -r 9fbad5cf7e9e -r c7922c5becf6 dvdata.h --- a/dvdata.h Sun Jan 26 23:11:08 2003 +0000 +++ b/dvdata.h Mon Jan 27 09:21:30 2003 +0000 @@ -18,6 +18,7 @@ */ #define NB_DV_VLC 409 +#define AAUX_OFFSET (80*6 + 80*16*3 + 3) static const UINT16 dv_vlc_bits[409] = { 0x0000, 0x0002, 0x0007, 0x0008, 0x0009, 0x0014, 0x0015, 0x0016, @@ -905,3 +906,41 @@ 0x0834, 0x2320, 0x2f44, 0x3810, 0x1658, }; +static const UINT16 dv_place_audio60[10][9] = { + { 0, 30, 60, 20, 50, 80, 10, 40, 70 }, /* 1st channel */ + { 6, 36, 66, 26, 56, 86, 16, 46, 76 }, + { 12, 42, 72, 2, 32, 62, 22, 52, 82 }, + { 18, 48, 78, 8, 38, 68, 28, 58, 88 }, + { 24, 54, 84, 14, 44, 74, 4, 34, 64 }, + + { 1, 31, 61, 21, 51, 81, 11, 41, 71 }, /* 2nd channel */ + { 7, 37, 67, 27, 57, 87, 17, 47, 77 }, + { 13, 43, 73, 3, 33, 63, 23, 53, 83 }, + { 19, 49, 79, 9, 39, 69, 29, 59, 89 }, + { 25, 55, 85, 15, 45, 75, 5, 35, 65 }, +}; + +static const UINT16 dv_place_audio50[12][9] = { + { 0, 36, 72, 26, 62, 98, 16, 52, 88}, /* 1st channel */ + { 6, 42, 78, 32, 68, 104, 22, 58, 94}, + { 12, 48, 84, 2, 38, 74, 28, 64, 100}, + { 18, 54, 90, 8, 44, 80, 34, 70, 106}, + { 24, 60, 96, 14, 50, 86, 4, 40, 76}, + { 30, 66, 102, 20, 56, 92, 10, 46, 82}, + + { 1, 37, 73, 27, 63, 99, 17, 53, 89}, /* 2nd channel */ + { 7, 43, 79, 33, 69, 105, 23, 59, 95}, + { 13, 49, 85, 3, 39, 75, 29, 65, 101}, + { 19, 55, 91, 9, 45, 81, 35, 71, 107}, + { 25, 61, 97, 15, 51, 87, 5, 41, 77}, + { 31, 67, 103, 21, 57, 93, 11, 47, 83}, +}; + +static const int dv_audio_frequency[3] = { + 48000, 44100, 32000, +}; + +static const int dv_audio_min_samples[2][3] = { + { 1580, 1452, 1053 }, /* 60 fields */ + { 1896, 1742, 1264 }, /* 50 fileds */ +};