mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-01-08 13:22:53 +02:00
Support playing SMV files.
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
This commit is contained in:
parent
cc0db8cf30
commit
14ec9d2590
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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" */
|
||||
{
|
||||
|
187
libavcodec/smvjpegdec.c
Normal file
187
libavcodec/smvjpegdec.c
Normal file
@ -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,
|
||||
};
|
@ -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];
|
||||
|
Loading…
Reference in New Issue
Block a user