comparison src/ffmpeg/libavcodec/qpeg.c @ 808:e8776388b02a trunk

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