VirtualBox

source: vbox/trunk/src/libs/ffmpeg-20060710/libavcodec/qpeg.c@ 11551

Last change on this file since 11551 was 5776, checked in by vboxsync, 17 years ago

ffmpeg: exported to OSE

File size: 9.4 KB
Line 
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 */
20
21/**
22 * @file qpeg.c
23 * QPEG codec.
24 */
25
26#include "avcodec.h"
27#include "mpegvideo.h"
28
29typedef struct QpegContext{
30 AVCodecContext *avctx;
31 AVFrame pic;
32 uint8_t *refdata;
33} QpegContext;
34
35static 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 int rows_to_go;
44
45 rows_to_go = height;
46 height--;
47 dst = dst + height * stride;
48
49 while((size > 0) && (rows_to_go > 0)) {
50 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
79 /* perform actual run or copy */
80 if(run) {
81 int p;
82
83 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 rows_to_go--;
91 if(rows_to_go <= 0)
92 break;
93 }
94 }
95 } else {
96 size -= copy;
97 for(i = 0; i < copy; i++) {
98 dst[filled++] = *src++;
99 if (filled >= width) {
100 filled = 0;
101 dst -= stride;
102 rows_to_go--;
103 if(rows_to_go <= 0)
104 break;
105 }
106 }
107 }
108 }
109}
110
111static int qpeg_table_h[16] =
112 { 0x00, 0x20, 0x20, 0x20, 0x18, 0x10, 0x10, 0x20, 0x10, 0x08, 0x18, 0x08, 0x08, 0x18, 0x10, 0x04};
113static int qpeg_table_w[16] =
114 { 0x00, 0x20, 0x18, 0x08, 0x18, 0x10, 0x20, 0x10, 0x08, 0x10, 0x20, 0x20, 0x08, 0x10, 0x18, 0x04};
115
116/* Decodes delta frames */
117static void qpeg_decode_inter(uint8_t *src, uint8_t *dst, int size,
118 int stride, int width, int height,
119 int delta, uint8_t *ctable, uint8_t *refdata)
120{
121 int i, j;
122 int code;
123 int filled = 0;
124 int orig_height;
125 uint8_t *blkdata;
126
127 /* copy prev frame */
128 for(i = 0; i < height; i++)
129 memcpy(refdata + (i * width), dst + (i * stride), width);
130
131 orig_height = height;
132 blkdata = src - 0x86;
133 height--;
134 dst = dst + height * stride;
135
136 while((size > 0) && (height >= 0)) {
137 code = *src++;
138 size--;
139
140 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
149 /* 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
154 /* extract motion vector */
155 corr = *src++;
156 size--;
157
158 val = corr >> 4;
159 if(val > 7)
160 val -= 16;
161 me_x = val;
162
163 val = corr & 0xF;
164 if(val > 7)
165 val -= 16;
166 me_y = val;
167
168 /* 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 }
182 }
183 code = *src++;
184 size--;
185 }
186 }
187
188 if(code == 0xE0) /* end-of-picture code */
189 break;
190 if(code > 0xE0) { /* run code: 0xE1..0xFF */
191 int p;
192
193 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
207 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
219 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 if(height < 0)
234 break;
235 }
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 }
249}
250
251static int decode_frame(AVCodecContext *avctx,
252 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
260 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 qpeg_decode_intra(buf+0x86, outdata, buf_size - 0x86, a->pic.linesize[0], avctx->width, avctx->height);
271 } else {
272 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 }
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
286 return buf_size;
287}
288
289static int decode_init(AVCodecContext *avctx){
290 QpegContext * const a = avctx->priv_data;
291
292 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
301static int decode_end(AVCodecContext *avctx){
302 QpegContext * const a = avctx->priv_data;
303 AVFrame * const p= (AVFrame*)&a->pic;
304
305 if(p->data[0])
306 avctx->release_buffer(avctx, p);
307
308 av_free(a->refdata);
309 return 0;
310}
311
312AVCodec 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};
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette