ffmpeg / libavcodec / roqvideo.c @ 5509bffa
History | View | Annotate | Download (14.5 KB)
1 |
/*
|
---|---|
2 |
* Copyright (C) 2003 the ffmpeg project
|
3 |
*
|
4 |
* This library is free software; you can redistribute it and/or
|
5 |
* modify it under the terms of the GNU Lesser General Public
|
6 |
* License as published by the Free Software Foundation; either
|
7 |
* version 2 of the License, or (at your option) any later version.
|
8 |
*
|
9 |
* This library is distributed in the hope that it will be useful,
|
10 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
12 |
* Lesser General Public License for more details.
|
13 |
*
|
14 |
* You should have received a copy of the GNU Lesser General Public
|
15 |
* License along with this library; if not, write to the Free Software
|
16 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
17 |
*
|
18 |
*/
|
19 |
|
20 |
/**
|
21 |
* @file roqvideo.c
|
22 |
* Id RoQ Video Decoder by Dr. Tim Ferguson
|
23 |
* For more information about the Id RoQ format, visit:
|
24 |
* http://www.csse.monash.edu.au/~timf/
|
25 |
*/
|
26 |
|
27 |
#include <stdio.h> |
28 |
#include <stdlib.h> |
29 |
#include <string.h> |
30 |
#include <unistd.h> |
31 |
|
32 |
#include "common.h" |
33 |
#include "avcodec.h" |
34 |
#include "dsputil.h" |
35 |
|
36 |
typedef struct { |
37 |
unsigned char y0, y1, y2, y3, u, v; |
38 |
} roq_cell; |
39 |
|
40 |
typedef struct { |
41 |
int idx[4]; |
42 |
} roq_qcell; |
43 |
|
44 |
static int uiclip[1024], *uiclp; /* clipping table */ |
45 |
#define avg2(a,b) uiclp[(((int)(a)+(int)(b)+1)>>1)] |
46 |
#define avg4(a,b,c,d) uiclp[(((int)(a)+(int)(b)+(int)(c)+(int)(d)+2)>>2)] |
47 |
|
48 |
typedef struct RoqContext { |
49 |
|
50 |
AVCodecContext *avctx; |
51 |
DSPContext dsp; |
52 |
AVFrame last_frame; |
53 |
AVFrame current_frame; |
54 |
int first_frame;
|
55 |
int y_stride;
|
56 |
int c_stride;
|
57 |
|
58 |
roq_cell cells[256];
|
59 |
roq_qcell qcells[256];
|
60 |
|
61 |
unsigned char *buf; |
62 |
int size;
|
63 |
|
64 |
} RoqContext; |
65 |
|
66 |
#define RoQ_INFO 0x1001 |
67 |
#define RoQ_QUAD_CODEBOOK 0x1002 |
68 |
#define RoQ_QUAD_VQ 0x1011 |
69 |
#define RoQ_SOUND_MONO 0x1020 |
70 |
#define RoQ_SOUND_STEREO 0x1021 |
71 |
|
72 |
#define RoQ_ID_MOT 0x00 |
73 |
#define RoQ_ID_FCC 0x01 |
74 |
#define RoQ_ID_SLD 0x02 |
75 |
#define RoQ_ID_CCC 0x03 |
76 |
|
77 |
#define get_byte(in_buffer) *(in_buffer++)
|
78 |
#define get_word(in_buffer) ((unsigned short)(in_buffer += 2, \ |
79 |
(in_buffer[-1] << 8 | in_buffer[-2]))) |
80 |
#define get_long(in_buffer) ((unsigned long)(in_buffer += 4, \ |
81 |
(in_buffer[-1] << 24 | in_buffer[-2] << 16 | in_buffer[-3] << 8 | in_buffer[-4]))) |
82 |
|
83 |
|
84 |
static void apply_vector_2x2(RoqContext *ri, int x, int y, roq_cell *cell) |
85 |
{ |
86 |
unsigned char *yptr; |
87 |
|
88 |
yptr = ri->current_frame.data[0] + (y * ri->y_stride) + x;
|
89 |
*yptr++ = cell->y0; |
90 |
*yptr++ = cell->y1; |
91 |
yptr += (ri->y_stride - 2);
|
92 |
*yptr++ = cell->y2; |
93 |
*yptr++ = cell->y3; |
94 |
ri->current_frame.data[1][(y/2) * (ri->c_stride) + x/2] = cell->u; |
95 |
ri->current_frame.data[2][(y/2) * (ri->c_stride) + x/2] = cell->v; |
96 |
} |
97 |
|
98 |
static void apply_vector_4x4(RoqContext *ri, int x, int y, roq_cell *cell) |
99 |
{ |
100 |
unsigned long row_inc, c_row_inc; |
101 |
register unsigned char y0, y1, u, v; |
102 |
unsigned char *yptr, *uptr, *vptr; |
103 |
|
104 |
yptr = ri->current_frame.data[0] + (y * ri->y_stride) + x;
|
105 |
uptr = ri->current_frame.data[1] + (y/2) * (ri->c_stride) + x/2; |
106 |
vptr = ri->current_frame.data[2] + (y/2) * (ri->c_stride) + x/2; |
107 |
|
108 |
row_inc = ri->y_stride - 4;
|
109 |
c_row_inc = (ri->c_stride) - 2;
|
110 |
*yptr++ = y0 = cell->y0; *uptr++ = u = cell->u; *vptr++ = v = cell->v; |
111 |
*yptr++ = y0; |
112 |
*yptr++ = y1 = cell->y1; *uptr++ = u; *vptr++ = v; |
113 |
*yptr++ = y1; |
114 |
|
115 |
yptr += row_inc; |
116 |
|
117 |
*yptr++ = y0; |
118 |
*yptr++ = y0; |
119 |
*yptr++ = y1; |
120 |
*yptr++ = y1; |
121 |
|
122 |
yptr += row_inc; uptr += c_row_inc; vptr += c_row_inc; |
123 |
|
124 |
*yptr++ = y0 = cell->y2; *uptr++ = u; *vptr++ = v; |
125 |
*yptr++ = y0; |
126 |
*yptr++ = y1 = cell->y3; *uptr++ = u; *vptr++ = v; |
127 |
*yptr++ = y1; |
128 |
|
129 |
yptr += row_inc; |
130 |
|
131 |
*yptr++ = y0; |
132 |
*yptr++ = y0; |
133 |
*yptr++ = y1; |
134 |
*yptr++ = y1; |
135 |
} |
136 |
|
137 |
static void apply_motion_4x4(RoqContext *ri, int x, int y, unsigned char mv, |
138 |
signed char mean_x, signed char mean_y) |
139 |
{ |
140 |
int i, hw, mx, my;
|
141 |
unsigned char *pa, *pb; |
142 |
|
143 |
mx = x + 8 - (mv >> 4) - mean_x; |
144 |
my = y + 8 - (mv & 0xf) - mean_y; |
145 |
|
146 |
/* check MV against frame boundaries */
|
147 |
if ((mx < 0) || (mx > ri->avctx->width - 4) || |
148 |
(my < 0) || (my > ri->avctx->height - 4)) { |
149 |
av_log(ri->avctx, AV_LOG_ERROR, "motion vector out of bounds: MV = (%d, %d), boundaries = (0, 0, %d, %d)\n",
|
150 |
mx, my, ri->avctx->width, ri->avctx->height); |
151 |
return;
|
152 |
} |
153 |
|
154 |
pa = ri->current_frame.data[0] + (y * ri->y_stride) + x;
|
155 |
pb = ri->last_frame.data[0] + (my * ri->y_stride) + mx;
|
156 |
for(i = 0; i < 4; i++) { |
157 |
pa[0] = pb[0]; |
158 |
pa[1] = pb[1]; |
159 |
pa[2] = pb[2]; |
160 |
pa[3] = pb[3]; |
161 |
pa += ri->y_stride; |
162 |
pb += ri->y_stride; |
163 |
} |
164 |
|
165 |
hw = ri->y_stride/2;
|
166 |
pa = ri->current_frame.data[1] + (y * ri->y_stride)/4 + x/2; |
167 |
pb = ri->last_frame.data[1] + (my/2) * (ri->y_stride/2) + (mx + 1)/2; |
168 |
|
169 |
for(i = 0; i < 2; i++) { |
170 |
switch(((my & 0x01) << 1) | (mx & 0x01)) { |
171 |
|
172 |
case 0: |
173 |
pa[0] = pb[0]; |
174 |
pa[1] = pb[1]; |
175 |
pa[hw] = pb[hw]; |
176 |
pa[hw+1] = pb[hw+1]; |
177 |
break;
|
178 |
|
179 |
case 1: |
180 |
pa[0] = avg2(pb[0], pb[1]); |
181 |
pa[1] = avg2(pb[1], pb[2]); |
182 |
pa[hw] = avg2(pb[hw], pb[hw+1]);
|
183 |
pa[hw+1] = avg2(pb[hw+1], pb[hw+2]); |
184 |
break;
|
185 |
|
186 |
case 2: |
187 |
pa[0] = avg2(pb[0], pb[hw]); |
188 |
pa[1] = avg2(pb[1], pb[hw+1]); |
189 |
pa[hw] = avg2(pb[hw], pb[hw*2]);
|
190 |
pa[hw+1] = avg2(pb[hw+1], pb[(hw*2)+1]); |
191 |
break;
|
192 |
|
193 |
case 3: |
194 |
pa[0] = avg4(pb[0], pb[1], pb[hw], pb[hw+1]); |
195 |
pa[1] = avg4(pb[1], pb[2], pb[hw+1], pb[hw+2]); |
196 |
pa[hw] = avg4(pb[hw], pb[hw+1], pb[hw*2], pb[(hw*2)+1]); |
197 |
pa[hw+1] = avg4(pb[hw+1], pb[hw+2], pb[(hw*2)+1], pb[(hw*2)+1]); |
198 |
break;
|
199 |
} |
200 |
|
201 |
pa = ri->current_frame.data[2] + (y * ri->y_stride)/4 + x/2; |
202 |
pb = ri->last_frame.data[2] + (my/2) * (ri->y_stride/2) + (mx + 1)/2; |
203 |
} |
204 |
} |
205 |
|
206 |
static void apply_motion_8x8(RoqContext *ri, int x, int y, |
207 |
unsigned char mv, signed char mean_x, signed char mean_y) |
208 |
{ |
209 |
int mx, my, i, j, hw;
|
210 |
unsigned char *pa, *pb; |
211 |
|
212 |
mx = x + 8 - (mv >> 4) - mean_x; |
213 |
my = y + 8 - (mv & 0xf) - mean_y; |
214 |
|
215 |
/* check MV against frame boundaries */
|
216 |
if ((mx < 0) || (mx > ri->avctx->width - 8) || |
217 |
(my < 0) || (my > ri->avctx->height - 8)) { |
218 |
av_log(ri->avctx, AV_LOG_ERROR, "motion vector out of bounds: MV = (%d, %d), boundaries = (0, 0, %d, %d)\n",
|
219 |
mx, my, ri->avctx->width, ri->avctx->height); |
220 |
return;
|
221 |
} |
222 |
|
223 |
pa = ri->current_frame.data[0] + (y * ri->y_stride) + x;
|
224 |
pb = ri->last_frame.data[0] + (my * ri->y_stride) + mx;
|
225 |
for(i = 0; i < 8; i++) { |
226 |
pa[0] = pb[0]; |
227 |
pa[1] = pb[1]; |
228 |
pa[2] = pb[2]; |
229 |
pa[3] = pb[3]; |
230 |
pa[4] = pb[4]; |
231 |
pa[5] = pb[5]; |
232 |
pa[6] = pb[6]; |
233 |
pa[7] = pb[7]; |
234 |
pa += ri->y_stride; |
235 |
pb += ri->y_stride; |
236 |
} |
237 |
|
238 |
hw = ri->c_stride; |
239 |
pa = ri->current_frame.data[1] + (y * ri->y_stride)/4 + x/2; |
240 |
pb = ri->last_frame.data[1] + (my/2) * (ri->y_stride/2) + (mx + 1)/2; |
241 |
for(j = 0; j < 2; j++) { |
242 |
for(i = 0; i < 4; i++) { |
243 |
switch(((my & 0x01) << 1) | (mx & 0x01)) { |
244 |
|
245 |
case 0: |
246 |
pa[0] = pb[0]; |
247 |
pa[1] = pb[1]; |
248 |
pa[2] = pb[2]; |
249 |
pa[3] = pb[3]; |
250 |
break;
|
251 |
|
252 |
case 1: |
253 |
pa[0] = avg2(pb[0], pb[1]); |
254 |
pa[1] = avg2(pb[1], pb[2]); |
255 |
pa[2] = avg2(pb[2], pb[3]); |
256 |
pa[3] = avg2(pb[3], pb[4]); |
257 |
break;
|
258 |
|
259 |
case 2: |
260 |
pa[0] = avg2(pb[0], pb[hw]); |
261 |
pa[1] = avg2(pb[1], pb[hw+1]); |
262 |
pa[2] = avg2(pb[2], pb[hw+2]); |
263 |
pa[3] = avg2(pb[3], pb[hw+3]); |
264 |
break;
|
265 |
|
266 |
case 3: |
267 |
pa[0] = avg4(pb[0], pb[1], pb[hw], pb[hw+1]); |
268 |
pa[1] = avg4(pb[1], pb[2], pb[hw+1], pb[hw+2]); |
269 |
pa[2] = avg4(pb[2], pb[3], pb[hw+2], pb[hw+3]); |
270 |
pa[3] = avg4(pb[3], pb[4], pb[hw+3], pb[hw+4]); |
271 |
break;
|
272 |
} |
273 |
pa += ri->c_stride; |
274 |
pb += ri->c_stride; |
275 |
} |
276 |
|
277 |
pa = ri->current_frame.data[2] + (y * ri->y_stride)/4 + x/2; |
278 |
pb = ri->last_frame.data[2] + (my/2) * (ri->y_stride/2) + (mx + 1)/2; |
279 |
} |
280 |
} |
281 |
|
282 |
static void roqvideo_decode_frame(RoqContext *ri) |
283 |
{ |
284 |
unsigned int chunk_id = 0, chunk_arg = 0; |
285 |
unsigned long chunk_size = 0; |
286 |
int i, j, k, nv1, nv2, vqflg = 0, vqflg_pos = -1; |
287 |
int vqid, bpos, xpos, ypos, xp, yp, x, y;
|
288 |
int frame_stats[2][4] = {{0},{0}}; |
289 |
roq_qcell *qcell; |
290 |
unsigned char *buf = ri->buf; |
291 |
unsigned char *buf_end = ri->buf + ri->size; |
292 |
|
293 |
while (buf < buf_end) {
|
294 |
chunk_id = get_word(buf); |
295 |
chunk_size = get_long(buf); |
296 |
chunk_arg = get_word(buf); |
297 |
|
298 |
if(chunk_id == RoQ_QUAD_VQ)
|
299 |
break;
|
300 |
if(chunk_id == RoQ_QUAD_CODEBOOK) {
|
301 |
if((nv1 = chunk_arg >> 8) == 0) |
302 |
nv1 = 256;
|
303 |
if((nv2 = chunk_arg & 0xff) == 0 && nv1 * 6 < chunk_size) |
304 |
nv2 = 256;
|
305 |
for(i = 0; i < nv1; i++) { |
306 |
ri->cells[i].y0 = get_byte(buf); |
307 |
ri->cells[i].y1 = get_byte(buf); |
308 |
ri->cells[i].y2 = get_byte(buf); |
309 |
ri->cells[i].y3 = get_byte(buf); |
310 |
ri->cells[i].u = get_byte(buf); |
311 |
ri->cells[i].v = get_byte(buf); |
312 |
} |
313 |
for(i = 0; i < nv2; i++) |
314 |
for(j = 0; j < 4; j++) |
315 |
ri->qcells[i].idx[j] = get_byte(buf); |
316 |
} |
317 |
} |
318 |
|
319 |
bpos = xpos = ypos = 0;
|
320 |
while(bpos < chunk_size) {
|
321 |
for (yp = ypos; yp < ypos + 16; yp += 8) |
322 |
for (xp = xpos; xp < xpos + 16; xp += 8) { |
323 |
if (vqflg_pos < 0) { |
324 |
vqflg = buf[bpos++]; vqflg |= (buf[bpos++] << 8);
|
325 |
vqflg_pos = 7;
|
326 |
} |
327 |
vqid = (vqflg >> (vqflg_pos * 2)) & 0x3; |
328 |
frame_stats[0][vqid]++;
|
329 |
vqflg_pos--; |
330 |
|
331 |
switch(vqid) {
|
332 |
case RoQ_ID_MOT:
|
333 |
apply_motion_8x8(ri, xp, yp, 0, 8, 8); |
334 |
break;
|
335 |
case RoQ_ID_FCC:
|
336 |
apply_motion_8x8(ri, xp, yp, buf[bpos++], chunk_arg >> 8,
|
337 |
chunk_arg & 0xff);
|
338 |
break;
|
339 |
case RoQ_ID_SLD:
|
340 |
qcell = ri->qcells + buf[bpos++]; |
341 |
apply_vector_4x4(ri, xp, yp, ri->cells + qcell->idx[0]);
|
342 |
apply_vector_4x4(ri, xp+4, yp, ri->cells + qcell->idx[1]); |
343 |
apply_vector_4x4(ri, xp, yp+4, ri->cells + qcell->idx[2]); |
344 |
apply_vector_4x4(ri, xp+4, yp+4, ri->cells + qcell->idx[3]); |
345 |
break;
|
346 |
case RoQ_ID_CCC:
|
347 |
for (k = 0; k < 4; k++) { |
348 |
x = xp; y = yp; |
349 |
if(k & 0x01) x += 4; |
350 |
if(k & 0x02) y += 4; |
351 |
|
352 |
if (vqflg_pos < 0) { |
353 |
vqflg = buf[bpos++]; |
354 |
vqflg |= (buf[bpos++] << 8);
|
355 |
vqflg_pos = 7;
|
356 |
} |
357 |
vqid = (vqflg >> (vqflg_pos * 2)) & 0x3; |
358 |
frame_stats[1][vqid]++;
|
359 |
vqflg_pos--; |
360 |
switch(vqid) {
|
361 |
case RoQ_ID_MOT:
|
362 |
apply_motion_4x4(ri, x, y, 0, 8, 8); |
363 |
break;
|
364 |
case RoQ_ID_FCC:
|
365 |
apply_motion_4x4(ri, x, y, buf[bpos++], |
366 |
chunk_arg >> 8, chunk_arg & 0xff); |
367 |
break;
|
368 |
case RoQ_ID_SLD:
|
369 |
qcell = ri->qcells + buf[bpos++]; |
370 |
apply_vector_2x2(ri, x, y, ri->cells + qcell->idx[0]);
|
371 |
apply_vector_2x2(ri, x+2, y, ri->cells + qcell->idx[1]); |
372 |
apply_vector_2x2(ri, x, y+2, ri->cells + qcell->idx[2]); |
373 |
apply_vector_2x2(ri, x+2, y+2, ri->cells + qcell->idx[3]); |
374 |
break;
|
375 |
case RoQ_ID_CCC:
|
376 |
apply_vector_2x2(ri, x, y, ri->cells + buf[bpos]); |
377 |
apply_vector_2x2(ri, x+2, y, ri->cells + buf[bpos+1]); |
378 |
apply_vector_2x2(ri, x, y+2, ri->cells + buf[bpos+2]); |
379 |
apply_vector_2x2(ri, x+2, y+2, ri->cells + buf[bpos+3]); |
380 |
bpos += 4;
|
381 |
break;
|
382 |
} |
383 |
} |
384 |
break;
|
385 |
default:
|
386 |
av_log(ri->avctx, AV_LOG_ERROR, "Unknown vq code: %d\n", vqid);
|
387 |
} |
388 |
} |
389 |
|
390 |
xpos += 16;
|
391 |
if (xpos >= ri->avctx->width) {
|
392 |
xpos -= ri->avctx->width; |
393 |
ypos += 16;
|
394 |
} |
395 |
if(ypos >= ri->avctx->height)
|
396 |
break;
|
397 |
} |
398 |
} |
399 |
|
400 |
|
401 |
static int roq_decode_init(AVCodecContext *avctx) |
402 |
{ |
403 |
RoqContext *s = avctx->priv_data; |
404 |
int i;
|
405 |
|
406 |
s->avctx = avctx; |
407 |
s->first_frame = 1;
|
408 |
avctx->pix_fmt = PIX_FMT_YUV420P; |
409 |
avctx->has_b_frames = 0;
|
410 |
dsputil_init(&s->dsp, avctx); |
411 |
|
412 |
uiclp = uiclip+512;
|
413 |
for(i = -512; i < 512; i++) |
414 |
uiclp[i] = (i < 0 ? 0 : (i > 255 ? 255 : i)); |
415 |
|
416 |
return 0; |
417 |
} |
418 |
|
419 |
static int roq_decode_frame(AVCodecContext *avctx, |
420 |
void *data, int *data_size, |
421 |
uint8_t *buf, int buf_size)
|
422 |
{ |
423 |
RoqContext *s = avctx->priv_data; |
424 |
|
425 |
if (avctx->get_buffer(avctx, &s->current_frame)) {
|
426 |
av_log(avctx, AV_LOG_ERROR, " RoQ: get_buffer() failed\n");
|
427 |
return -1; |
428 |
} |
429 |
s->y_stride = s->current_frame.linesize[0];
|
430 |
s->c_stride = s->current_frame.linesize[1];
|
431 |
|
432 |
s->buf = buf; |
433 |
s->size = buf_size; |
434 |
roqvideo_decode_frame(s); |
435 |
|
436 |
/* release the last frame if it is allocated */
|
437 |
if (s->first_frame)
|
438 |
s->first_frame = 0;
|
439 |
else
|
440 |
avctx->release_buffer(avctx, &s->last_frame); |
441 |
|
442 |
/* shuffle frames */
|
443 |
s->last_frame = s->current_frame; |
444 |
|
445 |
*data_size = sizeof(AVFrame);
|
446 |
*(AVFrame*)data = s->current_frame; |
447 |
|
448 |
return buf_size;
|
449 |
} |
450 |
|
451 |
static int roq_decode_end(AVCodecContext *avctx) |
452 |
{ |
453 |
RoqContext *s = avctx->priv_data; |
454 |
|
455 |
/* release the last frame */
|
456 |
if (s->last_frame.data[0]) |
457 |
avctx->release_buffer(avctx, &s->last_frame); |
458 |
|
459 |
return 0; |
460 |
} |
461 |
|
462 |
AVCodec roq_decoder = { |
463 |
"roqvideo",
|
464 |
CODEC_TYPE_VIDEO, |
465 |
CODEC_ID_ROQ, |
466 |
sizeof(RoqContext),
|
467 |
roq_decode_init, |
468 |
NULL,
|
469 |
roq_decode_end, |
470 |
roq_decode_frame, |
471 |
CODEC_CAP_DR1, |
472 |
}; |