1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Kega Game Video (KGV1) decoder 3cabdff1aSopenharmony_ci * Copyright (c) 2010 Daniel Verkamp 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/** 23cabdff1aSopenharmony_ci * @file 24cabdff1aSopenharmony_ci * Kega Game Video decoder 25cabdff1aSopenharmony_ci */ 26cabdff1aSopenharmony_ci 27cabdff1aSopenharmony_ci#include "libavutil/common.h" 28cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h" 29cabdff1aSopenharmony_ci#include "libavutil/imgutils.h" 30cabdff1aSopenharmony_ci#include "avcodec.h" 31cabdff1aSopenharmony_ci#include "codec_internal.h" 32cabdff1aSopenharmony_ci#include "internal.h" 33cabdff1aSopenharmony_ci 34cabdff1aSopenharmony_citypedef struct KgvContext { 35cabdff1aSopenharmony_ci uint16_t *frame_buffer; 36cabdff1aSopenharmony_ci uint16_t *last_frame_buffer; 37cabdff1aSopenharmony_ci} KgvContext; 38cabdff1aSopenharmony_ci 39cabdff1aSopenharmony_cistatic void decode_flush(AVCodecContext *avctx) 40cabdff1aSopenharmony_ci{ 41cabdff1aSopenharmony_ci KgvContext * const c = avctx->priv_data; 42cabdff1aSopenharmony_ci 43cabdff1aSopenharmony_ci av_freep(&c->frame_buffer); 44cabdff1aSopenharmony_ci av_freep(&c->last_frame_buffer); 45cabdff1aSopenharmony_ci} 46cabdff1aSopenharmony_ci 47cabdff1aSopenharmony_cistatic int decode_frame(AVCodecContext *avctx, AVFrame *frame, 48cabdff1aSopenharmony_ci int *got_frame, AVPacket *avpkt) 49cabdff1aSopenharmony_ci{ 50cabdff1aSopenharmony_ci const uint8_t *buf = avpkt->data; 51cabdff1aSopenharmony_ci const uint8_t *buf_end = buf + avpkt->size; 52cabdff1aSopenharmony_ci KgvContext * const c = avctx->priv_data; 53cabdff1aSopenharmony_ci int offsets[8]; 54cabdff1aSopenharmony_ci uint8_t *out, *prev; 55cabdff1aSopenharmony_ci int outcnt = 0, maxcnt; 56cabdff1aSopenharmony_ci int w, h, i, res; 57cabdff1aSopenharmony_ci 58cabdff1aSopenharmony_ci if (avpkt->size < 2) 59cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 60cabdff1aSopenharmony_ci 61cabdff1aSopenharmony_ci w = (buf[0] + 1) * 8; 62cabdff1aSopenharmony_ci h = (buf[1] + 1) * 8; 63cabdff1aSopenharmony_ci buf += 2; 64cabdff1aSopenharmony_ci 65cabdff1aSopenharmony_ci if (avpkt->size < 2 + w*h / 513) 66cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 67cabdff1aSopenharmony_ci 68cabdff1aSopenharmony_ci if (w != avctx->width || h != avctx->height) { 69cabdff1aSopenharmony_ci av_freep(&c->frame_buffer); 70cabdff1aSopenharmony_ci av_freep(&c->last_frame_buffer); 71cabdff1aSopenharmony_ci if ((res = ff_set_dimensions(avctx, w, h)) < 0) 72cabdff1aSopenharmony_ci return res; 73cabdff1aSopenharmony_ci } 74cabdff1aSopenharmony_ci 75cabdff1aSopenharmony_ci if (!c->frame_buffer) { 76cabdff1aSopenharmony_ci c->frame_buffer = av_mallocz(avctx->width * avctx->height * 2); 77cabdff1aSopenharmony_ci c->last_frame_buffer = av_mallocz(avctx->width * avctx->height * 2); 78cabdff1aSopenharmony_ci if (!c->frame_buffer || !c->last_frame_buffer) { 79cabdff1aSopenharmony_ci decode_flush(avctx); 80cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 81cabdff1aSopenharmony_ci } 82cabdff1aSopenharmony_ci } 83cabdff1aSopenharmony_ci 84cabdff1aSopenharmony_ci maxcnt = w * h; 85cabdff1aSopenharmony_ci 86cabdff1aSopenharmony_ci if ((res = ff_get_buffer(avctx, frame, 0)) < 0) 87cabdff1aSopenharmony_ci return res; 88cabdff1aSopenharmony_ci out = (uint8_t*)c->frame_buffer; 89cabdff1aSopenharmony_ci prev = (uint8_t*)c->last_frame_buffer; 90cabdff1aSopenharmony_ci 91cabdff1aSopenharmony_ci for (i = 0; i < 8; i++) 92cabdff1aSopenharmony_ci offsets[i] = -1; 93cabdff1aSopenharmony_ci 94cabdff1aSopenharmony_ci while (outcnt < maxcnt && buf_end - 2 >= buf) { 95cabdff1aSopenharmony_ci int code = AV_RL16(buf); 96cabdff1aSopenharmony_ci buf += 2; 97cabdff1aSopenharmony_ci 98cabdff1aSopenharmony_ci if (!(code & 0x8000)) { 99cabdff1aSopenharmony_ci AV_WN16A(&out[2 * outcnt], code); // rgb555 pixel coded directly 100cabdff1aSopenharmony_ci outcnt++; 101cabdff1aSopenharmony_ci } else { 102cabdff1aSopenharmony_ci int count; 103cabdff1aSopenharmony_ci 104cabdff1aSopenharmony_ci if ((code & 0x6000) == 0x6000) { 105cabdff1aSopenharmony_ci // copy from previous frame 106cabdff1aSopenharmony_ci int oidx = (code >> 10) & 7; 107cabdff1aSopenharmony_ci int start; 108cabdff1aSopenharmony_ci 109cabdff1aSopenharmony_ci count = (code & 0x3FF) + 3; 110cabdff1aSopenharmony_ci 111cabdff1aSopenharmony_ci if (offsets[oidx] < 0) { 112cabdff1aSopenharmony_ci if (buf_end - 3 < buf) 113cabdff1aSopenharmony_ci break; 114cabdff1aSopenharmony_ci offsets[oidx] = AV_RL24(buf); 115cabdff1aSopenharmony_ci buf += 3; 116cabdff1aSopenharmony_ci } 117cabdff1aSopenharmony_ci 118cabdff1aSopenharmony_ci start = (outcnt + offsets[oidx]) % maxcnt; 119cabdff1aSopenharmony_ci 120cabdff1aSopenharmony_ci if (maxcnt - start < count || maxcnt - outcnt < count) 121cabdff1aSopenharmony_ci break; 122cabdff1aSopenharmony_ci 123cabdff1aSopenharmony_ci if (!prev) { 124cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, 125cabdff1aSopenharmony_ci "Frame reference does not exist\n"); 126cabdff1aSopenharmony_ci break; 127cabdff1aSopenharmony_ci } 128cabdff1aSopenharmony_ci 129cabdff1aSopenharmony_ci memcpy(out + 2 * outcnt, prev + 2 * start, 2 * count); 130cabdff1aSopenharmony_ci } else { 131cabdff1aSopenharmony_ci // copy from earlier in this frame 132cabdff1aSopenharmony_ci int offset = (code & 0x1FFF) + 1; 133cabdff1aSopenharmony_ci 134cabdff1aSopenharmony_ci if (!(code & 0x6000)) { 135cabdff1aSopenharmony_ci count = 2; 136cabdff1aSopenharmony_ci } else if ((code & 0x6000) == 0x2000) { 137cabdff1aSopenharmony_ci count = 3; 138cabdff1aSopenharmony_ci } else { 139cabdff1aSopenharmony_ci if (buf_end - 1 < buf) 140cabdff1aSopenharmony_ci break; 141cabdff1aSopenharmony_ci count = 4 + *buf++; 142cabdff1aSopenharmony_ci } 143cabdff1aSopenharmony_ci 144cabdff1aSopenharmony_ci if (outcnt < offset || maxcnt - outcnt < count) 145cabdff1aSopenharmony_ci break; 146cabdff1aSopenharmony_ci 147cabdff1aSopenharmony_ci av_memcpy_backptr(out + 2 * outcnt, 2 * offset, 2 * count); 148cabdff1aSopenharmony_ci } 149cabdff1aSopenharmony_ci outcnt += count; 150cabdff1aSopenharmony_ci } 151cabdff1aSopenharmony_ci } 152cabdff1aSopenharmony_ci 153cabdff1aSopenharmony_ci if (outcnt - maxcnt) 154cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_DEBUG, "frame finished with %d diff\n", outcnt - maxcnt); 155cabdff1aSopenharmony_ci 156cabdff1aSopenharmony_ci av_image_copy_plane(frame->data[0], frame->linesize[0], 157cabdff1aSopenharmony_ci (const uint8_t*)c->frame_buffer, avctx->width * 2, 158cabdff1aSopenharmony_ci avctx->width * 2, avctx->height); 159cabdff1aSopenharmony_ci FFSWAP(uint16_t *, c->frame_buffer, c->last_frame_buffer); 160cabdff1aSopenharmony_ci 161cabdff1aSopenharmony_ci *got_frame = 1; 162cabdff1aSopenharmony_ci 163cabdff1aSopenharmony_ci return avpkt->size; 164cabdff1aSopenharmony_ci} 165cabdff1aSopenharmony_ci 166cabdff1aSopenharmony_cistatic av_cold int decode_init(AVCodecContext *avctx) 167cabdff1aSopenharmony_ci{ 168cabdff1aSopenharmony_ci avctx->pix_fmt = AV_PIX_FMT_RGB555; 169cabdff1aSopenharmony_ci 170cabdff1aSopenharmony_ci return 0; 171cabdff1aSopenharmony_ci} 172cabdff1aSopenharmony_ci 173cabdff1aSopenharmony_cistatic av_cold int decode_end(AVCodecContext *avctx) 174cabdff1aSopenharmony_ci{ 175cabdff1aSopenharmony_ci decode_flush(avctx); 176cabdff1aSopenharmony_ci return 0; 177cabdff1aSopenharmony_ci} 178cabdff1aSopenharmony_ci 179cabdff1aSopenharmony_ciconst FFCodec ff_kgv1_decoder = { 180cabdff1aSopenharmony_ci .p.name = "kgv1", 181cabdff1aSopenharmony_ci .p.long_name = NULL_IF_CONFIG_SMALL("Kega Game Video"), 182cabdff1aSopenharmony_ci .p.type = AVMEDIA_TYPE_VIDEO, 183cabdff1aSopenharmony_ci .p.id = AV_CODEC_ID_KGV1, 184cabdff1aSopenharmony_ci .priv_data_size = sizeof(KgvContext), 185cabdff1aSopenharmony_ci .init = decode_init, 186cabdff1aSopenharmony_ci .close = decode_end, 187cabdff1aSopenharmony_ci FF_CODEC_DECODE_CB(decode_frame), 188cabdff1aSopenharmony_ci .flush = decode_flush, 189cabdff1aSopenharmony_ci .p.capabilities = AV_CODEC_CAP_DR1, 190cabdff1aSopenharmony_ci .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, 191cabdff1aSopenharmony_ci}; 192