1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Interplay C93 video decoder 3cabdff1aSopenharmony_ci * Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.com> 4cabdff1aSopenharmony_ci * 5cabdff1aSopenharmony_ci * This file is part of FFmpeg. 6cabdff1aSopenharmony_ci * 7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 11cabdff1aSopenharmony_ci * 12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15cabdff1aSopenharmony_ci * Lesser General Public License for more details. 16cabdff1aSopenharmony_ci * 17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20cabdff1aSopenharmony_ci */ 21cabdff1aSopenharmony_ci 22cabdff1aSopenharmony_ci#include "avcodec.h" 23cabdff1aSopenharmony_ci#include "bytestream.h" 24cabdff1aSopenharmony_ci#include "codec_internal.h" 25cabdff1aSopenharmony_ci#include "internal.h" 26cabdff1aSopenharmony_ci 27cabdff1aSopenharmony_citypedef struct C93DecoderContext { 28cabdff1aSopenharmony_ci AVFrame *pictures[2]; 29cabdff1aSopenharmony_ci int currentpic; 30cabdff1aSopenharmony_ci} C93DecoderContext; 31cabdff1aSopenharmony_ci 32cabdff1aSopenharmony_citypedef enum { 33cabdff1aSopenharmony_ci C93_8X8_FROM_PREV = 0x02, 34cabdff1aSopenharmony_ci C93_4X4_FROM_PREV = 0x06, 35cabdff1aSopenharmony_ci C93_4X4_FROM_CURR = 0x07, 36cabdff1aSopenharmony_ci C93_8X8_2COLOR = 0x08, 37cabdff1aSopenharmony_ci C93_4X4_2COLOR = 0x0A, 38cabdff1aSopenharmony_ci C93_4X4_4COLOR_GRP = 0x0B, 39cabdff1aSopenharmony_ci C93_4X4_4COLOR = 0x0D, 40cabdff1aSopenharmony_ci C93_NOOP = 0x0E, 41cabdff1aSopenharmony_ci C93_8X8_INTRA = 0x0F, 42cabdff1aSopenharmony_ci} C93BlockType; 43cabdff1aSopenharmony_ci 44cabdff1aSopenharmony_ci#define WIDTH 320 45cabdff1aSopenharmony_ci#define HEIGHT 192 46cabdff1aSopenharmony_ci 47cabdff1aSopenharmony_ci#define C93_HAS_PALETTE 0x01 48cabdff1aSopenharmony_ci#define C93_FIRST_FRAME 0x02 49cabdff1aSopenharmony_ci 50cabdff1aSopenharmony_cistatic av_cold int decode_end(AVCodecContext *avctx) 51cabdff1aSopenharmony_ci{ 52cabdff1aSopenharmony_ci C93DecoderContext * const c93 = avctx->priv_data; 53cabdff1aSopenharmony_ci 54cabdff1aSopenharmony_ci av_frame_free(&c93->pictures[0]); 55cabdff1aSopenharmony_ci av_frame_free(&c93->pictures[1]); 56cabdff1aSopenharmony_ci 57cabdff1aSopenharmony_ci return 0; 58cabdff1aSopenharmony_ci} 59cabdff1aSopenharmony_ci 60cabdff1aSopenharmony_cistatic av_cold int decode_init(AVCodecContext *avctx) 61cabdff1aSopenharmony_ci{ 62cabdff1aSopenharmony_ci C93DecoderContext *s = avctx->priv_data; 63cabdff1aSopenharmony_ci avctx->pix_fmt = AV_PIX_FMT_PAL8; 64cabdff1aSopenharmony_ci 65cabdff1aSopenharmony_ci s->pictures[0] = av_frame_alloc(); 66cabdff1aSopenharmony_ci s->pictures[1] = av_frame_alloc(); 67cabdff1aSopenharmony_ci if (!s->pictures[0] || !s->pictures[1]) 68cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 69cabdff1aSopenharmony_ci 70cabdff1aSopenharmony_ci return 0; 71cabdff1aSopenharmony_ci} 72cabdff1aSopenharmony_ci 73cabdff1aSopenharmony_cistatic inline int copy_block(AVCodecContext *avctx, uint8_t *to, 74cabdff1aSopenharmony_ci uint8_t *from, int offset, int height, int stride) 75cabdff1aSopenharmony_ci{ 76cabdff1aSopenharmony_ci int i; 77cabdff1aSopenharmony_ci int width = height; 78cabdff1aSopenharmony_ci int from_x = offset % WIDTH; 79cabdff1aSopenharmony_ci int from_y = offset / WIDTH; 80cabdff1aSopenharmony_ci int overflow = from_x + width - WIDTH; 81cabdff1aSopenharmony_ci 82cabdff1aSopenharmony_ci if (!from) { 83cabdff1aSopenharmony_ci /* silently ignoring predictive blocks in first frame */ 84cabdff1aSopenharmony_ci return 0; 85cabdff1aSopenharmony_ci } 86cabdff1aSopenharmony_ci 87cabdff1aSopenharmony_ci if (from_y + height > HEIGHT) { 88cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "invalid offset %d during C93 decoding\n", 89cabdff1aSopenharmony_ci offset); 90cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 91cabdff1aSopenharmony_ci } 92cabdff1aSopenharmony_ci 93cabdff1aSopenharmony_ci if (overflow > 0) { 94cabdff1aSopenharmony_ci width -= overflow; 95cabdff1aSopenharmony_ci for (i = 0; i < height; i++) { 96cabdff1aSopenharmony_ci memcpy(&to[i*stride+width], &from[(from_y+i)*stride], overflow); 97cabdff1aSopenharmony_ci } 98cabdff1aSopenharmony_ci } 99cabdff1aSopenharmony_ci 100cabdff1aSopenharmony_ci for (i = 0; i < height; i++) { 101cabdff1aSopenharmony_ci memcpy(&to[i*stride], &from[(from_y+i)*stride+from_x], width); 102cabdff1aSopenharmony_ci } 103cabdff1aSopenharmony_ci 104cabdff1aSopenharmony_ci return 0; 105cabdff1aSopenharmony_ci} 106cabdff1aSopenharmony_ci 107cabdff1aSopenharmony_cistatic inline void draw_n_color(uint8_t *out, int stride, int width, 108cabdff1aSopenharmony_ci int height, int bpp, uint8_t cols[4], uint8_t grps[4], uint32_t col) 109cabdff1aSopenharmony_ci{ 110cabdff1aSopenharmony_ci int x, y; 111cabdff1aSopenharmony_ci for (y = 0; y < height; y++) { 112cabdff1aSopenharmony_ci if (grps) 113cabdff1aSopenharmony_ci cols[0] = grps[3 * (y >> 1)]; 114cabdff1aSopenharmony_ci for (x = 0; x < width; x++) { 115cabdff1aSopenharmony_ci if (grps) 116cabdff1aSopenharmony_ci cols[1]= grps[(x >> 1) + 1]; 117cabdff1aSopenharmony_ci out[x + y*stride] = cols[col & ((1 << bpp) - 1)]; 118cabdff1aSopenharmony_ci col >>= bpp; 119cabdff1aSopenharmony_ci } 120cabdff1aSopenharmony_ci } 121cabdff1aSopenharmony_ci} 122cabdff1aSopenharmony_ci 123cabdff1aSopenharmony_cistatic int decode_frame(AVCodecContext *avctx, AVFrame *rframe, 124cabdff1aSopenharmony_ci int *got_frame, AVPacket *avpkt) 125cabdff1aSopenharmony_ci{ 126cabdff1aSopenharmony_ci const uint8_t *buf = avpkt->data; 127cabdff1aSopenharmony_ci int buf_size = avpkt->size; 128cabdff1aSopenharmony_ci C93DecoderContext * const c93 = avctx->priv_data; 129cabdff1aSopenharmony_ci AVFrame * const newpic = c93->pictures[c93->currentpic]; 130cabdff1aSopenharmony_ci AVFrame * const oldpic = c93->pictures[c93->currentpic^1]; 131cabdff1aSopenharmony_ci GetByteContext gb; 132cabdff1aSopenharmony_ci uint8_t *out; 133cabdff1aSopenharmony_ci int stride, ret, i, x, y, b, bt = 0; 134cabdff1aSopenharmony_ci 135cabdff1aSopenharmony_ci if ((ret = ff_set_dimensions(avctx, WIDTH, HEIGHT)) < 0) 136cabdff1aSopenharmony_ci return ret; 137cabdff1aSopenharmony_ci 138cabdff1aSopenharmony_ci c93->currentpic ^= 1; 139cabdff1aSopenharmony_ci 140cabdff1aSopenharmony_ci if ((ret = ff_reget_buffer(avctx, newpic, 0)) < 0) 141cabdff1aSopenharmony_ci return ret; 142cabdff1aSopenharmony_ci 143cabdff1aSopenharmony_ci stride = newpic->linesize[0]; 144cabdff1aSopenharmony_ci 145cabdff1aSopenharmony_ci bytestream2_init(&gb, buf, buf_size); 146cabdff1aSopenharmony_ci b = bytestream2_get_byte(&gb); 147cabdff1aSopenharmony_ci if (b & C93_FIRST_FRAME) { 148cabdff1aSopenharmony_ci newpic->pict_type = AV_PICTURE_TYPE_I; 149cabdff1aSopenharmony_ci newpic->key_frame = 1; 150cabdff1aSopenharmony_ci } else { 151cabdff1aSopenharmony_ci newpic->pict_type = AV_PICTURE_TYPE_P; 152cabdff1aSopenharmony_ci newpic->key_frame = 0; 153cabdff1aSopenharmony_ci } 154cabdff1aSopenharmony_ci 155cabdff1aSopenharmony_ci for (y = 0; y < HEIGHT; y += 8) { 156cabdff1aSopenharmony_ci out = newpic->data[0] + y * stride; 157cabdff1aSopenharmony_ci for (x = 0; x < WIDTH; x += 8) { 158cabdff1aSopenharmony_ci uint8_t *copy_from = oldpic->data[0]; 159cabdff1aSopenharmony_ci unsigned int offset, j; 160cabdff1aSopenharmony_ci uint8_t cols[4], grps[4]; 161cabdff1aSopenharmony_ci C93BlockType block_type; 162cabdff1aSopenharmony_ci 163cabdff1aSopenharmony_ci if (!bt) 164cabdff1aSopenharmony_ci bt = bytestream2_get_byte(&gb); 165cabdff1aSopenharmony_ci 166cabdff1aSopenharmony_ci block_type= bt & 0x0F; 167cabdff1aSopenharmony_ci switch (block_type) { 168cabdff1aSopenharmony_ci case C93_8X8_FROM_PREV: 169cabdff1aSopenharmony_ci offset = bytestream2_get_le16(&gb); 170cabdff1aSopenharmony_ci if ((ret = copy_block(avctx, out, copy_from, offset, 8, stride)) < 0) 171cabdff1aSopenharmony_ci return ret; 172cabdff1aSopenharmony_ci break; 173cabdff1aSopenharmony_ci 174cabdff1aSopenharmony_ci case C93_4X4_FROM_CURR: 175cabdff1aSopenharmony_ci copy_from = newpic->data[0]; 176cabdff1aSopenharmony_ci case C93_4X4_FROM_PREV: 177cabdff1aSopenharmony_ci for (j = 0; j < 8; j += 4) { 178cabdff1aSopenharmony_ci for (i = 0; i < 8; i += 4) { 179cabdff1aSopenharmony_ci int offset = bytestream2_get_le16(&gb); 180cabdff1aSopenharmony_ci int from_x = offset % WIDTH; 181cabdff1aSopenharmony_ci int from_y = offset / WIDTH; 182cabdff1aSopenharmony_ci if (block_type == C93_4X4_FROM_CURR && from_y == y+j && 183cabdff1aSopenharmony_ci (FFABS(from_x - x-i) < 4 || FFABS(from_x - x-i) > WIDTH-4)) { 184cabdff1aSopenharmony_ci avpriv_request_sample(avctx, "block overlap %d %d %d %d", from_x, x+i, from_y, y+j); 185cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 186cabdff1aSopenharmony_ci } 187cabdff1aSopenharmony_ci if ((ret = copy_block(avctx, &out[j*stride+i], 188cabdff1aSopenharmony_ci copy_from, offset, 4, stride)) < 0) 189cabdff1aSopenharmony_ci return ret; 190cabdff1aSopenharmony_ci } 191cabdff1aSopenharmony_ci } 192cabdff1aSopenharmony_ci break; 193cabdff1aSopenharmony_ci 194cabdff1aSopenharmony_ci case C93_8X8_2COLOR: 195cabdff1aSopenharmony_ci bytestream2_get_buffer(&gb, cols, 2); 196cabdff1aSopenharmony_ci for (i = 0; i < 8; i++) { 197cabdff1aSopenharmony_ci draw_n_color(out + i*stride, stride, 8, 1, 1, cols, 198cabdff1aSopenharmony_ci NULL, bytestream2_get_byte(&gb)); 199cabdff1aSopenharmony_ci } 200cabdff1aSopenharmony_ci 201cabdff1aSopenharmony_ci break; 202cabdff1aSopenharmony_ci 203cabdff1aSopenharmony_ci case C93_4X4_2COLOR: 204cabdff1aSopenharmony_ci case C93_4X4_4COLOR: 205cabdff1aSopenharmony_ci case C93_4X4_4COLOR_GRP: 206cabdff1aSopenharmony_ci for (j = 0; j < 8; j += 4) { 207cabdff1aSopenharmony_ci for (i = 0; i < 8; i += 4) { 208cabdff1aSopenharmony_ci if (block_type == C93_4X4_2COLOR) { 209cabdff1aSopenharmony_ci bytestream2_get_buffer(&gb, cols, 2); 210cabdff1aSopenharmony_ci draw_n_color(out + i + j*stride, stride, 4, 4, 211cabdff1aSopenharmony_ci 1, cols, NULL, bytestream2_get_le16(&gb)); 212cabdff1aSopenharmony_ci } else if (block_type == C93_4X4_4COLOR) { 213cabdff1aSopenharmony_ci bytestream2_get_buffer(&gb, cols, 4); 214cabdff1aSopenharmony_ci draw_n_color(out + i + j*stride, stride, 4, 4, 215cabdff1aSopenharmony_ci 2, cols, NULL, bytestream2_get_le32(&gb)); 216cabdff1aSopenharmony_ci } else { 217cabdff1aSopenharmony_ci bytestream2_get_buffer(&gb, grps, 4); 218cabdff1aSopenharmony_ci draw_n_color(out + i + j*stride, stride, 4, 4, 219cabdff1aSopenharmony_ci 1, cols, grps, bytestream2_get_le16(&gb)); 220cabdff1aSopenharmony_ci } 221cabdff1aSopenharmony_ci } 222cabdff1aSopenharmony_ci } 223cabdff1aSopenharmony_ci break; 224cabdff1aSopenharmony_ci 225cabdff1aSopenharmony_ci case C93_NOOP: 226cabdff1aSopenharmony_ci break; 227cabdff1aSopenharmony_ci 228cabdff1aSopenharmony_ci case C93_8X8_INTRA: 229cabdff1aSopenharmony_ci for (j = 0; j < 8; j++) 230cabdff1aSopenharmony_ci bytestream2_get_buffer(&gb, out + j*stride, 8); 231cabdff1aSopenharmony_ci break; 232cabdff1aSopenharmony_ci 233cabdff1aSopenharmony_ci default: 234cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "unexpected type %x at %dx%d\n", 235cabdff1aSopenharmony_ci block_type, x, y); 236cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 237cabdff1aSopenharmony_ci } 238cabdff1aSopenharmony_ci bt >>= 4; 239cabdff1aSopenharmony_ci out += 8; 240cabdff1aSopenharmony_ci } 241cabdff1aSopenharmony_ci } 242cabdff1aSopenharmony_ci 243cabdff1aSopenharmony_ci if (b & C93_HAS_PALETTE) { 244cabdff1aSopenharmony_ci uint32_t *palette = (uint32_t *) newpic->data[1]; 245cabdff1aSopenharmony_ci for (i = 0; i < 256; i++) { 246cabdff1aSopenharmony_ci palette[i] = 0xFFU << 24 | bytestream2_get_be24(&gb); 247cabdff1aSopenharmony_ci } 248cabdff1aSopenharmony_ci newpic->palette_has_changed = 1; 249cabdff1aSopenharmony_ci } else { 250cabdff1aSopenharmony_ci if (oldpic->data[1]) 251cabdff1aSopenharmony_ci memcpy(newpic->data[1], oldpic->data[1], 256 * 4); 252cabdff1aSopenharmony_ci } 253cabdff1aSopenharmony_ci 254cabdff1aSopenharmony_ci if ((ret = av_frame_ref(rframe, newpic)) < 0) 255cabdff1aSopenharmony_ci return ret; 256cabdff1aSopenharmony_ci *got_frame = 1; 257cabdff1aSopenharmony_ci 258cabdff1aSopenharmony_ci return buf_size; 259cabdff1aSopenharmony_ci} 260cabdff1aSopenharmony_ci 261cabdff1aSopenharmony_ciconst FFCodec ff_c93_decoder = { 262cabdff1aSopenharmony_ci .p.name = "c93", 263cabdff1aSopenharmony_ci .p.long_name = NULL_IF_CONFIG_SMALL("Interplay C93"), 264cabdff1aSopenharmony_ci .p.type = AVMEDIA_TYPE_VIDEO, 265cabdff1aSopenharmony_ci .p.id = AV_CODEC_ID_C93, 266cabdff1aSopenharmony_ci .priv_data_size = sizeof(C93DecoderContext), 267cabdff1aSopenharmony_ci .init = decode_init, 268cabdff1aSopenharmony_ci .close = decode_end, 269cabdff1aSopenharmony_ci FF_CODEC_DECODE_CB(decode_frame), 270cabdff1aSopenharmony_ci .p.capabilities = AV_CODEC_CAP_DR1, 271cabdff1aSopenharmony_ci .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, 272cabdff1aSopenharmony_ci}; 273