Mercurial > libavcodec.hg
comparison roqvideo.c @ 1439:a4d00b1f0271 libavcodec
initial commit for Id RoQ and Interplay MVE multimedia subsystems
author | tmmm |
---|---|
date | Tue, 02 Sep 2003 04:32:02 +0000 |
parents | |
children | 07029b2cd44f |
comparison
equal
deleted
inserted
replaced
1438:6339c2b322e6 | 1439:a4d00b1f0271 |
---|---|
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 | |
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 | |
45 typedef 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 | |
81 static 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 | |
95 static 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 | |
134 static 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 | |
173 static 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 | |
220 static 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 | |
339 static 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 | |
352 static 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 | |
386 static 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 | |
396 AVCodec 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 }; |