Skip to content

Commit 19ce064

Browse files
committed
smvjpegdec: merge into mjpegdec
SMVJPEG stores frames as slices of a big JPEG image. The decoder is implemented as a wrapper that instantiates a full internal MJPEG decoder, then forwards the decoded frames with offset data pointers. This is unnecessarily complex and fragile, not supporting useful decoder capabilities like direct rendering. Re-implement the decoder inside the MJPEG decoder, which is accomplished by returning each decoded frame multiple times, setting cropping information appropriately on each instance. One peculiar aspect of the previous design is that since - the smvjpeg decoder returns one frame per input packet - there are multiple frames in each packets (the aformentioned slices) the demuxer needs to return each packet multiple times. This is now also eliminated - the demuxer now returns each packet exactly once, with the duration set to the number of frames it decodes to. This also removes one of the last remaining internal uses of the old video decoding API.
1 parent e9a2a87 commit 19ce064

File tree

8 files changed

+97
-237
lines changed

8 files changed

+97
-237
lines changed

MAINTAINERS

-1
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,6 @@ Codecs:
235235
rv10.c Michael Niedermayer
236236
s3tc* Ivo van Poorten
237237
smc.c Mike Melanson
238-
smvjpegdec.c Ash Hughes
239238
snow* Michael Niedermayer, Loren Merritt
240239
sonic.c Alex Beregszaszi
241240
speedhq.c Steinar H. Gunderson

configure

+1
Original file line numberDiff line numberDiff line change
@@ -2838,6 +2838,7 @@ rv40_decoder_select="golomb h264pred h264qpel mpegvideo rv34dsp"
28382838
screenpresso_decoder_deps="zlib"
28392839
shorten_decoder_select="bswapdsp"
28402840
sipr_decoder_select="lsp"
2841+
smvjpeg_decoder_select="mjpeg_decoder"
28412842
snow_decoder_select="dwt h264qpel hpeldsp me_cmp rangecoder videodsp"
28422843
snow_encoder_select="dwt h264qpel hpeldsp me_cmp mpegvideoenc rangecoder"
28432844
sonic_decoder_select="golomb rangecoder"

libavcodec/Makefile

-1
Original file line numberDiff line numberDiff line change
@@ -618,7 +618,6 @@ OBJS-$(CONFIG_SIREN_DECODER) += siren.o
618618
OBJS-$(CONFIG_SMACKAUD_DECODER) += smacker.o
619619
OBJS-$(CONFIG_SMACKER_DECODER) += smacker.o
620620
OBJS-$(CONFIG_SMC_DECODER) += smc.o
621-
OBJS-$(CONFIG_SMVJPEG_DECODER) += smvjpegdec.o
622621
OBJS-$(CONFIG_SNOW_DECODER) += snowdec.o snow.o snow_dwt.o
623622
OBJS-$(CONFIG_SNOW_ENCODER) += snowenc.o snow.o snow_dwt.o \
624623
h263.o h263data.o ituh263enc.o

libavcodec/mjpegdec.c

+88-1
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,19 @@ av_cold int ff_mjpeg_decode_init(AVCodecContext *avctx)
198198
s->interlace_polarity = 1;
199199
}
200200

201-
if ( avctx->extradata_size > 8
201+
if (avctx->codec_id == AV_CODEC_ID_SMVJPEG) {
202+
if (avctx->extradata_size >= 4)
203+
s->smv_frames_per_jpeg = AV_RL32(avctx->extradata);
204+
205+
if (s->smv_frames_per_jpeg <= 0) {
206+
av_log(avctx, AV_LOG_ERROR, "Invalid number of frames per jpeg.\n");
207+
return AVERROR_INVALIDDATA;
208+
}
209+
210+
s->smv_frame = av_frame_alloc();
211+
if (!s->smv_frame)
212+
return AVERROR(ENOMEM);
213+
} else if (avctx->extradata_size > 8
202214
&& AV_RL32(avctx->extradata) == 0x2C
203215
&& AV_RL32(avctx->extradata+4) == 0x18) {
204216
parse_avid(s, avctx->extradata, avctx->extradata_size);
@@ -472,6 +484,12 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s)
472484
size_change = 0;
473485
}
474486

487+
if (s->avctx->codec_id == AV_CODEC_ID_SMVJPEG) {
488+
s->avctx->height = s->avctx->coded_height / s->smv_frames_per_jpeg;
489+
if (s->avctx->height <= 0)
490+
return AVERROR_INVALIDDATA;
491+
}
492+
475493
if (s->got_picture && s->interlaced && (s->bottom_field == !s->interlace_polarity)) {
476494
if (s->progressive) {
477495
avpriv_request_sample(s->avctx, "progressively coded interlaced picture");
@@ -2336,6 +2354,42 @@ static void reset_icc_profile(MJpegDecodeContext *s)
23362354
s->iccnum = 0;
23372355
}
23382356

2357+
// SMV JPEG just stacks several output frames into one JPEG picture
2358+
// we handle that by setting up the cropping parameters appropriately
2359+
static int smv_process_frame(AVCodecContext *avctx, AVFrame *frame)
2360+
{
2361+
MJpegDecodeContext *s = avctx->priv_data;
2362+
int ret;
2363+
2364+
if (s->smv_next_frame > 0) {
2365+
av_assert0(s->smv_frame->buf[0]);
2366+
av_frame_unref(frame);
2367+
ret = av_frame_ref(frame, s->smv_frame);
2368+
if (ret < 0)
2369+
return ret;
2370+
} else {
2371+
av_assert0(frame->buf[0]);
2372+
av_frame_unref(s->smv_frame);
2373+
ret = av_frame_ref(s->smv_frame, frame);
2374+
if (ret < 0)
2375+
return ret;
2376+
}
2377+
2378+
av_assert0((s->smv_next_frame + 1) * avctx->height <= avctx->coded_height);
2379+
2380+
frame->width = avctx->coded_width;
2381+
frame->height = avctx->coded_height;
2382+
frame->crop_top = FFMIN(s->smv_next_frame * avctx->height, frame->height);
2383+
frame->crop_bottom = frame->height - (s->smv_next_frame + 1) * avctx->height;
2384+
2385+
s->smv_next_frame = (s->smv_next_frame + 1) % s->smv_frames_per_jpeg;
2386+
2387+
if (s->smv_next_frame == 0)
2388+
av_frame_unref(s->smv_frame);
2389+
2390+
return 0;
2391+
}
2392+
23392393
static int mjpeg_get_packet(AVCodecContext *avctx)
23402394
{
23412395
MJpegDecodeContext *s = avctx->priv_data;
@@ -2372,6 +2426,9 @@ int ff_mjpeg_receive_frame(AVCodecContext *avctx, AVFrame *frame)
23722426
int ret = 0;
23732427
int is16bit;
23742428

2429+
if (avctx->codec_id == AV_CODEC_ID_SMVJPEG && s->smv_next_frame > 0)
2430+
return smv_process_frame(avctx, frame);
2431+
23752432
av_dict_free(&s->exif_metadata);
23762433
av_freep(&s->stereo3d);
23772434
s->adobe_transform = -1;
@@ -2833,6 +2890,14 @@ int ff_mjpeg_receive_frame(AVCodecContext *avctx, AVFrame *frame)
28332890
av_dict_copy(&frame->metadata, s->exif_metadata, 0);
28342891
av_dict_free(&s->exif_metadata);
28352892

2893+
if (avctx->codec_id == AV_CODEC_ID_SMVJPEG) {
2894+
ret = smv_process_frame(avctx, frame);
2895+
if (ret < 0) {
2896+
av_frame_unref(frame);
2897+
return ret;
2898+
}
2899+
}
2900+
28362901
ret = 0;
28372902

28382903
the_end_no_picture:
@@ -2861,6 +2926,8 @@ av_cold int ff_mjpeg_decode_end(AVCodecContext *avctx)
28612926

28622927
av_packet_free(&s->pkt);
28632928

2929+
av_frame_free(&s->smv_frame);
2930+
28642931
av_freep(&s->buffer);
28652932
av_freep(&s->stereo3d);
28662933
av_freep(&s->ljpeg_buffer);
@@ -2887,6 +2954,9 @@ static void decode_flush(AVCodecContext *avctx)
28872954
{
28882955
MJpegDecodeContext *s = avctx->priv_data;
28892956
s->got_picture = 0;
2957+
2958+
s->smv_next_frame = 0;
2959+
av_frame_unref(s->smv_frame);
28902960
}
28912961

28922962
#if CONFIG_MJPEG_DECODER
@@ -2949,3 +3019,20 @@ AVCodec ff_thp_decoder = {
29493019
FF_CODEC_CAP_SETS_PKT_DTS,
29503020
};
29513021
#endif
3022+
3023+
#if CONFIG_SMVJPEG_DECODER
3024+
AVCodec ff_smvjpeg_decoder = {
3025+
.name = "smvjpeg",
3026+
.long_name = NULL_IF_CONFIG_SMALL("SMV JPEG"),
3027+
.type = AVMEDIA_TYPE_VIDEO,
3028+
.id = AV_CODEC_ID_SMVJPEG,
3029+
.priv_data_size = sizeof(MJpegDecodeContext),
3030+
.init = ff_mjpeg_decode_init,
3031+
.close = ff_mjpeg_decode_end,
3032+
.receive_frame = ff_mjpeg_receive_frame,
3033+
.flush = decode_flush,
3034+
.capabilities = AV_CODEC_CAP_DR1,
3035+
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_EXPORTS_CROPPING |
3036+
FF_CODEC_CAP_SETS_PKT_DTS,
3037+
};
3038+
#endif

libavcodec/mjpegdec.h

+4
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,10 @@ typedef struct MJpegDecodeContext {
142142
int iccnum;
143143
int iccread;
144144

145+
AVFrame *smv_frame;
146+
int smv_frames_per_jpeg;
147+
int smv_next_frame;
148+
145149
// Raw stream data for hwaccel use.
146150
const uint8_t *raw_image_buffer;
147151
size_t raw_image_buffer_size;

0 commit comments

Comments
 (0)