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

Ash Hughes ashes-iontach at hotmail.com
Wed May 22 03:16:51 CEST 2013


updated to use FF_CEIL_RSHIFT. The abs() was a throwback to testing, removing it changes the following '<' back to a '>'

Ash

---
>From cfbd2b64f895cced7c6add679ad3c1dfc3bb3bc7 Mon Sep 17 00:00:00 2001
From: Ash Hughes <ashes-iontach at hotmail.com>
Date: Wed, 22 May 2013 02:05:34 +0100
Subject: [PATCH] Support playing SMV files

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

diff --git a/MAINTAINERS b/MAINTAINERS
index 9f4301d..d316868 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -217,6 +217,7 @@ Codecs:
   s3tc*                                 Ivo van Poorten
   smacker.c                             Kostya Shishkov
   smc.c                                 Mike Melanson
+  smvjpegdec.c                          Ash Hughes
   snow.c                                Michael Niedermayer, Loren Merritt
   sonic.c                               Alex Beregszaszi
   srt*                                  Aurelien Jacobs
@@ -463,6 +464,7 @@ GnuPG Fingerprints of maintainers and contributors
 
 Anssi Hannula                 1A92 FF42 2DD9 8D2E 8AF7 65A9 4278 C520 513D F3CB
 Anton Khirnov                 6D0C 6625 56F8 65D1 E5F5 814B B50A 1241 C067 07AB
+Ash Hughes                    694D 43D2 D180 C7C7 6421 ABD3 A641 D0B7 623D 6029
 Attila Kinali                 11F0 F9A6 A1D2 11F6 C745 D10C 6520 BCDD F2DF E765
 Baptiste Coudurier            8D77 134D 20CC 9220 201F C5DB 0AC9 325C 5C1A BAAA
 Ben Littler                   3EE3 3723 E560 3214 A8CD 4DEB 2CDB FCE7 768C 8D2C
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 0982885..1a58c69 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -387,6 +387,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 1ebd46d..a15162d 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -245,6 +245,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 e959811..7ce9df4 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -297,6 +297,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 72071b9..9309a8d 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -1378,6 +1378,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..4d20316
--- /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 = FF_CEIL_RSHIFT(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 874847e..a94c0a9 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;
 
 #if CONFIG_WAV_DEMUXER
@@ -337,15 +340,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);
@@ -355,6 +366,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) {
@@ -447,10 +460,13 @@ static int wav_read_packet(AVFormatContext *s, AVPacket *pkt)
 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;
+            /*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;
@@ -468,8 +484,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);
@@ -528,7 +549,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: Tue, 21 May 2013 22:50:48 +0200
From: michaelni at gmx.at
To: ffmpeg-devel at ffmpeg.org
Subject: Re: [FFmpeg-devel] [PATCH 2/2] Support playing SMV files.

On Tue, May 21, 2013 at 07:21:08PM +0000, Ash Hughes wrote:
> 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.
 
seems i forgot about this patch
thanks for the ping
 
[...]
 
> +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);
 
FF_CEIL_RSHIFT()
 
 
[...]
> @@ -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));
 
what does the abs do here ?
 
also you might want to add yourself to MAINTAINERS and setup a
public git clone of ffmpeg where you maintain the code if you agree to
maintain it once its in ffmpeg ...
 
[...]
 
-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
 
The misfortune of the wise is better than the prosperity of the fool.
-- Epicurus

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


More information about the ffmpeg-devel mailing list