Libav 0.7.1
|
00001 /* 00002 * Quicktime Video (RPZA) Video Decoder 00003 * Copyright (C) 2003 the ffmpeg project 00004 * 00005 * This file is part of Libav. 00006 * 00007 * Libav is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * Libav is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with Libav; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00020 */ 00021 00037 #include <stdio.h> 00038 #include <stdlib.h> 00039 #include <string.h> 00040 00041 #include "libavutil/intreadwrite.h" 00042 #include "avcodec.h" 00043 00044 typedef struct RpzaContext { 00045 00046 AVCodecContext *avctx; 00047 AVFrame frame; 00048 00049 const unsigned char *buf; 00050 int size; 00051 00052 } RpzaContext; 00053 00054 #define ADVANCE_BLOCK() \ 00055 { \ 00056 pixel_ptr += 4; \ 00057 if (pixel_ptr >= width) \ 00058 { \ 00059 pixel_ptr = 0; \ 00060 row_ptr += stride * 4; \ 00061 } \ 00062 total_blocks--; \ 00063 if (total_blocks < 0) \ 00064 { \ 00065 av_log(s->avctx, AV_LOG_ERROR, "warning: block counter just went negative (this should not happen)\n"); \ 00066 return; \ 00067 } \ 00068 } 00069 00070 static void rpza_decode_stream(RpzaContext *s) 00071 { 00072 int width = s->avctx->width; 00073 int stride = s->frame.linesize[0] / 2; 00074 int row_inc = stride - 4; 00075 int stream_ptr = 0; 00076 int chunk_size; 00077 unsigned char opcode; 00078 int n_blocks; 00079 unsigned short colorA = 0, colorB; 00080 unsigned short color4[4]; 00081 unsigned char index, idx; 00082 unsigned short ta, tb; 00083 unsigned short *pixels = (unsigned short *)s->frame.data[0]; 00084 00085 int row_ptr = 0; 00086 int pixel_ptr = 0; 00087 int block_ptr; 00088 int pixel_x, pixel_y; 00089 int total_blocks; 00090 00091 /* First byte is always 0xe1. Warn if it's different */ 00092 if (s->buf[stream_ptr] != 0xe1) 00093 av_log(s->avctx, AV_LOG_ERROR, "First chunk byte is 0x%02x instead of 0xe1\n", 00094 s->buf[stream_ptr]); 00095 00096 /* Get chunk size, ingnoring first byte */ 00097 chunk_size = AV_RB32(&s->buf[stream_ptr]) & 0x00FFFFFF; 00098 stream_ptr += 4; 00099 00100 /* If length mismatch use size from MOV file and try to decode anyway */ 00101 if (chunk_size != s->size) 00102 av_log(s->avctx, AV_LOG_ERROR, "MOV chunk size != encoded chunk size; using MOV chunk size\n"); 00103 00104 chunk_size = s->size; 00105 00106 /* Number of 4x4 blocks in frame. */ 00107 total_blocks = ((s->avctx->width + 3) / 4) * ((s->avctx->height + 3) / 4); 00108 00109 /* Process chunk data */ 00110 while (stream_ptr < chunk_size) { 00111 opcode = s->buf[stream_ptr++]; /* Get opcode */ 00112 00113 n_blocks = (opcode & 0x1f) + 1; /* Extract block counter from opcode */ 00114 00115 /* If opcode MSbit is 0, we need more data to decide what to do */ 00116 if ((opcode & 0x80) == 0) { 00117 colorA = (opcode << 8) | (s->buf[stream_ptr++]); 00118 opcode = 0; 00119 if ((s->buf[stream_ptr] & 0x80) != 0) { 00120 /* Must behave as opcode 110xxxxx, using colorA computed 00121 * above. Use fake opcode 0x20 to enter switch block at 00122 * the right place */ 00123 opcode = 0x20; 00124 n_blocks = 1; 00125 } 00126 } 00127 00128 switch (opcode & 0xe0) { 00129 00130 /* Skip blocks */ 00131 case 0x80: 00132 while (n_blocks--) { 00133 ADVANCE_BLOCK(); 00134 } 00135 break; 00136 00137 /* Fill blocks with one color */ 00138 case 0xa0: 00139 colorA = AV_RB16 (&s->buf[stream_ptr]); 00140 stream_ptr += 2; 00141 while (n_blocks--) { 00142 block_ptr = row_ptr + pixel_ptr; 00143 for (pixel_y = 0; pixel_y < 4; pixel_y++) { 00144 for (pixel_x = 0; pixel_x < 4; pixel_x++){ 00145 pixels[block_ptr] = colorA; 00146 block_ptr++; 00147 } 00148 block_ptr += row_inc; 00149 } 00150 ADVANCE_BLOCK(); 00151 } 00152 break; 00153 00154 /* Fill blocks with 4 colors */ 00155 case 0xc0: 00156 colorA = AV_RB16 (&s->buf[stream_ptr]); 00157 stream_ptr += 2; 00158 case 0x20: 00159 colorB = AV_RB16 (&s->buf[stream_ptr]); 00160 stream_ptr += 2; 00161 00162 /* sort out the colors */ 00163 color4[0] = colorB; 00164 color4[1] = 0; 00165 color4[2] = 0; 00166 color4[3] = colorA; 00167 00168 /* red components */ 00169 ta = (colorA >> 10) & 0x1F; 00170 tb = (colorB >> 10) & 0x1F; 00171 color4[1] |= ((11 * ta + 21 * tb) >> 5) << 10; 00172 color4[2] |= ((21 * ta + 11 * tb) >> 5) << 10; 00173 00174 /* green components */ 00175 ta = (colorA >> 5) & 0x1F; 00176 tb = (colorB >> 5) & 0x1F; 00177 color4[1] |= ((11 * ta + 21 * tb) >> 5) << 5; 00178 color4[2] |= ((21 * ta + 11 * tb) >> 5) << 5; 00179 00180 /* blue components */ 00181 ta = colorA & 0x1F; 00182 tb = colorB & 0x1F; 00183 color4[1] |= ((11 * ta + 21 * tb) >> 5); 00184 color4[2] |= ((21 * ta + 11 * tb) >> 5); 00185 00186 if (s->size - stream_ptr < n_blocks * 4) 00187 return; 00188 while (n_blocks--) { 00189 block_ptr = row_ptr + pixel_ptr; 00190 for (pixel_y = 0; pixel_y < 4; pixel_y++) { 00191 index = s->buf[stream_ptr++]; 00192 for (pixel_x = 0; pixel_x < 4; pixel_x++){ 00193 idx = (index >> (2 * (3 - pixel_x))) & 0x03; 00194 pixels[block_ptr] = color4[idx]; 00195 block_ptr++; 00196 } 00197 block_ptr += row_inc; 00198 } 00199 ADVANCE_BLOCK(); 00200 } 00201 break; 00202 00203 /* Fill block with 16 colors */ 00204 case 0x00: 00205 if (s->size - stream_ptr < 16) 00206 return; 00207 block_ptr = row_ptr + pixel_ptr; 00208 for (pixel_y = 0; pixel_y < 4; pixel_y++) { 00209 for (pixel_x = 0; pixel_x < 4; pixel_x++){ 00210 /* We already have color of upper left pixel */ 00211 if ((pixel_y != 0) || (pixel_x !=0)) { 00212 colorA = AV_RB16 (&s->buf[stream_ptr]); 00213 stream_ptr += 2; 00214 } 00215 pixels[block_ptr] = colorA; 00216 block_ptr++; 00217 } 00218 block_ptr += row_inc; 00219 } 00220 ADVANCE_BLOCK(); 00221 break; 00222 00223 /* Unknown opcode */ 00224 default: 00225 av_log(s->avctx, AV_LOG_ERROR, "Unknown opcode %d in rpza chunk." 00226 " Skip remaining %d bytes of chunk data.\n", opcode, 00227 chunk_size - stream_ptr); 00228 return; 00229 } /* Opcode switch */ 00230 } 00231 } 00232 00233 static av_cold int rpza_decode_init(AVCodecContext *avctx) 00234 { 00235 RpzaContext *s = avctx->priv_data; 00236 00237 s->avctx = avctx; 00238 avctx->pix_fmt = PIX_FMT_RGB555; 00239 00240 s->frame.data[0] = NULL; 00241 00242 return 0; 00243 } 00244 00245 static int rpza_decode_frame(AVCodecContext *avctx, 00246 void *data, int *data_size, 00247 AVPacket *avpkt) 00248 { 00249 const uint8_t *buf = avpkt->data; 00250 int buf_size = avpkt->size; 00251 RpzaContext *s = avctx->priv_data; 00252 00253 s->buf = buf; 00254 s->size = buf_size; 00255 00256 s->frame.reference = 1; 00257 s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE; 00258 if (avctx->reget_buffer(avctx, &s->frame)) { 00259 av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); 00260 return -1; 00261 } 00262 00263 rpza_decode_stream(s); 00264 00265 *data_size = sizeof(AVFrame); 00266 *(AVFrame*)data = s->frame; 00267 00268 /* always report that the buffer was completely consumed */ 00269 return buf_size; 00270 } 00271 00272 static av_cold int rpza_decode_end(AVCodecContext *avctx) 00273 { 00274 RpzaContext *s = avctx->priv_data; 00275 00276 if (s->frame.data[0]) 00277 avctx->release_buffer(avctx, &s->frame); 00278 00279 return 0; 00280 } 00281 00282 AVCodec ff_rpza_decoder = { 00283 "rpza", 00284 AVMEDIA_TYPE_VIDEO, 00285 CODEC_ID_RPZA, 00286 sizeof(RpzaContext), 00287 rpza_decode_init, 00288 NULL, 00289 rpza_decode_end, 00290 rpza_decode_frame, 00291 CODEC_CAP_DR1, 00292 .long_name = NULL_IF_CONFIG_SMALL("QuickTime video (RPZA)"), 00293 };