comparison qpeg.c @ 2355:69fcdad5f7d5 libavcodec

native QPEG video decoder, courtesy of Konstantin Shishkov
author melanson
date Wed, 17 Nov 2004 03:45:53 +0000
parents
children f67b63ed036d
comparison
equal deleted inserted replaced
2354:643724c609ff 2355:69fcdad5f7d5
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 /* special case for last picture */
241 if (buf_size == 0) {
242 return 0;
243 }
244
245 if(p->data[0])
246 avctx->release_buffer(avctx, p);
247
248 p->reference= 0;
249 if(avctx->get_buffer(avctx, p) < 0){
250 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
251 return -1;
252 }
253 outdata = a->pic.data[0];
254 if(buf[0x85] == 0x10) {
255 qpeg_decode_intra(buf+0x86, outdata, buf_size - 0x86, a->pic.linesize[0], avctx->width, avctx->height);
256 } else {
257 delta = buf[0x85];
258 qpeg_decode_inter(buf+0x86, outdata, buf_size - 0x86, a->pic.linesize[0], avctx->width, avctx->height, delta, buf + 4, a->refdata);
259 }
260
261 /* make the palette available on the way out */
262 memcpy(a->pic.data[1], a->avctx->palctrl->palette, AVPALETTE_SIZE);
263 if (a->avctx->palctrl->palette_changed) {
264 a->pic.palette_has_changed = 1;
265 a->avctx->palctrl->palette_changed = 0;
266 }
267
268 *data_size = sizeof(AVFrame);
269 *(AVFrame*)data = a->pic;
270
271 return buf_size;
272 }
273
274 static int decode_init(AVCodecContext *avctx){
275 QpegContext * const a = avctx->priv_data;
276
277 a->avctx = avctx;
278 avctx->pix_fmt= PIX_FMT_PAL8;
279 avctx->has_b_frames = 0;
280 a->pic.data[0] = NULL;
281 a->refdata = av_malloc(avctx->width * avctx->height);
282
283 return 0;
284 }
285
286 static int decode_end(AVCodecContext *avctx){
287 QpegContext * const a = avctx->priv_data;
288
289 av_free(a->refdata);
290 return 0;
291 }
292
293 AVCodec qpeg_decoder = {
294 "qpeg",
295 CODEC_TYPE_VIDEO,
296 CODEC_ID_QPEG,
297 sizeof(QpegContext),
298 decode_init,
299 NULL,
300 decode_end,
301 decode_frame,
302 CODEC_CAP_DR1,
303 };