25c62874ea861d274d263ef5d0effa532a6e5f85
2 * Copyright (C) 2003 the ffmpeg project
4 * This file is part of FFmpeg.
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 * Id RoQ Video Decoder by Dr. Tim Ferguson
25 * For more information about the Id RoQ format, visit:
26 * http://www.csse.monash.edu.au/~timf/
35 #include "bytestream.h"
47 #define avg2(a,b) av_clip_uint8(((int)(a)+(int)(b)+1)>>1)
48 #define avg4(a,b,c,d) av_clip_uint8(((int)(a)+(int)(b)+(int)(c)+(int)(d)+2)>>2)
50 typedef struct RoqContext
{
52 AVCodecContext
*avctx
;
56 AVFrame
*current_frame
;
62 roq_qcell qcells
[256];
69 #define RoQ_INFO 0x1001
70 #define RoQ_QUAD_CODEBOOK 0x1002
71 #define RoQ_QUAD_VQ 0x1011
72 #define RoQ_SOUND_MONO 0x1020
73 #define RoQ_SOUND_STEREO 0x1021
75 #define RoQ_ID_MOT 0x00
76 #define RoQ_ID_FCC 0x01
77 #define RoQ_ID_SLD 0x02
78 #define RoQ_ID_CCC 0x03
80 #define get_byte(in_buffer) *(in_buffer++)
83 void ff_apply_vector_2x2(RoqContext
*ri
, int x
, int y
, roq_cell
*cell
)
87 yptr
= ri
->current_frame
->data
[0] + (y
* ri
->y_stride
) + x
;
90 yptr
+= (ri
->y_stride
- 2);
93 ri
->current_frame
->data
[1][(y
/2) * (ri
->c_stride
) + x
/2] = cell
->u
;
94 ri
->current_frame
->data
[2][(y
/2) * (ri
->c_stride
) + x
/2] = cell
->v
;
97 void ff_apply_vector_4x4(RoqContext
*ri
, int x
, int y
, roq_cell
*cell
)
99 unsigned long row_inc
, c_row_inc
;
100 register unsigned char y0
, y1
, u
, v
;
101 unsigned char *yptr
, *uptr
, *vptr
;
103 yptr
= ri
->current_frame
->data
[0] + (y
* ri
->y_stride
) + x
;
104 uptr
= ri
->current_frame
->data
[1] + (y
/2) * (ri
->c_stride
) + x
/2;
105 vptr
= ri
->current_frame
->data
[2] + (y
/2) * (ri
->c_stride
) + x
/2;
107 row_inc
= ri
->y_stride
- 4;
108 c_row_inc
= (ri
->c_stride
) - 2;
109 *yptr
++ = y0
= cell
->y
[0]; *uptr
++ = u
= cell
->u
; *vptr
++ = v
= cell
->v
;
111 *yptr
++ = y1
= cell
->y
[1]; *uptr
++ = u
; *vptr
++ = v
;
121 yptr
+= row_inc
; uptr
+= c_row_inc
; vptr
+= c_row_inc
;
123 *yptr
++ = y0
= cell
->y
[2]; *uptr
++ = u
; *vptr
++ = v
;
125 *yptr
++ = y1
= cell
->y
[3]; *uptr
++ = u
; *vptr
++ = v
;
136 void ff_apply_motion_4x4(RoqContext
*ri
, int x
, int y
,
137 int deltax
, int deltay
)
140 unsigned char *pa
, *pb
;
145 /* check MV against frame boundaries */
146 if ((mx
< 0) || (mx
> ri
->avctx
->width
- 4) ||
147 (my
< 0) || (my
> ri
->avctx
->height
- 4)) {
148 av_log(ri
->avctx
, AV_LOG_ERROR
, "motion vector out of bounds: MV = (%d, %d), boundaries = (0, 0, %d, %d)\n",
149 mx
, my
, ri
->avctx
->width
, ri
->avctx
->height
);
153 pa
= ri
->current_frame
->data
[0] + (y
* ri
->y_stride
) + x
;
154 pb
= ri
->last_frame
->data
[0] + (my
* ri
->y_stride
) + mx
;
155 for(i
= 0; i
< 4; i
++) {
165 pa
= ri
->current_frame
->data
[1] + (y
* ri
->y_stride
)/4 + x
/2;
166 pb
= ri
->last_frame
->data
[1] + (my
/2) * (ri
->y_stride
/2) + (mx
+ 1)/2;
168 for(i
= 0; i
< 2; i
++) {
169 switch(((my
& 0x01) << 1) | (mx
& 0x01)) {
179 pa
[0] = avg2(pb
[0], pb
[1]);
180 pa
[1] = avg2(pb
[1], pb
[2]);
181 pa
[hw
] = avg2(pb
[hw
], pb
[hw
+1]);
182 pa
[hw
+1] = avg2(pb
[hw
+1], pb
[hw
+2]);
186 pa
[0] = avg2(pb
[0], pb
[hw
]);
187 pa
[1] = avg2(pb
[1], pb
[hw
+1]);
188 pa
[hw
] = avg2(pb
[hw
], pb
[hw
*2]);
189 pa
[hw
+1] = avg2(pb
[hw
+1], pb
[(hw
*2)+1]);
193 pa
[0] = avg4(pb
[0], pb
[1], pb
[hw
], pb
[hw
+1]);
194 pa
[1] = avg4(pb
[1], pb
[2], pb
[hw
+1], pb
[hw
+2]);
195 pa
[hw
] = avg4(pb
[hw
], pb
[hw
+1], pb
[hw
*2], pb
[(hw
*2)+1]);
196 pa
[hw
+1] = avg4(pb
[hw
+1], pb
[hw
+2], pb
[(hw
*2)+1], pb
[(hw
*2)+1]);
200 pa
= ri
->current_frame
->data
[2] + (y
* ri
->y_stride
)/4 + x
/2;
201 pb
= ri
->last_frame
->data
[2] + (my
/2) * (ri
->y_stride
/2) + (mx
+ 1)/2;
205 void ff_apply_motion_8x8(RoqContext
*ri
, int x
, int y
,
206 int deltax
, int deltay
)
208 int mx
, my
, i
, j
, hw
;
209 unsigned char *pa
, *pb
;
214 /* check MV against frame boundaries */
215 if ((mx
< 0) || (mx
> ri
->avctx
->width
- 8) ||
216 (my
< 0) || (my
> ri
->avctx
->height
- 8)) {
217 av_log(ri
->avctx
, AV_LOG_ERROR
, "motion vector out of bounds: MV = (%d, %d), boundaries = (0, 0, %d, %d)\n",
218 mx
, my
, ri
->avctx
->width
, ri
->avctx
->height
);
222 pa
= ri
->current_frame
->data
[0] + (y
* ri
->y_stride
) + x
;
223 pb
= ri
->last_frame
->data
[0] + (my
* ri
->y_stride
) + mx
;
224 for(i
= 0; i
< 8; i
++) {
238 pa
= ri
->current_frame
->data
[1] + (y
* ri
->y_stride
)/4 + x
/2;
239 pb
= ri
->last_frame
->data
[1] + (my
/2) * (ri
->y_stride
/2) + (mx
+ 1)/2;
240 for(j
= 0; j
< 2; j
++) {
241 for(i
= 0; i
< 4; i
++) {
242 switch(((my
& 0x01) << 1) | (mx
& 0x01)) {
252 pa
[0] = avg2(pb
[0], pb
[1]);
253 pa
[1] = avg2(pb
[1], pb
[2]);
254 pa
[2] = avg2(pb
[2], pb
[3]);
255 pa
[3] = avg2(pb
[3], pb
[4]);
259 pa
[0] = avg2(pb
[0], pb
[hw
]);
260 pa
[1] = avg2(pb
[1], pb
[hw
+1]);
261 pa
[2] = avg2(pb
[2], pb
[hw
+2]);
262 pa
[3] = avg2(pb
[3], pb
[hw
+3]);
266 pa
[0] = avg4(pb
[0], pb
[1], pb
[hw
], pb
[hw
+1]);
267 pa
[1] = avg4(pb
[1], pb
[2], pb
[hw
+1], pb
[hw
+2]);
268 pa
[2] = avg4(pb
[2], pb
[3], pb
[hw
+2], pb
[hw
+3]);
269 pa
[3] = avg4(pb
[3], pb
[4], pb
[hw
+3], pb
[hw
+4]);
276 pa
= ri
->current_frame
->data
[2] + (y
* ri
->y_stride
)/4 + x
/2;
277 pb
= ri
->last_frame
->data
[2] + (my
/2) * (ri
->y_stride
/2) + (mx
+ 1)/2;
281 static void roqvideo_decode_frame(RoqContext
*ri
)
283 unsigned int chunk_id
= 0, chunk_arg
= 0;
284 unsigned long chunk_size
= 0;
285 int i
, j
, k
, nv1
, nv2
, vqflg
= 0, vqflg_pos
= -1;
286 int vqid
, bpos
, xpos
, ypos
, xp
, yp
, x
, y
, mx
, my
;
287 int frame_stats
[2][4] = {{0},{0}};
289 unsigned char *buf
= ri
->buf
;
290 unsigned char *buf_end
= ri
->buf
+ ri
->size
;
292 while (buf
< buf_end
) {
293 chunk_id
= bytestream_get_le16(&buf
);
294 chunk_size
= bytestream_get_le32(&buf
);
295 chunk_arg
= bytestream_get_le16(&buf
);
297 if(chunk_id
== RoQ_QUAD_VQ
)
299 if(chunk_id
== RoQ_QUAD_CODEBOOK
) {
300 if((nv1
= chunk_arg
>> 8) == 0)
302 if((nv2
= chunk_arg
& 0xff) == 0 && nv1
* 6 < chunk_size
)
304 for(i
= 0; i
< nv1
; i
++) {
305 ri
->cells
[i
].y
[0] = get_byte(buf
);
306 ri
->cells
[i
].y
[1] = get_byte(buf
);
307 ri
->cells
[i
].y
[2] = get_byte(buf
);
308 ri
->cells
[i
].y
[3] = get_byte(buf
);
309 ri
->cells
[i
].u
= get_byte(buf
);
310 ri
->cells
[i
].v
= get_byte(buf
);
312 for(i
= 0; i
< nv2
; i
++)
313 for(j
= 0; j
< 4; j
++)
314 ri
->qcells
[i
].idx
[j
] = get_byte(buf
);
318 bpos
= xpos
= ypos
= 0;
319 while(bpos
< chunk_size
) {
320 for (yp
= ypos
; yp
< ypos
+ 16; yp
+= 8)
321 for (xp
= xpos
; xp
< xpos
+ 16; xp
+= 8) {
323 vqflg
= buf
[bpos
++]; vqflg
|= (buf
[bpos
++] << 8);
326 vqid
= (vqflg
>> (vqflg_pos
* 2)) & 0x3;
327 frame_stats
[0][vqid
]++;
332 ff_apply_motion_8x8(ri
, xp
, yp
, 0, 0);
335 mx
= 8 - (buf
[bpos
] >> 4) - ((signed char) (chunk_arg
>> 8));
336 my
= 8 - (buf
[bpos
++] & 0xf) - ((signed char) chunk_arg
);
337 ff_apply_motion_8x8(ri
, xp
, yp
, mx
, my
);
340 qcell
= ri
->qcells
+ buf
[bpos
++];
341 ff_apply_vector_4x4(ri
, xp
, yp
, ri
->cells
+ qcell
->idx
[0]);
342 ff_apply_vector_4x4(ri
, xp
+4, yp
, ri
->cells
+ qcell
->idx
[1]);
343 ff_apply_vector_4x4(ri
, xp
, yp
+4, ri
->cells
+ qcell
->idx
[2]);
344 ff_apply_vector_4x4(ri
, xp
+4, yp
+4, ri
->cells
+ qcell
->idx
[3]);
347 for (k
= 0; k
< 4; k
++) {
354 vqflg
|= (buf
[bpos
++] << 8);
357 vqid
= (vqflg
>> (vqflg_pos
* 2)) & 0x3;
358 frame_stats
[1][vqid
]++;
362 ff_apply_motion_4x4(ri
, x
, y
, 0, 0);
365 mx
= 8 - (buf
[bpos
] >> 4) - ((signed char) (chunk_arg
>> 8));
366 my
= 8 - (buf
[bpos
++] & 0xf) - ((signed char) chunk_arg
);
367 ff_apply_motion_4x4(ri
, x
, y
, mx
, my
);
370 qcell
= ri
->qcells
+ buf
[bpos
++];
371 ff_apply_vector_2x2(ri
, x
, y
, ri
->cells
+ qcell
->idx
[0]);
372 ff_apply_vector_2x2(ri
, x
+2, y
, ri
->cells
+ qcell
->idx
[1]);
373 ff_apply_vector_2x2(ri
, x
, y
+2, ri
->cells
+ qcell
->idx
[2]);
374 ff_apply_vector_2x2(ri
, x
+2, y
+2, ri
->cells
+ qcell
->idx
[3]);
377 ff_apply_vector_2x2(ri
, x
, y
, ri
->cells
+ buf
[bpos
]);
378 ff_apply_vector_2x2(ri
, x
+2, y
, ri
->cells
+ buf
[bpos
+1]);
379 ff_apply_vector_2x2(ri
, x
, y
+2, ri
->cells
+ buf
[bpos
+2]);
380 ff_apply_vector_2x2(ri
, x
+2, y
+2, ri
->cells
+ buf
[bpos
+3]);
387 av_log(ri
->avctx
, AV_LOG_ERROR
, "Unknown vq code: %d\n", vqid
);
392 if (xpos
>= ri
->avctx
->width
) {
393 xpos
-= ri
->avctx
->width
;
396 if(ypos
>= ri
->avctx
->height
)
402 static int roq_decode_init(AVCodecContext
*avctx
)
404 RoqContext
*s
= avctx
->priv_data
;
408 s
->last_frame
= &s
->frames
[0];
409 s
->current_frame
= &s
->frames
[1];
410 avctx
->pix_fmt
= PIX_FMT_YUV420P
;
411 dsputil_init(&s
->dsp
, avctx
);
416 static int roq_decode_frame(AVCodecContext
*avctx
,
417 void *data
, int *data_size
,
418 uint8_t *buf
, int buf_size
)
420 RoqContext
*s
= avctx
->priv_data
;
422 if (avctx
->get_buffer(avctx
, s
->current_frame
)) {
423 av_log(avctx
, AV_LOG_ERROR
, " RoQ: get_buffer() failed\n");
426 s
->y_stride
= s
->current_frame
->linesize
[0];
427 s
->c_stride
= s
->current_frame
->linesize
[1];
431 roqvideo_decode_frame(s
);
433 /* release the last frame if it is allocated */
437 avctx
->release_buffer(avctx
, s
->last_frame
);
439 *data_size
= sizeof(AVFrame
);
440 *(AVFrame
*)data
= *s
->current_frame
;
443 FFSWAP(AVFrame
*, s
->current_frame
, s
->last_frame
);
448 static int roq_decode_end(AVCodecContext
*avctx
)
450 RoqContext
*s
= avctx
->priv_data
;
452 /* release the last frame */
453 if (s
->last_frame
->data
[0])
454 avctx
->release_buffer(avctx
, s
->last_frame
);
459 AVCodec roq_decoder
= {