westwood_vqa: fix SND0 chunk handling
Version from vqa header does not dictate which sound chunks may appear in file. Signed-off-by: Paul B Mahol <onemda@gmail.com> Signed-off-by: Justin Ruggles <justin.ruggles@gmail.com>
This commit is contained in:
parent
f0a343f399
commit
55abaa58e5
@ -128,7 +128,7 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CODEC_ID_ADPCM_IMA_WS:
|
case CODEC_ID_ADPCM_IMA_WS:
|
||||||
if (avctx->extradata && avctx->extradata_size >= 42)
|
if (avctx->extradata && avctx->extradata_size >= 2)
|
||||||
c->vqa_version = AV_RL16(avctx->extradata);
|
c->vqa_version = AV_RL16(avctx->extradata);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -54,7 +54,10 @@
|
|||||||
#define VQA_PREAMBLE_SIZE 8
|
#define VQA_PREAMBLE_SIZE 8
|
||||||
|
|
||||||
typedef struct WsVqaDemuxContext {
|
typedef struct WsVqaDemuxContext {
|
||||||
int audio_channels;
|
int version;
|
||||||
|
int bps;
|
||||||
|
int channels;
|
||||||
|
int sample_rate;
|
||||||
int audio_stream_index;
|
int audio_stream_index;
|
||||||
int video_stream_index;
|
int video_stream_index;
|
||||||
} WsVqaDemuxContext;
|
} WsVqaDemuxContext;
|
||||||
@ -82,7 +85,7 @@ static int wsvqa_read_header(AVFormatContext *s)
|
|||||||
unsigned char scratch[VQA_PREAMBLE_SIZE];
|
unsigned char scratch[VQA_PREAMBLE_SIZE];
|
||||||
unsigned int chunk_tag;
|
unsigned int chunk_tag;
|
||||||
unsigned int chunk_size;
|
unsigned int chunk_size;
|
||||||
int fps, version, flags, sample_rate, channels;
|
int fps;
|
||||||
|
|
||||||
/* initialize the video decoder stream */
|
/* initialize the video decoder stream */
|
||||||
st = avformat_new_stream(s, NULL);
|
st = avformat_new_stream(s, NULL);
|
||||||
@ -117,53 +120,13 @@ static int wsvqa_read_header(AVFormatContext *s)
|
|||||||
}
|
}
|
||||||
avpriv_set_pts_info(st, 64, 1, fps);
|
avpriv_set_pts_info(st, 64, 1, fps);
|
||||||
|
|
||||||
/* initialize the audio decoder stream for VQA v1 or nonzero samplerate */
|
wsvqa->version = AV_RL16(&header[ 0]);
|
||||||
version = AV_RL16(&header[ 0]);
|
wsvqa->sample_rate = AV_RL16(&header[24]);
|
||||||
flags = AV_RL16(&header[ 2]);
|
wsvqa->channels = header[26];
|
||||||
sample_rate = AV_RL16(&header[24]);
|
wsvqa->bps = header[27];
|
||||||
channels = header[26];
|
wsvqa->audio_stream_index = -1;
|
||||||
if (sample_rate || (version == 1 && flags == 1)) {
|
|
||||||
st = avformat_new_stream(s, NULL);
|
|
||||||
if (!st)
|
|
||||||
return AVERROR(ENOMEM);
|
|
||||||
st->start_time = 0;
|
|
||||||
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
|
|
||||||
|
|
||||||
st->codec->extradata_size = VQA_HEADER_SIZE;
|
s->ctx_flags |= AVFMTCTX_NOHEADER;
|
||||||
st->codec->extradata = av_mallocz(VQA_HEADER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE);
|
|
||||||
if (!st->codec->extradata)
|
|
||||||
return AVERROR(ENOMEM);
|
|
||||||
memcpy(st->codec->extradata, header, VQA_HEADER_SIZE);
|
|
||||||
|
|
||||||
if (!sample_rate)
|
|
||||||
sample_rate = 22050;
|
|
||||||
st->codec->sample_rate = sample_rate;
|
|
||||||
avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
|
|
||||||
|
|
||||||
if (!channels)
|
|
||||||
channels = 1;
|
|
||||||
st->codec->channels = channels;
|
|
||||||
|
|
||||||
switch (version) {
|
|
||||||
case 1:
|
|
||||||
st->codec->codec_id = CODEC_ID_WESTWOOD_SND1;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
case 3:
|
|
||||||
st->codec->codec_id = CODEC_ID_ADPCM_IMA_WS;
|
|
||||||
st->codec->bits_per_coded_sample = 4;
|
|
||||||
st->codec->bit_rate = channels * sample_rate * 4;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/* NOTE: version 0 is supposedly raw pcm_u8 or pcm_s16le, but we do
|
|
||||||
not have any samples to validate this */
|
|
||||||
av_log_ask_for_sample(s, "VQA version %d audio\n", version);
|
|
||||||
return AVERROR_PATCHWELCOME;
|
|
||||||
}
|
|
||||||
|
|
||||||
wsvqa->audio_stream_index = st->index;
|
|
||||||
wsvqa->audio_channels = st->codec->channels;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* there are 0 or more chunks before the FINF chunk; iterate until
|
/* there are 0 or more chunks before the FINF chunk; iterate until
|
||||||
* FINF has been skipped and the file will be ready to be demuxed */
|
* FINF has been skipped and the file will be ready to be demuxed */
|
||||||
@ -216,12 +179,8 @@ static int wsvqa_read_packet(AVFormatContext *s,
|
|||||||
chunk_size = AV_RB32(&preamble[4]);
|
chunk_size = AV_RB32(&preamble[4]);
|
||||||
skip_byte = chunk_size & 0x01;
|
skip_byte = chunk_size & 0x01;
|
||||||
|
|
||||||
if ((chunk_type == SND2_TAG || chunk_type == SND1_TAG) && wsvqa->audio_channels == 0) {
|
if ((chunk_type == SND0_TAG) || (chunk_type == SND1_TAG) ||
|
||||||
av_log(s, AV_LOG_ERROR, "audio chunk without any audio header information found\n");
|
(chunk_type == SND2_TAG) || (chunk_type == VQFR_TAG)) {
|
||||||
return AVERROR_INVALIDDATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((chunk_type == SND1_TAG) || (chunk_type == SND2_TAG) || (chunk_type == VQFR_TAG)) {
|
|
||||||
|
|
||||||
if (av_new_packet(pkt, chunk_size))
|
if (av_new_packet(pkt, chunk_size))
|
||||||
return AVERROR(EIO);
|
return AVERROR(EIO);
|
||||||
@ -231,18 +190,68 @@ static int wsvqa_read_packet(AVFormatContext *s,
|
|||||||
return AVERROR(EIO);
|
return AVERROR(EIO);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chunk_type == SND2_TAG) {
|
switch (chunk_type) {
|
||||||
pkt->stream_index = wsvqa->audio_stream_index;
|
case SND0_TAG:
|
||||||
/* 2 samples/byte, 1 or 2 samples per frame depending on stereo */
|
case SND1_TAG:
|
||||||
pkt->duration = (chunk_size * 2) / wsvqa->audio_channels;
|
case SND2_TAG:
|
||||||
} else if(chunk_type == SND1_TAG) {
|
if (wsvqa->audio_stream_index == -1) {
|
||||||
|
AVStream *st = avformat_new_stream(s, NULL);
|
||||||
|
if (!st)
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
|
||||||
|
wsvqa->audio_stream_index = st->index;
|
||||||
|
if (!wsvqa->sample_rate)
|
||||||
|
wsvqa->sample_rate = 22050;
|
||||||
|
if (!wsvqa->channels)
|
||||||
|
wsvqa->channels = 1;
|
||||||
|
if (!wsvqa->bps)
|
||||||
|
wsvqa->bps = 8;
|
||||||
|
st->codec->sample_rate = wsvqa->sample_rate;
|
||||||
|
st->codec->bits_per_coded_sample = wsvqa->bps;
|
||||||
|
st->codec->channels = wsvqa->channels;
|
||||||
|
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||||
|
|
||||||
|
avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
|
||||||
|
|
||||||
|
switch (chunk_type) {
|
||||||
|
case SND0_TAG:
|
||||||
|
if (wsvqa->bps == 16)
|
||||||
|
st->codec->codec_id = CODEC_ID_PCM_S16LE;
|
||||||
|
else
|
||||||
|
st->codec->codec_id = CODEC_ID_PCM_U8;
|
||||||
|
break;
|
||||||
|
case SND1_TAG:
|
||||||
|
st->codec->codec_id = CODEC_ID_WESTWOOD_SND1;
|
||||||
|
break;
|
||||||
|
case SND2_TAG:
|
||||||
|
st->codec->codec_id = CODEC_ID_ADPCM_IMA_WS;
|
||||||
|
st->codec->extradata_size = 2;
|
||||||
|
st->codec->extradata = av_mallocz(2 + FF_INPUT_BUFFER_PADDING_SIZE);
|
||||||
|
if (!st->codec->extradata)
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
AV_WL16(st->codec->extradata, wsvqa->version);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pkt->stream_index = wsvqa->audio_stream_index;
|
pkt->stream_index = wsvqa->audio_stream_index;
|
||||||
|
switch (chunk_type) {
|
||||||
|
case SND1_TAG:
|
||||||
/* unpacked size is stored in header */
|
/* unpacked size is stored in header */
|
||||||
pkt->duration = AV_RL16(pkt->data) / wsvqa->audio_channels;
|
pkt->duration = AV_RL16(pkt->data) / wsvqa->channels;
|
||||||
} else {
|
break;
|
||||||
|
case SND2_TAG:
|
||||||
|
/* 2 samples/byte, 1 or 2 samples per frame depending on stereo */
|
||||||
|
pkt->duration = (chunk_size * 2) / wsvqa->channels;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case VQFR_TAG:
|
||||||
pkt->stream_index = wsvqa->video_stream_index;
|
pkt->stream_index = wsvqa->video_stream_index;
|
||||||
pkt->duration = 1;
|
pkt->duration = 1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* stay on 16-bit alignment */
|
/* stay on 16-bit alignment */
|
||||||
if (skip_byte)
|
if (skip_byte)
|
||||||
avio_skip(pb, 1);
|
avio_skip(pb, 1);
|
||||||
@ -251,7 +260,6 @@ static int wsvqa_read_packet(AVFormatContext *s,
|
|||||||
} else {
|
} else {
|
||||||
switch(chunk_type){
|
switch(chunk_type){
|
||||||
case CMDS_TAG:
|
case CMDS_TAG:
|
||||||
case SND0_TAG:
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
av_log(s, AV_LOG_INFO, "Skipping unknown chunk 0x%08X\n", chunk_type);
|
av_log(s, AV_LOG_INFO, "Skipping unknown chunk 0x%08X\n", chunk_type);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user