]> rtime.felk.cvut.cz Git - frescor/ffmpeg.git/blob - libavcodec/rpza.c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
[frescor/ffmpeg.git] / libavcodec / rpza.c
1 /*
2  * Quicktime Video (RPZA) Video Decoder
3  * Copyright (C) 2003 the ffmpeg project
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  *
21  */
22
23 /**
24  * @file rpza.c
25  * QT RPZA Video Decoder by Roberto Togni <rtogni@bresciaonline.it>
26  * For more information about the RPZA format, visit:
27  *   http://www.pcisys.net/~melanson/codecs/
28  *
29  * The RPZA decoder outputs RGB555 colorspace data.
30  *
31  * Note that this decoder reads big endian RGB555 pixel values from the
32  * bytestream, arranges them in the host's endian order, and outputs
33  * them to the final rendered map in the same host endian order. This is
34  * intended behavior as the ffmpeg documentation states that RGB555 pixels
35  * shall be stored in native CPU endianness.
36  */
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42
43 #include "common.h"
44 #include "avcodec.h"
45 #include "dsputil.h"
46
47 typedef struct RpzaContext {
48
49     AVCodecContext *avctx;
50     DSPContext dsp;
51     AVFrame frame;
52
53     unsigned char *buf;
54     int size;
55
56 } RpzaContext;
57
58 #define ADVANCE_BLOCK() \
59 { \
60     pixel_ptr += 4; \
61     if (pixel_ptr >= width) \
62     { \
63         pixel_ptr = 0; \
64         row_ptr += stride * 4; \
65     } \
66     total_blocks--; \
67     if (total_blocks < 0) \
68     { \
69         av_log(s->avctx, AV_LOG_ERROR, "warning: block counter just went negative (this should not happen)\n"); \
70         return; \
71     } \
72 }
73
74 static void rpza_decode_stream(RpzaContext *s)
75 {
76     int width = s->avctx->width;
77     int stride = s->frame.linesize[0] / 2;
78     int row_inc = stride - 4;
79     int stream_ptr = 0;
80     int chunk_size;
81     unsigned char opcode;
82     int n_blocks;
83     unsigned short colorA = 0, colorB;
84     unsigned short color4[4];
85     unsigned char index, idx;
86     unsigned short ta, tb;
87     unsigned short *pixels = (unsigned short *)s->frame.data[0];
88
89     int row_ptr = 0;
90     int pixel_ptr = 0;
91     int block_ptr;
92     int pixel_x, pixel_y;
93     int total_blocks;
94
95     /* First byte is always 0xe1. Warn if it's different */
96     if (s->buf[stream_ptr] != 0xe1)
97         av_log(s->avctx, AV_LOG_ERROR, "First chunk byte is 0x%02x instead of 0xe1\n",
98             s->buf[stream_ptr]);
99
100     /* Get chunk size, ingnoring first byte */
101     chunk_size = BE_32(&s->buf[stream_ptr]) & 0x00FFFFFF;
102     stream_ptr += 4;
103
104     /* If length mismatch use size from MOV file and try to decode anyway */
105     if (chunk_size != s->size)
106         av_log(s->avctx, AV_LOG_ERROR, "MOV chunk size != encoded chunk size; using MOV chunk size\n");
107
108     chunk_size = s->size;
109
110     /* Number of 4x4 blocks in frame. */
111     total_blocks = ((s->avctx->width + 3) / 4) * ((s->avctx->height + 3) / 4);
112
113     /* Process chunk data */
114     while (stream_ptr < chunk_size) {
115         opcode = s->buf[stream_ptr++]; /* Get opcode */
116
117         n_blocks = (opcode & 0x1f) + 1; /* Extract block counter from opcode */
118
119         /* If opcode MSbit is 0, we need more data to decide what to do */
120         if ((opcode & 0x80) == 0) {
121             colorA = (opcode << 8) | (s->buf[stream_ptr++]);
122             opcode = 0;
123             if ((s->buf[stream_ptr] & 0x80) != 0) {
124                 /* Must behave as opcode 110xxxxx, using colorA computed
125                  * above. Use fake opcode 0x20 to enter switch block at
126                  * the right place */
127                 opcode = 0x20;
128                 n_blocks = 1;
129             }
130         }
131
132         switch (opcode & 0xe0) {
133
134         /* Skip blocks */
135         case 0x80:
136             while (n_blocks--) {
137               ADVANCE_BLOCK();
138             }
139             break;
140
141         /* Fill blocks with one color */
142         case 0xa0:
143             colorA = BE_16 (&s->buf[stream_ptr]);
144             stream_ptr += 2;
145             while (n_blocks--) {
146                 block_ptr = row_ptr + pixel_ptr;
147                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
148                     for (pixel_x = 0; pixel_x < 4; pixel_x++){
149                         pixels[block_ptr] = colorA;
150                         block_ptr++;
151                     }
152                     block_ptr += row_inc;
153                 }
154                 ADVANCE_BLOCK();
155             }
156             break;
157
158         /* Fill blocks with 4 colors */
159         case 0xc0:
160             colorA = BE_16 (&s->buf[stream_ptr]);
161             stream_ptr += 2;
162         case 0x20:
163             colorB = BE_16 (&s->buf[stream_ptr]);
164             stream_ptr += 2;
165
166             /* sort out the colors */
167             color4[0] = colorB;
168             color4[1] = 0;
169             color4[2] = 0;
170             color4[3] = colorA;
171
172             /* red components */
173             ta = (colorA >> 10) & 0x1F;
174             tb = (colorB >> 10) & 0x1F;
175             color4[1] |= ((11 * ta + 21 * tb) >> 5) << 10;
176             color4[2] |= ((21 * ta + 11 * tb) >> 5) << 10;
177
178             /* green components */
179             ta = (colorA >> 5) & 0x1F;
180             tb = (colorB >> 5) & 0x1F;
181             color4[1] |= ((11 * ta + 21 * tb) >> 5) << 5;
182             color4[2] |= ((21 * ta + 11 * tb) >> 5) << 5;
183
184             /* blue components */
185             ta = colorA & 0x1F;
186             tb = colorB & 0x1F;
187             color4[1] |= ((11 * ta + 21 * tb) >> 5);
188             color4[2] |= ((21 * ta + 11 * tb) >> 5);
189
190             while (n_blocks--) {
191                 block_ptr = row_ptr + pixel_ptr;
192                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
193                     index = s->buf[stream_ptr++];
194                     for (pixel_x = 0; pixel_x < 4; pixel_x++){
195                         idx = (index >> (2 * (3 - pixel_x))) & 0x03;
196                         pixels[block_ptr] = color4[idx];
197                         block_ptr++;
198                     }
199                     block_ptr += row_inc;
200                 }
201                 ADVANCE_BLOCK();
202             }
203             break;
204
205         /* Fill block with 16 colors */
206         case 0x00:
207             block_ptr = row_ptr + pixel_ptr;
208             for (pixel_y = 0; pixel_y < 4; pixel_y++) {
209                 for (pixel_x = 0; pixel_x < 4; pixel_x++){
210                     /* We already have color of upper left pixel */
211                     if ((pixel_y != 0) || (pixel_x !=0)) {
212                         colorA = BE_16 (&s->buf[stream_ptr]);
213                         stream_ptr += 2;
214                     }
215                     pixels[block_ptr] = colorA;
216                     block_ptr++;
217                 }
218                 block_ptr += row_inc;
219             }
220             ADVANCE_BLOCK();
221             break;
222
223         /* Unknown opcode */
224         default:
225             av_log(s->avctx, AV_LOG_ERROR, "Unknown opcode %d in rpza chunk."
226                  " Skip remaining %d bytes of chunk data.\n", opcode,
227                  chunk_size - stream_ptr);
228             return;
229         } /* Opcode switch */
230     }
231 }
232
233 static int rpza_decode_init(AVCodecContext *avctx)
234 {
235     RpzaContext *s = (RpzaContext *)avctx->priv_data;
236
237     s->avctx = avctx;
238     avctx->pix_fmt = PIX_FMT_RGB555;
239     avctx->has_b_frames = 0;
240     dsputil_init(&s->dsp, avctx);
241
242     s->frame.data[0] = NULL;
243
244     return 0;
245 }
246
247 static int rpza_decode_frame(AVCodecContext *avctx,
248                              void *data, int *data_size,
249                              uint8_t *buf, int buf_size)
250 {
251     RpzaContext *s = (RpzaContext *)avctx->priv_data;
252
253     s->buf = buf;
254     s->size = buf_size;
255
256     s->frame.reference = 1;
257     s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;
258     if (avctx->reget_buffer(avctx, &s->frame)) {
259         av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
260         return -1;
261     }
262
263     rpza_decode_stream(s);
264
265     *data_size = sizeof(AVFrame);
266     *(AVFrame*)data = s->frame;
267
268     /* always report that the buffer was completely consumed */
269     return buf_size;
270 }
271
272 static int rpza_decode_end(AVCodecContext *avctx)
273 {
274     RpzaContext *s = (RpzaContext *)avctx->priv_data;
275
276     if (s->frame.data[0])
277         avctx->release_buffer(avctx, &s->frame);
278
279     return 0;
280 }
281
282 AVCodec rpza_decoder = {
283     "rpza",
284     CODEC_TYPE_VIDEO,
285     CODEC_ID_RPZA,
286     sizeof(RpzaContext),
287     rpza_decode_init,
288     NULL,
289     rpza_decode_end,
290     rpza_decode_frame,
291     CODEC_CAP_DR1,
292 };