1/* 2 * Quicktime Planar RGB (8BPS) Video Decoder 3 * Copyright (C) 2003 Roberto Togni 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 * @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 alpha) 31 * 32 */ 33 34#include <stdio.h> 35#include <stdlib.h> 36#include <string.h> 37 38#include "libavutil/internal.h" 39#include "libavutil/intreadwrite.h" 40#include "avcodec.h" 41#include "internal.h" 42 43 44static const enum AVPixelFormat pixfmt_rgb24[] = { 45 AV_PIX_FMT_BGR24, AV_PIX_FMT_RGB32, AV_PIX_FMT_NONE }; 46 47typedef struct EightBpsContext { 48 AVCodecContext *avctx; 49 50 unsigned char planes; 51 unsigned char planemap[4]; 52 53 uint32_t pal[256]; 54} EightBpsContext; 55 56static int decode_frame(AVCodecContext *avctx, void *data, 57 int *got_frame, AVPacket *avpkt) 58{ 59 AVFrame *frame = data; 60 const uint8_t *buf = avpkt->data; 61 int buf_size = avpkt->size; 62 EightBpsContext * const c = avctx->priv_data; 63 const unsigned char *encoded = buf; 64 unsigned char *pixptr, *pixptr_end; 65 unsigned int height = avctx->height; // Real image height 66 unsigned int dlen, p, row; 67 const unsigned char *lp, *dp, *ep; 68 unsigned char count; 69 unsigned int planes = c->planes; 70 unsigned char *planemap = c->planemap; 71 int ret; 72 73 if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) 74 return ret; 75 76 ep = encoded + buf_size; 77 78 /* Set data pointer after line lengths */ 79 dp = encoded + planes * (height << 1); 80 81 for (p = 0; p < planes; p++) { 82 /* Lines length pointer for this plane */ 83 lp = encoded + p * (height << 1); 84 85 /* Decode a plane */ 86 for (row = 0; row < height; row++) { 87 pixptr = frame->data[0] + row * frame->linesize[0] + planemap[p]; 88 pixptr_end = pixptr + frame->linesize[0]; 89 if (ep - lp < row * 2 + 2) 90 return AVERROR_INVALIDDATA; 91 dlen = av_be2ne16(*(const unsigned short *)(lp + row * 2)); 92 /* Decode a row of this plane */ 93 while (dlen > 0) { 94 if (ep - dp <= 1) 95 return AVERROR_INVALIDDATA; 96 if ((count = *dp++) <= 127) { 97 count++; 98 dlen -= count + 1; 99 if (pixptr_end - pixptr < count * planes) 100 break; 101 if (ep - dp < count) 102 return AVERROR_INVALIDDATA; 103 while (count--) { 104 *pixptr = *dp++; 105 pixptr += planes; 106 } 107 } else { 108 count = 257 - count; 109 if (pixptr_end - pixptr < count * planes) 110 break; 111 while (count--) { 112 *pixptr = *dp; 113 pixptr += planes; 114 } 115 dp++; 116 dlen -= 2; 117 } 118 } 119 } 120 } 121 122 if (avctx->bits_per_coded_sample <= 8) { 123 const uint8_t *pal = av_packet_get_side_data(avpkt, 124 AV_PKT_DATA_PALETTE, 125 NULL); 126 if (pal) { 127 frame->palette_has_changed = 1; 128 memcpy(c->pal, pal, AVPALETTE_SIZE); 129 } 130 131 memcpy (frame->data[1], c->pal, AVPALETTE_SIZE); 132 } 133 134 *got_frame = 1; 135 136 /* always report that the buffer was completely consumed */ 137 return buf_size; 138} 139 140static av_cold int decode_init(AVCodecContext *avctx) 141{ 142 EightBpsContext * const c = avctx->priv_data; 143 144 c->avctx = avctx; 145 146 switch (avctx->bits_per_coded_sample) { 147 case 8: 148 avctx->pix_fmt = AV_PIX_FMT_PAL8; 149 c->planes = 1; 150 c->planemap[0] = 0; // 1st plane is palette indexes 151 break; 152 case 24: 153 avctx->pix_fmt = ff_get_format(avctx, pixfmt_rgb24); 154 c->planes = 3; 155 c->planemap[0] = 2; // 1st plane is red 156 c->planemap[1] = 1; // 2nd plane is green 157 c->planemap[2] = 0; // 3rd plane is blue 158 break; 159 case 32: 160 avctx->pix_fmt = AV_PIX_FMT_RGB32; 161 c->planes = 4; 162 /* handle planemap setup later for decoding rgb24 data as rbg32 */ 163 break; 164 default: 165 av_log(avctx, AV_LOG_ERROR, "Error: Unsupported color depth: %u.\n", 166 avctx->bits_per_coded_sample); 167 return AVERROR_INVALIDDATA; 168 } 169 170 if (avctx->pix_fmt == AV_PIX_FMT_RGB32) { 171 c->planemap[0] = HAVE_BIGENDIAN ? 1 : 2; // 1st plane is red 172 c->planemap[1] = HAVE_BIGENDIAN ? 2 : 1; // 2nd plane is green 173 c->planemap[2] = HAVE_BIGENDIAN ? 3 : 0; // 3rd plane is blue 174 c->planemap[3] = HAVE_BIGENDIAN ? 0 : 3; // 4th plane is alpha 175 } 176 return 0; 177} 178 179AVCodec ff_eightbps_decoder = { 180 .name = "8bps", 181 .long_name = NULL_IF_CONFIG_SMALL("QuickTime 8BPS video"), 182 .type = AVMEDIA_TYPE_VIDEO, 183 .id = AV_CODEC_ID_8BPS, 184 .priv_data_size = sizeof(EightBpsContext), 185 .init = decode_init, 186 .decode = decode_frame, 187 .capabilities = CODEC_CAP_DR1, 188}; 189