[FFmpeg-devel] [PATCH] Support playing SMV files.

Reimar Döffinger Reimar.Doeffinger at gmx.de
Sat Aug 27 23:56:26 CEST 2011


Quite hackish, audio and video are not properly interleaved.
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 at gmx.de>
---
 libavformat/wav.c |   82 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 81 insertions(+), 1 deletions(-)

diff --git a/libavformat/wav.c b/libavformat/wav.c
index 1ae9413..72124f1 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,36 @@ static int wav_read_packet(AVFormatContext *s,
     AVStream *st;
     WAVContext *wav = s->priv_data;
 
+retry:
+    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_data_ofs > 0 &&
+        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 out;
+        }
+        size = avio_rl24(s->pb);
+        ret  = av_get_packet(s->pb, pkt, size);
+        if (ret < 0)
+            goto out;
+        pkt->pos -= 3;
+        pkt->pts = wav->smv_block * wav->smv_frames_per_jpeg;
+        wav->smv_block++;
+        pkt->stream_index = 1;
+out:
+        avio_seek(s->pb, old_pos, SEEK_SET);
+        if (ret == AVERROR_EOF) {
+            wav->smv_eof = 1;
+            goto retry;
+        }
+        return ret;
+    }
+
     st = s->streams[0];
 
     left = wav->data_end - avio_tell(s->pb);
@@ -535,8 +600,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 retry;
             return AVERROR_EOF;
+        }
         wav->data_end= avio_tell(s->pb) + left;
     }
 
@@ -558,7 +627,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) {
-- 
1.7.5.4



More information about the ffmpeg-devel mailing list