diff options
author | Reimar Döffinger <Reimar.Doeffinger@gmx.de> | 2011-08-27 19:27:07 +0200 |
---|---|---|
committer | Reimar Döffinger <Reimar.Doeffinger@gmx.de> | 2011-10-10 17:38:51 +0200 |
commit | 4b4a6ebd68ca1d901b291f9bb4f5225daf876b8b (patch) | |
tree | 0dbc8575b008dfd53d74173f9b8ef905eb9a1e21 /libavformat/wav.c | |
parent | 86a771143fc8bf0e0de988745c689417c90b76b5 (diff) | |
download | ffmpeg-4b4a6ebd68ca1d901b291f9bb4f5225daf876b8b.tar.gz |
Support playing SMV files.
Audio and video are interleaved via stream cur_dts - no idea how
reliable this is.
It also cannot display the video properly - it is stored with
about 15 in a single JPEG frame, I cannot think of a reasonable
way to implement this.
Samples: http://samples.mplayerhq.hu/smv/
Format description: http://wiki.multimedia.cx/index.php?title=SMV
Signed-off-by: Reimar Döffinger <Reimar.Doeffinger@gmx.de>
Diffstat (limited to 'libavformat/wav.c')
-rw-r--r-- | libavformat/wav.c | 91 |
1 files changed, 90 insertions, 1 deletions
diff --git a/libavformat/wav.c b/libavformat/wav.c index 327d8917b8..d6b9b53b4f 100644 --- a/libavformat/wav.c +++ b/libavformat/wav.c @@ -45,6 +45,13 @@ typedef struct { int last_duration; int w64; int write_bext; + int64_t smv_data_ofs; + int smv_block_size; + int smv_frames_per_jpeg; + int smv_block; + int smv_last_stream; + int smv_eof; + int audio_eof; } WAVContext; #if CONFIG_WAV_MUXER @@ -392,6 +399,8 @@ static int wav_read_header(AVFormatContext *s, int ret, got_fmt = 0; int64_t next_tag_ofs, data_ofs = -1; + wav->smv_data_ofs = -1; + /* check RIFF header */ tag = avio_rl32(pb); @@ -423,6 +432,7 @@ static int wav_read_header(AVFormatContext *s, } for (;;) { + AVStream *vst; size = next_tag(pb, &tag); next_tag_ofs = avio_tell(pb) + size; @@ -468,6 +478,31 @@ static int wav_read_header(AVFormatContext *s, if ((ret = wav_parse_bext_tag(s, size)) < 0) return ret; break; + case MKTAG('S','M','V','0'): + // SMV file, a wav file with video appended. + if (size != MKTAG('0','2','0','0')) { + av_log(s, AV_LOG_ERROR, "Unknown SMV version found\n"); + goto break_loop; + } + av_log(s, AV_LOG_DEBUG, "Found SMV data\n"); + vst = av_new_stream(s, 1); + if (!vst) + return AVERROR(ENOMEM); + avio_r8(pb); + vst->codec->codec_type = AVMEDIA_TYPE_VIDEO; + vst->codec->codec_id = CODEC_ID_MJPEG; + vst->codec->width = avio_rl24(pb); + vst->codec->height = avio_rl24(pb); + size = avio_rl24(pb); + wav->smv_data_ofs = avio_tell(pb) + (size - 5) * 3; + avio_rl24(pb); + wav->smv_block_size = avio_rl24(pb); + av_set_pts_info(vst, 32, 1, avio_rl24(pb)); + vst->duration = avio_rl24(pb); + avio_rl24(pb); + avio_rl24(pb); + wav->smv_frames_per_jpeg = avio_rl24(pb); + goto break_loop; } /* seek to next tag unless we know that we'll run into EOF */ @@ -527,6 +562,45 @@ static int wav_read_packet(AVFormatContext *s, AVStream *st; WAVContext *wav = s->priv_data; + if (wav->smv_data_ofs > 0) { + int64_t audio_dts, video_dts; +smv_retry: + audio_dts = s->streams[0]->cur_dts; + video_dts = s->streams[1]->cur_dts; + if (audio_dts != AV_NOPTS_VALUE && video_dts != AV_NOPTS_VALUE) { + audio_dts = av_rescale_q(audio_dts, s->streams[0]->time_base, AV_TIME_BASE_Q); + video_dts = av_rescale_q(video_dts, s->streams[1]->time_base, AV_TIME_BASE_Q); + wav->smv_last_stream = video_dts >= audio_dts; + } + wav->smv_last_stream = !wav->smv_last_stream; + wav->smv_last_stream |= wav->audio_eof; + wav->smv_last_stream &= !wav->smv_eof; + if (wav->smv_last_stream) { + uint64_t old_pos = avio_tell(s->pb); + uint64_t new_pos = wav->smv_data_ofs + + wav->smv_block * wav->smv_block_size; + if (avio_seek(s->pb, new_pos, SEEK_SET) < 0) { + ret = AVERROR_EOF; + goto smv_out; + } + size = avio_rl24(s->pb); + ret = av_get_packet(s->pb, pkt, size); + if (ret < 0) + goto smv_out; + pkt->pos -= 3; + pkt->pts = wav->smv_block * wav->smv_frames_per_jpeg; + wav->smv_block++; + pkt->stream_index = 1; +smv_out: + avio_seek(s->pb, old_pos, SEEK_SET); + if (ret == AVERROR_EOF) { + wav->smv_eof = 1; + goto smv_retry; + } + return ret; + } + } + st = s->streams[0]; left = wav->data_end - avio_tell(s->pb); @@ -535,8 +609,12 @@ static int wav_read_packet(AVFormatContext *s, left = find_guid(s->pb, guid_data) - 24; else left = find_tag(s->pb, MKTAG('d', 'a', 't', 'a')); - if (left < 0) + if (left < 0) { + wav->audio_eof = 1; + if (wav->smv_data_ofs > 0 && !wav->smv_eof) + goto smv_retry; return AVERROR_EOF; + } wav->data_end= avio_tell(s->pb) + left; } @@ -558,7 +636,18 @@ static int wav_read_packet(AVFormatContext *s, static int wav_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) { + WAVContext *wav = s->priv_data; AVStream *st; + wav->smv_eof = 0; + wav->audio_eof = 0; + if (wav->smv_data_ofs > 0) { + int64_t smv_timestamp = timestamp; + if (stream_index == 0) + smv_timestamp = av_rescale_q(timestamp, s->streams[0]->time_base, s->streams[1]->time_base); + else + timestamp = av_rescale_q(smv_timestamp, s->streams[1]->time_base, s->streams[0]->time_base); + wav->smv_block = smv_timestamp / wav->smv_frames_per_jpeg; + } st = s->streams[0]; switch (st->codec->codec_id) { |