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 |
|
---|
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 | 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 |
|
---|
111 | static int qpeg_table_h[16] =
|
---|
112 | { 0x00, 0x20, 0x20, 0x20, 0x18, 0x10, 0x10, 0x20, 0x10, 0x08, 0x18, 0x08, 0x08, 0x18, 0x10, 0x04};
|
---|
113 | static 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 */
|
---|
117 | static 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 |
|
---|
251 | static 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 |
|
---|
289 | static 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 |
|
---|
301 | static 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 |
|
---|
312 | AVCodec 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 | };
|
---|