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:
parent
850742d785
commit
425ed6e223
@ -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);
|
||||
|
118
libavcodec/dv.c
118
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;
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user