[FFmpeg-devel] [PATCH 2/2] Support playing SMV files.
Ash Hughes
ashes-iontach at hotmail.com
Tue Feb 26 22:22:21 CET 2013
Updated to fix parse errors, patch against trunk. Both plays and converts...
Ash
---
diff -uNr ffmpeg-vanilla//libavcodec/allcodecs.c ffmpeg-smv//libavcodec/allcodecs.c
--- ffmpeg-vanilla//libavcodec/allcodecs.c 2013-02-25 16:21:26.273439321 +0000
+++ ffmpeg-smv//libavcodec/allcodecs.c 2013-02-25 16:53:43.203286417 +0000
@@ -243,6 +243,7 @@
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 -uNr ffmpeg-vanilla//libavcodec/avcodec.h ffmpeg-smv//libavcodec/avcodec.h
--- ffmpeg-vanilla//libavcodec/avcodec.h 2013-02-25 16:21:26.286439462 +0000
+++ ffmpeg-smv//libavcodec/avcodec.h 2013-02-25 16:54:44.031951057 +0000
@@ -290,6 +290,7 @@
AV_CODEC_ID_SGIRLE = MKBETAG('S','G','I','R'),
AV_CODEC_ID_MVC1 = MKBETAG('M','V','C','1'),
AV_CODEC_ID_MVC2 = MKBETAG('M','V','C','2'),
+ 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 -uNr ffmpeg-vanilla//libavcodec/Makefile ffmpeg-smv//libavcodec/Makefile
--- ffmpeg-vanilla//libavcodec/Makefile 2013-02-25 16:21:26.264439224 +0000
+++ ffmpeg-smv//libavcodec/Makefile 2013-02-25 16:55:27.815429521 +0000
@@ -396,6 +396,7 @@
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 -uNr ffmpeg-vanilla//libavformat/wavdec.c ffmpeg-smv//libavformat/wavdec.c
--- ffmpeg-vanilla//libavformat/wavdec.c 2013-02-25 16:21:26.531442106 +0000
+++ ffmpeg-smv//libavformat/wavdec.c 2013-02-26 21:12:01.970495165 +0000
@@ -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,7 @@
int audio_eof;
int ignore_length;
int spdif;
+ int smv_cur_pt;
} WAVDemuxContext;
@@ -329,9 +331,16 @@
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 +350,8 @@
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) {
@@ -429,10 +440,11 @@
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[0]->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;
@@ -450,8 +462,13 @@
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);
@@ -510,7 +527,10 @@
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];
diff -uNr ffmpeg-vanilla//libavcodec/smvjpegdec.c ffmpeg-smv//libavcodec/smvjpegdec.c
--- ffmpeg-vanilla//libavcodec/smvjpegdec.c 1970-01-01 01:00:00.000000000 +0100
+++ ffmpeg-smv//libavcodec/smvjpegdec.c 2013-02-26 01:45:24.519843486 +0000
@@ -0,0 +1,182 @@
+/*
+ * 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->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];
+ AVFrame* output = data;
+ 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].base[i] = s->picture[1].data[i];
+ s->picture[1].linesize[i] = mjpeg_data->linesize[i];
+ }
+
+ *output = 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;
+ if (s->picture[1].data[0])
+ avctx->release_buffer(avctx, &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 -uNr ffmpeg-vanilla//libavcodec/codec_desc.c ffmpeg-smv//libavcodec/codec_desc.c
--- ffmpeg-vanilla//libavcodec/codec_desc.c 2013-02-25 16:21:26.293439537 +0000
+++ ffmpeg-smv//libavcodec/codec_desc.c 2013-02-25 16:50:42.657314358 +0000
@@ -1362,6 +1362,13 @@
.name = "brender_pix",
.long_name = NULL_IF_CONFIG_SMALL("BRender PIX image"),
},
+ {
+ .id = AV_CODEC_ID_SMVJPEG,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "smv",
+ .long_name = NULL_IF_CONFIG_SMALL("Sigmatel Motion Video"),
+ },
+
/* various PCM "codecs" */
{
Date: Fri, 26 Oct 2012 04:04:21 +0200
From: michaelni at gmx.at
To: ffmpeg-devel at ffmpeg.org
Subject: Re: [FFmpeg-devel] [PATCH 2/2] Support playing SMV files.
On Thu, Oct 25, 2012 at 07:59:30PM +0000, Ash Hughes wrote:
> Updated to patch against trunk.
tried it with:
ffmpeg -i smv/bear3.smv out.avi
fails with:
Unable to parse option value "-1" as pixel format
[...]
> @@ -326,9 +328,16 @@
> 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);
> @@ -338,6 +347,10 @@
> 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;
> + if (wav->smv_frames_per_jpeg > 0)
> + vst->codec->height /= wav->smv_frames_per_jpeg;
> goto break_loop;
> case MKTAG('L', 'I', 'S', 'T'):
> if (size < 4) {
> @@ -436,8 +449,13 @@
> 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);
> @@ -496,7 +514,10 @@
> 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];
> diff -uNr ffmpeg-vanilla/libavcodec/smvjpegdec.c ffmpeg/libavcodec/smvjpegdec.c
> --- ffmpeg-vanilla/libavcodec/smvjpegdec.c 1970-01-01 01:00:00.000000000 +0100
> +++ ffmpeg/libavcodec/smvjpegdec.c 2012-10-19 01:48:26.496972741 +0100
> @@ -0,0 +1,182 @@
> +/*
> + * SMV JPEG decoder
> + * Copyright (c) 2012 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->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;
> + }
iam not sure its a good idea to continue on errors like this
have you tested that this works ?
[...]
--
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
It is what and why we do it that matters, not just one of them.
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel at ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
More information about the ffmpeg-devel
mailing list