[FFmpeg-devel] [PATCH] Support playing SMV files.
Michael Niedermayer
michaelni at gmx.at
Sat Oct 13 04:23:33 CEST 2012
On Thu, Oct 11, 2012 at 05:06:07PM +0000, Ash Hughes wrote:
> Thanks for the feedback, here's an update with fixes from your comments.
>
> Ash
> ---
> diff -uNr ffmpeg-vanilla/libavcodec/allcodecs.c ffmpeg/libavcodec/allcodecs.c
> --- ffmpeg-vanilla/libavcodec/allcodecs.c 2012-10-01 19:34:06.944974579 +0100
> +++ ffmpeg/libavcodec/allcodecs.c 2012-10-01 19:36:15.533611881 +0100
> @@ -215,6 +215,7 @@
> REGISTER_ENCDEC (SGI, sgi);
> 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/libavcodec/avcodec.h
> --- ffmpeg-vanilla/libavcodec/avcodec.h 2012-10-01 19:34:06.956974647 +0100
> +++ ffmpeg/libavcodec/avcodec.h 2012-10-11 15:23:28.037828767 +0100
> @@ -282,6 +282,7 @@
> AV_CODEC_ID_PAF_VIDEO = MKBETAG('P','A','F','V'),
> AV_CODEC_ID_AVRN = MKBETAG('A','V','R','n'),
> AV_CODEC_ID_CPIA = MKBETAG('C','P','I','A'),
> + AV_CODEC_ID_SMVJPEG,
missing MKBETAG
>
> /* 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/libavcodec/Makefile
> --- ffmpeg-vanilla/libavcodec/Makefile 2012-10-01 19:34:06.928974504 +0100
> +++ ffmpeg/libavcodec/Makefile 2012-10-01 19:36:15.537611963 +0100
> @@ -388,6 +388,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
> OBJS-$(CONFIG_SNOW_ENCODER) += snowenc.o snow.o \
> h263.o ituh263enc.o
> diff -uNr ffmpeg-vanilla/libavformat/wav.c ffmpeg/libavformat/wav.c
> --- ffmpeg-vanilla/libavformat/wav.c 2012-10-01 19:34:06.872974243 +0100
> +++ ffmpeg/libavformat/wav.c 2012-10-11 15:08:30.253376898 +0100
> @@ -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"
> @@ -53,6 +54,7 @@
> int smv_eof;
> int audio_eof;
> int ignore_length;
> + int smv_cur_pt;
> } WAVContext;
>
> #if CONFIG_WAV_MUXER
> @@ -506,9 +508,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);
> @@ -518,6 +527,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'):
> list_type = avio_rl32(pb);
> @@ -617,8 +630,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 == 0)
> + wav->smv_block++;
> +
> pkt->stream_index = 1;
> smv_out:
> avio_seek(s->pb, old_pos, SEEK_SET);
> @@ -677,7 +695,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-11 15:40:10.854801495 +0100
> @@ -0,0 +1,203 @@
> +/*
> + * 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"
> +
> +int ff_smvjpeg_decode_init(AVCodecContext *avctx);
> +int ff_smvjpeg_decode_end(AVCodecContext *avctx);
> +int ff_smvjpeg_decode_frame(AVCodecContext *avctx,
> + void *data, int *data_size,
> + AVPacket *avpkt);
> +void smv_image_pnt(uint8_t *dst_data[4], int dst_linesizes[4],
> + uint8_t *src_data[4], const int src_linesizes[4],
> + enum PixelFormat pix_fmt, int width, int height, int nlines);
> +void smv_image_pnt_plane(uint8_t **dst, int dst_linesize,
> + uint8_t *src, int src_linesize,
> + int bytewidth, int height, int nlines);
> +
> +typedef struct SMVJpegDecodeContext {
> + MJpegDecodeContext jpg;
> + AVFrame picture[2]; /* pictures array */
> + AVCodecContext* avctx;
> + int frames_per_jpeg;
> +} SMVJpegDecodeContext;
> +
> +void smv_image_pnt_plane(uint8_t **dst, int dst_linesize,
> + uint8_t *src, int src_linesize,
> + int bytewidth, int height, int nlines)
> +{
> + if (!dst || !src)
> + return;
> + src += (nlines) * src_linesize * height;
> + *dst = src;
> +}
this is used just once, so certainly should be static, but maybe
inlining it would be even clearer
> +
> +void smv_image_pnt(uint8_t *dst_data[4], int dst_linesizes[4],
> + uint8_t *src_data[4], const int src_linesizes[4],
> + enum PixelFormat pix_fmt, int width, int height, int nlines)
this too is used just once
> +{
> + 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;
> + int bwidth = av_image_get_linesize(pix_fmt, width, i);
> + if (i == 1 || i == 2) {
> + h= -((-height)>>desc->log2_chroma_h);
> + }
> + smv_image_pnt_plane(&dst_data[i], dst_linesizes[i], src_data[i],
> + src_linesizes[i], bwidth, h, nlines);
> + }
> +}
> +
> +av_cold int ff_smvjpeg_decode_init(AVCodecContext *avctx)
doesnt need ff_ prefix and can be static (applies to more functions)
> +{
> + SMVJpegDecodeContext *s = avctx->priv_data;
> + AVCodec *codec;
> + AVDictionary *thread_opt = NULL;
> +
> + s->frames_per_jpeg = AV_RL32(avctx->extradata);
this is missing a check on extradata_size
> + s->jpg.picture_ptr = &s->picture[0];
> +
> + 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");
> +
> + s->avctx = avcodec_alloc_context3(codec);
> +
> + av_dict_set(&thread_opt, "threads", "1", 0);
> + if (avcodec_open2_recursive(s->avctx, codec, &thread_opt) < 0) {
> + av_log(avctx, AV_LOG_ERROR, "MJPEG codec failed to open\n");
> + return -1;
> + }
> + av_dict_free(&thread_opt);
> +
> + return 0;
> +}
> +
> +int ff_smvjpeg_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
> + AVPacket *avpkt)
> +{
> + SMVJpegDecodeContext *s = avctx->priv_data;
> + int ret = 0;
> + AVFrame* mjpeg_data = &s->picture[0];
> + AVFrame* output = data;
> + int i, new_height;
> + int cur_frame = 0;
> +
> + if (s->frames_per_jpeg > 0)
> + cur_frame = avpkt->pts % s->frames_per_jpeg;
does it make sense to not just fail in init for frames_per_jpeg <=0 ?
> +
> + /* Are we at the start of a block? */
> + if (cur_frame == 0)
> + 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;
> + new_height = mjpeg_data->height;
> + if (s->frames_per_jpeg > 0) {
> + if (new_height % s->frames_per_jpeg != 0) {
> + av_log(avctx, AV_LOG_WARNING,
> + "There should be an integer number of frames per jpeg.\n");
> + }
> + new_height /= s->frames_per_jpeg;
> + } else {
> + av_log(avctx, AV_LOG_ERROR, "Invalid number of frames per jpeg.\n");
> + ret = -1;
> + }
> +
> + avcodec_set_dimensions(avctx, mjpeg_data->width, new_height);
> +
> + s->picture[1].type = FF_BUFFER_TYPE_INTERNAL;
why do you need this ?
> + s->picture[1].extended_data = s->picture[1].data;
this is likely a bad idea, simply setting extended_data to NULL
is safer
> + 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_image_pnt(s->picture[1].data, s->picture[1].linesize,
> + 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;
> +
> +}
> +
> +av_cold int ff_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]);
> + avcodec_close_recursive(s->avctx);
> + av_free(s->avctx);
av_freep() is safer
> + return 0;
> +}
> +
> +static const AVOption options[] = {
> + { NULL },
> +};
shouldnt be needed if its empty
> +
> +static const AVClass smvjpegdec_class = {
> + .class_name = "SMVJPEG decoder",
> + .item_name = av_default_item_name,
> + .option = options,
> + .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 = ff_smvjpeg_decode_init,
> + .close = ff_smvjpeg_decode_end,
> + .decode = ff_smvjpeg_decode_frame,
> + .max_lowres = 3,
> + .long_name = NULL_IF_CONFIG_SMALL("SMV JPEG"),
> + .priv_class = &smvjpegdec_class,
> +};
> diff -uNr ffmpeg-vanilla/libavcodec/utils.c ffmpeg/libavcodec/utils.c
> --- ffmpeg-vanilla/libavcodec/utils.c 2012-10-01 19:34:06.932974542 +0100
> +++ ffmpeg/libavcodec/utils.c 2012-10-11 14:28:35.269500814 +0100
> @@ -796,6 +796,27 @@
> }
> #endif
>
> +int attribute_align_arg avcodec_open2_recursive(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options)
> +{
> + int ret = 0;
this should be in a seperate patch
[...]
--
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
Complexity theory is the science of finding the exact solution to an
approximation. Benchmarking OTOH is finding an approximation of the exact
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: Digital signature
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20121013/1ab9d343/attachment.asc>
More information about the ffmpeg-devel
mailing list