1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Feeble Files/ScummVM DXA decoder 3cabdff1aSopenharmony_ci * Copyright (c) 2007 Konstantin Shishkov 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 * DXA Video decoder 25cabdff1aSopenharmony_ci */ 26cabdff1aSopenharmony_ci 27cabdff1aSopenharmony_ci#include <stdio.h> 28cabdff1aSopenharmony_ci#include <stdlib.h> 29cabdff1aSopenharmony_ci 30cabdff1aSopenharmony_ci#include "libavutil/common.h" 31cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h" 32cabdff1aSopenharmony_ci#include "bytestream.h" 33cabdff1aSopenharmony_ci#include "avcodec.h" 34cabdff1aSopenharmony_ci#include "codec_internal.h" 35cabdff1aSopenharmony_ci#include "internal.h" 36cabdff1aSopenharmony_ci 37cabdff1aSopenharmony_ci#include <zlib.h> 38cabdff1aSopenharmony_ci 39cabdff1aSopenharmony_ci/* 40cabdff1aSopenharmony_ci * Decoder context 41cabdff1aSopenharmony_ci */ 42cabdff1aSopenharmony_citypedef struct DxaDecContext { 43cabdff1aSopenharmony_ci AVFrame *prev; 44cabdff1aSopenharmony_ci 45cabdff1aSopenharmony_ci int dsize; 46cabdff1aSopenharmony_ci#define DECOMP_BUF_PADDING 16 47cabdff1aSopenharmony_ci uint8_t *decomp_buf; 48cabdff1aSopenharmony_ci uint32_t pal[256]; 49cabdff1aSopenharmony_ci} DxaDecContext; 50cabdff1aSopenharmony_ci 51cabdff1aSopenharmony_cistatic const int shift1[6] = { 0, 8, 8, 8, 4, 4 }; 52cabdff1aSopenharmony_cistatic const int shift2[6] = { 0, 0, 8, 4, 0, 4 }; 53cabdff1aSopenharmony_ci 54cabdff1aSopenharmony_cistatic int decode_13(AVCodecContext *avctx, DxaDecContext *c, uint8_t* dst, 55cabdff1aSopenharmony_ci int stride, uint8_t *src, int srcsize, uint8_t *ref) 56cabdff1aSopenharmony_ci{ 57cabdff1aSopenharmony_ci uint8_t *code, *data, *mv, *msk, *tmp, *tmp2; 58cabdff1aSopenharmony_ci uint8_t *src_end = src + srcsize; 59cabdff1aSopenharmony_ci int i, j, k; 60cabdff1aSopenharmony_ci int type, x, y, d, d2; 61cabdff1aSopenharmony_ci uint32_t mask; 62cabdff1aSopenharmony_ci 63cabdff1aSopenharmony_ci if (12ULL + ((avctx->width * avctx->height) >> 4) + AV_RB32(src + 0) + AV_RB32(src + 4) > srcsize) 64cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 65cabdff1aSopenharmony_ci 66cabdff1aSopenharmony_ci code = src + 12; 67cabdff1aSopenharmony_ci data = code + ((avctx->width * avctx->height) >> 4); 68cabdff1aSopenharmony_ci mv = data + AV_RB32(src + 0); 69cabdff1aSopenharmony_ci msk = mv + AV_RB32(src + 4); 70cabdff1aSopenharmony_ci 71cabdff1aSopenharmony_ci for(j = 0; j < avctx->height; j += 4){ 72cabdff1aSopenharmony_ci for(i = 0; i < avctx->width; i += 4){ 73cabdff1aSopenharmony_ci if (data > src_end || mv > src_end || msk > src_end) 74cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 75cabdff1aSopenharmony_ci tmp = dst + i; 76cabdff1aSopenharmony_ci tmp2 = ref + i; 77cabdff1aSopenharmony_ci type = *code++; 78cabdff1aSopenharmony_ci switch(type){ 79cabdff1aSopenharmony_ci case 4: // motion compensation 80cabdff1aSopenharmony_ci x = (*mv) >> 4; if(x & 8) x = 8 - x; 81cabdff1aSopenharmony_ci y = (*mv++) & 0xF; if(y & 8) y = 8 - y; 82cabdff1aSopenharmony_ci if (i < -x || avctx->width - i - 4 < x || 83cabdff1aSopenharmony_ci j < -y || avctx->height - j - 4 < y) { 84cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "MV %d %d out of bounds\n", x,y); 85cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 86cabdff1aSopenharmony_ci } 87cabdff1aSopenharmony_ci tmp2 += x + y*stride; 88cabdff1aSopenharmony_ci case 0: // skip 89cabdff1aSopenharmony_ci case 5: // skip in method 12 90cabdff1aSopenharmony_ci for(y = 0; y < 4; y++){ 91cabdff1aSopenharmony_ci memcpy(tmp, tmp2, 4); 92cabdff1aSopenharmony_ci tmp += stride; 93cabdff1aSopenharmony_ci tmp2 += stride; 94cabdff1aSopenharmony_ci } 95cabdff1aSopenharmony_ci break; 96cabdff1aSopenharmony_ci case 1: // masked change 97cabdff1aSopenharmony_ci case 10: // masked change with only half of pixels changed 98cabdff1aSopenharmony_ci case 11: // cases 10-15 are for method 12 only 99cabdff1aSopenharmony_ci case 12: 100cabdff1aSopenharmony_ci case 13: 101cabdff1aSopenharmony_ci case 14: 102cabdff1aSopenharmony_ci case 15: 103cabdff1aSopenharmony_ci if(type == 1){ 104cabdff1aSopenharmony_ci mask = AV_RB16(msk); 105cabdff1aSopenharmony_ci msk += 2; 106cabdff1aSopenharmony_ci }else{ 107cabdff1aSopenharmony_ci type -= 10; 108cabdff1aSopenharmony_ci mask = ((msk[0] & 0xF0) << shift1[type]) | ((msk[0] & 0xF) << shift2[type]); 109cabdff1aSopenharmony_ci msk++; 110cabdff1aSopenharmony_ci } 111cabdff1aSopenharmony_ci for(y = 0; y < 4; y++){ 112cabdff1aSopenharmony_ci for(x = 0; x < 4; x++){ 113cabdff1aSopenharmony_ci tmp[x] = (mask & 0x8000) ? *data++ : tmp2[x]; 114cabdff1aSopenharmony_ci mask <<= 1; 115cabdff1aSopenharmony_ci } 116cabdff1aSopenharmony_ci tmp += stride; 117cabdff1aSopenharmony_ci tmp2 += stride; 118cabdff1aSopenharmony_ci } 119cabdff1aSopenharmony_ci break; 120cabdff1aSopenharmony_ci case 2: // fill block 121cabdff1aSopenharmony_ci for(y = 0; y < 4; y++){ 122cabdff1aSopenharmony_ci memset(tmp, data[0], 4); 123cabdff1aSopenharmony_ci tmp += stride; 124cabdff1aSopenharmony_ci } 125cabdff1aSopenharmony_ci data++; 126cabdff1aSopenharmony_ci break; 127cabdff1aSopenharmony_ci case 3: // raw block 128cabdff1aSopenharmony_ci for(y = 0; y < 4; y++){ 129cabdff1aSopenharmony_ci memcpy(tmp, data, 4); 130cabdff1aSopenharmony_ci data += 4; 131cabdff1aSopenharmony_ci tmp += stride; 132cabdff1aSopenharmony_ci } 133cabdff1aSopenharmony_ci break; 134cabdff1aSopenharmony_ci case 8: // subblocks - method 13 only 135cabdff1aSopenharmony_ci mask = *msk++; 136cabdff1aSopenharmony_ci for(k = 0; k < 4; k++){ 137cabdff1aSopenharmony_ci d = ((k & 1) << 1) + ((k & 2) * stride); 138cabdff1aSopenharmony_ci d2 = ((k & 1) << 1) + ((k & 2) * stride); 139cabdff1aSopenharmony_ci tmp2 = ref + i + d2; 140cabdff1aSopenharmony_ci switch(mask & 0xC0){ 141cabdff1aSopenharmony_ci case 0x80: // motion compensation 142cabdff1aSopenharmony_ci x = (*mv) >> 4; if(x & 8) x = 8 - x; 143cabdff1aSopenharmony_ci y = (*mv++) & 0xF; if(y & 8) y = 8 - y; 144cabdff1aSopenharmony_ci if (i + 2*(k & 1) < -x || avctx->width - i - 2*(k & 1) - 2 < x || 145cabdff1aSopenharmony_ci j + (k & 2) < -y || avctx->height - j - (k & 2) - 2 < y) { 146cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "MV %d %d out of bounds\n", x,y); 147cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 148cabdff1aSopenharmony_ci } 149cabdff1aSopenharmony_ci tmp2 += x + y*stride; 150cabdff1aSopenharmony_ci case 0x00: // skip 151cabdff1aSopenharmony_ci tmp[d + 0 ] = tmp2[0]; 152cabdff1aSopenharmony_ci tmp[d + 1 ] = tmp2[1]; 153cabdff1aSopenharmony_ci tmp[d + 0 + stride] = tmp2[0 + stride]; 154cabdff1aSopenharmony_ci tmp[d + 1 + stride] = tmp2[1 + stride]; 155cabdff1aSopenharmony_ci break; 156cabdff1aSopenharmony_ci case 0x40: // fill 157cabdff1aSopenharmony_ci tmp[d + 0 ] = data[0]; 158cabdff1aSopenharmony_ci tmp[d + 1 ] = data[0]; 159cabdff1aSopenharmony_ci tmp[d + 0 + stride] = data[0]; 160cabdff1aSopenharmony_ci tmp[d + 1 + stride] = data[0]; 161cabdff1aSopenharmony_ci data++; 162cabdff1aSopenharmony_ci break; 163cabdff1aSopenharmony_ci case 0xC0: // raw 164cabdff1aSopenharmony_ci tmp[d + 0 ] = *data++; 165cabdff1aSopenharmony_ci tmp[d + 1 ] = *data++; 166cabdff1aSopenharmony_ci tmp[d + 0 + stride] = *data++; 167cabdff1aSopenharmony_ci tmp[d + 1 + stride] = *data++; 168cabdff1aSopenharmony_ci break; 169cabdff1aSopenharmony_ci } 170cabdff1aSopenharmony_ci mask <<= 2; 171cabdff1aSopenharmony_ci } 172cabdff1aSopenharmony_ci break; 173cabdff1aSopenharmony_ci case 32: // vector quantization - 2 colors 174cabdff1aSopenharmony_ci mask = AV_RB16(msk); 175cabdff1aSopenharmony_ci msk += 2; 176cabdff1aSopenharmony_ci for(y = 0; y < 4; y++){ 177cabdff1aSopenharmony_ci for(x = 0; x < 4; x++){ 178cabdff1aSopenharmony_ci tmp[x] = data[mask & 1]; 179cabdff1aSopenharmony_ci mask >>= 1; 180cabdff1aSopenharmony_ci } 181cabdff1aSopenharmony_ci tmp += stride; 182cabdff1aSopenharmony_ci tmp2 += stride; 183cabdff1aSopenharmony_ci } 184cabdff1aSopenharmony_ci data += 2; 185cabdff1aSopenharmony_ci break; 186cabdff1aSopenharmony_ci case 33: // vector quantization - 3 or 4 colors 187cabdff1aSopenharmony_ci case 34: 188cabdff1aSopenharmony_ci mask = AV_RB32(msk); 189cabdff1aSopenharmony_ci msk += 4; 190cabdff1aSopenharmony_ci for(y = 0; y < 4; y++){ 191cabdff1aSopenharmony_ci for(x = 0; x < 4; x++){ 192cabdff1aSopenharmony_ci tmp[x] = data[mask & 3]; 193cabdff1aSopenharmony_ci mask >>= 2; 194cabdff1aSopenharmony_ci } 195cabdff1aSopenharmony_ci tmp += stride; 196cabdff1aSopenharmony_ci tmp2 += stride; 197cabdff1aSopenharmony_ci } 198cabdff1aSopenharmony_ci data += type - 30; 199cabdff1aSopenharmony_ci break; 200cabdff1aSopenharmony_ci default: 201cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Unknown opcode %d\n", type); 202cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 203cabdff1aSopenharmony_ci } 204cabdff1aSopenharmony_ci } 205cabdff1aSopenharmony_ci dst += stride * 4; 206cabdff1aSopenharmony_ci ref += stride * 4; 207cabdff1aSopenharmony_ci } 208cabdff1aSopenharmony_ci return 0; 209cabdff1aSopenharmony_ci} 210cabdff1aSopenharmony_ci 211cabdff1aSopenharmony_cistatic int decode_frame(AVCodecContext *avctx, AVFrame *frame, 212cabdff1aSopenharmony_ci int *got_frame, AVPacket *avpkt) 213cabdff1aSopenharmony_ci{ 214cabdff1aSopenharmony_ci DxaDecContext * const c = avctx->priv_data; 215cabdff1aSopenharmony_ci uint8_t *outptr, *srcptr, *tmpptr; 216cabdff1aSopenharmony_ci unsigned long dsize; 217cabdff1aSopenharmony_ci int i, j, compr, ret; 218cabdff1aSopenharmony_ci int stride; 219cabdff1aSopenharmony_ci int pc = 0; 220cabdff1aSopenharmony_ci GetByteContext gb; 221cabdff1aSopenharmony_ci 222cabdff1aSopenharmony_ci bytestream2_init(&gb, avpkt->data, avpkt->size); 223cabdff1aSopenharmony_ci 224cabdff1aSopenharmony_ci /* make the palette available on the way out */ 225cabdff1aSopenharmony_ci if (bytestream2_peek_le32(&gb) == MKTAG('C','M','A','P')) { 226cabdff1aSopenharmony_ci bytestream2_skip(&gb, 4); 227cabdff1aSopenharmony_ci for(i = 0; i < 256; i++){ 228cabdff1aSopenharmony_ci c->pal[i] = 0xFFU << 24 | bytestream2_get_be24(&gb); 229cabdff1aSopenharmony_ci } 230cabdff1aSopenharmony_ci pc = 1; 231cabdff1aSopenharmony_ci } 232cabdff1aSopenharmony_ci 233cabdff1aSopenharmony_ci if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0) 234cabdff1aSopenharmony_ci return ret; 235cabdff1aSopenharmony_ci memcpy(frame->data[1], c->pal, AVPALETTE_SIZE); 236cabdff1aSopenharmony_ci frame->palette_has_changed = pc; 237cabdff1aSopenharmony_ci 238cabdff1aSopenharmony_ci outptr = frame->data[0]; 239cabdff1aSopenharmony_ci srcptr = c->decomp_buf; 240cabdff1aSopenharmony_ci tmpptr = c->prev->data[0]; 241cabdff1aSopenharmony_ci stride = frame->linesize[0]; 242cabdff1aSopenharmony_ci 243cabdff1aSopenharmony_ci if (bytestream2_get_le32(&gb) == MKTAG('N','U','L','L')) 244cabdff1aSopenharmony_ci compr = -1; 245cabdff1aSopenharmony_ci else 246cabdff1aSopenharmony_ci compr = bytestream2_get_byte(&gb); 247cabdff1aSopenharmony_ci 248cabdff1aSopenharmony_ci dsize = c->dsize; 249cabdff1aSopenharmony_ci if (compr != 4 && compr != -1) { 250cabdff1aSopenharmony_ci bytestream2_skip(&gb, 4); 251cabdff1aSopenharmony_ci if (uncompress(c->decomp_buf, &dsize, avpkt->data + bytestream2_tell(&gb), 252cabdff1aSopenharmony_ci bytestream2_get_bytes_left(&gb)) != Z_OK) { 253cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Uncompress failed!\n"); 254cabdff1aSopenharmony_ci return AVERROR_UNKNOWN; 255cabdff1aSopenharmony_ci } 256cabdff1aSopenharmony_ci memset(c->decomp_buf + dsize, 0, DECOMP_BUF_PADDING); 257cabdff1aSopenharmony_ci } 258cabdff1aSopenharmony_ci 259cabdff1aSopenharmony_ci if (avctx->debug & FF_DEBUG_PICT_INFO) 260cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_DEBUG, "compr:%2d, dsize:%d\n", compr, (int)dsize); 261cabdff1aSopenharmony_ci 262cabdff1aSopenharmony_ci switch(compr){ 263cabdff1aSopenharmony_ci case -1: 264cabdff1aSopenharmony_ci frame->key_frame = 0; 265cabdff1aSopenharmony_ci frame->pict_type = AV_PICTURE_TYPE_P; 266cabdff1aSopenharmony_ci if (c->prev->data[0]) 267cabdff1aSopenharmony_ci memcpy(frame->data[0], c->prev->data[0], frame->linesize[0] * avctx->height); 268cabdff1aSopenharmony_ci else{ // Should happen only when first frame is 'NULL' 269cabdff1aSopenharmony_ci memset(frame->data[0], 0, frame->linesize[0] * avctx->height); 270cabdff1aSopenharmony_ci frame->key_frame = 1; 271cabdff1aSopenharmony_ci frame->pict_type = AV_PICTURE_TYPE_I; 272cabdff1aSopenharmony_ci } 273cabdff1aSopenharmony_ci break; 274cabdff1aSopenharmony_ci case 2: 275cabdff1aSopenharmony_ci case 4: 276cabdff1aSopenharmony_ci frame->key_frame = 1; 277cabdff1aSopenharmony_ci frame->pict_type = AV_PICTURE_TYPE_I; 278cabdff1aSopenharmony_ci for (j = 0; j < avctx->height; j++) { 279cabdff1aSopenharmony_ci memcpy(outptr, srcptr, avctx->width); 280cabdff1aSopenharmony_ci outptr += stride; 281cabdff1aSopenharmony_ci srcptr += avctx->width; 282cabdff1aSopenharmony_ci } 283cabdff1aSopenharmony_ci break; 284cabdff1aSopenharmony_ci case 3: 285cabdff1aSopenharmony_ci case 5: 286cabdff1aSopenharmony_ci if (!tmpptr) { 287cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Missing reference frame.\n"); 288cabdff1aSopenharmony_ci if (!(avctx->flags2 & AV_CODEC_FLAG2_SHOW_ALL)) 289cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 290cabdff1aSopenharmony_ci } 291cabdff1aSopenharmony_ci frame->key_frame = 0; 292cabdff1aSopenharmony_ci frame->pict_type = AV_PICTURE_TYPE_P; 293cabdff1aSopenharmony_ci for (j = 0; j < avctx->height; j++) { 294cabdff1aSopenharmony_ci if(tmpptr){ 295cabdff1aSopenharmony_ci for(i = 0; i < avctx->width; i++) 296cabdff1aSopenharmony_ci outptr[i] = srcptr[i] ^ tmpptr[i]; 297cabdff1aSopenharmony_ci tmpptr += stride; 298cabdff1aSopenharmony_ci }else 299cabdff1aSopenharmony_ci memcpy(outptr, srcptr, avctx->width); 300cabdff1aSopenharmony_ci outptr += stride; 301cabdff1aSopenharmony_ci srcptr += avctx->width; 302cabdff1aSopenharmony_ci } 303cabdff1aSopenharmony_ci break; 304cabdff1aSopenharmony_ci case 12: // ScummVM coding 305cabdff1aSopenharmony_ci case 13: 306cabdff1aSopenharmony_ci frame->key_frame = 0; 307cabdff1aSopenharmony_ci frame->pict_type = AV_PICTURE_TYPE_P; 308cabdff1aSopenharmony_ci if (!c->prev->data[0]) { 309cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Missing reference frame\n"); 310cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 311cabdff1aSopenharmony_ci } 312cabdff1aSopenharmony_ci decode_13(avctx, c, frame->data[0], frame->linesize[0], srcptr, dsize, c->prev->data[0]); 313cabdff1aSopenharmony_ci break; 314cabdff1aSopenharmony_ci default: 315cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Unknown/unsupported compression type %d\n", compr); 316cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 317cabdff1aSopenharmony_ci } 318cabdff1aSopenharmony_ci 319cabdff1aSopenharmony_ci av_frame_unref(c->prev); 320cabdff1aSopenharmony_ci if ((ret = av_frame_ref(c->prev, frame)) < 0) 321cabdff1aSopenharmony_ci return ret; 322cabdff1aSopenharmony_ci 323cabdff1aSopenharmony_ci *got_frame = 1; 324cabdff1aSopenharmony_ci 325cabdff1aSopenharmony_ci /* always report that the buffer was completely consumed */ 326cabdff1aSopenharmony_ci return avpkt->size; 327cabdff1aSopenharmony_ci} 328cabdff1aSopenharmony_ci 329cabdff1aSopenharmony_cistatic av_cold int decode_init(AVCodecContext *avctx) 330cabdff1aSopenharmony_ci{ 331cabdff1aSopenharmony_ci DxaDecContext * const c = avctx->priv_data; 332cabdff1aSopenharmony_ci 333cabdff1aSopenharmony_ci if (avctx->width%4 || avctx->height%4) { 334cabdff1aSopenharmony_ci avpriv_request_sample(avctx, "dimensions are not a multiple of 4"); 335cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 336cabdff1aSopenharmony_ci } 337cabdff1aSopenharmony_ci 338cabdff1aSopenharmony_ci c->prev = av_frame_alloc(); 339cabdff1aSopenharmony_ci if (!c->prev) 340cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 341cabdff1aSopenharmony_ci 342cabdff1aSopenharmony_ci avctx->pix_fmt = AV_PIX_FMT_PAL8; 343cabdff1aSopenharmony_ci 344cabdff1aSopenharmony_ci c->dsize = avctx->width * avctx->height * 2; 345cabdff1aSopenharmony_ci c->decomp_buf = av_malloc(c->dsize + DECOMP_BUF_PADDING); 346cabdff1aSopenharmony_ci if (!c->decomp_buf) { 347cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Can't allocate decompression buffer.\n"); 348cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 349cabdff1aSopenharmony_ci } 350cabdff1aSopenharmony_ci 351cabdff1aSopenharmony_ci return 0; 352cabdff1aSopenharmony_ci} 353cabdff1aSopenharmony_ci 354cabdff1aSopenharmony_cistatic av_cold int decode_end(AVCodecContext *avctx) 355cabdff1aSopenharmony_ci{ 356cabdff1aSopenharmony_ci DxaDecContext * const c = avctx->priv_data; 357cabdff1aSopenharmony_ci 358cabdff1aSopenharmony_ci av_freep(&c->decomp_buf); 359cabdff1aSopenharmony_ci av_frame_free(&c->prev); 360cabdff1aSopenharmony_ci 361cabdff1aSopenharmony_ci return 0; 362cabdff1aSopenharmony_ci} 363cabdff1aSopenharmony_ci 364cabdff1aSopenharmony_ciconst FFCodec ff_dxa_decoder = { 365cabdff1aSopenharmony_ci .p.name = "dxa", 366cabdff1aSopenharmony_ci .p.long_name = NULL_IF_CONFIG_SMALL("Feeble Files/ScummVM DXA"), 367cabdff1aSopenharmony_ci .p.type = AVMEDIA_TYPE_VIDEO, 368cabdff1aSopenharmony_ci .p.id = AV_CODEC_ID_DXA, 369cabdff1aSopenharmony_ci .priv_data_size = sizeof(DxaDecContext), 370cabdff1aSopenharmony_ci .init = decode_init, 371cabdff1aSopenharmony_ci .close = decode_end, 372cabdff1aSopenharmony_ci FF_CODEC_DECODE_CB(decode_frame), 373cabdff1aSopenharmony_ci .p.capabilities = AV_CODEC_CAP_DR1, 374cabdff1aSopenharmony_ci .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, 375cabdff1aSopenharmony_ci}; 376