Browse code

y41p encoder and decoder

y41p is a packed 12-bit 4:1:1 YUV format used by Brooktree.

Fixes issue 1123 / ticket #102.

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

Paul B Mahol authored on 2012/01/01 21:16:42
Showing 10 changed files
... ...
@@ -16,6 +16,7 @@ version next:
16 16
 - Indeo 4 decoder
17 17
 - SMJPEG demuxer
18 18
 - Automatic thread count based on detection number of (available) CPU cores
19
+- y41p Brooktree Uncompressed 4:1:1 12-bit encoder and decoder
19 20
 
20 21
 
21 22
 version 0.9:
... ...
@@ -445,6 +445,7 @@ following image formats are supported:
445 445
     @tab Used in some games from Bethesda Softworks.
446 446
 @item Bink Video             @tab     @tab  X
447 447
 @item Bitmap Brothers JV video  @tab   @tab X
448
+@item y41p Brooktree uncompressed 4:1:1 12-bit     @tab  X  @tab  X
448 449
 @item Brute Force & Ignorance   @tab   @tab X
449 450
     @tab Used in the game Flash Traffic: City of Angels.
450 451
 @item C93 video              @tab     @tab  X
... ...
@@ -467,6 +467,8 @@ OBJS-$(CONFIG_XBIN_DECODER)            += bintext.o cga_data.o
467 467
 OBJS-$(CONFIG_XL_DECODER)              += xl.o
468 468
 OBJS-$(CONFIG_XSUB_DECODER)            += xsubdec.o
469 469
 OBJS-$(CONFIG_XSUB_ENCODER)            += xsubenc.o
470
+OBJS-$(CONFIG_Y41P_DECODER)            += y41pdec.o
471
+OBJS-$(CONFIG_Y41P_ENCODER)            += y41penc.o
470 472
 OBJS-$(CONFIG_YOP_DECODER)             += yop.o
471 473
 OBJS-$(CONFIG_ZLIB_DECODER)            += lcldec.o
472 474
 OBJS-$(CONFIG_ZLIB_ENCODER)            += lclenc.o
... ...
@@ -243,6 +243,7 @@ void avcodec_register_all(void)
243 243
     REGISTER_DECODER (XAN_WC3, xan_wc3);
244 244
     REGISTER_DECODER (XAN_WC4, xan_wc4);
245 245
     REGISTER_DECODER (XL, xl);
246
+    REGISTER_ENCDEC  (Y41P, y41p);
246 247
     REGISTER_DECODER (YOP, yop);
247 248
     REGISTER_ENCDEC  (ZLIB, zlib);
248 249
     REGISTER_ENCDEC  (ZMBV, zmbv);
... ...
@@ -255,6 +255,7 @@ enum CodecID {
255 255
     CODEC_ID_VBLE,
256 256
     CODEC_ID_DXTORY,
257 257
     CODEC_ID_V410,
258
+    CODEC_ID_Y41P       = MKBETAG('Y','4','1','P'),
258 259
     CODEC_ID_UTVIDEO = 0x800,
259 260
     CODEC_ID_ESCAPE130  = MKBETAG('E','1','3','0'),
260 261
 
... ...
@@ -21,8 +21,8 @@
21 21
 #define AVCODEC_VERSION_H
22 22
 
23 23
 #define LIBAVCODEC_VERSION_MAJOR 53
24
-#define LIBAVCODEC_VERSION_MINOR 49
25
-#define LIBAVCODEC_VERSION_MICRO 102
24
+#define LIBAVCODEC_VERSION_MINOR 50
25
+#define LIBAVCODEC_VERSION_MICRO 100
26 26
 
27 27
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
28 28
                                                LIBAVCODEC_VERSION_MINOR, \
29 29
new file mode 100644
... ...
@@ -0,0 +1,116 @@
0
+/*
1
+ * y41p decoder
2
+ *
3
+ * Copyright (c) 2012 Paul B Mahol
4
+ *
5
+ * This file is part of FFmpeg.
6
+ *
7
+ * FFmpeg is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU Lesser General Public
9
+ * License as published by the Free Software Foundation; either
10
+ * version 2.1 of the License, or (at your option) any later version.
11
+ *
12
+ * FFmpeg is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
+ * Lesser General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU Lesser General Public
18
+ * License along with FFmpeg; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
+ */
21
+
22
+#include "avcodec.h"
23
+
24
+static av_cold int y41p_decode_init(AVCodecContext *avctx)
25
+{
26
+    avctx->pix_fmt             = PIX_FMT_YUV411P;
27
+    avctx->bits_per_raw_sample = 12;
28
+
29
+    if (avctx->width & 7) {
30
+        av_log(avctx, AV_LOG_WARNING, "y41p requires width to be divisible by 8.\n");
31
+    }
32
+
33
+    avctx->coded_frame = avcodec_alloc_frame();
34
+    if (!avctx->coded_frame) {
35
+        av_log(avctx, AV_LOG_ERROR, "Could not allocate frame.\n");
36
+        return AVERROR(ENOMEM);
37
+    }
38
+
39
+    return 0;
40
+}
41
+
42
+static int y41p_decode_frame(AVCodecContext *avctx, void *data,
43
+                             int *data_size, AVPacket *avpkt)
44
+{
45
+    AVFrame *pic = avctx->coded_frame;
46
+    uint8_t *src = avpkt->data;
47
+    uint8_t *y, *u, *v;
48
+    int i, j;
49
+
50
+    if (pic->data[0])
51
+        avctx->release_buffer(avctx, pic);
52
+
53
+    if (avpkt->size < 1.5 * avctx->height * avctx->width) {
54
+        av_log(avctx, AV_LOG_ERROR, "Insufficient input data.\n");
55
+        return AVERROR(EINVAL);
56
+    }
57
+
58
+    pic->reference = 0;
59
+
60
+    if (avctx->get_buffer(avctx, pic) < 0) {
61
+        av_log(avctx, AV_LOG_ERROR, "Could not allocate buffer.\n");
62
+        return AVERROR(ENOMEM);
63
+    }
64
+
65
+    pic->key_frame = 1;
66
+    pic->pict_type = FF_I_TYPE;
67
+
68
+    for (i = avctx->height - 1; i >= 0 ; i--) {
69
+        y = &pic->data[0][i * pic->linesize[0]];
70
+        u = &pic->data[1][i * pic->linesize[1]];
71
+        v = &pic->data[2][i * pic->linesize[2]];
72
+        for (j = 0; j < avctx->width; j += 8) {
73
+            *(u++) = *src++;
74
+            *(y++) = *src++;
75
+            *(v++) = *src++;
76
+            *(y++) = *src++;
77
+
78
+            *(u++) = *src++;
79
+            *(y++) = *src++;
80
+            *(v++) = *src++;
81
+            *(y++) = *src++;
82
+
83
+            *(y++) = *src++;
84
+            *(y++) = *src++;
85
+            *(y++) = *src++;
86
+            *(y++) = *src++;
87
+        }
88
+    }
89
+
90
+    *data_size = sizeof(AVFrame);
91
+    *(AVFrame *)data = *pic;
92
+
93
+    return avpkt->size;
94
+}
95
+
96
+static av_cold int y41p_decode_close(AVCodecContext *avctx)
97
+{
98
+    if (avctx->coded_frame->data[0])
99
+        avctx->release_buffer(avctx, avctx->coded_frame);
100
+
101
+    av_freep(&avctx->coded_frame);
102
+
103
+    return 0;
104
+}
105
+
106
+AVCodec ff_y41p_decoder = {
107
+    .name         = "y41p",
108
+    .type         = AVMEDIA_TYPE_VIDEO,
109
+    .id           = CODEC_ID_Y41P,
110
+    .init         = y41p_decode_init,
111
+    .decode       = y41p_decode_frame,
112
+    .close        = y41p_decode_close,
113
+    .capabilities = CODEC_CAP_DR1,
114
+    .long_name    = NULL_IF_CONFIG_SMALL("Uncompressed YUV 4:1:1 12-bit"),
115
+};
0 116
new file mode 100644
... ...
@@ -0,0 +1,101 @@
0
+/*
1
+ * y41p encoder
2
+ *
3
+ * Copyright (c) 2012 Paul B Mahol
4
+ *
5
+ * This file is part of FFmpeg.
6
+ *
7
+ * FFmpeg is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU Lesser General Public
9
+ * License as published by the Free Software Foundation; either
10
+ * version 2.1 of the License, or (at your option) any later version.
11
+ *
12
+ * FFmpeg is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
+ * Lesser General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU Lesser General Public
18
+ * License along with FFmpeg; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
+ */
21
+
22
+#include "avcodec.h"
23
+
24
+static av_cold int y41p_encode_init(AVCodecContext *avctx)
25
+{
26
+    if (avctx->width & 7) {
27
+        av_log(avctx, AV_LOG_ERROR, "y41p requires width to be divisible by 8.\n");
28
+        return AVERROR_INVALIDDATA;
29
+    }
30
+
31
+    avctx->coded_frame = avcodec_alloc_frame();
32
+
33
+    if (!avctx->coded_frame) {
34
+        av_log(avctx, AV_LOG_ERROR, "Could not allocate frame.\n");
35
+        return AVERROR(ENOMEM);
36
+    }
37
+
38
+    return 0;
39
+}
40
+
41
+static int y41p_encode_frame(AVCodecContext *avctx, uint8_t *buf,
42
+                             int buf_size, void *data)
43
+{
44
+    AVFrame *pic = data;
45
+    uint8_t *dst = buf;
46
+    uint8_t *y, *u, *v;
47
+    int i, j;
48
+
49
+    if (buf_size < avctx->width * avctx->height * 1.5) {
50
+        av_log(avctx, AV_LOG_ERROR, "Out buffer is too small.\n");
51
+        return AVERROR(ENOMEM);
52
+    }
53
+
54
+    avctx->coded_frame->reference = 0;
55
+    avctx->coded_frame->key_frame = 1;
56
+    avctx->coded_frame->pict_type = FF_I_TYPE;
57
+
58
+    for (i = avctx->height - 1; i >= 0; i--) {
59
+        y = &pic->data[0][i * pic->linesize[0]];
60
+        u = &pic->data[1][i * pic->linesize[1]];
61
+        v = &pic->data[2][i * pic->linesize[2]];
62
+        for (j = 0; j < avctx->width; j += 8) {
63
+            *(dst++) = *(u++);
64
+            *(dst++) = *(y++);
65
+            *(dst++) = *(v++);
66
+            *(dst++) = *(y++);
67
+
68
+            *(dst++) = *(u++);
69
+            *(dst++) = *(y++);
70
+            *(dst++) = *(v++);
71
+            *(dst++) = *(y++);
72
+
73
+            *(dst++) = *(y++);
74
+            *(dst++) = *(y++);
75
+            *(dst++) = *(y++);
76
+            *(dst++) = *(y++);
77
+        }
78
+    }
79
+
80
+    return avctx->width * avctx->height * 1.5;
81
+}
82
+
83
+static av_cold int y41p_encode_close(AVCodecContext *avctx)
84
+{
85
+    av_freep(&avctx->coded_frame);
86
+
87
+    return 0;
88
+}
89
+
90
+AVCodec ff_y41p_encoder = {
91
+    .name         = "y41p",
92
+    .type         = AVMEDIA_TYPE_VIDEO,
93
+    .id           = CODEC_ID_Y41P,
94
+    .init         = y41p_encode_init,
95
+    .encode       = y41p_encode_frame,
96
+    .close        = y41p_encode_close,
97
+    .pix_fmts     = (const enum PixelFormat[]) { PIX_FMT_YUV411P,
98
+                                                 PIX_FMT_NONE },
99
+    .long_name    = NULL_IF_CONFIG_SMALL("Uncompressed YUV 4:1:1 12-bit"),
100
+};
... ...
@@ -91,6 +91,7 @@ const AVCodecTag codec_movvideo_tags[] = {
91 91
     { CODEC_ID_R210,   MKTAG('r', '2', '1', '0') }, /* UNCOMPRESSED 10BIT RGB */
92 92
     { CODEC_ID_V210,   MKTAG('v', '2', '1', '0') }, /* UNCOMPRESSED 10BIT 4:2:2 */
93 93
     { CODEC_ID_V410,   MKTAG('v', '4', '1', '0') }, /* UNCOMPRESSED 10BIT 4:4:4 */
94
+    { CODEC_ID_Y41P,   MKTAG('Y', '4', '1', 'P') }, /* UNCOMPRESSED 12BIT 4:1:1 */
94 95
 
95 96
     { CODEC_ID_MJPEG,  MKTAG('j', 'p', 'e', 'g') }, /* PhotoJPEG */
96 97
     { CODEC_ID_MJPEG,  MKTAG('m', 'j', 'p', 'a') }, /* Motion-JPEG (format A) */
... ...
@@ -290,6 +290,7 @@ const AVCodecTag ff_codec_bmp_tags[] = {
290 290
     { CODEC_ID_VBLE,         MKTAG('V', 'B', 'L', 'E') },
291 291
     { CODEC_ID_ESCAPE130,    MKTAG('E', '1', '3', '0') },
292 292
     { CODEC_ID_DXTORY,       MKTAG('x', 't', 'o', 'r') },
293
+    { CODEC_ID_Y41P,         MKTAG('Y', '4', '1', 'P') },
293 294
     { CODEC_ID_NONE,         0 }
294 295
 };
295 296