Statistics
| Branch: | Revision:

ffmpeg / libavcodec / qpeg.c @ 5b225466

History | View | Annotate | Download (7.01 KB)

1
/*
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
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 *
19
 */
20
 
21
/**
22
 * @file qpeg.c
23
 * QPEG codec.
24
 */
25
 
26
#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
                            int stride, int width, int height)
37
{
38
    int i;
39
    int code;
40
    int c0, c1;
41
    int run, copy;
42
    int filled = 0;
43
    
44
    height--;
45
    dst = dst + height * stride;
46
    
47
    while(size > 0) {
48
        code = *src++;
49
        size--;
50
        run = copy = 0;
51
        if(code == 0xFC) /* end-of-picture code */
52
            break;
53
        if(code >= 0xF8) { /* very long run */
54
            c0 = *src++;
55
            c1 = *src++;
56
            size -= 2;
57
            run = ((code & 0x7) << 16) + (c0 << 8) + c1 + 2;
58
        } else if (code >= 0xF0) { /* long run */
59
            c0 = *src++;
60
            size--;
61
            run = ((code & 0xF) << 8) + c0 + 2;
62
        } else if (code >= 0xE0) { /* short run */
63
            run = (code & 0x1F) + 2;
64
        } else if (code >= 0xC0) { /* very long copy */
65
            c0 = *src++;
66
            c1 = *src++;
67
            size -= 2;
68
            copy = ((code & 0x3F) << 16) + (c0 << 8) + c1 + 1;
69
        } else if (code >= 0x80) { /* long copy */
70
            c0 = *src++;
71
            size--;
72
            copy = ((code & 0x7F) << 8) + c0 + 1;
73
        } else { /* short copy */
74
            copy = code + 1;
75
        }
76
        
77
        /* perform actual run or copy */
78
        if(run) {
79
            int p;
80
            
81
            p = *src++;
82
            size--;
83
            for(i = 0; i < run; i++) {
84
                dst[filled++] = p;
85
                if (filled >= width) {
86
                    filled = 0;
87
                    dst -= stride;
88
                }
89
            }
90
        } else {
91
            for(i = 0; i < copy; i++) {
92
                dst[filled++] = *src++;
93
                if (filled >= width) {
94
                    filled = 0;
95
                    dst -= stride;
96
                }
97
            }
98
            size -= copy;
99
        }
100
    }
101
}
102

    
103
static int qpeg_table_h[16] = 
104
 { 0x00, 0x20, 0x20, 0x20, 0x18, 0x10, 0x10, 0x20, 0x10, 0x08, 0x18, 0x08, 0x08, 0x18, 0x10, 0x04};
105
static int qpeg_table_w[16] =
106
 { 0x00, 0x20, 0x18, 0x08, 0x18, 0x10, 0x20, 0x10, 0x08, 0x10, 0x20, 0x20, 0x08, 0x10, 0x18, 0x04};
107
 
108
/* Decodes delta frames */
109
static void qpeg_decode_inter(uint8_t *src, uint8_t *dst, int size,
110
                            int stride, int width, int height,
111
                            int delta, uint8_t *ctable, uint8_t *refdata)
112
{
113
    int i, j;
114
    int code;
115
    int filled = 0;
116
    uint8_t *blkdata;
117
    
118
    /* copy prev frame */
119
    for(i = 0; i < height; i++)
120
        memcpy(refdata + (i * width), dst + (i * stride), width);
121
    
122
    blkdata = src - 0x86;
123
    height--;
124
    dst = dst + height * stride;
125

    
126
    while(size > 0) {
127
        code = *src++;
128
        size--;
129
        
130
        if(delta) {
131
            /* motion compensation */
132
            while((code & 0xF0) == 0xF0) {
133
                if(delta == 1) {
134
                    int me_idx;
135
                    int me_w, me_h, me_x, me_y;
136
                    uint8_t *me_plane;
137
                    int corr, val;
138
                    
139
                    /* get block size by index */
140
                    me_idx = code & 0xF;
141
                    me_w = qpeg_table_w[me_idx];
142
                    me_h = qpeg_table_h[me_idx];
143
                    
144
                    /* extract motion vector */
145
                    corr = *src++;
146
                    size--;
147

    
148
                    val = corr >> 4;
149
                    if(val > 7)
150
                        val -= 16;
151
                    me_x = val;
152
                    
153
                    val = corr & 0xF;
154
                    if(val > 7)
155
                        val -= 16;
156
                    me_y = val;
157
                    
158
                    /* do motion compensation */
159
                    me_plane = refdata + (filled + me_x) + (height - me_y) * width;
160
                    for(j = 0; j < me_h; j++) {
161
                        for(i = 0; i < me_w; i++)
162
                            dst[filled + i - (j * stride)] = me_plane[i - (j * width)];
163
                    }
164
                }
165
                code = *src++;
166
                size--;
167
            }
168
        }
169
        
170
        if(code == 0xE0) /* end-of-picture code */
171
            break;
172
        if(code > 0xE0) { /* run code: 0xE1..0xFF */
173
            int p;
174

    
175
            code &= 0x1F;
176
            p = *src++;
177
            size--;
178
            for(i = 0; i <= code; i++) {
179
                dst[filled++] = p;
180
                if(filled >= width) {
181
                    filled = 0;
182
                    dst -= stride;
183
                    height--;
184
                }
185
            }
186
        } else if(code >= 0xC0) { /* copy code: 0xC0..0xDF */
187
            code &= 0x1F;
188
            
189
            for(i = 0; i <= code; i++) {
190
                dst[filled++] = *src++;
191
                if(filled >= width) {
192
                    filled = 0;
193
                    dst -= stride;
194
                    height--;
195
                }
196
            }
197
            size -= code + 1;
198
        } else if(code >= 0x80) { /* skip code: 0x80..0xBF */
199
            int skip;
200
            
201
            code &= 0x3F;
202
            /* codes 0x80 and 0x81 are actually escape codes,
203
               skip value minus constant is in the next byte */
204
            if(!code)
205
                skip = (*src++) + 64;
206
            else if(code == 1)
207
                skip = (*src++) + 320;
208
            else
209
                skip = code;
210
            filled += skip;
211
            while( filled >= width) {
212
                filled -= width;
213
                dst -= stride;
214
                height--;
215
            }
216
        } else {
217
            /* zero code treated as one-pixel skip */
218
            if(code)
219
                dst[filled++] = ctable[code & 0x7F];
220
            else
221
                filled++;
222
            if(filled >= width) {
223
                filled = 0;
224
                dst -= stride;
225
                height--;
226
            }
227
        }
228
    }
229
}
230

    
231
static int decode_frame(AVCodecContext *avctx, 
232
                        void *data, int *data_size,
233
                        uint8_t *buf, int buf_size)
234
{
235
    QpegContext * const a = avctx->priv_data;
236
    AVFrame * const p= (AVFrame*)&a->pic;
237
    uint8_t* outdata;
238
    int delta;
239
    
240
    if(p->data[0])
241
        avctx->release_buffer(avctx, p);
242

    
243
    p->reference= 0;
244
    if(avctx->get_buffer(avctx, p) < 0){
245
        av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
246
        return -1;
247
    }
248
    outdata = a->pic.data[0];
249
    if(buf[0x85] == 0x10) {
250
        qpeg_decode_intra(buf+0x86, outdata, buf_size - 0x86, a->pic.linesize[0], avctx->width, avctx->height);
251
    } else {
252
        delta = buf[0x85];
253
        qpeg_decode_inter(buf+0x86, outdata, buf_size - 0x86, a->pic.linesize[0], avctx->width, avctx->height, delta, buf + 4, a->refdata);
254
    }
255

    
256
    /* make the palette available on the way out */
257
    memcpy(a->pic.data[1], a->avctx->palctrl->palette, AVPALETTE_SIZE);
258
    if (a->avctx->palctrl->palette_changed) {
259
        a->pic.palette_has_changed = 1;
260
        a->avctx->palctrl->palette_changed = 0;
261
    }
262

    
263
    *data_size = sizeof(AVFrame);
264
    *(AVFrame*)data = a->pic;
265
    
266
    return buf_size;
267
}
268

    
269
static int decode_init(AVCodecContext *avctx){
270
    QpegContext * const a = avctx->priv_data;
271
    
272
    a->avctx = avctx;
273
    avctx->pix_fmt= PIX_FMT_PAL8;
274
    avctx->has_b_frames = 0;
275
    a->pic.data[0] = NULL;
276
    a->refdata = av_malloc(avctx->width * avctx->height);
277

    
278
    return 0;
279
}
280

    
281
static int decode_end(AVCodecContext *avctx){
282
    QpegContext * const a = avctx->priv_data;
283
    AVFrame * const p= (AVFrame*)&a->pic;
284
    
285
    if(p->data[0])
286
        avctx->release_buffer(avctx, p);
287

    
288
    av_free(a->refdata);
289
    return 0;
290
}
291

    
292
AVCodec qpeg_decoder = {
293
    "qpeg",
294
    CODEC_TYPE_VIDEO,
295
    CODEC_ID_QPEG,
296
    sizeof(QpegContext),
297
    decode_init,
298
    NULL,
299
    decode_end,
300
    decode_frame,
301
    CODEC_CAP_DR1,
302
};