Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

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