]> git.sesse.net Git - ffmpeg/blob - libavcodec/rpza.c
static (inline) X => ff_X
[ffmpeg] / 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 "avcodec.h"
44 #include "dsputil.h"
45
46 typedef struct RpzaContext {
47
48     AVCodecContext *avctx;
49     DSPContext dsp;
50     AVFrame frame;
51
52     unsigned char *buf;
53     int size;
54
55 } RpzaContext;
56
57 #define ADVANCE_BLOCK() \
58 { \
59     pixel_ptr += 4; \
60     if (pixel_ptr >= width) \
61     { \
62         pixel_ptr = 0; \
63         row_ptr += stride * 4; \
64     } \
65     total_blocks--; \
66     if (total_blocks < 0) \
67     { \
68         av_log(s->avctx, AV_LOG_ERROR, "warning: block counter just went negative (this should not happen)\n"); \
69         return; \
70     } \
71 }
72
73 static void rpza_decode_stream(RpzaContext *s)
74 {
75     int width = s->avctx->width;
76     int stride = s->frame.linesize[0] / 2;
77     int row_inc = stride - 4;
78     int stream_ptr = 0;
79     int chunk_size;
80     unsigned char opcode;
81     int n_blocks;
82     unsigned short colorA = 0, colorB;
83     unsigned short color4[4];
84     unsigned char index, idx;
85     unsigned short ta, tb;
86     unsigned short *pixels = (unsigned short *)s->frame.data[0];
87
88     int row_ptr = 0;
89     int pixel_ptr = 0;
90     int block_ptr;
91     int pixel_x, pixel_y;
92     int total_blocks;
93
94     /* First byte is always 0xe1. Warn if it's different */
95     if (s->buf[stream_ptr] != 0xe1)
96         av_log(s->avctx, AV_LOG_ERROR, "First chunk byte is 0x%02x instead of 0xe1\n",
97             s->buf[stream_ptr]);
98
99     /* Get chunk size, ingnoring first byte */
100     chunk_size = AV_RB32(&s->buf[stream_ptr]) & 0x00FFFFFF;
101     stream_ptr += 4;
102
103     /* If length mismatch use size from MOV file and try to decode anyway */
104     if (chunk_size != s->size)
105         av_log(s->avctx, AV_LOG_ERROR, "MOV chunk size != encoded chunk size; using MOV chunk size\n");
106
107     chunk_size = s->size;
108
109     /* Number of 4x4 blocks in frame. */
110     total_blocks = ((s->avctx->width + 3) / 4) * ((s->avctx->height + 3) / 4);
111
112     /* Process chunk data */
113     while (stream_ptr < chunk_size) {
114         opcode = s->buf[stream_ptr++]; /* Get opcode */
115
116         n_blocks = (opcode & 0x1f) + 1; /* Extract block counter from opcode */
117
118         /* If opcode MSbit is 0, we need more data to decide what to do */
119         if ((opcode & 0x80) == 0) {
120             colorA = (opcode << 8) | (s->buf[stream_ptr++]);
121             opcode = 0;
122             if ((s->buf[stream_ptr] & 0x80) != 0) {
123                 /* Must behave as opcode 110xxxxx, using colorA computed
124                  * above. Use fake opcode 0x20 to enter switch block at
125                  * the right place */
126                 opcode = 0x20;
127                 n_blocks = 1;
128             }
129         }
130
131         switch (opcode & 0xe0) {
132
133         /* Skip blocks */
134         case 0x80:
135             while (n_blocks--) {
136               ADVANCE_BLOCK();
137             }
138             break;
139
140         /* Fill blocks with one color */
141         case 0xa0:
142             colorA = AV_RB16 (&s->buf[stream_ptr]);
143             stream_ptr += 2;
144             while (n_blocks--) {
145                 block_ptr = row_ptr + pixel_ptr;
146                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
147                     for (pixel_x = 0; pixel_x < 4; pixel_x++){
148                         pixels[block_ptr] = colorA;
149                         block_ptr++;
150                     }
151                     block_ptr += row_inc;
152                 }
153                 ADVANCE_BLOCK();
154             }
155             break;
156
157         /* Fill blocks with 4 colors */
158         case 0xc0:
159             colorA = AV_RB16 (&s->buf[stream_ptr]);
160             stream_ptr += 2;
161         case 0x20:
162             colorB = AV_RB16 (&s->buf[stream_ptr]);
163             stream_ptr += 2;
164
165             /* sort out the colors */
166             color4[0] = colorB;
167             color4[1] = 0;
168             color4[2] = 0;
169             color4[3] = colorA;
170
171             /* red components */
172             ta = (colorA >> 10) & 0x1F;
173             tb = (colorB >> 10) & 0x1F;
174             color4[1] |= ((11 * ta + 21 * tb) >> 5) << 10;
175             color4[2] |= ((21 * ta + 11 * tb) >> 5) << 10;
176
177             /* green components */
178             ta = (colorA >> 5) & 0x1F;
179             tb = (colorB >> 5) & 0x1F;
180             color4[1] |= ((11 * ta + 21 * tb) >> 5) << 5;
181             color4[2] |= ((21 * ta + 11 * tb) >> 5) << 5;
182
183             /* blue components */
184             ta = colorA & 0x1F;
185             tb = colorB & 0x1F;
186             color4[1] |= ((11 * ta + 21 * tb) >> 5);
187             color4[2] |= ((21 * ta + 11 * tb) >> 5);
188
189             while (n_blocks--) {
190                 block_ptr = row_ptr + pixel_ptr;
191                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
192                     index = s->buf[stream_ptr++];
193                     for (pixel_x = 0; pixel_x < 4; pixel_x++){
194                         idx = (index >> (2 * (3 - pixel_x))) & 0x03;
195                         pixels[block_ptr] = color4[idx];
196                         block_ptr++;
197                     }
198                     block_ptr += row_inc;
199                 }
200                 ADVANCE_BLOCK();
201             }
202             break;
203
204         /* Fill block with 16 colors */
205         case 0x00:
206             block_ptr = row_ptr + pixel_ptr;
207             for (pixel_y = 0; pixel_y < 4; pixel_y++) {
208                 for (pixel_x = 0; pixel_x < 4; pixel_x++){
209                     /* We already have color of upper left pixel */
210                     if ((pixel_y != 0) || (pixel_x !=0)) {
211                         colorA = AV_RB16 (&s->buf[stream_ptr]);
212                         stream_ptr += 2;
213                     }
214                     pixels[block_ptr] = colorA;
215                     block_ptr++;
216                 }
217                 block_ptr += row_inc;
218             }
219             ADVANCE_BLOCK();
220             break;
221
222         /* Unknown opcode */
223         default:
224             av_log(s->avctx, AV_LOG_ERROR, "Unknown opcode %d in rpza chunk."
225                  " Skip remaining %d bytes of chunk data.\n", opcode,
226                  chunk_size - stream_ptr);
227             return;
228         } /* Opcode switch */
229     }
230 }
231
232 static int rpza_decode_init(AVCodecContext *avctx)
233 {
234     RpzaContext *s = avctx->priv_data;
235
236     s->avctx = avctx;
237     avctx->pix_fmt = PIX_FMT_RGB555;
238     dsputil_init(&s->dsp, avctx);
239
240     s->frame.data[0] = NULL;
241
242     return 0;
243 }
244
245 static int rpza_decode_frame(AVCodecContext *avctx,
246                              void *data, int *data_size,
247                              uint8_t *buf, int buf_size)
248 {
249     RpzaContext *s = avctx->priv_data;
250
251     s->buf = buf;
252     s->size = buf_size;
253
254     s->frame.reference = 1;
255     s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;
256     if (avctx->reget_buffer(avctx, &s->frame)) {
257         av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
258         return -1;
259     }
260
261     rpza_decode_stream(s);
262
263     *data_size = sizeof(AVFrame);
264     *(AVFrame*)data = s->frame;
265
266     /* always report that the buffer was completely consumed */
267     return buf_size;
268 }
269
270 static int rpza_decode_end(AVCodecContext *avctx)
271 {
272     RpzaContext *s = avctx->priv_data;
273
274     if (s->frame.data[0])
275         avctx->release_buffer(avctx, &s->frame);
276
277     return 0;
278 }
279
280 AVCodec rpza_decoder = {
281     "rpza",
282     CODEC_TYPE_VIDEO,
283     CODEC_ID_RPZA,
284     sizeof(RpzaContext),
285     rpza_decode_init,
286     NULL,
287     rpza_decode_end,
288     rpza_decode_frame,
289     CODEC_CAP_DR1,
290 };