initial commit for Id RoQ and Interplay MVE multimedia subsystems
[libav.git] / libavcodec / roqvideo.c
CommitLineData
3ef8be2b
MM
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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
36typedef struct {
37 unsigned char y0, y1, y2, y3, u, v;
38} roq_cell;
39
40typedef struct {
41 int idx[4];
42} roq_qcell;
43
44
45typedef struct RoqContext {
46
47 AVCodecContext *avctx;
48 DSPContext dsp;
49 AVFrame last_frame;
50 AVFrame current_frame;
51 int first_frame;
52 int y_stride;
53 int c_stride;
54
55 roq_cell cells[256];
56 roq_qcell qcells[256];
57
58 unsigned char *buf;
59 int size;
60
61} RoqContext;
62
63#define RoQ_INFO 0x1001
64#define RoQ_QUAD_CODEBOOK 0x1002
65#define RoQ_QUAD_VQ 0x1011
66#define RoQ_SOUND_MONO 0x1020
67#define RoQ_SOUND_STEREO 0x1021
68
69#define RoQ_ID_MOT 0x00
70#define RoQ_ID_FCC 0x01
71#define RoQ_ID_SLD 0x02
72#define RoQ_ID_CCC 0x03
73
74#define get_byte(in_buffer) *(in_buffer++)
75#define get_word(in_buffer) ((unsigned short)(in_buffer += 2, \
76 (in_buffer[-1] << 8 | in_buffer[-2])))
77#define get_long(in_buffer) ((unsigned long)(in_buffer += 4, \
78 (in_buffer[-1] << 24 | in_buffer[-2] << 16 | in_buffer[-3] << 8 | in_buffer[-4])))
79
80
81static void apply_vector_2x2(RoqContext *ri, int x, int y, roq_cell *cell)
82{
83 unsigned char *yptr;
84
85 yptr = ri->current_frame.data[0] + (y * ri->y_stride) + x;
86 *yptr++ = cell->y0;
87 *yptr++ = cell->y1;
88 yptr += (ri->y_stride - 2);
89 *yptr++ = cell->y2;
90 *yptr++ = cell->y3;
91 ri->current_frame.data[1][(y/2) * (ri->c_stride) + x/2] = cell->u;
92 ri->current_frame.data[2][(y/2) * (ri->c_stride) + x/2] = cell->v;
93}
94
95static void apply_vector_4x4(RoqContext *ri, int x, int y, roq_cell *cell)
96{
97 unsigned long row_inc, c_row_inc;
98 register unsigned char y0, y1, u, v;
99 unsigned char *yptr, *uptr, *vptr;
100
101 yptr = ri->current_frame.data[0] + (y * ri->y_stride) + x;
102 uptr = ri->current_frame.data[1] + (y/2) * (ri->c_stride) + x/2;
103 vptr = ri->current_frame.data[2] + (y/2) * (ri->c_stride) + x/2;
104
105 row_inc = ri->y_stride - 4;
106 c_row_inc = (ri->c_stride) - 2;
107 *yptr++ = y0 = cell->y0; *uptr++ = u = cell->u; *vptr++ = v = cell->v;
108 *yptr++ = y0;
109 *yptr++ = y1 = cell->y1; *uptr++ = u; *vptr++ = v;
110 *yptr++ = y1;
111
112 yptr += row_inc;
113
114 *yptr++ = y0;
115 *yptr++ = y0;
116 *yptr++ = y1;
117 *yptr++ = y1;
118
119 yptr += row_inc; uptr += c_row_inc; vptr += c_row_inc;
120
121 *yptr++ = y0 = cell->y2; *uptr++ = u; *vptr++ = v;
122 *yptr++ = y0;
123 *yptr++ = y1 = cell->y3; *uptr++ = u; *vptr++ = v;
124 *yptr++ = y1;
125
126 yptr += row_inc;
127
128 *yptr++ = y0;
129 *yptr++ = y0;
130 *yptr++ = y1;
131 *yptr++ = y1;
132}
133
134static void apply_motion_4x4(RoqContext *ri, int x, int y, unsigned char mv,
135 char mean_x, char mean_y)
136{
137 int i, mx, my;
138 unsigned char *pa, *pb;
139
140 mx = x + 8 - (mv >> 4) - mean_x;
141 my = y + 8 - (mv & 0xf) - mean_y;
142
143 pa = ri->current_frame.data[0] + (y * ri->y_stride) + x;
144 pb = ri->last_frame.data[0] + (my * ri->y_stride) + mx;
145 for(i = 0; i < 4; i++) {
146 pa[0] = pb[0];
147 pa[1] = pb[1];
148 pa[2] = pb[2];
149 pa[3] = pb[3];
150 pa += ri->y_stride;
151 pb += ri->y_stride;
152 }
153
154 pa = ri->current_frame.data[1] + (y/2) * (ri->c_stride) + x/2;
155 pb = ri->last_frame.data[1] + (my/2) * (ri->c_stride) + (mx + 1)/2;
156 for(i = 0; i < 2; i++) {
157 pa[0] = pb[0];
158 pa[1] = pb[1];
159 pa += ri->c_stride;
160 pb += ri->c_stride;
161 }
162
163 pa = ri->current_frame.data[2] + (y/2) * (ri->c_stride) + x/2;
164 pb = ri->last_frame.data[2] + (my/2) * (ri->c_stride) + (mx + 1)/2;
165 for(i = 0; i < 2; i++) {
166 pa[0] = pb[0];
167 pa[1] = pb[1];
168 pa += ri->c_stride;
169 pb += ri->c_stride;
170 }
171}
172
173static void apply_motion_8x8(RoqContext *ri, int x, int y,
174 unsigned char mv, char mean_x, char mean_y)
175{
176 int mx, my, i;
177 unsigned char *pa, *pb;
178
179 mx = x + 8 - (mv >> 4) - mean_x;
180 my = y + 8 - (mv & 0xf) - mean_y;
181
182 pa = ri->current_frame.data[0] + (y * ri->y_stride) + x;
183 pb = ri->last_frame.data[0] + (my * ri->y_stride) + mx;
184 for(i = 0; i < 8; i++) {
185 pa[0] = pb[0];
186 pa[1] = pb[1];
187 pa[2] = pb[2];
188 pa[3] = pb[3];
189 pa[4] = pb[4];
190 pa[5] = pb[5];
191 pa[6] = pb[6];
192 pa[7] = pb[7];
193 pa += ri->y_stride;
194 pb += ri->y_stride;
195 }
196
197 pa = ri->current_frame.data[1] + (y/2) * (ri->c_stride) + x/2;
198 pb = ri->last_frame.data[1] + (my/2) * (ri->c_stride) + (mx + 1)/2;
199 for(i = 0; i < 4; i++) {
200 pa[0] = pb[0];
201 pa[1] = pb[1];
202 pa[2] = pb[2];
203 pa[3] = pb[3];
204 pa += ri->c_stride;
205 pb += ri->c_stride;
206 }
207
208 pa = ri->current_frame.data[2] + (y/2) * (ri->c_stride) + x/2;
209 pb = ri->last_frame.data[2] + (my/2) * (ri->c_stride) + (mx + 1)/2;
210 for(i = 0; i < 4; i++) {
211 pa[0] = pb[0];
212 pa[1] = pb[1];
213 pa[2] = pb[2];
214 pa[3] = pb[3];
215 pa += ri->c_stride;
216 pb += ri->c_stride;
217 }
218}
219
220static void roqvideo_decode_frame(RoqContext *ri)
221{
222 unsigned int chunk_id = 0, chunk_arg = 0;
223 unsigned long chunk_size = 0;
224 int i, j, k, nv1, nv2, vqflg = 0, vqflg_pos = -1;
225 int vqid, bpos, xpos, ypos, xp, yp, x, y;
226 int frame_stats[2][4] = {{0},{0}};
227 roq_qcell *qcell;
228 unsigned char *buf = ri->buf;
229 unsigned char *buf_end = ri->buf + ri->size;
230
231 while (buf < buf_end) {
232 chunk_id = get_word(buf);
233 chunk_size = get_long(buf);
234 chunk_arg = get_word(buf);
235
236 if(chunk_id == RoQ_QUAD_VQ)
237 break;
238 if(chunk_id == RoQ_QUAD_CODEBOOK) {
239 if((nv1 = chunk_arg >> 8) == 0)
240 nv1 = 256;
241 if((nv2 = chunk_arg & 0xff) == 0 && nv1 * 6 < chunk_size)
242 nv2 = 256;
243 for(i = 0; i < nv1; i++) {
244 ri->cells[i].y0 = get_byte(buf);
245 ri->cells[i].y1 = get_byte(buf);
246 ri->cells[i].y2 = get_byte(buf);
247 ri->cells[i].y3 = get_byte(buf);
248 ri->cells[i].u = get_byte(buf);
249 ri->cells[i].v = get_byte(buf);
250 }
251 for(i = 0; i < nv2; i++)
252 for(j = 0; j < 4; j++)
253 ri->qcells[i].idx[j] = get_byte(buf);
254 }
255 }
256
257 bpos = xpos = ypos = 0;
258 while(bpos < chunk_size) {
259 for (yp = ypos; yp < ypos + 16; yp += 8)
260 for (xp = xpos; xp < xpos + 16; xp += 8) {
261 if (vqflg_pos < 0) {
262 vqflg = buf[bpos++]; vqflg |= (buf[bpos++] << 8);
263 vqflg_pos = 7;
264 }
265 vqid = (vqflg >> (vqflg_pos * 2)) & 0x3;
266 frame_stats[0][vqid]++;
267 vqflg_pos--;
268
269 switch(vqid) {
270 case RoQ_ID_MOT:
271 apply_motion_8x8(ri, xp, yp, 0, 8, 8);
272 break;
273 case RoQ_ID_FCC:
274 apply_motion_8x8(ri, xp, yp, buf[bpos++], chunk_arg >> 8,
275 chunk_arg & 0xff);
276 break;
277 case RoQ_ID_SLD:
278 qcell = ri->qcells + buf[bpos++];
279 apply_vector_4x4(ri, xp, yp, ri->cells + qcell->idx[0]);
280 apply_vector_4x4(ri, xp+4, yp, ri->cells + qcell->idx[1]);
281 apply_vector_4x4(ri, xp, yp+4, ri->cells + qcell->idx[2]);
282 apply_vector_4x4(ri, xp+4, yp+4, ri->cells + qcell->idx[3]);
283 break;
284 case RoQ_ID_CCC:
285 for (k = 0; k < 4; k++) {
286 x = xp; y = yp;
287 if(k & 0x01) x += 4;
288 if(k & 0x02) y += 4;
289
290 if (vqflg_pos < 0) {
291 vqflg = buf[bpos++];
292 vqflg |= (buf[bpos++] << 8);
293 vqflg_pos = 7;
294 }
295 vqid = (vqflg >> (vqflg_pos * 2)) & 0x3;
296 frame_stats[1][vqid]++;
297 vqflg_pos--;
298 switch(vqid) {
299 case RoQ_ID_MOT:
300 apply_motion_4x4(ri, x, y, 0, 8, 8);
301 break;
302 case RoQ_ID_FCC:
303 apply_motion_4x4(ri, x, y, buf[bpos++],
304 chunk_arg >> 8, chunk_arg & 0xff);
305 break;
306 case RoQ_ID_SLD:
307 qcell = ri->qcells + buf[bpos++];
308 apply_vector_2x2(ri, x, y, ri->cells + qcell->idx[0]);
309 apply_vector_2x2(ri, x+2, y, ri->cells + qcell->idx[1]);
310 apply_vector_2x2(ri, x, y+2, ri->cells + qcell->idx[2]);
311 apply_vector_2x2(ri, x+2, y+2, ri->cells + qcell->idx[3]);
312 break;
313 case RoQ_ID_CCC:
314 apply_vector_2x2(ri, x, y, ri->cells + buf[bpos]);
315 apply_vector_2x2(ri, x+2, y, ri->cells + buf[bpos+1]);
316 apply_vector_2x2(ri, x, y+2, ri->cells + buf[bpos+2]);
317 apply_vector_2x2(ri, x+2, y+2, ri->cells + buf[bpos+3]);
318 bpos += 4;
319 break;
320 }
321 }
322 break;
323 default:
324 printf("Unknown vq code: %d\n", vqid);
325 }
326 }
327
328 xpos += 16;
329 if (xpos >= ri->avctx->width) {
330 xpos -= ri->avctx->width;
331 ypos += 16;
332 }
333 if(ypos >= ri->avctx->height)
334 break;
335 }
336}
337
338
339static int roq_decode_init(AVCodecContext *avctx)
340{
341 RoqContext *s = avctx->priv_data;
342
343 s->avctx = avctx;
344 s->first_frame = 1;
345 avctx->pix_fmt = PIX_FMT_YUV420P;
346 avctx->has_b_frames = 0;
347 dsputil_init(&s->dsp, avctx);
348
349 return 0;
350}
351
352static int roq_decode_frame(AVCodecContext *avctx,
353 void *data, int *data_size,
354 uint8_t *buf, int buf_size)
355{
356 RoqContext *s = avctx->priv_data;
357
358 *data_size = 0;
359
360 if (avctx->get_buffer(avctx, &s->current_frame)) {
361 printf (" RoQ: get_buffer() failed\n");
362 return -1;
363 }
364 s->y_stride = s->current_frame.linesize[0];
365 s->c_stride = s->current_frame.linesize[1];
366
367 s->buf = buf;
368 s->size = buf_size;
369 roqvideo_decode_frame(s);
370
371 /* release the last frame if it is allocated */
372 if (s->first_frame)
373 s->first_frame = 0;
374 else
375 avctx->release_buffer(avctx, &s->last_frame);
376
377 /* shuffle frames */
378 s->last_frame = s->current_frame;
379
380 *data_size = sizeof(AVFrame);
381 *(AVFrame*)data = s->current_frame;
382
383 return buf_size;
384}
385
386static int roq_decode_end(AVCodecContext *avctx)
387{
388 RoqContext *s = avctx->priv_data;
389
390 /* release the last frame */
391 avctx->release_buffer(avctx, &s->last_frame);
392
393 return 0;
394}
395
396AVCodec roq_decoder = {
397 "roqvideo",
398 CODEC_TYPE_VIDEO,
399 CODEC_ID_ROQ,
400 sizeof(RoqContext),
401 roq_decode_init,
402 NULL,
403 roq_decode_end,
404 roq_decode_frame,
405 CODEC_CAP_DR1,
406};