Mercurial > libavcodec.hg
comparison rpza.c @ 1491:222643544cf1 libavcodec
New demuxers: Sega FILM/CPK, Westwood VQA & AUD; new decoders: MS RLE &
Video-1, Apple RPZA, Cinepak, Westwood IMA ADPCM
author | tmmm |
---|---|
date | Wed, 01 Oct 2003 04:39:38 +0000 |
parents | |
children | df7ab60d1ee0 |
comparison
equal
deleted
inserted
replaced
1490:0355f2b3519a | 1491:222643544cf1 |
---|---|
1 /* | |
2 * Quicktime Video (RPZA) Video Decoder | |
3 * Copyright (C) 2003 the ffmpeg project | |
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 /** | |
22 * @file rpza.c | |
23 * QT RPZA Video Decoder by Roberto Togni <rtogni@bresciaonline.it> | |
24 * For more information about the RPZA format, visit: | |
25 * http://www.pcisys.net/~melanson/codecs/ | |
26 * | |
27 * The RPZA decoder outputs RGB555 colorspace data. | |
28 * | |
29 * Note that this decoder reads big endian RGB555 pixel values from the | |
30 * bytestream, arranges them in the host's endian order, and outputs | |
31 * them to the final rendered map in the same host endian order. This is | |
32 * intended behavior as the ffmpeg documentation states that RGB555 pixels | |
33 * shall be stored in native CPU endianness. | |
34 */ | |
35 | |
36 #include <stdio.h> | |
37 #include <stdlib.h> | |
38 #include <string.h> | |
39 #include <unistd.h> | |
40 | |
41 #include "common.h" | |
42 #include "avcodec.h" | |
43 #include "dsputil.h" | |
44 | |
45 typedef struct RpzaContext { | |
46 | |
47 AVCodecContext *avctx; | |
48 DSPContext dsp; | |
49 AVFrame frame; | |
50 AVFrame prev_frame; | |
51 | |
52 unsigned char *buf; | |
53 int size; | |
54 | |
55 } RpzaContext; | |
56 | |
57 #define BE_16(x) ((((uint8_t*)(x))[0] << 8) | ((uint8_t*)(x))[1]) | |
58 #define BE_32(x) ((((uint8_t*)(x))[0] << 24) | \ | |
59 (((uint8_t*)(x))[1] << 16) | \ | |
60 (((uint8_t*)(x))[2] << 8) | \ | |
61 ((uint8_t*)(x))[3]) | |
62 | |
63 #define ADVANCE_BLOCK() \ | |
64 { \ | |
65 pixel_ptr += 4; \ | |
66 if (pixel_ptr >= width) \ | |
67 { \ | |
68 pixel_ptr = 0; \ | |
69 row_ptr += stride * 4; \ | |
70 } \ | |
71 total_blocks--; \ | |
72 if (total_blocks < 0) \ | |
73 { \ | |
74 printf("warning: block counter just went negative (this should not happen)\n"); \ | |
75 return; \ | |
76 } \ | |
77 } | |
78 | |
79 static void rpza_decode_stream(RpzaContext *s) | |
80 { | |
81 int width = s->avctx->width; | |
82 int stride = s->frame.linesize[0] / 2; | |
83 int row_inc = stride - 4; | |
84 int stream_ptr = 0; | |
85 int chunk_size; | |
86 unsigned char opcode; | |
87 int n_blocks; | |
88 unsigned short colorA = 0, colorB; | |
89 unsigned short color4[4]; | |
90 unsigned char index, idx; | |
91 unsigned short ta, tb; | |
92 unsigned short *pixels = (unsigned short *)s->frame.data[0]; | |
93 unsigned short *prev_pixels = (unsigned short *)s->prev_frame.data[0]; | |
94 | |
95 int row_ptr = 0; | |
96 int pixel_ptr = 0; | |
97 int block_ptr; | |
98 int pixel_x, pixel_y; | |
99 int total_blocks; | |
100 | |
101 /* First byte is always 0xe1. Warn if it's different */ | |
102 if (s->buf[stream_ptr] != 0xe1) | |
103 printf("First chunk byte is 0x%02x instead of 0x1e\n", | |
104 s->buf[stream_ptr]); | |
105 | |
106 /* Get chunk size, ingnoring first byte */ | |
107 chunk_size = BE_32(&s->buf[stream_ptr]) & 0x00FFFFFF; | |
108 stream_ptr += 4; | |
109 | |
110 /* If length mismatch use size from MOV file and try to decode anyway */ | |
111 if (chunk_size != s->size) | |
112 printf("MOV chunk size != encoded chunk size; using MOV chunk size\n"); | |
113 | |
114 chunk_size = s->size; | |
115 | |
116 /* Number of 4x4 blocks in frame. */ | |
117 total_blocks = (s->avctx->width * s->avctx->height) / (4 * 4); | |
118 | |
119 /* Process chunk data */ | |
120 while (stream_ptr < chunk_size) { | |
121 opcode = s->buf[stream_ptr++]; /* Get opcode */ | |
122 | |
123 n_blocks = (opcode & 0x1f) + 1; /* Extract block counter from opcode */ | |
124 | |
125 /* If opcode MSbit is 0, we need more data to decide what to do */ | |
126 if ((opcode & 0x80) == 0) { | |
127 colorA = (opcode << 8) | (s->buf[stream_ptr++]); | |
128 opcode = 0; | |
129 if ((s->buf[stream_ptr] & 0x80) != 0) { | |
130 /* Must behave as opcode 110xxxxx, using colorA computed | |
131 * above. Use fake opcode 0x20 to enter switch block at | |
132 * the right place */ | |
133 opcode = 0x20; | |
134 n_blocks = 1; | |
135 } | |
136 } | |
137 | |
138 switch (opcode & 0xe0) { | |
139 | |
140 /* Skip blocks */ | |
141 case 0x80: | |
142 while (n_blocks--) { | |
143 block_ptr = row_ptr + pixel_ptr; | |
144 for (pixel_y = 0; pixel_y < 4; pixel_y++) { | |
145 for (pixel_x = 0; pixel_x < 4; pixel_x++){ | |
146 pixels[block_ptr] = prev_pixels[block_ptr]; | |
147 block_ptr++; | |
148 } | |
149 block_ptr += row_inc; | |
150 } | |
151 ADVANCE_BLOCK(); | |
152 } | |
153 break; | |
154 | |
155 /* Fill blocks with one color */ | |
156 case 0xa0: | |
157 colorA = BE_16 (&s->buf[stream_ptr]); | |
158 stream_ptr += 2; | |
159 while (n_blocks--) { | |
160 block_ptr = row_ptr + pixel_ptr; | |
161 for (pixel_y = 0; pixel_y < 4; pixel_y++) { | |
162 for (pixel_x = 0; pixel_x < 4; pixel_x++){ | |
163 pixels[block_ptr] = colorA; | |
164 block_ptr++; | |
165 } | |
166 block_ptr += row_inc; | |
167 } | |
168 ADVANCE_BLOCK(); | |
169 } | |
170 break; | |
171 | |
172 /* Fill blocks with 4 colors */ | |
173 case 0xc0: | |
174 colorA = BE_16 (&s->buf[stream_ptr]); | |
175 stream_ptr += 2; | |
176 case 0x20: | |
177 colorB = BE_16 (&s->buf[stream_ptr]); | |
178 stream_ptr += 2; | |
179 | |
180 /* sort out the colors */ | |
181 color4[0] = colorB; | |
182 color4[1] = 0; | |
183 color4[2] = 0; | |
184 color4[3] = colorA; | |
185 | |
186 /* red components */ | |
187 ta = (colorA >> 10) & 0x1F; | |
188 tb = (colorB >> 10) & 0x1F; | |
189 color4[1] |= ((11 * ta + 21 * tb) >> 5) << 10; | |
190 color4[2] |= ((21 * ta + 11 * tb) >> 5) << 10; | |
191 | |
192 /* green components */ | |
193 ta = (colorA >> 5) & 0x1F; | |
194 tb = (colorB >> 5) & 0x1F; | |
195 color4[1] |= ((11 * ta + 21 * tb) >> 5) << 5; | |
196 color4[2] |= ((21 * ta + 11 * tb) >> 5) << 5; | |
197 | |
198 /* blue components */ | |
199 ta = colorA & 0x1F; | |
200 tb = colorB & 0x1F; | |
201 color4[1] |= ((11 * ta + 21 * tb) >> 5); | |
202 color4[2] |= ((21 * ta + 11 * tb) >> 5); | |
203 | |
204 while (n_blocks--) { | |
205 block_ptr = row_ptr + pixel_ptr; | |
206 for (pixel_y = 0; pixel_y < 4; pixel_y++) { | |
207 index = s->buf[stream_ptr++]; | |
208 for (pixel_x = 0; pixel_x < 4; pixel_x++){ | |
209 idx = (index >> (2 * (3 - pixel_x))) & 0x03; | |
210 pixels[block_ptr] = color4[idx]; | |
211 block_ptr++; | |
212 } | |
213 block_ptr += row_inc; | |
214 } | |
215 ADVANCE_BLOCK(); | |
216 } | |
217 break; | |
218 | |
219 /* Fill block with 16 colors */ | |
220 case 0x00: | |
221 block_ptr = row_ptr + pixel_ptr; | |
222 for (pixel_y = 0; pixel_y < 4; pixel_y++) { | |
223 for (pixel_x = 0; pixel_x < 4; pixel_x++){ | |
224 /* We already have color of upper left pixel */ | |
225 if ((pixel_y != 0) || (pixel_x !=0)) { | |
226 colorA = BE_16 (&s->buf[stream_ptr]); | |
227 stream_ptr += 2; | |
228 } | |
229 pixels[block_ptr] = colorA; | |
230 block_ptr++; | |
231 } | |
232 block_ptr += row_inc; | |
233 } | |
234 ADVANCE_BLOCK(); | |
235 break; | |
236 | |
237 /* Unknown opcode */ | |
238 default: | |
239 printf("Unknown opcode %d in rpza chunk." | |
240 " Skip remaining %d bytes of chunk data.\n", opcode, | |
241 chunk_size - stream_ptr); | |
242 return; | |
243 } /* Opcode switch */ | |
244 } | |
245 } | |
246 | |
247 static int rpza_decode_init(AVCodecContext *avctx) | |
248 { | |
249 RpzaContext *s = (RpzaContext *)avctx->priv_data; | |
250 | |
251 s->avctx = avctx; | |
252 avctx->pix_fmt = PIX_FMT_RGB555; | |
253 avctx->has_b_frames = 0; | |
254 dsputil_init(&s->dsp, avctx); | |
255 | |
256 s->frame.data[0] = s->prev_frame.data[0] = NULL; | |
257 | |
258 return 0; | |
259 } | |
260 | |
261 static int rpza_decode_frame(AVCodecContext *avctx, | |
262 void *data, int *data_size, | |
263 uint8_t *buf, int buf_size) | |
264 { | |
265 RpzaContext *s = (RpzaContext *)avctx->priv_data; | |
266 | |
267 s->buf = buf; | |
268 s->size = buf_size; | |
269 | |
270 if (avctx->get_buffer(avctx, &s->frame)) { | |
271 printf (" RPZA Video: get_buffer() failed\n"); | |
272 return -1; | |
273 } | |
274 | |
275 rpza_decode_stream(s); | |
276 | |
277 if (s->prev_frame.data[0]) | |
278 avctx->release_buffer(avctx, &s->prev_frame); | |
279 | |
280 /* shuffle frames */ | |
281 s->prev_frame = s->frame; | |
282 | |
283 *data_size = sizeof(AVFrame); | |
284 *(AVFrame*)data = s->frame; | |
285 | |
286 /* always report that the buffer was completely consumed */ | |
287 return buf_size; | |
288 } | |
289 | |
290 static int rpza_decode_end(AVCodecContext *avctx) | |
291 { | |
292 RpzaContext *s = (RpzaContext *)avctx->priv_data; | |
293 | |
294 if (s->prev_frame.data[0]) | |
295 avctx->release_buffer(avctx, &s->prev_frame); | |
296 | |
297 return 0; | |
298 } | |
299 | |
300 AVCodec rpza_decoder = { | |
301 "rpza", | |
302 CODEC_TYPE_VIDEO, | |
303 CODEC_ID_RPZA, | |
304 sizeof(RpzaContext), | |
305 rpza_decode_init, | |
306 NULL, | |
307 rpza_decode_end, | |
308 rpza_decode_frame, | |
309 CODEC_CAP_DR1, | |
310 }; |