1/* 2 * Quicktime Planar RGB (8BPS) Video Decoder 3 * Copyright (C) 2003 Roberto Togni 4 * 5 * This file is part of Libav. 6 * 7 * Libav 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 * Libav 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 Libav; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22/** 23 * @file 24 * QT 8BPS Video Decoder by Roberto Togni 25 * For more information about the 8BPS format, visit: 26 * http://www.pcisys.net/~melanson/codecs/ 27 * 28 * Supports: PAL8 (RGB 8bpp, paletted) 29 * : BGR24 (RGB 24bpp) (can also output it as RGB32) 30 * : RGB32 (RGB 32bpp, 4th plane is probably alpha and it's ignored) 31 * 32 */ 33 34#include <stdio.h> 35#include <stdlib.h> 36 37#include "libavutil/intreadwrite.h" 38#include "avcodec.h" 39 40 41static const enum PixelFormat pixfmt_rgb24[] = {PIX_FMT_BGR24, PIX_FMT_RGB32, PIX_FMT_NONE}; 42 43/* 44 * Decoder context 45 */ 46typedef struct EightBpsContext { 47 48 AVCodecContext *avctx; 49 AVFrame pic; 50 51 unsigned char planes; 52 unsigned char planemap[4]; 53 54 uint32_t pal[256]; 55} EightBpsContext; 56 57 58/* 59 * 60 * Decode a frame 61 * 62 */ 63static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPacket *avpkt) 64{ 65 const uint8_t *buf = avpkt->data; 66 int buf_size = avpkt->size; 67 EightBpsContext * const c = avctx->priv_data; 68 const unsigned char *encoded = buf; 69 unsigned char *pixptr, *pixptr_end; 70 unsigned int height = avctx->height; // Real image height 71 unsigned int dlen, p, row; 72 const unsigned char *lp, *dp; 73 unsigned char count; 74 unsigned int px_inc; 75 unsigned int planes = c->planes; 76 unsigned char *planemap = c->planemap; 77 78 if(c->pic.data[0]) 79 avctx->release_buffer(avctx, &c->pic); 80 81 c->pic.reference = 0; 82 c->pic.buffer_hints = FF_BUFFER_HINTS_VALID; 83 if(avctx->get_buffer(avctx, &c->pic) < 0){ 84 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); 85 return -1; 86 } 87 88 /* Set data pointer after line lengths */ 89 dp = encoded + planes * (height << 1); 90 91 /* Ignore alpha plane, don't know what to do with it */ 92 if (planes == 4) 93 planes--; 94 95 px_inc = planes + (avctx->pix_fmt == PIX_FMT_RGB32); 96 97 for (p = 0; p < planes; p++) { 98 /* Lines length pointer for this plane */ 99 lp = encoded + p * (height << 1); 100 101 /* Decode a plane */ 102 for(row = 0; row < height; row++) { 103 pixptr = c->pic.data[0] + row * c->pic.linesize[0] + planemap[p]; 104 pixptr_end = pixptr + c->pic.linesize[0]; 105 dlen = av_be2ne16(*(const unsigned short *)(lp+row*2)); 106 /* Decode a row of this plane */ 107 while(dlen > 0) { 108 if(dp + 1 >= buf+buf_size) return -1; 109 if ((count = *dp++) <= 127) { 110 count++; 111 dlen -= count + 1; 112 if (pixptr + count * px_inc > pixptr_end) 113 break; 114 if(dp + count > buf+buf_size) return -1; 115 while(count--) { 116 *pixptr = *dp++; 117 pixptr += px_inc; 118 } 119 } else { 120 count = 257 - count; 121 if (pixptr + count * px_inc > pixptr_end) 122 break; 123 while(count--) { 124 *pixptr = *dp; 125 pixptr += px_inc; 126 } 127 dp++; 128 dlen -= 2; 129 } 130 } 131 } 132 } 133 134 if (avctx->bits_per_coded_sample <= 8) { 135 const uint8_t *pal = av_packet_get_side_data(avpkt, 136 AV_PKT_DATA_PALETTE, 137 NULL); 138 if (pal) { 139 c->pic.palette_has_changed = 1; 140 memcpy(c->pal, pal, AVPALETTE_SIZE); 141 } 142 143 memcpy (c->pic.data[1], c->pal, AVPALETTE_SIZE); 144 } 145 146 *data_size = sizeof(AVFrame); 147 *(AVFrame*)data = c->pic; 148 149 /* always report that the buffer was completely consumed */ 150 return buf_size; 151} 152 153 154/* 155 * 156 * Init 8BPS decoder 157 * 158 */ 159static av_cold int decode_init(AVCodecContext *avctx) 160{ 161 EightBpsContext * const c = avctx->priv_data; 162 163 c->avctx = avctx; 164 165 c->pic.data[0] = NULL; 166 167 switch (avctx->bits_per_coded_sample) { 168 case 8: 169 avctx->pix_fmt = PIX_FMT_PAL8; 170 c->planes = 1; 171 c->planemap[0] = 0; // 1st plane is palette indexes 172 break; 173 case 24: 174 avctx->pix_fmt = avctx->get_format(avctx, pixfmt_rgb24); 175 c->planes = 3; 176 c->planemap[0] = 2; // 1st plane is red 177 c->planemap[1] = 1; // 2nd plane is green 178 c->planemap[2] = 0; // 3rd plane is blue 179 break; 180 case 32: 181 avctx->pix_fmt = PIX_FMT_RGB32; 182 c->planes = 4; 183#if HAVE_BIGENDIAN 184 c->planemap[0] = 1; // 1st plane is red 185 c->planemap[1] = 2; // 2nd plane is green 186 c->planemap[2] = 3; // 3rd plane is blue 187 c->planemap[3] = 0; // 4th plane is alpha??? 188#else 189 c->planemap[0] = 2; // 1st plane is red 190 c->planemap[1] = 1; // 2nd plane is green 191 c->planemap[2] = 0; // 3rd plane is blue 192 c->planemap[3] = 3; // 4th plane is alpha??? 193#endif 194 break; 195 default: 196 av_log(avctx, AV_LOG_ERROR, "Error: Unsupported color depth: %u.\n", avctx->bits_per_coded_sample); 197 return -1; 198 } 199 200 return 0; 201} 202 203 204 205 206/* 207 * 208 * Uninit 8BPS decoder 209 * 210 */ 211static av_cold int decode_end(AVCodecContext *avctx) 212{ 213 EightBpsContext * const c = avctx->priv_data; 214 215 if (c->pic.data[0]) 216 avctx->release_buffer(avctx, &c->pic); 217 218 return 0; 219} 220 221 222 223AVCodec ff_eightbps_decoder = { 224 .name = "8bps", 225 .type = AVMEDIA_TYPE_VIDEO, 226 .id = CODEC_ID_8BPS, 227 .priv_data_size = sizeof(EightBpsContext), 228 .init = decode_init, 229 .close = decode_end, 230 .decode = decode_frame, 231 .capabilities = CODEC_CAP_DR1, 232 .long_name = NULL_IF_CONFIG_SMALL("QuickTime 8BPS video"), 233}; 234