ffmpeg / libavcodec / qpeg.c @ 5509bffa
History | View | Annotate | Download (9.36 KB)
1 | acfd8f0f | Mike Melanson | /*
|
---|---|---|---|
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 | 5509bffa | Diego Biurrun | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
18 | acfd8f0f | Mike Melanson | *
|
19 | */
|
||
20 | 115329f1 | Diego Biurrun | |
21 | acfd8f0f | Mike Melanson | /**
|
22 | * @file qpeg.c
|
||
23 | * QPEG codec.
|
||
24 | */
|
||
25 | 115329f1 | Diego Biurrun | |
26 | acfd8f0f | Mike Melanson | #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 | bb270c08 | Diego Biurrun | int stride, int width, int height) |
37 | acfd8f0f | Mike Melanson | { |
38 | int i;
|
||
39 | int code;
|
||
40 | int c0, c1;
|
||
41 | int run, copy;
|
||
42 | int filled = 0; |
||
43 | f63166f8 | Kostya Shishkov | int rows_to_go;
|
44 | 115329f1 | Diego Biurrun | |
45 | f63166f8 | Kostya Shishkov | rows_to_go = height; |
46 | acfd8f0f | Mike Melanson | height--; |
47 | dst = dst + height * stride; |
||
48 | 115329f1 | Diego Biurrun | |
49 | f63166f8 | Kostya Shishkov | while((size > 0) && (rows_to_go > 0)) { |
50 | bb270c08 | Diego Biurrun | 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 | 115329f1 | Diego Biurrun | |
79 | bb270c08 | Diego Biurrun | /* perform actual run or copy */
|
80 | if(run) {
|
||
81 | int p;
|
||
82 | 115329f1 | Diego Biurrun | |
83 | bb270c08 | Diego Biurrun | 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 | f63166f8 | Kostya Shishkov | rows_to_go--; |
91 | if(rows_to_go <= 0) |
||
92 | break;
|
||
93 | bb270c08 | Diego Biurrun | } |
94 | } |
||
95 | } else {
|
||
96 | f63166f8 | Kostya Shishkov | size -= copy; |
97 | bb270c08 | Diego Biurrun | for(i = 0; i < copy; i++) { |
98 | dst[filled++] = *src++; |
||
99 | if (filled >= width) {
|
||
100 | filled = 0;
|
||
101 | dst -= stride; |
||
102 | f63166f8 | Kostya Shishkov | rows_to_go--; |
103 | if(rows_to_go <= 0) |
||
104 | break;
|
||
105 | bb270c08 | Diego Biurrun | } |
106 | } |
||
107 | } |
||
108 | acfd8f0f | Mike Melanson | } |
109 | } |
||
110 | |||
111 | 115329f1 | Diego Biurrun | static int qpeg_table_h[16] = |
112 | acfd8f0f | Mike Melanson | { 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 | 115329f1 | Diego Biurrun | |
116 | acfd8f0f | Mike Melanson | /* Decodes delta frames */
|
117 | static void qpeg_decode_inter(uint8_t *src, uint8_t *dst, int size, |
||
118 | bb270c08 | Diego Biurrun | int stride, int width, int height, |
119 | int delta, uint8_t *ctable, uint8_t *refdata)
|
||
120 | acfd8f0f | Mike Melanson | { |
121 | int i, j;
|
||
122 | int code;
|
||
123 | int filled = 0; |
||
124 | f63166f8 | Kostya Shishkov | int orig_height;
|
125 | acfd8f0f | Mike Melanson | uint8_t *blkdata; |
126 | 115329f1 | Diego Biurrun | |
127 | acfd8f0f | Mike Melanson | /* copy prev frame */
|
128 | for(i = 0; i < height; i++) |
||
129 | bb270c08 | Diego Biurrun | memcpy(refdata + (i * width), dst + (i * stride), width); |
130 | 115329f1 | Diego Biurrun | |
131 | f63166f8 | Kostya Shishkov | orig_height = height; |
132 | acfd8f0f | Mike Melanson | blkdata = src - 0x86;
|
133 | height--; |
||
134 | dst = dst + height * stride; |
||
135 | |||
136 | f63166f8 | Kostya Shishkov | while((size > 0) && (height >= 0)) { |
137 | bb270c08 | Diego Biurrun | code = *src++; |
138 | size--; |
||
139 | 115329f1 | Diego Biurrun | |
140 | bb270c08 | Diego Biurrun | 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 | 115329f1 | Diego Biurrun | |
149 | bb270c08 | Diego Biurrun | /* 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 | 115329f1 | Diego Biurrun | |
154 | bb270c08 | Diego Biurrun | /* extract motion vector */
|
155 | corr = *src++; |
||
156 | size--; |
||
157 | acfd8f0f | Mike Melanson | |
158 | bb270c08 | Diego Biurrun | val = corr >> 4;
|
159 | if(val > 7) |
||
160 | val -= 16;
|
||
161 | me_x = val; |
||
162 | 115329f1 | Diego Biurrun | |
163 | bb270c08 | Diego Biurrun | val = corr & 0xF;
|
164 | if(val > 7) |
||
165 | val -= 16;
|
||
166 | me_y = val; |
||
167 | 115329f1 | Diego Biurrun | |
168 | f63166f8 | Kostya Shishkov | /* 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 | bb270c08 | Diego Biurrun | } |
182 | } |
||
183 | code = *src++; |
||
184 | size--; |
||
185 | } |
||
186 | } |
||
187 | 115329f1 | Diego Biurrun | |
188 | bb270c08 | Diego Biurrun | if(code == 0xE0) /* end-of-picture code */ |
189 | break;
|
||
190 | if(code > 0xE0) { /* run code: 0xE1..0xFF */ |
||
191 | int p;
|
||
192 | acfd8f0f | Mike Melanson | |
193 | bb270c08 | Diego Biurrun | 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 | 115329f1 | Diego Biurrun | |
207 | bb270c08 | Diego Biurrun | 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 | 115329f1 | Diego Biurrun | |
219 | bb270c08 | Diego Biurrun | 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 | f63166f8 | Kostya Shishkov | if(height < 0) |
234 | break;
|
||
235 | bb270c08 | Diego Biurrun | } |
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 | acfd8f0f | Mike Melanson | } |
249 | } |
||
250 | |||
251 | 115329f1 | Diego Biurrun | static int decode_frame(AVCodecContext *avctx, |
252 | acfd8f0f | Mike Melanson | 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 | 115329f1 | Diego Biurrun | |
260 | acfd8f0f | Mike Melanson | 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 | bb270c08 | Diego Biurrun | qpeg_decode_intra(buf+0x86, outdata, buf_size - 0x86, a->pic.linesize[0], avctx->width, avctx->height); |
271 | acfd8f0f | Mike Melanson | } else {
|
272 | bb270c08 | Diego Biurrun | 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 | acfd8f0f | Mike Melanson | } |
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 | 115329f1 | Diego Biurrun | |
286 | acfd8f0f | Mike Melanson | return buf_size;
|
287 | } |
||
288 | |||
289 | static int decode_init(AVCodecContext *avctx){ |
||
290 | QpegContext * const a = avctx->priv_data;
|
||
291 | 115329f1 | Diego Biurrun | |
292 | acfd8f0f | Mike Melanson | 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 | 5b225466 | Mike Melanson | AVFrame * const p= (AVFrame*)&a->pic;
|
304 | 115329f1 | Diego Biurrun | |
305 | 5b225466 | Mike Melanson | if(p->data[0]) |
306 | avctx->release_buffer(avctx, p); |
||
307 | acfd8f0f | Mike Melanson | |
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 | }; |