Mercurial > libavcodec.hg
comparison truemotion1.c @ 1650:bdade3baabfc libavcodec
initial support for Duck TrueMotion v1 (think of it as On2 VP1); only
16-bit mode supported thus far
author | melanson |
---|---|
date | Wed, 03 Dec 2003 04:22:15 +0000 |
parents | |
children | 1c123e036890 |
comparison
equal
deleted
inserted
replaced
1649:e6a474a5b929 | 1650:bdade3baabfc |
---|---|
1 /* | |
2 * Duck TrueMotion 1.0 Decoder | |
3 * Copyright (C) 2003 Alex Beregszaszi & Mike Melanson | |
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 */ | |
19 | |
20 /** | |
21 * @file truemotion1.c | |
22 * Duck TrueMotion v1 Video Decoder by | |
23 * Alex Beregszaszi (alex@fsn.hu) and | |
24 * Mike Melanson (melanson@pcisys.net) | |
25 * | |
26 * The TrueMotion v1 decoder presently only decodes 16-bit TM1 data and | |
27 * outputs RGB555 data. 24-bit TM1 data is not supported yet. | |
28 */ | |
29 | |
30 #include <stdio.h> | |
31 #include <stdlib.h> | |
32 #include <string.h> | |
33 #include <unistd.h> | |
34 | |
35 #include "common.h" | |
36 #include "avcodec.h" | |
37 #include "dsputil.h" | |
38 | |
39 #include "truemotion1data.h" | |
40 | |
41 #define LE_16(x) ((((uint8_t*)(x))[1] << 8) | ((uint8_t*)(x))[0]) | |
42 | |
43 typedef struct TrueMotion1Context { | |
44 AVCodecContext *avctx; | |
45 AVFrame frame; | |
46 AVFrame prev_frame; | |
47 | |
48 unsigned char *buf; | |
49 int size; | |
50 | |
51 unsigned char *mb_change_bits; | |
52 int mb_change_bits_row_size; | |
53 unsigned char *index_stream; | |
54 int index_stream_size; | |
55 | |
56 int flags; | |
57 int x, y, w, h; | |
58 | |
59 uint32_t y_predictor_table[1024]; | |
60 uint32_t c_predictor_table[1024]; | |
61 | |
62 int compression; | |
63 int block_type; | |
64 int block_width; | |
65 int block_height; | |
66 | |
67 int16_t *ydt; | |
68 int16_t *cdt; | |
69 int16_t *fat_ydt; | |
70 int16_t *fat_cdt; | |
71 | |
72 int last_deltaset, last_vectable; | |
73 | |
74 unsigned int *vert_pred; | |
75 | |
76 } TrueMotion1Context; | |
77 | |
78 #define FLAG_SPRITE 32 | |
79 #define FLAG_KEYFRAME 16 | |
80 #define FLAG_INTERFRAME 8 | |
81 #define FLAG_INTERPOLATED 4 | |
82 | |
83 struct frame_header { | |
84 uint8_t header_size; | |
85 uint8_t compression; | |
86 uint8_t deltaset; | |
87 uint8_t vectable; | |
88 uint16_t ysize; | |
89 uint16_t xsize; | |
90 uint16_t checksum; | |
91 uint8_t version; | |
92 uint8_t header_type; | |
93 uint8_t flags; | |
94 uint8_t control; | |
95 uint16_t xoffset; | |
96 uint16_t yoffset; | |
97 uint16_t width; | |
98 uint16_t height; | |
99 }; | |
100 | |
101 #define ALGO_NOP 0 | |
102 #define ALGO_RGB16V 1 | |
103 #define ALGO_RGB16H 2 | |
104 #define ALGO_RGB24H 3 | |
105 | |
106 /* these are the various block sizes that can occupy a 4x4 block */ | |
107 #define BLOCK_2x2 0 | |
108 #define BLOCK_2x4 1 | |
109 #define BLOCK_4x2 2 | |
110 #define BLOCK_4x4 3 | |
111 | |
112 typedef struct comp_types { | |
113 int algorithm; | |
114 int block_width; | |
115 int block_height; | |
116 int block_type; | |
117 } comp_types; | |
118 | |
119 /* { valid for metatype }, algorithm, num of deltas, horiz res, vert res */ | |
120 static comp_types compression_types[17] = { | |
121 { ALGO_NOP, 0, 0, 0 }, | |
122 | |
123 { ALGO_RGB16V, 4, 4, BLOCK_4x4 }, | |
124 { ALGO_RGB16H, 4, 4, BLOCK_4x4 }, | |
125 { ALGO_RGB16V, 4, 2, BLOCK_4x2 }, | |
126 { ALGO_RGB16H, 4, 2, BLOCK_4x2 }, | |
127 | |
128 { ALGO_RGB16V, 2, 4, BLOCK_2x4 }, | |
129 { ALGO_RGB16H, 2, 4, BLOCK_2x4 }, | |
130 { ALGO_RGB16V, 2, 2, BLOCK_2x2 }, | |
131 { ALGO_RGB16H, 2, 2, BLOCK_2x2 }, | |
132 | |
133 { ALGO_NOP, 4, 4, BLOCK_4x4 }, | |
134 { ALGO_RGB24H, 4, 4, BLOCK_4x4 }, | |
135 { ALGO_NOP, 4, 2, BLOCK_4x2 }, | |
136 { ALGO_RGB24H, 4, 2, BLOCK_4x2 }, | |
137 | |
138 { ALGO_NOP, 2, 4, BLOCK_2x4 }, | |
139 { ALGO_RGB24H, 2, 4, BLOCK_2x4 }, | |
140 { ALGO_NOP, 2, 2, BLOCK_2x2 }, | |
141 { ALGO_RGB24H, 2, 2, BLOCK_2x2 } | |
142 }; | |
143 | |
144 static void select_delta_tables(TrueMotion1Context *s, int delta_table_index) | |
145 { | |
146 int i; | |
147 | |
148 if (delta_table_index > 3) | |
149 return; | |
150 | |
151 s->ydt = ydts[delta_table_index]; | |
152 s->cdt = cdts[delta_table_index]; | |
153 s->fat_ydt = fat_ydts[delta_table_index]; | |
154 s->fat_cdt = fat_cdts[delta_table_index]; | |
155 | |
156 /* Y skinny deltas need to be halved for some reason; maybe the | |
157 * skinny Y deltas should be modified */ | |
158 for (i = 0; i < 8; i++) | |
159 { | |
160 /* drop the lsb before dividing by 2-- net effect: round down | |
161 * when dividing a negative number (e.g., -3/2 = -2, not -1) */ | |
162 s->ydt[i] &= 0xFFFE; | |
163 s->ydt[i] /= 2; | |
164 } | |
165 } | |
166 | |
167 static int make_ydt_entry(int p1, int p2, int16_t *ydt) | |
168 { | |
169 int lo, hi; | |
170 | |
171 lo = ydt[p1]; | |
172 lo += (lo << 5) + (lo << 10); | |
173 hi = ydt[p2]; | |
174 hi += (hi << 5) + (hi << 10); | |
175 return ((lo + (hi << 16)) << 1); | |
176 } | |
177 | |
178 static int make_cdt_entry(int p1, int p2, int16_t *cdt) | |
179 { | |
180 int r, b, lo; | |
181 | |
182 b = cdt[p2]; | |
183 r = cdt[p1] << 10; | |
184 lo = b + r; | |
185 return ((lo + (lo << 16)) << 1); | |
186 } | |
187 | |
188 static void gen_vector_table(TrueMotion1Context *s, uint8_t *sel_vector_table) | |
189 { | |
190 int len, i, j; | |
191 unsigned char delta_pair; | |
192 | |
193 for (i = 0; i < 1024; i += 4) | |
194 { | |
195 len = *sel_vector_table++ / 2; | |
196 for (j = 0; j < len; j++) | |
197 { | |
198 delta_pair = *sel_vector_table++; | |
199 s->y_predictor_table[i+j] = 0xfffffffe & | |
200 make_ydt_entry(delta_pair >> 4, delta_pair & 0xf, s->ydt); | |
201 s->c_predictor_table[i+j] = 0xfffffffe & | |
202 make_cdt_entry(delta_pair >> 4, delta_pair & 0xf, s->cdt); | |
203 } | |
204 s->y_predictor_table[i+(j-1)] |= 1; | |
205 s->c_predictor_table[i+(j-1)] |= 1; | |
206 } | |
207 } | |
208 | |
209 /* Returns the number of bytes consumed from the bytestream. Returns -1 if | |
210 * there was an error while decoding the header */ | |
211 static int truemotion1_decode_header(TrueMotion1Context *s) | |
212 { | |
213 int i; | |
214 struct frame_header header; | |
215 uint8_t header_buffer[128]; /* logical maximum size of the header */ | |
216 uint8_t *sel_vector_table; | |
217 | |
218 /* There is 1 change bit per 4 pixels, so each change byte represents | |
219 * 32 pixels; divide width by 4 to obtain the number of change bits and | |
220 * then round up to the nearest byte. */ | |
221 s->mb_change_bits_row_size = ((s->avctx->width >> 2) + 7) >> 3; | |
222 | |
223 header.header_size = ((s->buf[0] >> 5) | (s->buf[0] << 3)) & 0x7f; | |
224 if (s->buf[0] < 0x10) | |
225 { | |
226 printf("invalid header size\n"); | |
227 return -1; | |
228 } | |
229 | |
230 /* unscramble the header bytes with a XOR operation */ | |
231 memset(header_buffer, 0, 128); | |
232 for (i = 1; i < header.header_size; i++) | |
233 header_buffer[i - 1] = s->buf[i] ^ s->buf[i + 1]; | |
234 header.compression = header_buffer[0]; | |
235 header.deltaset = header_buffer[1]; | |
236 header.vectable = header_buffer[2]; | |
237 header.ysize = LE_16(&header_buffer[3]); | |
238 header.xsize = LE_16(&header_buffer[5]); | |
239 header.checksum = LE_16(&header_buffer[7]); | |
240 header.version = header_buffer[9]; | |
241 header.header_type = header_buffer[10]; | |
242 header.flags = header_buffer[11]; | |
243 header.control = header_buffer[12]; | |
244 | |
245 /* Version 2 */ | |
246 if (header.version >= 2) | |
247 { | |
248 if (header.header_type > 3) | |
249 { | |
250 av_log(s->avctx, AV_LOG_ERROR, "truemotion1: invalid header type\n"); | |
251 return -1; | |
252 } else if ((header.header_type == 2) || (header.header_type == 3)) { | |
253 s->flags = header.flags; | |
254 if (!(s->flags & FLAG_INTERFRAME)) | |
255 s->flags |= FLAG_KEYFRAME; | |
256 } else | |
257 s->flags = FLAG_KEYFRAME; | |
258 } else /* Version 1 */ | |
259 s->flags = FLAG_KEYFRAME; | |
260 | |
261 if (s->flags & FLAG_SPRITE) { | |
262 s->w = header.width; | |
263 s->h = header.height; | |
264 s->x = header.xoffset; | |
265 s->y = header.yoffset; | |
266 } else { | |
267 s->w = header.xsize; | |
268 s->h = header.ysize; | |
269 if (header.header_type < 2) { | |
270 if ((s->w < 213) && (s->h >= 176)) | |
271 s->flags |= FLAG_INTERPOLATED; | |
272 } | |
273 } | |
274 | |
275 if (header.compression > 17) { | |
276 printf("invalid compression type (%d)\n", header.compression); | |
277 return -1; | |
278 } | |
279 | |
280 if ((header.deltaset != s->last_deltaset) || | |
281 (header.vectable != s->last_vectable)) | |
282 select_delta_tables(s, header.deltaset); | |
283 | |
284 if ((header.compression & 1) && header.header_type) | |
285 sel_vector_table = pc_tbl2; | |
286 else { | |
287 if (header.vectable < 4) | |
288 sel_vector_table = tables[header.vectable - 1]; | |
289 else { | |
290 printf("invalid vector table id (%d)\n", header.vectable); | |
291 return -1; | |
292 } | |
293 } | |
294 | |
295 if ((header.deltaset != s->last_deltaset) || (header.vectable != s->last_vectable)) | |
296 { | |
297 if (compression_types[header.compression].algorithm == ALGO_RGB24H) | |
298 { | |
299 printf("24bit compression not yet supported\n"); | |
300 } | |
301 else | |
302 gen_vector_table(s, sel_vector_table); | |
303 } | |
304 | |
305 /* set up pointers to the other key data chunks */ | |
306 s->mb_change_bits = s->buf + header.header_size; | |
307 if (s->flags & FLAG_KEYFRAME) { | |
308 /* no change bits specified for a keyframe; only index bytes */ | |
309 s->index_stream = s->mb_change_bits; | |
310 } else { | |
311 /* one change bit per 4x4 block */ | |
312 s->index_stream = s->mb_change_bits + | |
313 (s->mb_change_bits_row_size * (s->avctx->height >> 2)); | |
314 } | |
315 s->index_stream_size = s->size - (s->index_stream - s->buf); | |
316 | |
317 s->last_deltaset = header.deltaset; | |
318 s->last_vectable = header.vectable; | |
319 s->compression = header.compression; | |
320 s->block_width = compression_types[header.compression].block_width; | |
321 s->block_height = compression_types[header.compression].block_height; | |
322 s->block_type = compression_types[header.compression].block_type; | |
323 | |
324 return header.header_size; | |
325 } | |
326 | |
327 static int truemotion1_decode_init(AVCodecContext *avctx) | |
328 { | |
329 TrueMotion1Context *s = (TrueMotion1Context *)avctx->priv_data; | |
330 | |
331 s->avctx = avctx; | |
332 | |
333 avctx->pix_fmt = PIX_FMT_RGB555; | |
334 avctx->has_b_frames = 0; | |
335 s->frame.data[0] = s->prev_frame.data[0] = NULL; | |
336 | |
337 /* there is a vertical predictor for each pixel in a line; each vertical | |
338 * predictor is 0 to start with */ | |
339 s->vert_pred = | |
340 (unsigned int *)av_malloc(s->avctx->width * sizeof(unsigned short)); | |
341 | |
342 return 0; | |
343 } | |
344 | |
345 #define GET_NEXT_INDEX() \ | |
346 {\ | |
347 if (index_stream_index >= s->index_stream_size) { \ | |
348 printf (" help! truemotion1 decoder went out of bounds\n"); \ | |
349 return; \ | |
350 } \ | |
351 index = s->index_stream[index_stream_index++] * 4; \ | |
352 } | |
353 | |
354 #define APPLY_C_PREDICTOR() \ | |
355 predictor_pair = s->c_predictor_table[index]; \ | |
356 horiz_pred += (predictor_pair >> 1); \ | |
357 if (predictor_pair & 1) { \ | |
358 GET_NEXT_INDEX() \ | |
359 if (!index) { \ | |
360 GET_NEXT_INDEX() \ | |
361 predictor_pair = s->c_predictor_table[index]; \ | |
362 horiz_pred += ((predictor_pair >> 1) * 5); \ | |
363 if (predictor_pair & 1) \ | |
364 GET_NEXT_INDEX() \ | |
365 else \ | |
366 index++; \ | |
367 } \ | |
368 } else \ | |
369 index++; | |
370 | |
371 #define APPLY_Y_PREDICTOR() \ | |
372 predictor_pair = s->y_predictor_table[index]; \ | |
373 horiz_pred += (predictor_pair >> 1); \ | |
374 if (predictor_pair & 1) { \ | |
375 GET_NEXT_INDEX() \ | |
376 if (!index) { \ | |
377 GET_NEXT_INDEX() \ | |
378 predictor_pair = s->y_predictor_table[index]; \ | |
379 horiz_pred += ((predictor_pair >> 1) * 5); \ | |
380 if (predictor_pair & 1) \ | |
381 GET_NEXT_INDEX() \ | |
382 else \ | |
383 index++; \ | |
384 } \ | |
385 } else \ | |
386 index++; | |
387 | |
388 #define OUTPUT_PIXEL_PAIR() \ | |
389 *current_pixel_pair = *vert_pred + horiz_pred; \ | |
390 *vert_pred++ = *current_pixel_pair++; \ | |
391 prev_pixel_pair++; | |
392 | |
393 static void truemotion1_decode_16bit(TrueMotion1Context *s) | |
394 { | |
395 int y; | |
396 int pixels_left; /* remaining pixels on this line */ | |
397 unsigned int predictor_pair; | |
398 unsigned int horiz_pred; | |
399 unsigned int *vert_pred; | |
400 unsigned int *current_pixel_pair; | |
401 unsigned int *prev_pixel_pair; | |
402 unsigned char *current_line = s->frame.data[0]; | |
403 unsigned char *prev_line = s->prev_frame.data[0]; | |
404 int keyframe = s->flags & FLAG_KEYFRAME; | |
405 | |
406 /* these variables are for managing the stream of macroblock change bits */ | |
407 unsigned char *mb_change_bits = s->mb_change_bits; | |
408 unsigned char mb_change_byte; | |
409 unsigned char mb_change_byte_mask; | |
410 int mb_change_index; | |
411 | |
412 /* these variables are for managing the main index stream */ | |
413 int index_stream_index = 0; /* yes, the index into the index stream */ | |
414 int index; | |
415 | |
416 /* clean out the line buffer */ | |
417 memset(s->vert_pred, 0, s->avctx->width * sizeof(unsigned short)); | |
418 | |
419 GET_NEXT_INDEX(); | |
420 | |
421 for (y = 0; y < s->avctx->height; y++) { | |
422 | |
423 /* re-init variables for the next line iteration */ | |
424 horiz_pred = 0; | |
425 current_pixel_pair = (unsigned int *)current_line; | |
426 prev_pixel_pair = (unsigned int *)prev_line; | |
427 vert_pred = s->vert_pred; | |
428 mb_change_index = 0; | |
429 mb_change_byte = mb_change_bits[mb_change_index++]; | |
430 mb_change_byte_mask = 0x01; | |
431 pixels_left = s->avctx->width; | |
432 | |
433 while (pixels_left > 0) { | |
434 | |
435 if (keyframe || ((mb_change_byte & mb_change_byte_mask) == 0)) { | |
436 | |
437 switch (y & 3) { | |
438 case 0: | |
439 /* if macroblock width is 2, apply C-Y-C-Y; else | |
440 * apply C-Y-Y */ | |
441 if ((s->block_type == BLOCK_2x2) || | |
442 (s->block_type == BLOCK_2x4)) { | |
443 APPLY_C_PREDICTOR(); | |
444 APPLY_Y_PREDICTOR(); | |
445 OUTPUT_PIXEL_PAIR(); | |
446 APPLY_C_PREDICTOR(); | |
447 APPLY_Y_PREDICTOR(); | |
448 OUTPUT_PIXEL_PAIR(); | |
449 } else { | |
450 APPLY_C_PREDICTOR(); | |
451 APPLY_Y_PREDICTOR(); | |
452 OUTPUT_PIXEL_PAIR(); | |
453 APPLY_Y_PREDICTOR(); | |
454 OUTPUT_PIXEL_PAIR(); | |
455 } | |
456 break; | |
457 | |
458 case 1: | |
459 case 3: | |
460 /* always apply 2 Y predictors on these iterations */ | |
461 APPLY_Y_PREDICTOR(); | |
462 OUTPUT_PIXEL_PAIR(); | |
463 APPLY_Y_PREDICTOR(); | |
464 OUTPUT_PIXEL_PAIR(); | |
465 break; | |
466 | |
467 case 2: | |
468 /* this iteration might be C-Y-C-Y, Y-Y, or C-Y-Y | |
469 * depending on the macroblock type */ | |
470 if (s->block_type == BLOCK_2x2) { | |
471 APPLY_C_PREDICTOR(); | |
472 APPLY_Y_PREDICTOR(); | |
473 OUTPUT_PIXEL_PAIR(); | |
474 APPLY_C_PREDICTOR(); | |
475 APPLY_Y_PREDICTOR(); | |
476 OUTPUT_PIXEL_PAIR(); | |
477 } else if (s->block_type == BLOCK_4x2) { | |
478 APPLY_C_PREDICTOR(); | |
479 APPLY_Y_PREDICTOR(); | |
480 OUTPUT_PIXEL_PAIR(); | |
481 APPLY_Y_PREDICTOR(); | |
482 OUTPUT_PIXEL_PAIR(); | |
483 } else { | |
484 APPLY_Y_PREDICTOR(); | |
485 OUTPUT_PIXEL_PAIR(); | |
486 APPLY_Y_PREDICTOR(); | |
487 OUTPUT_PIXEL_PAIR(); | |
488 } | |
489 break; | |
490 } | |
491 | |
492 } else { | |
493 | |
494 /* skip (copy) four pixels, but reassign the horizontal | |
495 * predictor */ | |
496 *current_pixel_pair = *prev_pixel_pair++; | |
497 *vert_pred++ = *current_pixel_pair++; | |
498 *current_pixel_pair = *prev_pixel_pair++; | |
499 horiz_pred = *current_pixel_pair - *vert_pred; | |
500 *vert_pred++ = *current_pixel_pair++; | |
501 | |
502 } | |
503 | |
504 if (!keyframe) { | |
505 mb_change_byte_mask <<= 1; | |
506 | |
507 /* next byte */ | |
508 if (!mb_change_byte_mask) { | |
509 mb_change_byte = mb_change_bits[mb_change_index++]; | |
510 mb_change_byte_mask = 0x01; | |
511 } | |
512 } | |
513 | |
514 pixels_left -= 4; | |
515 } | |
516 | |
517 /* next change row */ | |
518 if (((y + 1) & 3) == 0) | |
519 mb_change_bits += s->mb_change_bits_row_size; | |
520 | |
521 current_line += s->frame.linesize[0]; | |
522 prev_line += s->prev_frame.linesize[0]; | |
523 } | |
524 } | |
525 | |
526 static int truemotion1_decode_frame(AVCodecContext *avctx, | |
527 void *data, int *data_size, | |
528 uint8_t *buf, int buf_size) | |
529 { | |
530 TrueMotion1Context *s = (TrueMotion1Context *)avctx->priv_data; | |
531 | |
532 s->buf = buf; | |
533 s->size = buf_size; | |
534 | |
535 s->frame.reference = 1; | |
536 if (avctx->get_buffer(avctx, &s->frame) < 0) { | |
537 fprintf(stderr, "truemotion1: get_buffer() failed\n"); | |
538 return -1; | |
539 } | |
540 | |
541 /* no supplementary picture */ | |
542 if (buf_size == 0) | |
543 return 0; | |
544 | |
545 *data_size = 0; | |
546 | |
547 if (truemotion1_decode_header(s) == -1) | |
548 return -1; | |
549 | |
550 /* check for a do-nothing frame and copy the previous frame */ | |
551 if (compression_types[s->compression].algorithm == ALGO_NOP) | |
552 { | |
553 memcpy(s->frame.data[0], s->prev_frame.data[0], | |
554 s->frame.linesize[0] * s->avctx->height); | |
555 } else if (compression_types[s->compression].algorithm == ALGO_RGB24H) { | |
556 printf (" 24-bit Duck TrueMotion decoding not yet implemented\n"); | |
557 } else { | |
558 truemotion1_decode_16bit(s); | |
559 } | |
560 | |
561 if (s->prev_frame.data[0]) | |
562 avctx->release_buffer(avctx, &s->prev_frame); | |
563 | |
564 /* shuffle frames */ | |
565 s->prev_frame = s->frame; | |
566 | |
567 *data_size = sizeof(AVFrame); | |
568 *(AVFrame*)data = s->frame; | |
569 | |
570 /* report that the buffer was completely consumed */ | |
571 return buf_size; | |
572 } | |
573 | |
574 static int truemotion1_decode_end(AVCodecContext *avctx) | |
575 { | |
576 TrueMotion1Context *s = (TrueMotion1Context *)avctx->priv_data; | |
577 | |
578 /* release the last frame */ | |
579 if (s->prev_frame.data[0]) | |
580 avctx->release_buffer(avctx, &s->prev_frame); | |
581 | |
582 av_free(s->vert_pred); | |
583 | |
584 return 0; | |
585 } | |
586 | |
587 AVCodec truemotion1_decoder = { | |
588 "truemotion1", | |
589 CODEC_TYPE_VIDEO, | |
590 CODEC_ID_TRUEMOTION1, | |
591 sizeof(TrueMotion1Context), | |
592 truemotion1_decode_init, | |
593 NULL, | |
594 truemotion1_decode_end, | |
595 truemotion1_decode_frame, | |
596 CODEC_CAP_DR1, | |
597 }; |