]> git.sesse.net Git - ffmpeg/blob - libavcodec/mvcdec.c
Add add_pixels4/8() to h264dsp, and remove add_pixels4 from dsputil.
[ffmpeg] / libavcodec / mvcdec.c
1 /*
2  * Silicon Graphics Motion Video Compressor 1 & 2 decoder
3  * Copyright (c) 2012 Peter Ross
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 /**
23  * @file
24  * Silicon Graphics Motion Video Compressor 1 & 2 decoder
25  */
26
27 #include "libavutil/intreadwrite.h"
28 #include "avcodec.h"
29 #include "bytestream.h"
30
31 typedef struct MvcContext {
32     int vflip;
33 } MvcContext;
34
35 static av_cold int mvc_decode_init(AVCodecContext *avctx)
36 {
37     MvcContext *s = avctx->priv_data;
38     int width  = avctx->width;
39     int height = avctx->height;
40
41     if (avctx->codec_id == AV_CODEC_ID_MVC1) {
42         width  += 3;
43         height += 3;
44     }
45     width  &= ~3;
46     height &= ~3;
47     if (width != avctx->width || height != avctx->height)
48         avcodec_set_dimensions(avctx, width, height);
49
50     avctx->pix_fmt = (avctx->codec_id == AV_CODEC_ID_MVC1) ? AV_PIX_FMT_RGB555 : AV_PIX_FMT_BGRA;
51     avctx->coded_frame = avcodec_alloc_frame();
52     if (!avctx->coded_frame)
53         return AVERROR(ENOMEM);
54
55     s->vflip = avctx->extradata_size >= 9 && !memcmp(avctx->extradata + avctx->extradata_size - 9, "BottomUp", 9);
56     return 0;
57 }
58
59 static int decode_mvc1(AVCodecContext *avctx, GetByteContext *gb, uint8_t *dst_start, int width, int height, int linesize)
60 {
61     uint8_t *dst;
62     uint16_t v[8];
63     int mask, x, y, i;
64
65     x = y= 0;
66     while (bytestream2_get_bytes_left(gb) >= 6) {
67         mask = bytestream2_get_be16u(gb);
68         v[0] = bytestream2_get_be16u(gb);
69         v[1] = bytestream2_get_be16u(gb);
70         if ((v[0] & 0x8000)) {
71             if (bytestream2_get_bytes_left(gb) < 12) {
72                 av_log(avctx, AV_LOG_WARNING, "buffer overflow\n");
73                 return AVERROR_INVALIDDATA;
74             }
75             for (i = 2; i < 8; i++)
76                 v[i] = bytestream2_get_be16u(gb);
77         } else {
78             v[2] = v[4] = v[6] = v[0];
79             v[3] = v[5] = v[7] = v[1];
80         }
81
82 #define PIX16(target, true, false) \
83         i = (mask & target) ? true : false; \
84         AV_WN16A(dst, (v[i] & 0x7C00) | (v[i] & 0x3E0) | (v[i] & 0x1F)); \
85         dst += 2;
86
87 #define ROW16(row, a1, a0, b1, b0) \
88         dst = dst_start + (y + row) * linesize + x * 2; \
89         PIX16(1 << (row * 4),     a1, a0) \
90         PIX16(1 << (row * 4 + 1), a1, a0) \
91         PIX16(1 << (row * 4 + 2), b1, b0) \
92         PIX16(1 << (row * 4 + 3), b1, b0)
93
94         ROW16(0, 0, 1, 2, 3);
95         ROW16(1, 0, 1, 2, 3);
96         ROW16(2, 4, 5, 6, 7);
97         ROW16(3, 4, 5, 6, 7);
98
99         x += 4;
100         if (x >= width) {
101             y += 4;
102             if (y >= height) {
103                 break;
104             }
105             x = 0;
106         }
107     }
108     return 0;
109 }
110
111 static void set_4x4_block(uint8_t *dst, int linesize, uint32_t pixel)
112 {
113     int i, j;
114     for (j = 0; j < 4; j++)
115         for (i = 0; i < 4; i++)
116             AV_WN32A(dst + j * linesize + i * 4, pixel);
117 }
118
119 #define PIX32(target, true, false) \
120     AV_WN32A(dst, (mask & target) ? v[true] : v[false]); \
121     dst += 4;
122
123 #define ROW32(row, a1, a0, b1, b0) \
124     dst = dst_start + (y + row) * linesize + x * 4; \
125     PIX32(1 << (row * 4),     a1, a0) \
126     PIX32(1 << (row * 4 + 1), a1, a0) \
127     PIX32(1 << (row * 4 + 2), b1, b0) \
128     PIX32(1 << (row * 4 + 3), b1, b0)
129
130 #define MVC2_BLOCK \
131     ROW32(0, 1, 0, 3, 2); \
132     ROW32(1, 1, 0, 3, 2); \
133     ROW32(2, 5, 4, 7, 6); \
134     ROW32(3, 5, 4, 7, 6);
135
136 static int decode_mvc2(AVCodecContext *avctx, GetByteContext *gb, uint8_t *dst_start, int width, int height, int linesize, int vflip)
137 {
138     uint8_t *dst;
139     uint32_t color[128], v[8];
140     int w, h, nb_colors, i, x, y, p0, p1, mask;
141
142     if (bytestream2_get_bytes_left(gb) < 6)
143         return AVERROR_INVALIDDATA;
144
145     w = bytestream2_get_be16u(gb);
146     h = bytestream2_get_be16u(gb);
147     if ((w & ~3) != width || (h & ~3) != height)
148         av_log(avctx, AV_LOG_WARNING, "dimension mismatch\n");
149
150     if (bytestream2_get_byteu(gb)) {
151         av_log_ask_for_sample(avctx, "bitmap feature\n");
152         return AVERROR_PATCHWELCOME;
153     }
154
155     nb_colors = bytestream2_get_byteu(gb);
156     if (bytestream2_get_bytes_left(gb) < nb_colors * 3)
157         return AVERROR_INVALIDDATA;
158     for (i = 0; i < FFMIN(nb_colors, 128); i++)
159         color[i] = 0xFF000000 | bytestream2_get_be24u(gb);
160     if (nb_colors > 128)
161         bytestream2_skip(gb, (nb_colors - 128) * 3);
162
163     if (vflip) {
164         dst_start += (height - 1) * linesize;
165         linesize = -linesize;
166     }
167     x = y = 0;
168     while (bytestream2_get_bytes_left(gb) >= 1) {
169         p0 = bytestream2_get_byteu(gb);
170         if ((p0 & 0x80)) {
171             if ((p0 & 0x40)) {
172                 p0 &= 0x3F;
173                 p0 = (p0 << 2) | (p0 >> 4);
174                 set_4x4_block(dst_start + y * linesize + x * 4, linesize, 0xFF000000 | (p0 << 16) | (p0 << 8) | p0);
175             } else {
176                 int g, r;
177                 p0 &= 0x3F;
178                 p0 = (p0 << 2) | (p0 >> 4);
179                 if (bytestream2_get_bytes_left(gb) < 2)
180                     return AVERROR_INVALIDDATA;
181                 g = bytestream2_get_byteu(gb);
182                 r = bytestream2_get_byteu(gb);
183                 set_4x4_block(dst_start + y * linesize + x * 4, linesize, 0xFF000000 | (r << 16) | (g << 8) | p0);
184             }
185         } else {
186             if (bytestream2_get_bytes_left(gb) < 1)
187                 return AVERROR_INVALIDDATA;
188             p1 = bytestream2_get_byteu(gb);
189             if ((p1 & 0x80)) {
190                 if ((p0 & 0x7F) == (p1 & 0x7F)) {
191                     set_4x4_block(dst_start + y * linesize + x * 4, linesize, color[p0 & 0x7F]);
192                 } else {
193                     if (bytestream2_get_bytes_left(gb) < 2)
194                         return AVERROR_INVALIDDATA;
195                     v[0] = v[2] = v[4] = v[6] = color[p0 & 0x7F];
196                     v[1] = v[3] = v[5] = v[7] = color[p1 & 0x7F];
197                     mask = bytestream2_get_le16u(gb);
198                     MVC2_BLOCK
199                 }
200             } else {
201                 if (bytestream2_get_bytes_left(gb) < 8)
202                     return AVERROR_INVALIDDATA;
203                 v[0] = color[p0 & 0x7F];
204                 v[1] = color[p1 & 0x7F];
205                 for (i = 2; i < 8; i++)
206                     v[i] = color[bytestream2_get_byteu(gb) & 0x7F];
207                 mask = bytestream2_get_le16u(gb);
208                 MVC2_BLOCK
209             }
210         }
211
212         x += 4;
213         if (x >= width) {
214             y += 4;
215             if (y >= height)
216                 break;
217             x = 0;
218         }
219     }
220     return 0;
221 }
222
223 static int mvc_decode_frame(AVCodecContext *avctx,
224                             void *data, int *got_frame,
225                             AVPacket *avpkt)
226 {
227     MvcContext *s = avctx->priv_data;
228     GetByteContext gb;
229     int ret;
230
231     avctx->coded_frame->reference = 3;
232     avctx->coded_frame->buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE |
233                             FF_BUFFER_HINTS_REUSABLE | FF_BUFFER_HINTS_READABLE;
234     ret = avctx->reget_buffer(avctx, avctx->coded_frame);
235     if (ret < 0) {
236         av_log (avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
237         return AVERROR(ENOMEM);
238     }
239
240     bytestream2_init(&gb, avpkt->data, avpkt->size);
241     if (avctx->codec_id == AV_CODEC_ID_MVC1)
242         ret = decode_mvc1(avctx, &gb, avctx->coded_frame->data[0], avctx->width, avctx->height, avctx->coded_frame->linesize[0]);
243     else
244         ret = decode_mvc2(avctx, &gb, avctx->coded_frame->data[0], avctx->width, avctx->height, avctx->coded_frame->linesize[0], s->vflip);
245     if (ret < 0)
246         return ret;
247
248     *got_frame      = 1;
249     *(AVFrame*)data = *avctx->coded_frame;
250     return avpkt->size;
251 }
252
253 static av_cold int mvc_decode_end(AVCodecContext *avctx)
254 {
255     if (avctx->coded_frame->data[0])
256         avctx->release_buffer(avctx, avctx->coded_frame);
257     av_freep(&avctx->coded_frame);
258     return 0;
259 }
260
261 #if CONFIG_MVC1_DECODER
262 AVCodec ff_mvc1_decoder = {
263     .name           = "mvc1",
264     .type           = AVMEDIA_TYPE_VIDEO,
265     .id             = AV_CODEC_ID_MVC1,
266     .priv_data_size = sizeof(MvcContext),
267     .init           = mvc_decode_init,
268     .close          = mvc_decode_end,
269     .decode         = mvc_decode_frame,
270     .capabilities   = CODEC_CAP_DR1,
271     .long_name      = NULL_IF_CONFIG_SMALL("Silicon Graphics Motion Video Compressor 1"),
272 };
273 #endif
274
275 #if CONFIG_MVC2_DECODER
276 AVCodec ff_mvc2_decoder = {
277     .name           = "mvc2",
278     .type           = AVMEDIA_TYPE_VIDEO,
279     .id             = AV_CODEC_ID_MVC2,
280     .priv_data_size = sizeof(MvcContext),
281     .init           = mvc_decode_init,
282     .close          = mvc_decode_end,
283     .decode         = mvc_decode_frame,
284     .capabilities   = CODEC_CAP_DR1,
285     .long_name      = NULL_IF_CONFIG_SMALL("Silicon Graphics Motion Video Compressor 2"),
286 };
287 #endif