1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2024-12-23 12:43:46 +02:00

DV audio decoder by Roman Shaposhnick

Originally committed as revision 1514 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
Fabrice Bellard 2003-01-27 09:21:30 +00:00
parent 850742d785
commit 425ed6e223
4 changed files with 184 additions and 27 deletions

View File

@ -72,7 +72,7 @@ void avcodec_register_all(void)
register_avcodec(&rv10_decoder); register_avcodec(&rv10_decoder);
register_avcodec(&svq1_decoder); register_avcodec(&svq1_decoder);
register_avcodec(&dvvideo_decoder); register_avcodec(&dvvideo_decoder);
// register_avcodec(&dvaudio_decoder); register_avcodec(&dvaudio_decoder);
register_avcodec(&mjpeg_decoder); register_avcodec(&mjpeg_decoder);
register_avcodec(&mjpegb_decoder); register_avcodec(&mjpegb_decoder);
register_avcodec(&mp2_decoder); register_avcodec(&mp2_decoder);

View File

@ -634,7 +634,6 @@ AVCodec dvvideo_decoder = {
typedef struct DVAudioDecodeContext { typedef struct DVAudioDecodeContext {
AVCodecContext *avctx; AVCodecContext *avctx;
GetBitContext gb; GetBitContext gb;
} DVAudioDecodeContext; } DVAudioDecodeContext;
static int dvaudio_decode_init(AVCodecContext *avctx) static int dvaudio_decode_init(AVCodecContext *avctx)
@ -643,13 +642,126 @@ static int dvaudio_decode_init(AVCodecContext *avctx)
return 0; 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, /* 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, static int dvaudio_decode_frame(AVCodecContext *avctx,
void *data, int *data_size, void *data, int *data_size,
UINT8 *buf, int buf_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; return buf_size;
} }

View File

@ -18,6 +18,7 @@
*/ */
#define NB_DV_VLC 409 #define NB_DV_VLC 409
#define AAUX_OFFSET (80*6 + 80*16*3 + 3)
static const UINT16 dv_vlc_bits[409] = { static const UINT16 dv_vlc_bits[409] = {
0x0000, 0x0002, 0x0007, 0x0008, 0x0009, 0x0014, 0x0015, 0x0016, 0x0000, 0x0002, 0x0007, 0x0008, 0x0009, 0x0014, 0x0015, 0x0016,
@ -905,3 +906,41 @@ static const UINT16 dv_place_411[1350] = {
0x0834, 0x2320, 0x2f44, 0x3810, 0x1658, 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 */
};

View File

@ -22,15 +22,17 @@
#define PAL_FRAME_SIZE 144000 #define PAL_FRAME_SIZE 144000
typedef struct DVDemuxContext { typedef struct DVDemuxContext {
int is_audio; int is_audio;
uint8_t buf[PAL_FRAME_SIZE];
int size;
} DVDemuxContext; } DVDemuxContext;
/* raw input */ /* raw input */
static int dv_read_header(AVFormatContext *s, static int dv_read_header(AVFormatContext *s,
AVFormatParameters *ap) AVFormatParameters *ap)
{ {
AVStream *vst; AVStream *vst, *ast;
// AVStream *ast; DVDemuxContext *c = s->priv_data;
vst = av_new_stream(s, 0); vst = av_new_stream(s, 0);
if (!vst) if (!vst)
@ -38,42 +40,46 @@ static int dv_read_header(AVFormatContext *s,
vst->codec.codec_type = CODEC_TYPE_VIDEO; vst->codec.codec_type = CODEC_TYPE_VIDEO;
vst->codec.codec_id = CODEC_ID_DVVIDEO; vst->codec.codec_id = CODEC_ID_DVVIDEO;
#if 0
ast = av_new_stream(s, 1); ast = av_new_stream(s, 1);
if (!ast) if (!ast)
return AVERROR_NOMEM; return AVERROR_NOMEM;
ast->codec.codec_type = CODEC_TYPE_AUDIO; ast->codec.codec_type = CODEC_TYPE_AUDIO;
ast->codec.codec_id = CODEC_ID_DVAUDIO; ast->codec.codec_id = CODEC_ID_DVAUDIO;
#endif ast->codec.channels = 2;
c->is_audio = 0;
return 0; return 0;
} }
/* XXX: build fake audio stream when DV audio decoder will be finished */ /* XXX: build fake audio stream when DV audio decoder will be finished */
static int dv_read_packet(AVFormatContext *s, AVPacket *pkt) static int dv_read_packet(AVFormatContext *s, AVPacket *pkt)
{ {
int ret, size, dsf; int ret, dsf;
uint8_t buf[4]; DVDemuxContext *c = s->priv_data;
ret = get_buffer(&s->pb, buf, 4); if (!c->is_audio) {
if (ret <= 0) ret = get_buffer(&s->pb, c->buf, 4);
return -EIO; if (ret <= 0)
dsf = buf[3] & 0x80; return -EIO;
if (!dsf) dsf = c->buf[3] & 0x80;
size = NTSC_FRAME_SIZE; if (!dsf)
else c->size = NTSC_FRAME_SIZE;
size = PAL_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; return -EIO;
pkt->stream_index = 0; pkt->stream_index = c->is_audio;
memcpy(pkt->data, buf, 4); c->is_audio = !c->is_audio;
ret = get_buffer(&s->pb, pkt->data + 4, size - 4); memcpy(pkt->data, c->buf, c->size);
if (ret <= 0) {
av_free_packet(pkt);
return -EIO;
}
return ret; return ret;
} }