1/* 2 * Tiertex Limited SEQ Video Decoder 3 * Copyright (c) 2006 Gregory Montoir (cyx@users.sourceforge.net) 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 * Tiertex Limited SEQ video decoder 25 */ 26 27#define BITSTREAM_READER_LE 28#include "avcodec.h" 29#include "codec_internal.h" 30#include "get_bits.h" 31#include "internal.h" 32 33 34typedef struct SeqVideoContext { 35 AVCodecContext *avctx; 36 AVFrame *frame; 37} SeqVideoContext; 38 39 40static const unsigned char *seq_unpack_rle_block(const unsigned char *src, 41 const unsigned char *src_end, 42 unsigned char *dst, int dst_size) 43{ 44 int i, len, sz; 45 GetBitContext gb; 46 int code_table[64]; 47 48 /* get the rle codes */ 49 init_get_bits(&gb, src, (src_end - src) * 8); 50 for (i = 0, sz = 0; i < 64 && sz < dst_size; i++) { 51 if (get_bits_left(&gb) < 4) 52 return NULL; 53 code_table[i] = get_sbits(&gb, 4); 54 sz += FFABS(code_table[i]); 55 } 56 src += (get_bits_count(&gb) + 7) / 8; 57 58 /* do the rle unpacking */ 59 for (i = 0; i < 64 && dst_size > 0; i++) { 60 len = code_table[i]; 61 if (len < 0) { 62 len = -len; 63 if (src_end - src < 1) 64 return NULL; 65 memset(dst, *src++, FFMIN(len, dst_size)); 66 } else { 67 if (src_end - src < len) 68 return NULL; 69 memcpy(dst, src, FFMIN(len, dst_size)); 70 src += len; 71 } 72 dst += len; 73 dst_size -= len; 74 } 75 return src; 76} 77 78static const unsigned char *seq_decode_op1(SeqVideoContext *seq, 79 const unsigned char *src, 80 const unsigned char *src_end, 81 unsigned char *dst) 82{ 83 const unsigned char *color_table; 84 int b, i, len, bits; 85 GetBitContext gb; 86 unsigned char block[8 * 8]; 87 88 if (src_end - src < 1) 89 return NULL; 90 len = *src++; 91 if (len & 0x80) { 92 switch (len & 3) { 93 case 1: 94 src = seq_unpack_rle_block(src, src_end, block, sizeof(block)); 95 for (b = 0; b < 8; b++) { 96 memcpy(dst, &block[b * 8], 8); 97 dst += seq->frame->linesize[0]; 98 } 99 break; 100 case 2: 101 src = seq_unpack_rle_block(src, src_end, block, sizeof(block)); 102 for (i = 0; i < 8; i++) { 103 for (b = 0; b < 8; b++) 104 dst[b * seq->frame->linesize[0]] = block[i * 8 + b]; 105 ++dst; 106 } 107 break; 108 } 109 } else { 110 if (len <= 0) 111 return NULL; 112 bits = ff_log2_tab[len - 1] + 1; 113 if (src_end - src < len + 8 * bits) 114 return NULL; 115 color_table = src; 116 src += len; 117 init_get_bits(&gb, src, bits * 8 * 8); src += bits * 8; 118 for (b = 0; b < 8; b++) { 119 for (i = 0; i < 8; i++) 120 dst[i] = color_table[get_bits(&gb, bits)]; 121 dst += seq->frame->linesize[0]; 122 } 123 } 124 125 return src; 126} 127 128static const unsigned char *seq_decode_op2(SeqVideoContext *seq, 129 const unsigned char *src, 130 const unsigned char *src_end, 131 unsigned char *dst) 132{ 133 int i; 134 135 if (src_end - src < 8 * 8) 136 return NULL; 137 138 for (i = 0; i < 8; i++) { 139 memcpy(dst, src, 8); 140 src += 8; 141 dst += seq->frame->linesize[0]; 142 } 143 144 return src; 145} 146 147static const unsigned char *seq_decode_op3(SeqVideoContext *seq, 148 const unsigned char *src, 149 const unsigned char *src_end, 150 unsigned char *dst) 151{ 152 int pos, offset; 153 154 do { 155 if (src_end - src < 2) 156 return NULL; 157 pos = *src++; 158 offset = ((pos >> 3) & 7) * seq->frame->linesize[0] + (pos & 7); 159 dst[offset] = *src++; 160 } while (!(pos & 0x80)); 161 162 return src; 163} 164 165static int seqvideo_decode(SeqVideoContext *seq, const unsigned char *data, int data_size) 166{ 167 const unsigned char *data_end = data + data_size; 168 GetBitContext gb; 169 int flags, i, j, x, y, op; 170 unsigned char c[3]; 171 unsigned char *dst; 172 uint32_t *palette; 173 174 flags = *data++; 175 176 if (flags & 1) { 177 palette = (uint32_t *)seq->frame->data[1]; 178 if (data_end - data < 256 * 3) 179 return AVERROR_INVALIDDATA; 180 for (i = 0; i < 256; i++) { 181 for (j = 0; j < 3; j++, data++) 182 c[j] = (*data << 2) | (*data >> 4); 183 palette[i] = 0xFFU << 24 | AV_RB24(c); 184 } 185 seq->frame->palette_has_changed = 1; 186 } 187 188 if (flags & 2) { 189 if (data_end - data < 128) 190 return AVERROR_INVALIDDATA; 191 init_get_bits(&gb, data, 128 * 8); data += 128; 192 for (y = 0; y < 128; y += 8) 193 for (x = 0; x < 256; x += 8) { 194 dst = &seq->frame->data[0][y * seq->frame->linesize[0] + x]; 195 op = get_bits(&gb, 2); 196 switch (op) { 197 case 1: 198 data = seq_decode_op1(seq, data, data_end, dst); 199 break; 200 case 2: 201 data = seq_decode_op2(seq, data, data_end, dst); 202 break; 203 case 3: 204 data = seq_decode_op3(seq, data, data_end, dst); 205 break; 206 } 207 if (!data) 208 return AVERROR_INVALIDDATA; 209 } 210 } 211 return 0; 212} 213 214static av_cold int seqvideo_decode_init(AVCodecContext *avctx) 215{ 216 SeqVideoContext *seq = avctx->priv_data; 217 int ret; 218 219 seq->avctx = avctx; 220 avctx->pix_fmt = AV_PIX_FMT_PAL8; 221 222 ret = ff_set_dimensions(avctx, 256, 128); 223 if (ret < 0) 224 return ret; 225 226 seq->frame = av_frame_alloc(); 227 if (!seq->frame) 228 return AVERROR(ENOMEM); 229 230 return 0; 231} 232 233static int seqvideo_decode_frame(AVCodecContext *avctx, AVFrame *rframe, 234 int *got_frame, AVPacket *avpkt) 235{ 236 const uint8_t *buf = avpkt->data; 237 int buf_size = avpkt->size; 238 int ret; 239 240 SeqVideoContext *seq = avctx->priv_data; 241 242 if ((ret = ff_reget_buffer(avctx, seq->frame, 0)) < 0) 243 return ret; 244 245 if (seqvideo_decode(seq, buf, buf_size)) 246 return AVERROR_INVALIDDATA; 247 248 if ((ret = av_frame_ref(rframe, seq->frame)) < 0) 249 return ret; 250 *got_frame = 1; 251 252 return buf_size; 253} 254 255static av_cold int seqvideo_decode_end(AVCodecContext *avctx) 256{ 257 SeqVideoContext *seq = avctx->priv_data; 258 259 av_frame_free(&seq->frame); 260 261 return 0; 262} 263 264const FFCodec ff_tiertexseqvideo_decoder = { 265 .p.name = "tiertexseqvideo", 266 .p.long_name = NULL_IF_CONFIG_SMALL("Tiertex Limited SEQ video"), 267 .p.type = AVMEDIA_TYPE_VIDEO, 268 .p.id = AV_CODEC_ID_TIERTEXSEQVIDEO, 269 .priv_data_size = sizeof(SeqVideoContext), 270 .init = seqvideo_decode_init, 271 .close = seqvideo_decode_end, 272 FF_CODEC_DECODE_CB(seqvideo_decode_frame), 273 .p.capabilities = AV_CODEC_CAP_DR1, 274 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, 275}; 276