Browse code

Support playing SMV files.

Signed-off-by: Michael Niedermayer <michaelni@gmx.at>

Ash Hughes authored on 2013/05/22 10:16:51
Showing 7 changed files
... ...
@@ -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];