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

Ash Hughes ashes-iontach at hotmail.com
Tue May 21 21:21:08 CEST 2013


Does this still need more work? ffmpeg now plays and converts all of the samples correctly with this patch, so far as I can see.

A

From: ashes-iontach at hotmail.com
To: ffmpeg-devel at ffmpeg.org
Subject: RE: [FFmpeg-devel] [PATCH 2/2] Support playing SMV files.
Date: Wed, 17 Apr 2013 00:33:19 +0000




Updated, similar to other decoders,

Ash

---

>From faf3706922771f02c8e1d23d7bcafdcad3488a97 Mon Sep 17 00:00:00 2001
From: Ash Hughes <ashes-iontach at hotmail.com>
Date: Wed, 17 Apr 2013 01:27:18 +0100
Subject: [PATCH 1/1] Support playing SMV files

---
 libavcodec/Makefile     |   1 +
 libavcodec/allcodecs.c  |   1 +
 libavcodec/avcodec.h    |   1 +
 libavcodec/codec_desc.c |   7 ++
 libavcodec/smvjpegdec.c | 187 ++++++++++++++++++++++++++++++++++++++++++++++++
 libavformat/wavdec.c    |  38 ++++++++--
 6 files changed, 228 insertions(+), 7 deletions(-)
 create mode 100644 libavcodec/smvjpegdec.c

diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 357ac48..327f753 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -382,6 +382,7 @@ OBJS-$(CONFIG_SIPR_DECODER)            += sipr.o acelp_pitch_delay.o \
 OBJS-$(CONFIG_SMACKAUD_DECODER)        += smacker.o
 OBJS-$(CONFIG_SMACKER_DECODER)         += smacker.o
 OBJS-$(CONFIG_SMC_DECODER)             += smc.o
+OBJS-$(CONFIG_SMVJPEG_DECODER)         += smvjpegdec.o
 OBJS-$(CONFIG_SNOW_DECODER)            += snowdec.o snow.o snow_dwt.o
 OBJS-$(CONFIG_SNOW_ENCODER)            += snowenc.o snow.o snow_dwt.o             \
                                           h263.o ituh263enc.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index b06e9a5..34aeb79 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -243,6 +243,7 @@ void avcodec_register_all(void)
     REGISTER_DECODER(SGIRLE,            sgirle);
     REGISTER_DECODER(SMACKER,           smacker);
     REGISTER_DECODER(SMC,               smc);
+    REGISTER_DECODER(SMVJPEG,           smvjpeg);
     REGISTER_ENCDEC (SNOW,              snow);
     REGISTER_DECODER(SP5X,              sp5x);
     REGISTER_ENCDEC (SUNRAST,           sunrast);
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 3f52037..57cd8a1 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -293,6 +293,7 @@ enum AVCodecID {
     AV_CODEC_ID_MVC2       = MKBETAG('M','V','C','2'),
     AV_CODEC_ID_SNOW       = MKBETAG('S','N','O','W'),
     AV_CODEC_ID_WEBP       = MKBETAG('W','E','B','P'),
+    AV_CODEC_ID_SMVJPEG    = MKBETAG('S','M','V','J'),
 
     /* various PCM "codecs" */
     AV_CODEC_ID_FIRST_AUDIO = 0x10000,     ///< A dummy id pointing at the start of audio codecs
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index 2b3eed7..4f629e2 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -1371,6 +1371,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
         .long_name = NULL_IF_CONFIG_SMALL("BRender PIX image"),
         .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
     },
+    {
+        .id        = AV_CODEC_ID_SMVJPEG,
+        .type      = AVMEDIA_TYPE_VIDEO,
+        .name      = "smv",
+        .long_name = NULL_IF_CONFIG_SMALL("Sigmatel Motion Video"),
+    },
+
 
     /* various PCM "codecs" */
     {
diff --git a/libavcodec/smvjpegdec.c b/libavcodec/smvjpegdec.c
new file mode 100644
index 0000000..431fd04
--- /dev/null
+++ b/libavcodec/smvjpegdec.c
@@ -0,0 +1,187 @@
+/*
+ * SMV JPEG decoder
+ * Copyright (c) 2013 Ash Hughes
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * SMV JPEG decoder.
+ */
+
+// #define DEBUG
+#include "avcodec.h"
+#include "libavutil/opt.h"
+#include "libavutil/imgutils.h"
+#include "mjpegdec.h"
+#include "internal.h"
+
+typedef struct SMVJpegDecodeContext {
+    MJpegDecodeContext jpg;
+    AVFrame *picture[2]; /* pictures array */
+    AVCodecContext* avctx;
+    int frames_per_jpeg;
+} SMVJpegDecodeContext;
+
+static inline void smv_img_pnt_plane(uint8_t      **dst, uint8_t *src,
+                                     int src_linesize, int height, int nlines)
+{
+    if (!dst || !src)
+        return;
+    src += (nlines) * src_linesize * height;
+    *dst = src;
+}
+
+static inline void smv_img_pnt(uint8_t *dst_data[4], uint8_t *src_data[4],
+                               const int src_linesizes[4],
+                               enum PixelFormat pix_fmt, int width, int height,
+                               int nlines)
+{
+    const AVPixFmtDescriptor *desc = &av_pix_fmt_descriptors[pix_fmt];
+    int i, planes_nb = 0;
+
+    if (desc->flags & PIX_FMT_HWACCEL)
+        return;
+
+    for (i = 0; i < desc->nb_components; i++)
+        planes_nb = FFMAX(planes_nb, desc->comp[i].plane + 1);
+
+    for (i = 0; i < planes_nb; i++) {
+        int h = height;
+        if (i == 1 || i == 2) {
+            h= -((-height)>>desc->log2_chroma_h);
+        }
+        smv_img_pnt_plane(&dst_data[i], src_data[i],
+            src_linesizes[i], h, nlines);
+    }
+}
+
+static av_cold int smvjpeg_decode_init(AVCodecContext *avctx)
+{
+    SMVJpegDecodeContext *s = avctx->priv_data;
+    AVCodec *codec;
+    AVDictionary *thread_opt = NULL;
+    int ret = 0;
+
+    s->frames_per_jpeg = 0;
+
+    s->picture[0] = av_frame_alloc();
+    if (!s->picture[0])
+        return AVERROR(ENOMEM);
+
+    s->picture[1] = av_frame_alloc();
+    if (!s->picture[1])
+        return AVERROR(ENOMEM);
+
+    s->jpg.picture_ptr      = s->picture[0];
+
+    if (avctx->extradata_size >= 4)
+        s->frames_per_jpeg = AV_RL32(avctx->extradata);
+
+    if (s->frames_per_jpeg <= 0) {
+        av_log(avctx, AV_LOG_ERROR, "Invalid number of frames per jpeg.\n");
+        ret = -1;
+    }
+
+    avcodec_get_frame_defaults(s->picture[1]);
+    avctx->coded_frame = s->picture[1];
+    codec = avcodec_find_decoder(AV_CODEC_ID_MJPEG);
+    if (!codec) {
+        av_log(avctx, AV_LOG_ERROR, "MJPEG codec not found\n");
+        ret = -1;
+    }
+
+    s->avctx = avcodec_alloc_context3(codec);
+
+    av_dict_set(&thread_opt, "threads", "1", 0);
+    if (ff_codec_open2_recursive(s->avctx, codec, &thread_opt) < 0) {
+        av_log(avctx, AV_LOG_ERROR, "MJPEG codec failed to open\n");
+        ret = -1;
+    }
+    av_dict_free(&thread_opt);
+
+    return ret;
+}
+
+static int smvjpeg_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
+                            AVPacket *avpkt)
+{
+    SMVJpegDecodeContext *s = avctx->priv_data;
+    AVFrame* mjpeg_data = s->picture[0];
+    int i, cur_frame = 0, ret = 0;
+
+    cur_frame = avpkt->pts % s->frames_per_jpeg;
+
+    /* Are we at the start of a block? */
+    if (!cur_frame)
+        ret = avcodec_decode_video2(s->avctx, mjpeg_data, data_size, avpkt);
+    else /*use the last lot... */
+        *data_size = sizeof(AVPicture);
+
+    avctx->pix_fmt = s->avctx->pix_fmt;
+
+    /* We shouldn't get here if frames_per_jpeg <= 0 because this was rejected
+       in init */
+    avcodec_set_dimensions(avctx, mjpeg_data->width,
+        mjpeg_data->height / s->frames_per_jpeg);
+
+    s->picture[1]->extended_data = NULL;
+    s->picture[1]->width         = avctx->width;
+    s->picture[1]->height        = avctx->height;
+    s->picture[1]->format        = avctx->pix_fmt;
+    /* ff_init_buffer_info(avctx, &s->picture[1]); */
+    smv_img_pnt(s->picture[1]->data, mjpeg_data->data, mjpeg_data->linesize,
+                avctx->pix_fmt, avctx->width, avctx->height, cur_frame);
+    for (i = 0; i < AV_NUM_DATA_POINTERS; i++)
+        s->picture[1]->linesize[i] = mjpeg_data->linesize[i];
+
+    ret = av_frame_ref(data, s->picture[1]);
+
+    return ret;
+}
+
+static av_cold int smvjpeg_decode_end(AVCodecContext *avctx)
+{
+    SMVJpegDecodeContext *s = avctx->priv_data;
+    MJpegDecodeContext *jpg = &s->jpg;
+
+    jpg->picture_ptr = NULL;
+    av_frame_free(&s->picture[1]);
+    ff_codec_close_recursive(s->avctx);
+    av_freep(&s->avctx);
+    return 0;
+}
+
+static const AVClass smvjpegdec_class = {
+    .class_name = "SMVJPEG decoder",
+    .item_name  = av_default_item_name,
+    .version    = LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_smvjpeg_decoder = {
+    .name           = "smvjpeg",
+    .type           = AVMEDIA_TYPE_VIDEO,
+    .id             = AV_CODEC_ID_SMVJPEG,
+    .priv_data_size = sizeof(SMVJpegDecodeContext),
+    .init           = smvjpeg_decode_init,
+    .close          = smvjpeg_decode_end,
+    .decode         = smvjpeg_decode_frame,
+    .max_lowres     = 3,
+    .long_name      = NULL_IF_CONFIG_SMALL("SMV JPEG"),
+    .priv_class     = &smvjpegdec_class,
+};
diff --git a/libavformat/wavdec.c b/libavformat/wavdec.c
index 14c52f8..963812c 100644
--- a/libavformat/wavdec.c
+++ b/libavformat/wavdec.c
@@ -25,6 +25,7 @@
 
 #include "libavutil/avassert.h"
 #include "libavutil/dict.h"
+#include "libavutil/intreadwrite.h"
 #include "libavutil/log.h"
 #include "libavutil/mathematics.h"
 #include "libavutil/opt.h"
@@ -51,6 +52,8 @@ typedef struct WAVDemuxContext {
     int audio_eof;
     int ignore_length;
     int spdif;
+    int smv_cur_pt;
+    int smv_given_first;
 } WAVDemuxContext;
 
 
@@ -323,15 +326,23 @@ static int wav_read_header(AVFormatContext *s)
                 goto break_loop;
             }
             av_log(s, AV_LOG_DEBUG, "Found SMV data\n");
+            wav->smv_given_first = 0;
             vst = avformat_new_stream(s, NULL);
             if (!vst)
                 return AVERROR(ENOMEM);
             avio_r8(pb);
             vst->id = 1;
             vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
-            vst->codec->codec_id = AV_CODEC_ID_MJPEG;
+            vst->codec->codec_id = AV_CODEC_ID_SMVJPEG;
             vst->codec->width  = avio_rl24(pb);
             vst->codec->height = avio_rl24(pb);
+            vst->codec->extradata_size = 4;
+            vst->codec->extradata = av_malloc(vst->codec->extradata_size +
+                                              FF_INPUT_BUFFER_PADDING_SIZE);
+            if (!vst->codec->extradata) {
+                av_log(s, AV_LOG_ERROR, "Could not allocate extradata.\n");
+                return AVERROR(ENOMEM);
+            }
             size = avio_rl24(pb);
             wav->smv_data_ofs = avio_tell(pb) + (size - 5) * 3;
             avio_rl24(pb);
@@ -341,6 +352,8 @@ static int wav_read_header(AVFormatContext *s)
             avio_rl24(pb);
             avio_rl24(pb);
             wav->smv_frames_per_jpeg = avio_rl24(pb);
+            AV_WL32(vst->codec->extradata, wav->smv_frames_per_jpeg);
+            wav->smv_cur_pt = 0;
             goto break_loop;
         case MKTAG('L', 'I', 'S', 'T'):
             if (size < 4) {
@@ -432,10 +445,13 @@ static int wav_read_packet(AVFormatContext *s,
 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;
+            audio_dts = abs(av_rescale_q(audio_dts, s->streams[0]->time_base, AV_TIME_BASE_Q));
+            video_dts = abs(av_rescale_q(video_dts, s->streams[1]->time_base, AV_TIME_BASE_Q));
+            /*We always return a video frame first to get the pixel format first*/
+            wav->smv_last_stream = wav->smv_given_first ? video_dts < audio_dts : 0;
+            wav->smv_given_first = 1;
         }
         wav->smv_last_stream = !wav->smv_last_stream;
         wav->smv_last_stream |= wav->audio_eof;
@@ -453,8 +469,13 @@ smv_retry:
             if (ret < 0)
                 goto smv_out;
             pkt->pos -= 3;
-            pkt->pts = wav->smv_block * wav->smv_frames_per_jpeg;
-            wav->smv_block++;
+            pkt->pts = wav->smv_block * wav->smv_frames_per_jpeg + wav->smv_cur_pt;
+            wav->smv_cur_pt++;
+            if (wav->smv_frames_per_jpeg > 0)
+                wav->smv_cur_pt %= wav->smv_frames_per_jpeg;
+            if (!wav->smv_cur_pt)
+                wav->smv_block++;
+
             pkt->stream_index = 1;
 smv_out:
             avio_seek(s->pb, old_pos, SEEK_SET);
@@ -513,7 +534,10 @@ static int wav_read_seek(AVFormatContext *s,
             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;
+        if (wav->smv_frames_per_jpeg > 0) {
+            wav->smv_block = smv_timestamp / wav->smv_frames_per_jpeg;
+            wav->smv_cur_pt = smv_timestamp % wav->smv_frames_per_jpeg;
+        }
     }
 
     st = s->streams[0];
-- 
1.8.1.4


Date: Wed, 20 Mar 2013 03:02:48 +0100
From: michaelni at gmx.at
To: ffmpeg-devel at ffmpeg.org
Subject: Re: [FFmpeg-devel] [PATCH 2/2] Support playing SMV files.

On Tue, Feb 26, 2013 at 09:22:21PM +0000, Ash Hughes wrote:
> Updated to fix parse errors, patch against trunk. Both plays and converts...
[...]
> +static av_cold int smvjpeg_decode_end(AVCodecContext *avctx)
> +{
> +    SMVJpegDecodeContext *s = avctx->priv_data;
> +    MJpegDecodeContext *jpg = &s->jpg;
> +
> +    jpg->picture_ptr = NULL;
 
> +    if (s->picture[1].data[0])
> +        avctx->release_buffer(avctx, &s->picture[1]);
 
this needs to be updated to the buffer reference API
 
also please make sure to create the patch with
git format-patch or git send-email
 
thanks
 
[...]
-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
 
Dictatorship naturally arises out of democracy, and the most aggravated
form of tyranny and slavery out of the most extreme liberty. -- Plato

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel at ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel 		 	   		   		 	   		  


More information about the ffmpeg-devel mailing list