diff options
author | Fabrice Bellard <fabrice@bellard.org> | 2003-01-27 09:21:30 +0000 |
---|---|---|
committer | Fabrice Bellard <fabrice@bellard.org> | 2003-01-27 09:21:30 +0000 |
commit | 425ed6e223b8dd190e9fbeb4a41c6479f3fc8df0 (patch) | |
tree | 57fbdc23c600efc2cc0f99df119b9a2752b9ac5a | |
parent | 850742d785cd566204b112d77c018e9f2b701239 (diff) | |
download | ffmpeg-425ed6e223b8dd190e9fbeb4a41c6479f3fc8df0.tar.gz |
DV audio decoder by Roman Shaposhnick
Originally committed as revision 1514 to svn://svn.ffmpeg.org/ffmpeg/trunk
-rw-r--r-- | libavcodec/allcodecs.c | 2 | ||||
-rw-r--r-- | libavcodec/dv.c | 118 | ||||
-rw-r--r-- | libavcodec/dvdata.h | 39 | ||||
-rw-r--r-- | libavformat/dv.c | 52 |
4 files changed, 184 insertions, 27 deletions
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index a5d2e41cfb..cc06645395 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -72,7 +72,7 @@ void avcodec_register_all(void) 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 --git a/libavcodec/dv.c b/libavcodec/dv.c index f312c0264c..554b593e7a 100644 --- a/libavcodec/dv.c +++ b/libavcodec/dv.c @@ -634,7 +634,6 @@ AVCodec dvvideo_decoder = { typedef struct DVAudioDecodeContext { AVCodecContext *avctx; GetBitContext gb; - } DVAudioDecodeContext; static int dvaudio_decode_init(AVCodecContext *avctx) @@ -643,13 +642,126 @@ static int dvaudio_decode_init(AVCodecContext *avctx) 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 --git a/libavcodec/dvdata.h b/libavcodec/dvdata.h index b5c1f56077..4e1fc39c7f 100644 --- a/libavcodec/dvdata.h +++ b/libavcodec/dvdata.h @@ -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 @@ static const UINT16 dv_place_411[1350] = { 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 */ +}; diff --git a/libavformat/dv.c b/libavformat/dv.c index d6d5fd938c..64cc0bef1b 100644 --- a/libavformat/dv.c +++ b/libavformat/dv.c @@ -22,15 +22,17 @@ #define PAL_FRAME_SIZE 144000 typedef struct DVDemuxContext { - int is_audio; + int is_audio; + uint8_t buf[PAL_FRAME_SIZE]; + int size; } DVDemuxContext; /* raw input */ static int dv_read_header(AVFormatContext *s, AVFormatParameters *ap) { - AVStream *vst; - // AVStream *ast; + AVStream *vst, *ast; + DVDemuxContext *c = s->priv_data; vst = av_new_stream(s, 0); if (!vst) @@ -38,42 +40,46 @@ static int dv_read_header(AVFormatContext *s, vst->codec.codec_type = CODEC_TYPE_VIDEO; vst->codec.codec_id = CODEC_ID_DVVIDEO; -#if 0 + ast = av_new_stream(s, 1); if (!ast) return AVERROR_NOMEM; ast->codec.codec_type = CODEC_TYPE_AUDIO; ast->codec.codec_id = CODEC_ID_DVAUDIO; -#endif + ast->codec.channels = 2; + c->is_audio = 0; + return 0; } /* XXX: build fake audio stream when DV audio decoder will be finished */ static int dv_read_packet(AVFormatContext *s, AVPacket *pkt) { - int ret, size, dsf; - uint8_t buf[4]; + int ret, dsf; + DVDemuxContext *c = s->priv_data; - ret = get_buffer(&s->pb, buf, 4); - if (ret <= 0) - return -EIO; - dsf = buf[3] & 0x80; - if (!dsf) - size = NTSC_FRAME_SIZE; - else - size = PAL_FRAME_SIZE; + if (!c->is_audio) { + ret = get_buffer(&s->pb, c->buf, 4); + if (ret <= 0) + return -EIO; + dsf = c->buf[3] & 0x80; + if (!dsf) + c->size = NTSC_FRAME_SIZE; + else + c->size = PAL_FRAME_SIZE; + + ret = get_buffer(&s->pb, c->buf + 4, c->size - 4); + if (ret <= 0) + return -EIO; + } - if (av_new_packet(pkt, size) < 0) + if (av_new_packet(pkt, c->size) < 0) return -EIO; - pkt->stream_index = 0; - memcpy(pkt->data, buf, 4); - ret = get_buffer(&s->pb, pkt->data + 4, size - 4); - if (ret <= 0) { - av_free_packet(pkt); - return -EIO; - } + pkt->stream_index = c->is_audio; + c->is_audio = !c->is_audio; + memcpy(pkt->data, c->buf, c->size); return ret; } |