|
|
@@ -49,6 +49,7 @@ typedef struct WAVDemuxContext { |
|
|
const AVClass *class; |
|
|
const AVClass *class; |
|
|
int64_t data_end; |
|
|
int64_t data_end; |
|
|
int w64; |
|
|
int w64; |
|
|
|
|
|
AVStream *vst; |
|
|
int64_t smv_data_ofs; |
|
|
int64_t smv_data_ofs; |
|
|
int smv_block_size; |
|
|
int smv_block_size; |
|
|
int smv_frames_per_jpeg; |
|
|
int smv_frames_per_jpeg; |
|
|
@@ -170,30 +171,26 @@ static void handle_stream_probing(AVStream *st) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static int wav_parse_fmt_tag(AVFormatContext *s, int64_t size, AVStream **st) |
|
|
|
|
|
|
|
|
static int wav_parse_fmt_tag(AVFormatContext *s, int64_t size, AVStream *st) |
|
|
{ |
|
|
{ |
|
|
AVIOContext *pb = s->pb; |
|
|
AVIOContext *pb = s->pb; |
|
|
WAVDemuxContext *wav = s->priv_data; |
|
|
WAVDemuxContext *wav = s->priv_data; |
|
|
int ret; |
|
|
int ret; |
|
|
|
|
|
|
|
|
/* parse fmt header */ |
|
|
/* parse fmt header */ |
|
|
*st = avformat_new_stream(s, NULL); |
|
|
|
|
|
if (!*st) |
|
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
|
|
|
|
|
|
|
ret = ff_get_wav_header(s, pb, (*st)->codecpar, size, wav->rifx); |
|
|
|
|
|
|
|
|
ret = ff_get_wav_header(s, pb, st->codecpar, size, wav->rifx); |
|
|
if (ret < 0) |
|
|
if (ret < 0) |
|
|
return ret; |
|
|
return ret; |
|
|
handle_stream_probing(*st); |
|
|
|
|
|
|
|
|
handle_stream_probing(st); |
|
|
|
|
|
|
|
|
(*st)->need_parsing = AVSTREAM_PARSE_FULL_RAW; |
|
|
|
|
|
|
|
|
st->need_parsing = AVSTREAM_PARSE_FULL_RAW; |
|
|
|
|
|
|
|
|
avpriv_set_pts_info(*st, 64, 1, (*st)->codecpar->sample_rate); |
|
|
|
|
|
|
|
|
avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate); |
|
|
|
|
|
|
|
|
return 0; |
|
|
return 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static int wav_parse_xma2_tag(AVFormatContext *s, int64_t size, AVStream **st) |
|
|
|
|
|
|
|
|
static int wav_parse_xma2_tag(AVFormatContext *s, int64_t size, AVStream *st) |
|
|
{ |
|
|
{ |
|
|
AVIOContext *pb = s->pb; |
|
|
AVIOContext *pb = s->pb; |
|
|
int version, num_streams, i, channels = 0, ret; |
|
|
int version, num_streams, i, channels = 0, ret; |
|
|
@@ -201,13 +198,9 @@ static int wav_parse_xma2_tag(AVFormatContext *s, int64_t size, AVStream **st) |
|
|
if (size < 36) |
|
|
if (size < 36) |
|
|
return AVERROR_INVALIDDATA; |
|
|
return AVERROR_INVALIDDATA; |
|
|
|
|
|
|
|
|
*st = avformat_new_stream(s, NULL); |
|
|
|
|
|
if (!*st) |
|
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
|
|
|
|
|
|
|
(*st)->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; |
|
|
|
|
|
(*st)->codecpar->codec_id = AV_CODEC_ID_XMA2; |
|
|
|
|
|
(*st)->need_parsing = AVSTREAM_PARSE_FULL_RAW; |
|
|
|
|
|
|
|
|
st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; |
|
|
|
|
|
st->codecpar->codec_id = AV_CODEC_ID_XMA2; |
|
|
|
|
|
st->need_parsing = AVSTREAM_PARSE_FULL_RAW; |
|
|
|
|
|
|
|
|
version = avio_r8(pb); |
|
|
version = avio_r8(pb); |
|
|
if (version != 3 && version != 4) |
|
|
if (version != 3 && version != 4) |
|
|
@@ -216,26 +209,26 @@ static int wav_parse_xma2_tag(AVFormatContext *s, int64_t size, AVStream **st) |
|
|
if (size != (32 + ((version==3)?0:8) + 4*num_streams)) |
|
|
if (size != (32 + ((version==3)?0:8) + 4*num_streams)) |
|
|
return AVERROR_INVALIDDATA; |
|
|
return AVERROR_INVALIDDATA; |
|
|
avio_skip(pb, 10); |
|
|
avio_skip(pb, 10); |
|
|
(*st)->codecpar->sample_rate = avio_rb32(pb); |
|
|
|
|
|
|
|
|
st->codecpar->sample_rate = avio_rb32(pb); |
|
|
if (version == 4) |
|
|
if (version == 4) |
|
|
avio_skip(pb, 8); |
|
|
avio_skip(pb, 8); |
|
|
avio_skip(pb, 4); |
|
|
avio_skip(pb, 4); |
|
|
(*st)->duration = avio_rb32(pb); |
|
|
|
|
|
|
|
|
st->duration = avio_rb32(pb); |
|
|
avio_skip(pb, 8); |
|
|
avio_skip(pb, 8); |
|
|
|
|
|
|
|
|
for (i = 0; i < num_streams; i++) { |
|
|
for (i = 0; i < num_streams; i++) { |
|
|
channels += avio_r8(pb); |
|
|
channels += avio_r8(pb); |
|
|
avio_skip(pb, 3); |
|
|
avio_skip(pb, 3); |
|
|
} |
|
|
} |
|
|
(*st)->codecpar->channels = channels; |
|
|
|
|
|
|
|
|
st->codecpar->channels = channels; |
|
|
|
|
|
|
|
|
if ((*st)->codecpar->channels <= 0 || (*st)->codecpar->sample_rate <= 0) |
|
|
|
|
|
|
|
|
if (st->codecpar->channels <= 0 || st->codecpar->sample_rate <= 0) |
|
|
return AVERROR_INVALIDDATA; |
|
|
return AVERROR_INVALIDDATA; |
|
|
|
|
|
|
|
|
avpriv_set_pts_info(*st, 64, 1, (*st)->codecpar->sample_rate); |
|
|
|
|
|
|
|
|
avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate); |
|
|
|
|
|
|
|
|
avio_seek(pb, -size, SEEK_CUR); |
|
|
avio_seek(pb, -size, SEEK_CUR); |
|
|
if ((ret = ff_get_extradata(s, (*st)->codecpar, pb, size)) < 0) |
|
|
|
|
|
|
|
|
if ((ret = ff_get_extradata(s, st->codecpar, pb, size)) < 0) |
|
|
return ret; |
|
|
return ret; |
|
|
|
|
|
|
|
|
return 0; |
|
|
return 0; |
|
|
@@ -407,6 +400,11 @@ static int wav_read_header(AVFormatContext *s) |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* Create the audio stream now so that its index is always zero */ |
|
|
|
|
|
st = avformat_new_stream(s, NULL); |
|
|
|
|
|
if (!st) |
|
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
|
|
|
|
for (;;) { |
|
|
for (;;) { |
|
|
AVStream *vst; |
|
|
AVStream *vst; |
|
|
size = next_tag(pb, &tag, wav->rifx); |
|
|
size = next_tag(pb, &tag, wav->rifx); |
|
|
@@ -418,7 +416,7 @@ static int wav_read_header(AVFormatContext *s) |
|
|
switch (tag) { |
|
|
switch (tag) { |
|
|
case MKTAG('f', 'm', 't', ' '): |
|
|
case MKTAG('f', 'm', 't', ' '): |
|
|
/* only parse the first 'fmt ' tag found */ |
|
|
/* only parse the first 'fmt ' tag found */ |
|
|
if (!got_xma2 && !got_fmt && (ret = wav_parse_fmt_tag(s, size, &st)) < 0) { |
|
|
|
|
|
|
|
|
if (!got_xma2 && !got_fmt && (ret = wav_parse_fmt_tag(s, size, st)) < 0) { |
|
|
return ret; |
|
|
return ret; |
|
|
} else if (got_fmt) |
|
|
} else if (got_fmt) |
|
|
av_log(s, AV_LOG_WARNING, "found more than one 'fmt ' tag\n"); |
|
|
av_log(s, AV_LOG_WARNING, "found more than one 'fmt ' tag\n"); |
|
|
@@ -427,7 +425,7 @@ static int wav_read_header(AVFormatContext *s) |
|
|
break; |
|
|
break; |
|
|
case MKTAG('X', 'M', 'A', '2'): |
|
|
case MKTAG('X', 'M', 'A', '2'): |
|
|
/* only parse the first 'XMA2' tag found */ |
|
|
/* only parse the first 'XMA2' tag found */ |
|
|
if (!got_fmt && !got_xma2 && (ret = wav_parse_xma2_tag(s, size, &st)) < 0) { |
|
|
|
|
|
|
|
|
if (!got_fmt && !got_xma2 && (ret = wav_parse_xma2_tag(s, size, st)) < 0) { |
|
|
return ret; |
|
|
return ret; |
|
|
} else if (got_xma2) |
|
|
} else if (got_xma2) |
|
|
av_log(s, AV_LOG_WARNING, "found more than one 'XMA2' tag\n"); |
|
|
av_log(s, AV_LOG_WARNING, "found more than one 'XMA2' tag\n"); |
|
|
@@ -484,6 +482,7 @@ static int wav_read_header(AVFormatContext *s) |
|
|
vst = avformat_new_stream(s, NULL); |
|
|
vst = avformat_new_stream(s, NULL); |
|
|
if (!vst) |
|
|
if (!vst) |
|
|
return AVERROR(ENOMEM); |
|
|
return AVERROR(ENOMEM); |
|
|
|
|
|
wav->vst = vst; |
|
|
avio_r8(pb); |
|
|
avio_r8(pb); |
|
|
vst->id = 1; |
|
|
vst->id = 1; |
|
|
vst->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; |
|
|
vst->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; |
|
|
@@ -693,23 +692,24 @@ static int wav_read_packet(AVFormatContext *s, AVPacket *pkt) |
|
|
{ |
|
|
{ |
|
|
int ret, size; |
|
|
int ret, size; |
|
|
int64_t left; |
|
|
int64_t left; |
|
|
AVStream *st; |
|
|
|
|
|
WAVDemuxContext *wav = s->priv_data; |
|
|
WAVDemuxContext *wav = s->priv_data; |
|
|
|
|
|
AVStream *st = s->streams[0]; |
|
|
|
|
|
|
|
|
if (CONFIG_SPDIF_DEMUXER && wav->spdif == 1) |
|
|
if (CONFIG_SPDIF_DEMUXER && wav->spdif == 1) |
|
|
return ff_spdif_read_packet(s, pkt); |
|
|
return ff_spdif_read_packet(s, pkt); |
|
|
|
|
|
|
|
|
if (wav->smv_data_ofs > 0) { |
|
|
if (wav->smv_data_ofs > 0) { |
|
|
int64_t audio_dts, video_dts; |
|
|
int64_t audio_dts, video_dts; |
|
|
|
|
|
AVStream *vst = wav->vst; |
|
|
smv_retry: |
|
|
smv_retry: |
|
|
audio_dts = (int32_t)s->streams[0]->cur_dts; |
|
|
|
|
|
video_dts = (int32_t)s->streams[1]->cur_dts; |
|
|
|
|
|
|
|
|
audio_dts = (int32_t)st->cur_dts; |
|
|
|
|
|
video_dts = (int32_t)vst->cur_dts; |
|
|
|
|
|
|
|
|
if (audio_dts != AV_NOPTS_VALUE && video_dts != AV_NOPTS_VALUE) { |
|
|
if (audio_dts != AV_NOPTS_VALUE && video_dts != AV_NOPTS_VALUE) { |
|
|
/*We always return a video frame first to get the pixel format first*/ |
|
|
/*We always return a video frame first to get the pixel format first*/ |
|
|
wav->smv_last_stream = wav->smv_given_first ? |
|
|
wav->smv_last_stream = wav->smv_given_first ? |
|
|
av_compare_ts(video_dts, s->streams[1]->time_base, |
|
|
|
|
|
audio_dts, s->streams[0]->time_base) > 0 : 0; |
|
|
|
|
|
|
|
|
av_compare_ts(video_dts, vst->time_base, |
|
|
|
|
|
audio_dts, st->time_base) > 0 : 0; |
|
|
wav->smv_given_first = 1; |
|
|
wav->smv_given_first = 1; |
|
|
} |
|
|
} |
|
|
wav->smv_last_stream = !wav->smv_last_stream; |
|
|
wav->smv_last_stream = !wav->smv_last_stream; |
|
|
@@ -732,7 +732,7 @@ smv_retry: |
|
|
pkt->duration = wav->smv_frames_per_jpeg; |
|
|
pkt->duration = wav->smv_frames_per_jpeg; |
|
|
wav->smv_block++; |
|
|
wav->smv_block++; |
|
|
|
|
|
|
|
|
pkt->stream_index = 1; |
|
|
|
|
|
|
|
|
pkt->stream_index = vst->index; |
|
|
smv_out: |
|
|
smv_out: |
|
|
avio_seek(s->pb, old_pos, SEEK_SET); |
|
|
avio_seek(s->pb, old_pos, SEEK_SET); |
|
|
if (ret == AVERROR_EOF) { |
|
|
if (ret == AVERROR_EOF) { |
|
|
@@ -743,8 +743,6 @@ smv_out: |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
st = s->streams[0]; |
|
|
|
|
|
|
|
|
|
|
|
left = wav->data_end - avio_tell(s->pb); |
|
|
left = wav->data_end - avio_tell(s->pb); |
|
|
if (wav->ignore_length) |
|
|
if (wav->ignore_length) |
|
|
left = INT_MAX; |
|
|
left = INT_MAX; |
|
|
@@ -781,22 +779,24 @@ static int wav_read_seek(AVFormatContext *s, |
|
|
int stream_index, int64_t timestamp, int flags) |
|
|
int stream_index, int64_t timestamp, int flags) |
|
|
{ |
|
|
{ |
|
|
WAVDemuxContext *wav = s->priv_data; |
|
|
WAVDemuxContext *wav = s->priv_data; |
|
|
AVStream *st; |
|
|
|
|
|
|
|
|
AVStream *ast = s->streams[0], *vst = wav->vst; |
|
|
wav->smv_eof = 0; |
|
|
wav->smv_eof = 0; |
|
|
wav->audio_eof = 0; |
|
|
wav->audio_eof = 0; |
|
|
|
|
|
|
|
|
|
|
|
if (stream_index != 0 && (!vst || stream_index != vst->index)) |
|
|
|
|
|
return AVERROR(EINVAL); |
|
|
if (wav->smv_data_ofs > 0) { |
|
|
if (wav->smv_data_ofs > 0) { |
|
|
int64_t smv_timestamp = timestamp; |
|
|
int64_t smv_timestamp = timestamp; |
|
|
if (stream_index == 0) |
|
|
if (stream_index == 0) |
|
|
smv_timestamp = av_rescale_q(timestamp, s->streams[0]->time_base, s->streams[1]->time_base); |
|
|
|
|
|
|
|
|
smv_timestamp = av_rescale_q(timestamp, ast->time_base, vst->time_base); |
|
|
else |
|
|
else |
|
|
timestamp = av_rescale_q(smv_timestamp, s->streams[1]->time_base, s->streams[0]->time_base); |
|
|
|
|
|
|
|
|
timestamp = av_rescale_q(smv_timestamp, vst->time_base, ast->time_base); |
|
|
if (wav->smv_frames_per_jpeg > 0) { |
|
|
if (wav->smv_frames_per_jpeg > 0) { |
|
|
wav->smv_block = smv_timestamp / wav->smv_frames_per_jpeg; |
|
|
wav->smv_block = smv_timestamp / wav->smv_frames_per_jpeg; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
st = s->streams[0]; |
|
|
|
|
|
switch (st->codecpar->codec_id) { |
|
|
|
|
|
|
|
|
switch (ast->codecpar->codec_id) { |
|
|
case AV_CODEC_ID_MP2: |
|
|
case AV_CODEC_ID_MP2: |
|
|
case AV_CODEC_ID_MP3: |
|
|
case AV_CODEC_ID_MP3: |
|
|
case AV_CODEC_ID_AC3: |
|
|
case AV_CODEC_ID_AC3: |
|
|
@@ -807,7 +807,7 @@ static int wav_read_seek(AVFormatContext *s, |
|
|
default: |
|
|
default: |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
return ff_pcm_read_seek(s, stream_index, timestamp, flags); |
|
|
|
|
|
|
|
|
return ff_pcm_read_seek(s, 0, timestamp, flags); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static const AVClass wav_demuxer_class = { |
|
|
static const AVClass wav_demuxer_class = { |
|
|
|