]> git.sesse.net Git - ffmpeg/blob - libavcodec/motionpixels.c
cbs: Add an explicit type for coded bitstream unit types
[ffmpeg] / libavcodec / motionpixels.c
1 /*
2  * Motion Pixels Video Decoder
3  * Copyright (c) 2008 Gregory Montoir (cyx@users.sourceforge.net)
4  *
5  * This file is part of Libav.
6  *
7  * Libav 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  * Libav 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 Libav; 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 #include "bitstream.h"
24 #include "bswapdsp.h"
25 #include "internal.h"
26 #include "vlc.h"
27
28 #define MAX_HUFF_CODES 16
29
30 #include "motionpixels_tablegen.h"
31
32 typedef struct HuffCode {
33     int code;
34     uint8_t size;
35     uint8_t delta;
36 } HuffCode;
37
38 typedef struct MotionPixelsContext {
39     AVCodecContext *avctx;
40     AVFrame *frame;
41     BswapDSPContext bdsp;
42     uint8_t *changes_map;
43     int offset_bits_len;
44     int codes_count, current_codes_count;
45     int max_codes_bits;
46     HuffCode codes[MAX_HUFF_CODES];
47     VLC vlc;
48     YuvPixel *vpt, *hpt;
49     uint8_t gradient_scale[3];
50     uint8_t *bswapbuf;
51     int bswapbuf_size;
52 } MotionPixelsContext;
53
54 static av_cold int mp_decode_end(AVCodecContext *avctx)
55 {
56     MotionPixelsContext *mp = avctx->priv_data;
57
58     av_freep(&mp->changes_map);
59     av_freep(&mp->vpt);
60     av_freep(&mp->hpt);
61     av_freep(&mp->bswapbuf);
62     av_frame_free(&mp->frame);
63
64     return 0;
65 }
66
67 static av_cold int mp_decode_init(AVCodecContext *avctx)
68 {
69     MotionPixelsContext *mp = avctx->priv_data;
70     int w4 = (avctx->width  + 3) & ~3;
71     int h4 = (avctx->height + 3) & ~3;
72
73     motionpixels_tableinit();
74     mp->avctx = avctx;
75     ff_bswapdsp_init(&mp->bdsp);
76     mp->changes_map = av_mallocz(avctx->width * h4);
77     mp->offset_bits_len = av_log2(avctx->width * avctx->height) + 1;
78     mp->vpt = av_mallocz(avctx->height * sizeof(YuvPixel));
79     mp->hpt = av_mallocz(h4 * w4 / 16 * sizeof(YuvPixel));
80     avctx->pix_fmt = AV_PIX_FMT_RGB555;
81
82     mp->frame = av_frame_alloc();
83     if (!mp->frame) {
84         mp_decode_end(avctx);
85         return AVERROR(ENOMEM);
86     }
87
88     return 0;
89 }
90
91 static void mp_read_changes_map(MotionPixelsContext *mp, BitstreamContext *bc,
92                                 int count, int bits_len, int read_color)
93 {
94     uint16_t *pixels;
95     int offset, w, h, color = 0, x, y, i;
96
97     while (count--) {
98         offset = bitstream_read(bc, mp->offset_bits_len);
99         w      = bitstream_read(bc, bits_len) + 1;
100         h      = bitstream_read(bc, bits_len) + 1;
101         if (read_color)
102             color = bitstream_read(bc, 15);
103         x = offset % mp->avctx->width;
104         y = offset / mp->avctx->width;
105         if (y >= mp->avctx->height)
106             continue;
107         w = FFMIN(w, mp->avctx->width  - x);
108         h = FFMIN(h, mp->avctx->height - y);
109         pixels = (uint16_t *)&mp->frame->data[0][y * mp->frame->linesize[0] + x * 2];
110         while (h--) {
111             mp->changes_map[offset] = w;
112             if (read_color)
113                 for (i = 0; i < w; ++i)
114                     pixels[i] = color;
115             offset += mp->avctx->width;
116             pixels += mp->frame->linesize[0] / 2;
117         }
118     }
119 }
120
121 static void mp_get_code(MotionPixelsContext *mp, BitstreamContext *bc,
122                         int size, int code)
123 {
124     while (bitstream_read_bit(bc)) {
125         ++size;
126         if (size > mp->max_codes_bits) {
127             av_log(mp->avctx, AV_LOG_ERROR, "invalid code size %d/%d\n", size, mp->max_codes_bits);
128             return;
129         }
130         code <<= 1;
131         mp_get_code(mp, bc, size, code + 1);
132     }
133     if (mp->current_codes_count >= MAX_HUFF_CODES) {
134         av_log(mp->avctx, AV_LOG_ERROR, "too many codes\n");
135         return;
136     }
137     mp->codes[mp->current_codes_count  ].code = code;
138     mp->codes[mp->current_codes_count++].size = size;
139 }
140
141 static void mp_read_codes_table(MotionPixelsContext *mp, BitstreamContext *bc)
142 {
143     if (mp->codes_count == 1) {
144         mp->codes[0].delta = bitstream_read(bc, 4);
145     } else {
146         int i;
147
148         mp->max_codes_bits = bitstream_read(bc, 4);
149         for (i = 0; i < mp->codes_count; ++i)
150             mp->codes[i].delta = bitstream_read(bc, 4);
151         mp->current_codes_count = 0;
152         mp_get_code(mp, bc, 0, 0);
153    }
154 }
155
156 static int mp_gradient(MotionPixelsContext *mp, int component, int v)
157 {
158     int delta;
159
160     delta = (v - 7) * mp->gradient_scale[component];
161     mp->gradient_scale[component] = (v == 0 || v == 14) ? 2 : 1;
162     return delta;
163 }
164
165 static YuvPixel mp_get_yuv_from_rgb(MotionPixelsContext *mp, int x, int y)
166 {
167     int color;
168
169     color = *(uint16_t *)&mp->frame->data[0][y * mp->frame->linesize[0] + x * 2];
170     return mp_rgb_yuv_table[color];
171 }
172
173 static void mp_set_rgb_from_yuv(MotionPixelsContext *mp, int x, int y, const YuvPixel *p)
174 {
175     int color;
176
177     color = mp_yuv_to_rgb(p->y, p->v, p->u, 1);
178     *(uint16_t *)&mp->frame->data[0][y * mp->frame->linesize[0] + x * 2] = color;
179 }
180
181 static int mp_get_vlc(MotionPixelsContext *mp, BitstreamContext *bc)
182 {
183     int i;
184
185     i = (mp->codes_count == 1) ? 0 : bitstream_read_vlc(bc, mp->vlc.table, mp->max_codes_bits, 1);
186     i = FFMIN(i, FF_ARRAY_ELEMS(mp->codes) - 1);
187     return mp->codes[i].delta;
188 }
189
190 static void mp_decode_line(MotionPixelsContext *mp, BitstreamContext *bc, int y)
191 {
192     YuvPixel p;
193     const int y0 = y * mp->avctx->width;
194     int w, i, x = 0;
195
196     p = mp->vpt[y];
197     if (mp->changes_map[y0 + x] == 0) {
198         memset(mp->gradient_scale, 1, sizeof(mp->gradient_scale));
199         ++x;
200     }
201     while (x < mp->avctx->width) {
202         w = mp->changes_map[y0 + x];
203         if (w != 0) {
204             if ((y & 3) == 0) {
205                 if (mp->changes_map[y0 + x + mp->avctx->width] < w ||
206                     mp->changes_map[y0 + x + mp->avctx->width * 2] < w ||
207                     mp->changes_map[y0 + x + mp->avctx->width * 3] < w) {
208                     for (i = (x + 3) & ~3; i < x + w; i += 4) {
209                         mp->hpt[((y / 4) * mp->avctx->width + i) / 4] = mp_get_yuv_from_rgb(mp, i, y);
210                     }
211                 }
212             }
213             x += w;
214             memset(mp->gradient_scale, 1, sizeof(mp->gradient_scale));
215             p = mp_get_yuv_from_rgb(mp, x - 1, y);
216         } else {
217             p.y += mp_gradient(mp, 0, mp_get_vlc(mp, bc));
218             p.y = av_clip_uintp2(p.y, 5);
219             if ((x & 3) == 0) {
220                 if ((y & 3) == 0) {
221                     p.v += mp_gradient(mp, 1, mp_get_vlc(mp, bc));
222                     p.v = av_clip_intp2(p.v, 5);
223                     p.u += mp_gradient(mp, 2, mp_get_vlc(mp, bc));
224                     p.u = av_clip_intp2(p.u, 5);
225                     mp->hpt[((y / 4) * mp->avctx->width + x) / 4] = p;
226                 } else {
227                     p.v = mp->hpt[((y / 4) * mp->avctx->width + x) / 4].v;
228                     p.u = mp->hpt[((y / 4) * mp->avctx->width + x) / 4].u;
229                 }
230             }
231             mp_set_rgb_from_yuv(mp, x, y, &p);
232             ++x;
233         }
234     }
235 }
236
237 static void mp_decode_frame_helper(MotionPixelsContext *mp,
238                                    BitstreamContext *bc)
239 {
240     YuvPixel p;
241     int y, y0;
242
243     for (y = 0; y < mp->avctx->height; ++y) {
244         if (mp->changes_map[y * mp->avctx->width] != 0) {
245             memset(mp->gradient_scale, 1, sizeof(mp->gradient_scale));
246             p = mp_get_yuv_from_rgb(mp, 0, y);
247         } else {
248             p.y += mp_gradient(mp, 0, mp_get_vlc(mp, bc));
249             p.y = av_clip_uintp2(p.y, 5);
250             if ((y & 3) == 0) {
251                 p.v += mp_gradient(mp, 1, mp_get_vlc(mp, bc));
252                 p.v = av_clip_intp2(p.v, 5);
253                 p.u += mp_gradient(mp, 2, mp_get_vlc(mp, bc));
254                 p.u = av_clip_intp2(p.u, 5);
255             }
256             mp->vpt[y] = p;
257             mp_set_rgb_from_yuv(mp, 0, y, &p);
258         }
259     }
260     for (y0 = 0; y0 < 2; ++y0)
261         for (y = y0; y < mp->avctx->height; y += 2)
262             mp_decode_line(mp, bc, y);
263 }
264
265 static int mp_decode_frame(AVCodecContext *avctx,
266                                  void *data, int *got_frame,
267                                  AVPacket *avpkt)
268 {
269     const uint8_t *buf = avpkt->data;
270     int buf_size = avpkt->size;
271     MotionPixelsContext *mp = avctx->priv_data;
272     BitstreamContext bc;
273     int i, count1, count2, sz, ret;
274
275     if ((ret = ff_reget_buffer(avctx, mp->frame)) < 0) {
276         av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
277         return ret;
278     }
279
280     /* le32 bitstream msb first */
281     av_fast_malloc(&mp->bswapbuf, &mp->bswapbuf_size, buf_size + AV_INPUT_BUFFER_PADDING_SIZE);
282     if (!mp->bswapbuf)
283         return AVERROR(ENOMEM);
284     mp->bdsp.bswap_buf((uint32_t *) mp->bswapbuf, (const uint32_t *) buf,
285                        buf_size / 4);
286     if (buf_size & 3)
287         memcpy(mp->bswapbuf + (buf_size & ~3), buf + (buf_size & ~3), buf_size & 3);
288     memset(mp->bswapbuf + buf_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
289     bitstream_init8(&bc, mp->bswapbuf, buf_size);
290
291     memset(mp->changes_map, 0, avctx->width * avctx->height);
292     for (i = !(avctx->extradata[1] & 2); i < 2; ++i) {
293         count1 = bitstream_read(&bc, 12);
294         count2 = bitstream_read(&bc, 12);
295         mp_read_changes_map(mp, &bc, count1, 8, i);
296         mp_read_changes_map(mp, &bc, count2, 4, i);
297     }
298
299     mp->codes_count = bitstream_read(&bc, 4);
300     if (mp->codes_count == 0)
301         goto end;
302
303     if (mp->changes_map[0] == 0) {
304         *(uint16_t *)mp->frame->data[0] = bitstream_read(&bc, 15);
305         mp->changes_map[0] = 1;
306     }
307     mp_read_codes_table(mp, &bc);
308
309     sz = bitstream_read(&bc, 18);
310     if (avctx->extradata[0] != 5)
311         sz += bitstream_read(&bc, 18);
312     if (sz == 0)
313         goto end;
314
315     if (mp->max_codes_bits <= 0)
316         goto end;
317     if (init_vlc(&mp->vlc, mp->max_codes_bits, mp->codes_count, &mp->codes[0].size, sizeof(HuffCode), 1, &mp->codes[0].code, sizeof(HuffCode), 4, 0))
318         goto end;
319     mp_decode_frame_helper(mp, &bc);
320     ff_free_vlc(&mp->vlc);
321
322 end:
323     if ((ret = av_frame_ref(data, mp->frame)) < 0)
324         return ret;
325     *got_frame       = 1;
326     return buf_size;
327 }
328
329 AVCodec ff_motionpixels_decoder = {
330     .name           = "motionpixels",
331     .long_name      = NULL_IF_CONFIG_SMALL("Motion Pixels video"),
332     .type           = AVMEDIA_TYPE_VIDEO,
333     .id             = AV_CODEC_ID_MOTIONPIXELS,
334     .priv_data_size = sizeof(MotionPixelsContext),
335     .init           = mp_decode_init,
336     .close          = mp_decode_end,
337     .decode         = mp_decode_frame,
338     .capabilities   = AV_CODEC_CAP_DR1,
339 };