Statistics
| Branch: | Revision:

ffmpeg / libavcodec / qpeg.c @ 5509bffa

History | View | Annotate | Download (9.36 KB)

1 acfd8f0f Mike Melanson
/*
2
 * QPEG codec
3
 * Copyright (c) 2004 Konstantin Shishkov
4
 *
5
 * This library is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU Lesser General Public
7
 * License as published by the Free Software Foundation; either
8
 * version 2 of the License, or (at your option) any later version.
9
 *
10
 * This library is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 * Lesser General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Lesser General Public
16
 * License along with this library; if not, write to the Free Software
17 5509bffa Diego Biurrun
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 acfd8f0f Mike Melanson
 *
19
 */
20 115329f1 Diego Biurrun
21 acfd8f0f Mike Melanson
/**
22
 * @file qpeg.c
23
 * QPEG codec.
24
 */
25 115329f1 Diego Biurrun
26 acfd8f0f Mike Melanson
#include "avcodec.h"
27
#include "mpegvideo.h"
28
29
typedef struct QpegContext{
30
    AVCodecContext *avctx;
31
    AVFrame pic;
32
    uint8_t *refdata;
33
} QpegContext;
34
35
static void qpeg_decode_intra(uint8_t *src, uint8_t *dst, int size,
36 bb270c08 Diego Biurrun
                            int stride, int width, int height)
37 acfd8f0f Mike Melanson
{
38
    int i;
39
    int code;
40
    int c0, c1;
41
    int run, copy;
42
    int filled = 0;
43 f63166f8 Kostya Shishkov
    int rows_to_go;
44 115329f1 Diego Biurrun
45 f63166f8 Kostya Shishkov
    rows_to_go = height;
46 acfd8f0f Mike Melanson
    height--;
47
    dst = dst + height * stride;
48 115329f1 Diego Biurrun
49 f63166f8 Kostya Shishkov
    while((size > 0) && (rows_to_go > 0)) {
50 bb270c08 Diego Biurrun
        code = *src++;
51
        size--;
52
        run = copy = 0;
53
        if(code == 0xFC) /* end-of-picture code */
54
            break;
55
        if(code >= 0xF8) { /* very long run */
56
            c0 = *src++;
57
            c1 = *src++;
58
            size -= 2;
59
            run = ((code & 0x7) << 16) + (c0 << 8) + c1 + 2;
60
        } else if (code >= 0xF0) { /* long run */
61
            c0 = *src++;
62
            size--;
63
            run = ((code & 0xF) << 8) + c0 + 2;
64
        } else if (code >= 0xE0) { /* short run */
65
            run = (code & 0x1F) + 2;
66
        } else if (code >= 0xC0) { /* very long copy */
67
            c0 = *src++;
68
            c1 = *src++;
69
            size -= 2;
70
            copy = ((code & 0x3F) << 16) + (c0 << 8) + c1 + 1;
71
        } else if (code >= 0x80) { /* long copy */
72
            c0 = *src++;
73
            size--;
74
            copy = ((code & 0x7F) << 8) + c0 + 1;
75
        } else { /* short copy */
76
            copy = code + 1;
77
        }
78 115329f1 Diego Biurrun
79 bb270c08 Diego Biurrun
        /* perform actual run or copy */
80
        if(run) {
81
            int p;
82 115329f1 Diego Biurrun
83 bb270c08 Diego Biurrun
            p = *src++;
84
            size--;
85
            for(i = 0; i < run; i++) {
86
                dst[filled++] = p;
87
                if (filled >= width) {
88
                    filled = 0;
89
                    dst -= stride;
90 f63166f8 Kostya Shishkov
                    rows_to_go--;
91
                    if(rows_to_go <= 0)
92
                        break;
93 bb270c08 Diego Biurrun
                }
94
            }
95
        } else {
96 f63166f8 Kostya Shishkov
            size -= copy;
97 bb270c08 Diego Biurrun
            for(i = 0; i < copy; i++) {
98
                dst[filled++] = *src++;
99
                if (filled >= width) {
100
                    filled = 0;
101
                    dst -= stride;
102 f63166f8 Kostya Shishkov
                    rows_to_go--;
103
                    if(rows_to_go <= 0)
104
                        break;
105 bb270c08 Diego Biurrun
                }
106
            }
107
        }
108 acfd8f0f Mike Melanson
    }
109
}
110
111 115329f1 Diego Biurrun
static int qpeg_table_h[16] =
112 acfd8f0f Mike Melanson
 { 0x00, 0x20, 0x20, 0x20, 0x18, 0x10, 0x10, 0x20, 0x10, 0x08, 0x18, 0x08, 0x08, 0x18, 0x10, 0x04};
113
static int qpeg_table_w[16] =
114
 { 0x00, 0x20, 0x18, 0x08, 0x18, 0x10, 0x20, 0x10, 0x08, 0x10, 0x20, 0x20, 0x08, 0x10, 0x18, 0x04};
115 115329f1 Diego Biurrun
116 acfd8f0f Mike Melanson
/* Decodes delta frames */
117
static void qpeg_decode_inter(uint8_t *src, uint8_t *dst, int size,
118 bb270c08 Diego Biurrun
                            int stride, int width, int height,
119
                            int delta, uint8_t *ctable, uint8_t *refdata)
120 acfd8f0f Mike Melanson
{
121
    int i, j;
122
    int code;
123
    int filled = 0;
124 f63166f8 Kostya Shishkov
    int orig_height;
125 acfd8f0f Mike Melanson
    uint8_t *blkdata;
126 115329f1 Diego Biurrun
127 acfd8f0f Mike Melanson
    /* copy prev frame */
128
    for(i = 0; i < height; i++)
129 bb270c08 Diego Biurrun
        memcpy(refdata + (i * width), dst + (i * stride), width);
130 115329f1 Diego Biurrun
131 f63166f8 Kostya Shishkov
    orig_height = height;
132 acfd8f0f Mike Melanson
    blkdata = src - 0x86;
133
    height--;
134
    dst = dst + height * stride;
135
136 f63166f8 Kostya Shishkov
    while((size > 0) && (height >= 0)) {
137 bb270c08 Diego Biurrun
        code = *src++;
138
        size--;
139 115329f1 Diego Biurrun
140 bb270c08 Diego Biurrun
        if(delta) {
141
            /* motion compensation */
142
            while((code & 0xF0) == 0xF0) {
143
                if(delta == 1) {
144
                    int me_idx;
145
                    int me_w, me_h, me_x, me_y;
146
                    uint8_t *me_plane;
147
                    int corr, val;
148 115329f1 Diego Biurrun
149 bb270c08 Diego Biurrun
                    /* get block size by index */
150
                    me_idx = code & 0xF;
151
                    me_w = qpeg_table_w[me_idx];
152
                    me_h = qpeg_table_h[me_idx];
153 115329f1 Diego Biurrun
154 bb270c08 Diego Biurrun
                    /* extract motion vector */
155
                    corr = *src++;
156
                    size--;
157 acfd8f0f Mike Melanson
158 bb270c08 Diego Biurrun
                    val = corr >> 4;
159
                    if(val > 7)
160
                        val -= 16;
161
                    me_x = val;
162 115329f1 Diego Biurrun
163 bb270c08 Diego Biurrun
                    val = corr & 0xF;
164
                    if(val > 7)
165
                        val -= 16;
166
                    me_y = val;
167 115329f1 Diego Biurrun
168 f63166f8 Kostya Shishkov
                    /* check motion vector */
169
                    if ((me_x + filled < 0) || (me_x + me_w + filled > width) ||
170
                       (height - me_y - me_h < 0) || (height - me_y > orig_height) ||
171
                       (filled + me_w > width) || (height - me_h < 0))
172
                        av_log(NULL, AV_LOG_ERROR, "Bogus motion vector (%i,%i), block size %ix%i at %i,%i\n",
173
                               me_x, me_y, me_w, me_h, filled, height);
174
                    else {
175
                        /* do motion compensation */
176
                        me_plane = refdata + (filled + me_x) + (height - me_y) * width;
177
                        for(j = 0; j < me_h; j++) {
178
                            for(i = 0; i < me_w; i++)
179
                                dst[filled + i - (j * stride)] = me_plane[i - (j * width)];
180
                        }
181 bb270c08 Diego Biurrun
                    }
182
                }
183
                code = *src++;
184
                size--;
185
            }
186
        }
187 115329f1 Diego Biurrun
188 bb270c08 Diego Biurrun
        if(code == 0xE0) /* end-of-picture code */
189
            break;
190
        if(code > 0xE0) { /* run code: 0xE1..0xFF */
191
            int p;
192 acfd8f0f Mike Melanson
193 bb270c08 Diego Biurrun
            code &= 0x1F;
194
            p = *src++;
195
            size--;
196
            for(i = 0; i <= code; i++) {
197
                dst[filled++] = p;
198
                if(filled >= width) {
199
                    filled = 0;
200
                    dst -= stride;
201
                    height--;
202
                }
203
            }
204
        } else if(code >= 0xC0) { /* copy code: 0xC0..0xDF */
205
            code &= 0x1F;
206 115329f1 Diego Biurrun
207 bb270c08 Diego Biurrun
            for(i = 0; i <= code; i++) {
208
                dst[filled++] = *src++;
209
                if(filled >= width) {
210
                    filled = 0;
211
                    dst -= stride;
212
                    height--;
213
                }
214
            }
215
            size -= code + 1;
216
        } else if(code >= 0x80) { /* skip code: 0x80..0xBF */
217
            int skip;
218 115329f1 Diego Biurrun
219 bb270c08 Diego Biurrun
            code &= 0x3F;
220
            /* codes 0x80 and 0x81 are actually escape codes,
221
               skip value minus constant is in the next byte */
222
            if(!code)
223
                skip = (*src++) + 64;
224
            else if(code == 1)
225
                skip = (*src++) + 320;
226
            else
227
                skip = code;
228
            filled += skip;
229
            while( filled >= width) {
230
                filled -= width;
231
                dst -= stride;
232
                height--;
233 f63166f8 Kostya Shishkov
                if(height < 0)
234
                    break;
235 bb270c08 Diego Biurrun
            }
236
        } else {
237
            /* zero code treated as one-pixel skip */
238
            if(code)
239
                dst[filled++] = ctable[code & 0x7F];
240
            else
241
                filled++;
242
            if(filled >= width) {
243
                filled = 0;
244
                dst -= stride;
245
                height--;
246
            }
247
        }
248 acfd8f0f Mike Melanson
    }
249
}
250
251 115329f1 Diego Biurrun
static int decode_frame(AVCodecContext *avctx,
252 acfd8f0f Mike Melanson
                        void *data, int *data_size,
253
                        uint8_t *buf, int buf_size)
254
{
255
    QpegContext * const a = avctx->priv_data;
256
    AVFrame * const p= (AVFrame*)&a->pic;
257
    uint8_t* outdata;
258
    int delta;
259 115329f1 Diego Biurrun
260 acfd8f0f Mike Melanson
    if(p->data[0])
261
        avctx->release_buffer(avctx, p);
262
263
    p->reference= 0;
264
    if(avctx->get_buffer(avctx, p) < 0){
265
        av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
266
        return -1;
267
    }
268
    outdata = a->pic.data[0];
269
    if(buf[0x85] == 0x10) {
270 bb270c08 Diego Biurrun
        qpeg_decode_intra(buf+0x86, outdata, buf_size - 0x86, a->pic.linesize[0], avctx->width, avctx->height);
271 acfd8f0f Mike Melanson
    } else {
272 bb270c08 Diego Biurrun
        delta = buf[0x85];
273
        qpeg_decode_inter(buf+0x86, outdata, buf_size - 0x86, a->pic.linesize[0], avctx->width, avctx->height, delta, buf + 4, a->refdata);
274 acfd8f0f Mike Melanson
    }
275
276
    /* make the palette available on the way out */
277
    memcpy(a->pic.data[1], a->avctx->palctrl->palette, AVPALETTE_SIZE);
278
    if (a->avctx->palctrl->palette_changed) {
279
        a->pic.palette_has_changed = 1;
280
        a->avctx->palctrl->palette_changed = 0;
281
    }
282
283
    *data_size = sizeof(AVFrame);
284
    *(AVFrame*)data = a->pic;
285 115329f1 Diego Biurrun
286 acfd8f0f Mike Melanson
    return buf_size;
287
}
288
289
static int decode_init(AVCodecContext *avctx){
290
    QpegContext * const a = avctx->priv_data;
291 115329f1 Diego Biurrun
292 acfd8f0f Mike Melanson
    a->avctx = avctx;
293
    avctx->pix_fmt= PIX_FMT_PAL8;
294
    avctx->has_b_frames = 0;
295
    a->pic.data[0] = NULL;
296
    a->refdata = av_malloc(avctx->width * avctx->height);
297
298
    return 0;
299
}
300
301
static int decode_end(AVCodecContext *avctx){
302
    QpegContext * const a = avctx->priv_data;
303 5b225466 Mike Melanson
    AVFrame * const p= (AVFrame*)&a->pic;
304 115329f1 Diego Biurrun
305 5b225466 Mike Melanson
    if(p->data[0])
306
        avctx->release_buffer(avctx, p);
307 acfd8f0f Mike Melanson
308
    av_free(a->refdata);
309
    return 0;
310
}
311
312
AVCodec qpeg_decoder = {
313
    "qpeg",
314
    CODEC_TYPE_VIDEO,
315
    CODEC_ID_QPEG,
316
    sizeof(QpegContext),
317
    decode_init,
318
    NULL,
319
    decode_end,
320
    decode_frame,
321
    CODEC_CAP_DR1,
322
};