ffmpeg / libavcodec / qpeg.c @ 94d85eaf
History | View | Annotate | Download (9.36 KB)
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 |
}; |