|
808
|
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 };
|