Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
Ash Hughes authored on 2013/05/22 10:16:51... | ... |
@@ -217,6 +217,7 @@ Codecs: |
217 | 217 |
s3tc* Ivo van Poorten |
218 | 218 |
smacker.c Kostya Shishkov |
219 | 219 |
smc.c Mike Melanson |
220 |
+ smvjpegdec.c Ash Hughes |
|
220 | 221 |
snow.c Michael Niedermayer, Loren Merritt |
221 | 222 |
sonic.c Alex Beregszaszi |
222 | 223 |
srt* Aurelien Jacobs |
... | ... |
@@ -463,6 +464,7 @@ GnuPG Fingerprints of maintainers and contributors |
463 | 463 |
|
464 | 464 |
Anssi Hannula 1A92 FF42 2DD9 8D2E 8AF7 65A9 4278 C520 513D F3CB |
465 | 465 |
Anton Khirnov 6D0C 6625 56F8 65D1 E5F5 814B B50A 1241 C067 07AB |
466 |
+Ash Hughes 694D 43D2 D180 C7C7 6421 ABD3 A641 D0B7 623D 6029 |
|
466 | 467 |
Attila Kinali 11F0 F9A6 A1D2 11F6 C745 D10C 6520 BCDD F2DF E765 |
467 | 468 |
Baptiste Coudurier 8D77 134D 20CC 9220 201F C5DB 0AC9 325C 5C1A BAAA |
468 | 469 |
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 \ |
387 | 387 |
OBJS-$(CONFIG_SMACKAUD_DECODER) += smacker.o |
388 | 388 |
OBJS-$(CONFIG_SMACKER_DECODER) += smacker.o |
389 | 389 |
OBJS-$(CONFIG_SMC_DECODER) += smc.o |
390 |
+OBJS-$(CONFIG_SMVJPEG_DECODER) += smvjpegdec.o |
|
390 | 391 |
OBJS-$(CONFIG_SNOW_DECODER) += snowdec.o snow.o snow_dwt.o |
391 | 392 |
OBJS-$(CONFIG_SNOW_ENCODER) += snowenc.o snow.o snow_dwt.o \ |
392 | 393 |
h263.o ituh263enc.o |
... | ... |
@@ -245,6 +245,7 @@ void avcodec_register_all(void) |
245 | 245 |
REGISTER_DECODER(SGIRLE, sgirle); |
246 | 246 |
REGISTER_DECODER(SMACKER, smacker); |
247 | 247 |
REGISTER_DECODER(SMC, smc); |
248 |
+ REGISTER_DECODER(SMVJPEG, smvjpeg); |
|
248 | 249 |
REGISTER_ENCDEC (SNOW, snow); |
249 | 250 |
REGISTER_DECODER(SP5X, sp5x); |
250 | 251 |
REGISTER_ENCDEC (SUNRAST, sunrast); |
... | ... |
@@ -297,6 +297,7 @@ enum AVCodecID { |
297 | 297 |
AV_CODEC_ID_MVC2 = MKBETAG('M','V','C','2'), |
298 | 298 |
AV_CODEC_ID_SNOW = MKBETAG('S','N','O','W'), |
299 | 299 |
AV_CODEC_ID_WEBP = MKBETAG('W','E','B','P'), |
300 |
+ AV_CODEC_ID_SMVJPEG = MKBETAG('S','M','V','J'), |
|
300 | 301 |
|
301 | 302 |
/* various PCM "codecs" */ |
302 | 303 |
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[] = { |
1378 | 1378 |
.long_name = NULL_IF_CONFIG_SMALL("BRender PIX image"), |
1379 | 1379 |
.props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, |
1380 | 1380 |
}, |
1381 |
+ { |
|
1382 |
+ .id = AV_CODEC_ID_SMVJPEG, |
|
1383 |
+ .type = AVMEDIA_TYPE_VIDEO, |
|
1384 |
+ .name = "smv", |
|
1385 |
+ .long_name = NULL_IF_CONFIG_SMALL("Sigmatel Motion Video"), |
|
1386 |
+ }, |
|
1387 |
+ |
|
1381 | 1388 |
|
1382 | 1389 |
/* various PCM "codecs" */ |
1383 | 1390 |
{ |
1384 | 1391 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,187 @@ |
0 |
+/* |
|
1 |
+ * SMV JPEG decoder |
|
2 |
+ * Copyright (c) 2013 Ash Hughes |
|
3 |
+ * |
|
4 |
+ * This file is part of FFmpeg. |
|
5 |
+ * |
|
6 |
+ * FFmpeg is free software; you can redistribute it and/or |
|
7 |
+ * modify it under the terms of the GNU Lesser General Public |
|
8 |
+ * License as published by the Free Software Foundation; either |
|
9 |
+ * version 2.1 of the License, or (at your option) any later version. |
|
10 |
+ * |
|
11 |
+ * FFmpeg is distributed in the hope that it will be useful, |
|
12 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
14 |
+ * Lesser General Public License for more details. |
|
15 |
+ * |
|
16 |
+ * You should have received a copy of the GNU Lesser General Public |
|
17 |
+ * License along with FFmpeg; if not, write to the Free Software |
|
18 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
19 |
+ */ |
|
20 |
+ |
|
21 |
+/** |
|
22 |
+ * @file |
|
23 |
+ * SMV JPEG decoder. |
|
24 |
+ */ |
|
25 |
+ |
|
26 |
+// #define DEBUG |
|
27 |
+#include "avcodec.h" |
|
28 |
+#include "libavutil/opt.h" |
|
29 |
+#include "libavutil/imgutils.h" |
|
30 |
+#include "mjpegdec.h" |
|
31 |
+#include "internal.h" |
|
32 |
+ |
|
33 |
+typedef struct SMVJpegDecodeContext { |
|
34 |
+ MJpegDecodeContext jpg; |
|
35 |
+ AVFrame *picture[2]; /* pictures array */ |
|
36 |
+ AVCodecContext* avctx; |
|
37 |
+ int frames_per_jpeg; |
|
38 |
+} SMVJpegDecodeContext; |
|
39 |
+ |
|
40 |
+static inline void smv_img_pnt_plane(uint8_t **dst, uint8_t *src, |
|
41 |
+ int src_linesize, int height, int nlines) |
|
42 |
+{ |
|
43 |
+ if (!dst || !src) |
|
44 |
+ return; |
|
45 |
+ src += (nlines) * src_linesize * height; |
|
46 |
+ *dst = src; |
|
47 |
+} |
|
48 |
+ |
|
49 |
+static inline void smv_img_pnt(uint8_t *dst_data[4], uint8_t *src_data[4], |
|
50 |
+ const int src_linesizes[4], |
|
51 |
+ enum PixelFormat pix_fmt, int width, int height, |
|
52 |
+ int nlines) |
|
53 |
+{ |
|
54 |
+ const AVPixFmtDescriptor *desc = &av_pix_fmt_descriptors[pix_fmt]; |
|
55 |
+ int i, planes_nb = 0; |
|
56 |
+ |
|
57 |
+ if (desc->flags & PIX_FMT_HWACCEL) |
|
58 |
+ return; |
|
59 |
+ |
|
60 |
+ for (i = 0; i < desc->nb_components; i++) |
|
61 |
+ planes_nb = FFMAX(planes_nb, desc->comp[i].plane + 1); |
|
62 |
+ |
|
63 |
+ for (i = 0; i < planes_nb; i++) { |
|
64 |
+ int h = height; |
|
65 |
+ if (i == 1 || i == 2) { |
|
66 |
+ h = FF_CEIL_RSHIFT(height, desc->log2_chroma_h); |
|
67 |
+ } |
|
68 |
+ smv_img_pnt_plane(&dst_data[i], src_data[i], |
|
69 |
+ src_linesizes[i], h, nlines); |
|
70 |
+ } |
|
71 |
+} |
|
72 |
+ |
|
73 |
+static av_cold int smvjpeg_decode_init(AVCodecContext *avctx) |
|
74 |
+{ |
|
75 |
+ SMVJpegDecodeContext *s = avctx->priv_data; |
|
76 |
+ AVCodec *codec; |
|
77 |
+ AVDictionary *thread_opt = NULL; |
|
78 |
+ int ret = 0; |
|
79 |
+ |
|
80 |
+ s->frames_per_jpeg = 0; |
|
81 |
+ |
|
82 |
+ s->picture[0] = av_frame_alloc(); |
|
83 |
+ if (!s->picture[0]) |
|
84 |
+ return AVERROR(ENOMEM); |
|
85 |
+ |
|
86 |
+ s->picture[1] = av_frame_alloc(); |
|
87 |
+ if (!s->picture[1]) |
|
88 |
+ return AVERROR(ENOMEM); |
|
89 |
+ |
|
90 |
+ s->jpg.picture_ptr = s->picture[0]; |
|
91 |
+ |
|
92 |
+ if (avctx->extradata_size >= 4) |
|
93 |
+ s->frames_per_jpeg = AV_RL32(avctx->extradata); |
|
94 |
+ |
|
95 |
+ if (s->frames_per_jpeg <= 0) { |
|
96 |
+ av_log(avctx, AV_LOG_ERROR, "Invalid number of frames per jpeg.\n"); |
|
97 |
+ ret = -1; |
|
98 |
+ } |
|
99 |
+ |
|
100 |
+ avcodec_get_frame_defaults(s->picture[1]); |
|
101 |
+ avctx->coded_frame = s->picture[1]; |
|
102 |
+ codec = avcodec_find_decoder(AV_CODEC_ID_MJPEG); |
|
103 |
+ if (!codec) { |
|
104 |
+ av_log(avctx, AV_LOG_ERROR, "MJPEG codec not found\n"); |
|
105 |
+ ret = -1; |
|
106 |
+ } |
|
107 |
+ |
|
108 |
+ s->avctx = avcodec_alloc_context3(codec); |
|
109 |
+ |
|
110 |
+ av_dict_set(&thread_opt, "threads", "1", 0); |
|
111 |
+ if (ff_codec_open2_recursive(s->avctx, codec, &thread_opt) < 0) { |
|
112 |
+ av_log(avctx, AV_LOG_ERROR, "MJPEG codec failed to open\n"); |
|
113 |
+ ret = -1; |
|
114 |
+ } |
|
115 |
+ av_dict_free(&thread_opt); |
|
116 |
+ |
|
117 |
+ return ret; |
|
118 |
+} |
|
119 |
+ |
|
120 |
+static int smvjpeg_decode_frame(AVCodecContext *avctx, void *data, int *data_size, |
|
121 |
+ AVPacket *avpkt) |
|
122 |
+{ |
|
123 |
+ SMVJpegDecodeContext *s = avctx->priv_data; |
|
124 |
+ AVFrame* mjpeg_data = s->picture[0]; |
|
125 |
+ int i, cur_frame = 0, ret = 0; |
|
126 |
+ |
|
127 |
+ cur_frame = avpkt->pts % s->frames_per_jpeg; |
|
128 |
+ |
|
129 |
+ /* Are we at the start of a block? */ |
|
130 |
+ if (!cur_frame) |
|
131 |
+ ret = avcodec_decode_video2(s->avctx, mjpeg_data, data_size, avpkt); |
|
132 |
+ else /*use the last lot... */ |
|
133 |
+ *data_size = sizeof(AVPicture); |
|
134 |
+ |
|
135 |
+ avctx->pix_fmt = s->avctx->pix_fmt; |
|
136 |
+ |
|
137 |
+ /* We shouldn't get here if frames_per_jpeg <= 0 because this was rejected |
|
138 |
+ in init */ |
|
139 |
+ avcodec_set_dimensions(avctx, mjpeg_data->width, |
|
140 |
+ mjpeg_data->height / s->frames_per_jpeg); |
|
141 |
+ |
|
142 |
+ s->picture[1]->extended_data = NULL; |
|
143 |
+ s->picture[1]->width = avctx->width; |
|
144 |
+ s->picture[1]->height = avctx->height; |
|
145 |
+ s->picture[1]->format = avctx->pix_fmt; |
|
146 |
+ /* ff_init_buffer_info(avctx, &s->picture[1]); */ |
|
147 |
+ smv_img_pnt(s->picture[1]->data, mjpeg_data->data, mjpeg_data->linesize, |
|
148 |
+ avctx->pix_fmt, avctx->width, avctx->height, cur_frame); |
|
149 |
+ for (i = 0; i < AV_NUM_DATA_POINTERS; i++) |
|
150 |
+ s->picture[1]->linesize[i] = mjpeg_data->linesize[i]; |
|
151 |
+ |
|
152 |
+ ret = av_frame_ref(data, s->picture[1]); |
|
153 |
+ |
|
154 |
+ return ret; |
|
155 |
+} |
|
156 |
+ |
|
157 |
+static av_cold int smvjpeg_decode_end(AVCodecContext *avctx) |
|
158 |
+{ |
|
159 |
+ SMVJpegDecodeContext *s = avctx->priv_data; |
|
160 |
+ MJpegDecodeContext *jpg = &s->jpg; |
|
161 |
+ |
|
162 |
+ jpg->picture_ptr = NULL; |
|
163 |
+ av_frame_free(&s->picture[1]); |
|
164 |
+ ff_codec_close_recursive(s->avctx); |
|
165 |
+ av_freep(&s->avctx); |
|
166 |
+ return 0; |
|
167 |
+} |
|
168 |
+ |
|
169 |
+static const AVClass smvjpegdec_class = { |
|
170 |
+ .class_name = "SMVJPEG decoder", |
|
171 |
+ .item_name = av_default_item_name, |
|
172 |
+ .version = LIBAVUTIL_VERSION_INT, |
|
173 |
+}; |
|
174 |
+ |
|
175 |
+AVCodec ff_smvjpeg_decoder = { |
|
176 |
+ .name = "smvjpeg", |
|
177 |
+ .type = AVMEDIA_TYPE_VIDEO, |
|
178 |
+ .id = AV_CODEC_ID_SMVJPEG, |
|
179 |
+ .priv_data_size = sizeof(SMVJpegDecodeContext), |
|
180 |
+ .init = smvjpeg_decode_init, |
|
181 |
+ .close = smvjpeg_decode_end, |
|
182 |
+ .decode = smvjpeg_decode_frame, |
|
183 |
+ .max_lowres = 3, |
|
184 |
+ .long_name = NULL_IF_CONFIG_SMALL("SMV JPEG"), |
|
185 |
+ .priv_class = &smvjpegdec_class, |
|
186 |
+}; |
... | ... |
@@ -25,6 +25,7 @@ |
25 | 25 |
|
26 | 26 |
#include "libavutil/avassert.h" |
27 | 27 |
#include "libavutil/dict.h" |
28 |
+#include "libavutil/intreadwrite.h" |
|
28 | 29 |
#include "libavutil/log.h" |
29 | 30 |
#include "libavutil/mathematics.h" |
30 | 31 |
#include "libavutil/opt.h" |
... | ... |
@@ -51,6 +52,8 @@ typedef struct WAVDemuxContext { |
51 | 51 |
int audio_eof; |
52 | 52 |
int ignore_length; |
53 | 53 |
int spdif; |
54 |
+ int smv_cur_pt; |
|
55 |
+ int smv_given_first; |
|
54 | 56 |
} WAVDemuxContext; |
55 | 57 |
|
56 | 58 |
#if CONFIG_WAV_DEMUXER |
... | ... |
@@ -337,15 +340,23 @@ static int wav_read_header(AVFormatContext *s) |
337 | 337 |
goto break_loop; |
338 | 338 |
} |
339 | 339 |
av_log(s, AV_LOG_DEBUG, "Found SMV data\n"); |
340 |
+ wav->smv_given_first = 0; |
|
340 | 341 |
vst = avformat_new_stream(s, NULL); |
341 | 342 |
if (!vst) |
342 | 343 |
return AVERROR(ENOMEM); |
343 | 344 |
avio_r8(pb); |
344 | 345 |
vst->id = 1; |
345 | 346 |
vst->codec->codec_type = AVMEDIA_TYPE_VIDEO; |
346 |
- vst->codec->codec_id = AV_CODEC_ID_MJPEG; |
|
347 |
+ vst->codec->codec_id = AV_CODEC_ID_SMVJPEG; |
|
347 | 348 |
vst->codec->width = avio_rl24(pb); |
348 | 349 |
vst->codec->height = avio_rl24(pb); |
350 |
+ vst->codec->extradata_size = 4; |
|
351 |
+ vst->codec->extradata = av_malloc(vst->codec->extradata_size + |
|
352 |
+ FF_INPUT_BUFFER_PADDING_SIZE); |
|
353 |
+ if (!vst->codec->extradata) { |
|
354 |
+ av_log(s, AV_LOG_ERROR, "Could not allocate extradata.\n"); |
|
355 |
+ return AVERROR(ENOMEM); |
|
356 |
+ } |
|
349 | 357 |
size = avio_rl24(pb); |
350 | 358 |
wav->smv_data_ofs = avio_tell(pb) + (size - 5) * 3; |
351 | 359 |
avio_rl24(pb); |
... | ... |
@@ -355,6 +366,8 @@ static int wav_read_header(AVFormatContext *s) |
355 | 355 |
avio_rl24(pb); |
356 | 356 |
avio_rl24(pb); |
357 | 357 |
wav->smv_frames_per_jpeg = avio_rl24(pb); |
358 |
+ AV_WL32(vst->codec->extradata, wav->smv_frames_per_jpeg); |
|
359 |
+ wav->smv_cur_pt = 0; |
|
358 | 360 |
goto break_loop; |
359 | 361 |
case MKTAG('L', 'I', 'S', 'T'): |
360 | 362 |
if (size < 4) { |
... | ... |
@@ -447,10 +460,13 @@ static int wav_read_packet(AVFormatContext *s, AVPacket *pkt) |
447 | 447 |
smv_retry: |
448 | 448 |
audio_dts = s->streams[0]->cur_dts; |
449 | 449 |
video_dts = s->streams[1]->cur_dts; |
450 |
+ |
|
450 | 451 |
if (audio_dts != AV_NOPTS_VALUE && video_dts != AV_NOPTS_VALUE) { |
451 | 452 |
audio_dts = av_rescale_q(audio_dts, s->streams[0]->time_base, AV_TIME_BASE_Q); |
452 | 453 |
video_dts = av_rescale_q(video_dts, s->streams[1]->time_base, AV_TIME_BASE_Q); |
453 |
- wav->smv_last_stream = video_dts >= audio_dts; |
|
454 |
+ /*We always return a video frame first to get the pixel format first*/ |
|
455 |
+ wav->smv_last_stream = wav->smv_given_first ? video_dts > audio_dts : 0; |
|
456 |
+ wav->smv_given_first = 1; |
|
454 | 457 |
} |
455 | 458 |
wav->smv_last_stream = !wav->smv_last_stream; |
456 | 459 |
wav->smv_last_stream |= wav->audio_eof; |
... | ... |
@@ -468,8 +484,13 @@ smv_retry: |
468 | 468 |
if (ret < 0) |
469 | 469 |
goto smv_out; |
470 | 470 |
pkt->pos -= 3; |
471 |
- pkt->pts = wav->smv_block * wav->smv_frames_per_jpeg; |
|
472 |
- wav->smv_block++; |
|
471 |
+ pkt->pts = wav->smv_block * wav->smv_frames_per_jpeg + wav->smv_cur_pt; |
|
472 |
+ wav->smv_cur_pt++; |
|
473 |
+ if (wav->smv_frames_per_jpeg > 0) |
|
474 |
+ wav->smv_cur_pt %= wav->smv_frames_per_jpeg; |
|
475 |
+ if (!wav->smv_cur_pt) |
|
476 |
+ wav->smv_block++; |
|
477 |
+ |
|
473 | 478 |
pkt->stream_index = 1; |
474 | 479 |
smv_out: |
475 | 480 |
avio_seek(s->pb, old_pos, SEEK_SET); |
... | ... |
@@ -528,7 +549,10 @@ static int wav_read_seek(AVFormatContext *s, |
528 | 528 |
smv_timestamp = av_rescale_q(timestamp, s->streams[0]->time_base, s->streams[1]->time_base); |
529 | 529 |
else |
530 | 530 |
timestamp = av_rescale_q(smv_timestamp, s->streams[1]->time_base, s->streams[0]->time_base); |
531 |
- wav->smv_block = smv_timestamp / wav->smv_frames_per_jpeg; |
|
531 |
+ if (wav->smv_frames_per_jpeg > 0) { |
|
532 |
+ wav->smv_block = smv_timestamp / wav->smv_frames_per_jpeg; |
|
533 |
+ wav->smv_cur_pt = smv_timestamp % wav->smv_frames_per_jpeg; |
|
534 |
+ } |
|
532 | 535 |
} |
533 | 536 |
|
534 | 537 |
st = s->streams[0]; |