1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Wing Commander/Xan Video Decoder 3cabdff1aSopenharmony_ci * Copyright (C) 2011 Konstantin Shishkov 4cabdff1aSopenharmony_ci * based on work by Mike Melanson 5cabdff1aSopenharmony_ci * 6cabdff1aSopenharmony_ci * This file is part of FFmpeg. 7cabdff1aSopenharmony_ci * 8cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 9cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 10cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 11cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 12cabdff1aSopenharmony_ci * 13cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 14cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 15cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16cabdff1aSopenharmony_ci * Lesser General Public License for more details. 17cabdff1aSopenharmony_ci * 18cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 19cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 20cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21cabdff1aSopenharmony_ci */ 22cabdff1aSopenharmony_ci 23cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h" 24cabdff1aSopenharmony_ci#include "libavutil/mem.h" 25cabdff1aSopenharmony_ci 26cabdff1aSopenharmony_ci#include "avcodec.h" 27cabdff1aSopenharmony_ci#include "bytestream.h" 28cabdff1aSopenharmony_ci#include "codec_internal.h" 29cabdff1aSopenharmony_ci#include "internal.h" 30cabdff1aSopenharmony_ci 31cabdff1aSopenharmony_citypedef struct XanContext { 32cabdff1aSopenharmony_ci AVCodecContext *avctx; 33cabdff1aSopenharmony_ci AVFrame *pic; 34cabdff1aSopenharmony_ci 35cabdff1aSopenharmony_ci uint8_t *y_buffer; 36cabdff1aSopenharmony_ci uint8_t *scratch_buffer; 37cabdff1aSopenharmony_ci int buffer_size; 38cabdff1aSopenharmony_ci GetByteContext gb; 39cabdff1aSopenharmony_ci} XanContext; 40cabdff1aSopenharmony_ci 41cabdff1aSopenharmony_cistatic av_cold int xan_decode_end(AVCodecContext *avctx) 42cabdff1aSopenharmony_ci{ 43cabdff1aSopenharmony_ci XanContext *s = avctx->priv_data; 44cabdff1aSopenharmony_ci 45cabdff1aSopenharmony_ci av_frame_free(&s->pic); 46cabdff1aSopenharmony_ci 47cabdff1aSopenharmony_ci av_freep(&s->y_buffer); 48cabdff1aSopenharmony_ci av_freep(&s->scratch_buffer); 49cabdff1aSopenharmony_ci 50cabdff1aSopenharmony_ci return 0; 51cabdff1aSopenharmony_ci} 52cabdff1aSopenharmony_ci 53cabdff1aSopenharmony_cistatic av_cold int xan_decode_init(AVCodecContext *avctx) 54cabdff1aSopenharmony_ci{ 55cabdff1aSopenharmony_ci XanContext *s = avctx->priv_data; 56cabdff1aSopenharmony_ci 57cabdff1aSopenharmony_ci s->avctx = avctx; 58cabdff1aSopenharmony_ci 59cabdff1aSopenharmony_ci avctx->pix_fmt = AV_PIX_FMT_YUV420P; 60cabdff1aSopenharmony_ci 61cabdff1aSopenharmony_ci if (avctx->height < 8) { 62cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Invalid frame height: %d.\n", avctx->height); 63cabdff1aSopenharmony_ci return AVERROR(EINVAL); 64cabdff1aSopenharmony_ci } 65cabdff1aSopenharmony_ci if (avctx->width & 1) { 66cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Invalid frame width: %d.\n", avctx->width); 67cabdff1aSopenharmony_ci return AVERROR(EINVAL); 68cabdff1aSopenharmony_ci } 69cabdff1aSopenharmony_ci 70cabdff1aSopenharmony_ci s->buffer_size = avctx->width * avctx->height; 71cabdff1aSopenharmony_ci s->y_buffer = av_malloc(s->buffer_size); 72cabdff1aSopenharmony_ci if (!s->y_buffer) 73cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 74cabdff1aSopenharmony_ci s->scratch_buffer = av_malloc(s->buffer_size + 130); 75cabdff1aSopenharmony_ci if (!s->scratch_buffer) 76cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 77cabdff1aSopenharmony_ci 78cabdff1aSopenharmony_ci s->pic = av_frame_alloc(); 79cabdff1aSopenharmony_ci if (!s->pic) 80cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 81cabdff1aSopenharmony_ci 82cabdff1aSopenharmony_ci return 0; 83cabdff1aSopenharmony_ci} 84cabdff1aSopenharmony_ci 85cabdff1aSopenharmony_cistatic int xan_unpack_luma(XanContext *s, 86cabdff1aSopenharmony_ci uint8_t *dst, const int dst_size) 87cabdff1aSopenharmony_ci{ 88cabdff1aSopenharmony_ci int tree_size, eof; 89cabdff1aSopenharmony_ci int bits, mask; 90cabdff1aSopenharmony_ci int tree_root, node; 91cabdff1aSopenharmony_ci const uint8_t *dst_end = dst + dst_size; 92cabdff1aSopenharmony_ci GetByteContext tree = s->gb; 93cabdff1aSopenharmony_ci int start_off = bytestream2_tell(&tree); 94cabdff1aSopenharmony_ci 95cabdff1aSopenharmony_ci tree_size = bytestream2_get_byte(&s->gb); 96cabdff1aSopenharmony_ci eof = bytestream2_get_byte(&s->gb); 97cabdff1aSopenharmony_ci tree_root = eof + tree_size; 98cabdff1aSopenharmony_ci bytestream2_skip(&s->gb, tree_size * 2); 99cabdff1aSopenharmony_ci 100cabdff1aSopenharmony_ci node = tree_root; 101cabdff1aSopenharmony_ci bits = bytestream2_get_byte(&s->gb); 102cabdff1aSopenharmony_ci mask = 0x80; 103cabdff1aSopenharmony_ci for (;;) { 104cabdff1aSopenharmony_ci int bit = !!(bits & mask); 105cabdff1aSopenharmony_ci mask >>= 1; 106cabdff1aSopenharmony_ci bytestream2_seek(&tree, start_off + node*2 + bit - eof * 2, SEEK_SET); 107cabdff1aSopenharmony_ci node = bytestream2_get_byte(&tree); 108cabdff1aSopenharmony_ci if (node == eof) 109cabdff1aSopenharmony_ci break; 110cabdff1aSopenharmony_ci if (node < eof) { 111cabdff1aSopenharmony_ci *dst++ = node; 112cabdff1aSopenharmony_ci if (dst > dst_end) 113cabdff1aSopenharmony_ci break; 114cabdff1aSopenharmony_ci node = tree_root; 115cabdff1aSopenharmony_ci } 116cabdff1aSopenharmony_ci if (!mask) { 117cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&s->gb) <= 0) 118cabdff1aSopenharmony_ci break; 119cabdff1aSopenharmony_ci bits = bytestream2_get_byteu(&s->gb); 120cabdff1aSopenharmony_ci mask = 0x80; 121cabdff1aSopenharmony_ci } 122cabdff1aSopenharmony_ci } 123cabdff1aSopenharmony_ci return dst != dst_end ? AVERROR_INVALIDDATA : 0; 124cabdff1aSopenharmony_ci} 125cabdff1aSopenharmony_ci 126cabdff1aSopenharmony_ci/* almost the same as in xan_wc3 decoder */ 127cabdff1aSopenharmony_cistatic int xan_unpack(XanContext *s, 128cabdff1aSopenharmony_ci uint8_t *dest, const int dest_len) 129cabdff1aSopenharmony_ci{ 130cabdff1aSopenharmony_ci uint8_t opcode; 131cabdff1aSopenharmony_ci int size; 132cabdff1aSopenharmony_ci uint8_t *orig_dest = dest; 133cabdff1aSopenharmony_ci const uint8_t *dest_end = dest + dest_len; 134cabdff1aSopenharmony_ci 135cabdff1aSopenharmony_ci while (dest < dest_end) { 136cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&s->gb) <= 0) 137cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 138cabdff1aSopenharmony_ci 139cabdff1aSopenharmony_ci opcode = bytestream2_get_byteu(&s->gb); 140cabdff1aSopenharmony_ci 141cabdff1aSopenharmony_ci if (opcode < 0xe0) { 142cabdff1aSopenharmony_ci int size2, back; 143cabdff1aSopenharmony_ci if ((opcode & 0x80) == 0) { 144cabdff1aSopenharmony_ci size = opcode & 3; 145cabdff1aSopenharmony_ci back = ((opcode & 0x60) << 3) + bytestream2_get_byte(&s->gb) + 1; 146cabdff1aSopenharmony_ci size2 = ((opcode & 0x1c) >> 2) + 3; 147cabdff1aSopenharmony_ci } else if ((opcode & 0x40) == 0) { 148cabdff1aSopenharmony_ci size = bytestream2_peek_byte(&s->gb) >> 6; 149cabdff1aSopenharmony_ci back = (bytestream2_get_be16(&s->gb) & 0x3fff) + 1; 150cabdff1aSopenharmony_ci size2 = (opcode & 0x3f) + 4; 151cabdff1aSopenharmony_ci } else { 152cabdff1aSopenharmony_ci size = opcode & 3; 153cabdff1aSopenharmony_ci back = ((opcode & 0x10) << 12) + bytestream2_get_be16(&s->gb) + 1; 154cabdff1aSopenharmony_ci size2 = ((opcode & 0x0c) << 6) + bytestream2_get_byte(&s->gb) + 5; 155cabdff1aSopenharmony_ci if (size + size2 > dest_end - dest) 156cabdff1aSopenharmony_ci break; 157cabdff1aSopenharmony_ci } 158cabdff1aSopenharmony_ci if (dest + size + size2 > dest_end || 159cabdff1aSopenharmony_ci dest - orig_dest + size < back) 160cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 161cabdff1aSopenharmony_ci bytestream2_get_buffer(&s->gb, dest, size); 162cabdff1aSopenharmony_ci dest += size; 163cabdff1aSopenharmony_ci av_memcpy_backptr(dest, back, size2); 164cabdff1aSopenharmony_ci dest += size2; 165cabdff1aSopenharmony_ci } else { 166cabdff1aSopenharmony_ci int finish = opcode >= 0xfc; 167cabdff1aSopenharmony_ci 168cabdff1aSopenharmony_ci size = finish ? opcode & 3 : ((opcode & 0x1f) << 2) + 4; 169cabdff1aSopenharmony_ci if (dest_end - dest < size) 170cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 171cabdff1aSopenharmony_ci bytestream2_get_buffer(&s->gb, dest, size); 172cabdff1aSopenharmony_ci dest += size; 173cabdff1aSopenharmony_ci if (finish) 174cabdff1aSopenharmony_ci break; 175cabdff1aSopenharmony_ci } 176cabdff1aSopenharmony_ci } 177cabdff1aSopenharmony_ci return dest - orig_dest; 178cabdff1aSopenharmony_ci} 179cabdff1aSopenharmony_ci 180cabdff1aSopenharmony_cistatic int xan_decode_chroma(AVCodecContext *avctx, unsigned chroma_off) 181cabdff1aSopenharmony_ci{ 182cabdff1aSopenharmony_ci XanContext *s = avctx->priv_data; 183cabdff1aSopenharmony_ci uint8_t *U, *V; 184cabdff1aSopenharmony_ci int val, uval, vval; 185cabdff1aSopenharmony_ci int i, j; 186cabdff1aSopenharmony_ci const uint8_t *src, *src_end; 187cabdff1aSopenharmony_ci const uint8_t *table; 188cabdff1aSopenharmony_ci int mode, offset, dec_size, table_size; 189cabdff1aSopenharmony_ci 190cabdff1aSopenharmony_ci if (!chroma_off) 191cabdff1aSopenharmony_ci return 0; 192cabdff1aSopenharmony_ci if (chroma_off + 4 >= bytestream2_get_bytes_left(&s->gb)) { 193cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Invalid chroma block position\n"); 194cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 195cabdff1aSopenharmony_ci } 196cabdff1aSopenharmony_ci bytestream2_seek(&s->gb, chroma_off + 4, SEEK_SET); 197cabdff1aSopenharmony_ci mode = bytestream2_get_le16(&s->gb); 198cabdff1aSopenharmony_ci table = s->gb.buffer; 199cabdff1aSopenharmony_ci table_size = bytestream2_get_le16(&s->gb); 200cabdff1aSopenharmony_ci offset = table_size * 2; 201cabdff1aSopenharmony_ci table_size += 1; 202cabdff1aSopenharmony_ci 203cabdff1aSopenharmony_ci if (offset >= bytestream2_get_bytes_left(&s->gb)) { 204cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Invalid chroma block offset\n"); 205cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 206cabdff1aSopenharmony_ci } 207cabdff1aSopenharmony_ci 208cabdff1aSopenharmony_ci bytestream2_skip(&s->gb, offset); 209cabdff1aSopenharmony_ci memset(s->scratch_buffer, 0, s->buffer_size); 210cabdff1aSopenharmony_ci dec_size = xan_unpack(s, s->scratch_buffer, s->buffer_size); 211cabdff1aSopenharmony_ci if (dec_size < 0) { 212cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Chroma unpacking failed\n"); 213cabdff1aSopenharmony_ci return dec_size; 214cabdff1aSopenharmony_ci } 215cabdff1aSopenharmony_ci 216cabdff1aSopenharmony_ci U = s->pic->data[1]; 217cabdff1aSopenharmony_ci V = s->pic->data[2]; 218cabdff1aSopenharmony_ci src = s->scratch_buffer; 219cabdff1aSopenharmony_ci src_end = src + dec_size; 220cabdff1aSopenharmony_ci if (mode) { 221cabdff1aSopenharmony_ci for (j = 0; j < avctx->height >> 1; j++) { 222cabdff1aSopenharmony_ci for (i = 0; i < avctx->width >> 1; i++) { 223cabdff1aSopenharmony_ci if (src_end - src < 1) 224cabdff1aSopenharmony_ci return 0; 225cabdff1aSopenharmony_ci val = *src++; 226cabdff1aSopenharmony_ci if (val) { 227cabdff1aSopenharmony_ci if (val >= table_size) 228cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 229cabdff1aSopenharmony_ci val = AV_RL16(table + (val << 1)); 230cabdff1aSopenharmony_ci uval = (val >> 3) & 0xF8; 231cabdff1aSopenharmony_ci vval = (val >> 8) & 0xF8; 232cabdff1aSopenharmony_ci U[i] = uval | (uval >> 5); 233cabdff1aSopenharmony_ci V[i] = vval | (vval >> 5); 234cabdff1aSopenharmony_ci } 235cabdff1aSopenharmony_ci } 236cabdff1aSopenharmony_ci U += s->pic->linesize[1]; 237cabdff1aSopenharmony_ci V += s->pic->linesize[2]; 238cabdff1aSopenharmony_ci } 239cabdff1aSopenharmony_ci if (avctx->height & 1) { 240cabdff1aSopenharmony_ci memcpy(U, U - s->pic->linesize[1], avctx->width >> 1); 241cabdff1aSopenharmony_ci memcpy(V, V - s->pic->linesize[2], avctx->width >> 1); 242cabdff1aSopenharmony_ci } 243cabdff1aSopenharmony_ci } else { 244cabdff1aSopenharmony_ci uint8_t *U2 = U + s->pic->linesize[1]; 245cabdff1aSopenharmony_ci uint8_t *V2 = V + s->pic->linesize[2]; 246cabdff1aSopenharmony_ci 247cabdff1aSopenharmony_ci for (j = 0; j < avctx->height >> 2; j++) { 248cabdff1aSopenharmony_ci for (i = 0; i < avctx->width >> 1; i += 2) { 249cabdff1aSopenharmony_ci if (src_end - src < 1) 250cabdff1aSopenharmony_ci return 0; 251cabdff1aSopenharmony_ci val = *src++; 252cabdff1aSopenharmony_ci if (val) { 253cabdff1aSopenharmony_ci if (val >= table_size) 254cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 255cabdff1aSopenharmony_ci val = AV_RL16(table + (val << 1)); 256cabdff1aSopenharmony_ci uval = (val >> 3) & 0xF8; 257cabdff1aSopenharmony_ci vval = (val >> 8) & 0xF8; 258cabdff1aSopenharmony_ci U[i] = U[i+1] = U2[i] = U2[i+1] = uval | (uval >> 5); 259cabdff1aSopenharmony_ci V[i] = V[i+1] = V2[i] = V2[i+1] = vval | (vval >> 5); 260cabdff1aSopenharmony_ci } 261cabdff1aSopenharmony_ci } 262cabdff1aSopenharmony_ci U += s->pic->linesize[1] * 2; 263cabdff1aSopenharmony_ci V += s->pic->linesize[2] * 2; 264cabdff1aSopenharmony_ci U2 += s->pic->linesize[1] * 2; 265cabdff1aSopenharmony_ci V2 += s->pic->linesize[2] * 2; 266cabdff1aSopenharmony_ci } 267cabdff1aSopenharmony_ci if (avctx->height & 3) { 268cabdff1aSopenharmony_ci int lines = ((avctx->height + 1) >> 1) - (avctx->height >> 2) * 2; 269cabdff1aSopenharmony_ci 270cabdff1aSopenharmony_ci memcpy(U, U - lines * s->pic->linesize[1], lines * s->pic->linesize[1]); 271cabdff1aSopenharmony_ci memcpy(V, V - lines * s->pic->linesize[2], lines * s->pic->linesize[2]); 272cabdff1aSopenharmony_ci } 273cabdff1aSopenharmony_ci } 274cabdff1aSopenharmony_ci 275cabdff1aSopenharmony_ci return 0; 276cabdff1aSopenharmony_ci} 277cabdff1aSopenharmony_ci 278cabdff1aSopenharmony_cistatic int xan_decode_frame_type0(AVCodecContext *avctx) 279cabdff1aSopenharmony_ci{ 280cabdff1aSopenharmony_ci XanContext *s = avctx->priv_data; 281cabdff1aSopenharmony_ci uint8_t *ybuf, *prev_buf, *src = s->scratch_buffer; 282cabdff1aSopenharmony_ci unsigned chroma_off, corr_off; 283cabdff1aSopenharmony_ci int cur, last; 284cabdff1aSopenharmony_ci int i, j; 285cabdff1aSopenharmony_ci int ret; 286cabdff1aSopenharmony_ci 287cabdff1aSopenharmony_ci chroma_off = bytestream2_get_le32(&s->gb); 288cabdff1aSopenharmony_ci corr_off = bytestream2_get_le32(&s->gb); 289cabdff1aSopenharmony_ci 290cabdff1aSopenharmony_ci if ((ret = xan_decode_chroma(avctx, chroma_off)) != 0) 291cabdff1aSopenharmony_ci return ret; 292cabdff1aSopenharmony_ci 293cabdff1aSopenharmony_ci if (corr_off >= bytestream2_size(&s->gb)) { 294cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_WARNING, "Ignoring invalid correction block position\n"); 295cabdff1aSopenharmony_ci corr_off = 0; 296cabdff1aSopenharmony_ci } 297cabdff1aSopenharmony_ci bytestream2_seek(&s->gb, 12, SEEK_SET); 298cabdff1aSopenharmony_ci ret = xan_unpack_luma(s, src, s->buffer_size >> 1); 299cabdff1aSopenharmony_ci if (ret) { 300cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Luma decoding failed\n"); 301cabdff1aSopenharmony_ci return ret; 302cabdff1aSopenharmony_ci } 303cabdff1aSopenharmony_ci 304cabdff1aSopenharmony_ci ybuf = s->y_buffer; 305cabdff1aSopenharmony_ci last = *src++; 306cabdff1aSopenharmony_ci ybuf[0] = last << 1; 307cabdff1aSopenharmony_ci for (j = 1; j < avctx->width - 1; j += 2) { 308cabdff1aSopenharmony_ci cur = (last + *src++) & 0x1F; 309cabdff1aSopenharmony_ci ybuf[j] = last + cur; 310cabdff1aSopenharmony_ci ybuf[j+1] = cur << 1; 311cabdff1aSopenharmony_ci last = cur; 312cabdff1aSopenharmony_ci } 313cabdff1aSopenharmony_ci ybuf[j] = last << 1; 314cabdff1aSopenharmony_ci prev_buf = ybuf; 315cabdff1aSopenharmony_ci ybuf += avctx->width; 316cabdff1aSopenharmony_ci 317cabdff1aSopenharmony_ci for (i = 1; i < avctx->height; i++) { 318cabdff1aSopenharmony_ci last = ((prev_buf[0] >> 1) + *src++) & 0x1F; 319cabdff1aSopenharmony_ci ybuf[0] = last << 1; 320cabdff1aSopenharmony_ci for (j = 1; j < avctx->width - 1; j += 2) { 321cabdff1aSopenharmony_ci cur = ((prev_buf[j + 1] >> 1) + *src++) & 0x1F; 322cabdff1aSopenharmony_ci ybuf[j] = last + cur; 323cabdff1aSopenharmony_ci ybuf[j+1] = cur << 1; 324cabdff1aSopenharmony_ci last = cur; 325cabdff1aSopenharmony_ci } 326cabdff1aSopenharmony_ci ybuf[j] = last << 1; 327cabdff1aSopenharmony_ci prev_buf = ybuf; 328cabdff1aSopenharmony_ci ybuf += avctx->width; 329cabdff1aSopenharmony_ci } 330cabdff1aSopenharmony_ci 331cabdff1aSopenharmony_ci if (corr_off) { 332cabdff1aSopenharmony_ci int dec_size; 333cabdff1aSopenharmony_ci 334cabdff1aSopenharmony_ci bytestream2_seek(&s->gb, 8 + corr_off, SEEK_SET); 335cabdff1aSopenharmony_ci dec_size = xan_unpack(s, s->scratch_buffer, s->buffer_size / 2); 336cabdff1aSopenharmony_ci if (dec_size < 0) 337cabdff1aSopenharmony_ci dec_size = 0; 338cabdff1aSopenharmony_ci else 339cabdff1aSopenharmony_ci dec_size = FFMIN(dec_size, s->buffer_size/2 - 1); 340cabdff1aSopenharmony_ci 341cabdff1aSopenharmony_ci for (i = 0; i < dec_size; i++) 342cabdff1aSopenharmony_ci s->y_buffer[i*2+1] = (s->y_buffer[i*2+1] + (s->scratch_buffer[i] << 1)) & 0x3F; 343cabdff1aSopenharmony_ci } 344cabdff1aSopenharmony_ci 345cabdff1aSopenharmony_ci src = s->y_buffer; 346cabdff1aSopenharmony_ci ybuf = s->pic->data[0]; 347cabdff1aSopenharmony_ci for (j = 0; j < avctx->height; j++) { 348cabdff1aSopenharmony_ci for (i = 0; i < avctx->width; i++) 349cabdff1aSopenharmony_ci ybuf[i] = (src[i] << 2) | (src[i] >> 3); 350cabdff1aSopenharmony_ci src += avctx->width; 351cabdff1aSopenharmony_ci ybuf += s->pic->linesize[0]; 352cabdff1aSopenharmony_ci } 353cabdff1aSopenharmony_ci 354cabdff1aSopenharmony_ci return 0; 355cabdff1aSopenharmony_ci} 356cabdff1aSopenharmony_ci 357cabdff1aSopenharmony_cistatic int xan_decode_frame_type1(AVCodecContext *avctx) 358cabdff1aSopenharmony_ci{ 359cabdff1aSopenharmony_ci XanContext *s = avctx->priv_data; 360cabdff1aSopenharmony_ci uint8_t *ybuf, *src = s->scratch_buffer; 361cabdff1aSopenharmony_ci int cur, last; 362cabdff1aSopenharmony_ci int i, j; 363cabdff1aSopenharmony_ci int ret; 364cabdff1aSopenharmony_ci 365cabdff1aSopenharmony_ci if ((ret = xan_decode_chroma(avctx, bytestream2_get_le32(&s->gb))) != 0) 366cabdff1aSopenharmony_ci return ret; 367cabdff1aSopenharmony_ci 368cabdff1aSopenharmony_ci bytestream2_seek(&s->gb, 16, SEEK_SET); 369cabdff1aSopenharmony_ci ret = xan_unpack_luma(s, src, 370cabdff1aSopenharmony_ci s->buffer_size >> 1); 371cabdff1aSopenharmony_ci if (ret) { 372cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Luma decoding failed\n"); 373cabdff1aSopenharmony_ci return ret; 374cabdff1aSopenharmony_ci } 375cabdff1aSopenharmony_ci 376cabdff1aSopenharmony_ci ybuf = s->y_buffer; 377cabdff1aSopenharmony_ci for (i = 0; i < avctx->height; i++) { 378cabdff1aSopenharmony_ci last = (ybuf[0] + (*src++ << 1)) & 0x3F; 379cabdff1aSopenharmony_ci ybuf[0] = last; 380cabdff1aSopenharmony_ci for (j = 1; j < avctx->width - 1; j += 2) { 381cabdff1aSopenharmony_ci cur = (ybuf[j + 1] + (*src++ << 1)) & 0x3F; 382cabdff1aSopenharmony_ci ybuf[j] = (last + cur) >> 1; 383cabdff1aSopenharmony_ci ybuf[j+1] = cur; 384cabdff1aSopenharmony_ci last = cur; 385cabdff1aSopenharmony_ci } 386cabdff1aSopenharmony_ci ybuf[j] = last; 387cabdff1aSopenharmony_ci ybuf += avctx->width; 388cabdff1aSopenharmony_ci } 389cabdff1aSopenharmony_ci 390cabdff1aSopenharmony_ci src = s->y_buffer; 391cabdff1aSopenharmony_ci ybuf = s->pic->data[0]; 392cabdff1aSopenharmony_ci for (j = 0; j < avctx->height; j++) { 393cabdff1aSopenharmony_ci for (i = 0; i < avctx->width; i++) 394cabdff1aSopenharmony_ci ybuf[i] = (src[i] << 2) | (src[i] >> 3); 395cabdff1aSopenharmony_ci src += avctx->width; 396cabdff1aSopenharmony_ci ybuf += s->pic->linesize[0]; 397cabdff1aSopenharmony_ci } 398cabdff1aSopenharmony_ci 399cabdff1aSopenharmony_ci return 0; 400cabdff1aSopenharmony_ci} 401cabdff1aSopenharmony_ci 402cabdff1aSopenharmony_cistatic int xan_decode_frame(AVCodecContext *avctx, AVFrame *rframe, 403cabdff1aSopenharmony_ci int *got_frame, AVPacket *avpkt) 404cabdff1aSopenharmony_ci{ 405cabdff1aSopenharmony_ci XanContext *s = avctx->priv_data; 406cabdff1aSopenharmony_ci int ftype; 407cabdff1aSopenharmony_ci int ret; 408cabdff1aSopenharmony_ci 409cabdff1aSopenharmony_ci if ((ret = ff_reget_buffer(avctx, s->pic, 0)) < 0) 410cabdff1aSopenharmony_ci return ret; 411cabdff1aSopenharmony_ci 412cabdff1aSopenharmony_ci bytestream2_init(&s->gb, avpkt->data, avpkt->size); 413cabdff1aSopenharmony_ci ftype = bytestream2_get_le32(&s->gb); 414cabdff1aSopenharmony_ci switch (ftype) { 415cabdff1aSopenharmony_ci case 0: 416cabdff1aSopenharmony_ci ret = xan_decode_frame_type0(avctx); 417cabdff1aSopenharmony_ci break; 418cabdff1aSopenharmony_ci case 1: 419cabdff1aSopenharmony_ci ret = xan_decode_frame_type1(avctx); 420cabdff1aSopenharmony_ci break; 421cabdff1aSopenharmony_ci default: 422cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Unknown frame type %d\n", ftype); 423cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 424cabdff1aSopenharmony_ci } 425cabdff1aSopenharmony_ci if (ret) 426cabdff1aSopenharmony_ci return ret; 427cabdff1aSopenharmony_ci 428cabdff1aSopenharmony_ci if ((ret = av_frame_ref(rframe, s->pic)) < 0) 429cabdff1aSopenharmony_ci return ret; 430cabdff1aSopenharmony_ci 431cabdff1aSopenharmony_ci *got_frame = 1; 432cabdff1aSopenharmony_ci 433cabdff1aSopenharmony_ci return avpkt->size; 434cabdff1aSopenharmony_ci} 435cabdff1aSopenharmony_ci 436cabdff1aSopenharmony_ciconst FFCodec ff_xan_wc4_decoder = { 437cabdff1aSopenharmony_ci .p.name = "xan_wc4", 438cabdff1aSopenharmony_ci .p.long_name = NULL_IF_CONFIG_SMALL("Wing Commander IV / Xxan"), 439cabdff1aSopenharmony_ci .p.type = AVMEDIA_TYPE_VIDEO, 440cabdff1aSopenharmony_ci .p.id = AV_CODEC_ID_XAN_WC4, 441cabdff1aSopenharmony_ci .priv_data_size = sizeof(XanContext), 442cabdff1aSopenharmony_ci .init = xan_decode_init, 443cabdff1aSopenharmony_ci .close = xan_decode_end, 444cabdff1aSopenharmony_ci FF_CODEC_DECODE_CB(xan_decode_frame), 445cabdff1aSopenharmony_ci .p.capabilities = AV_CODEC_CAP_DR1, 446cabdff1aSopenharmony_ci .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_INIT_THREADSAFE, 447cabdff1aSopenharmony_ci}; 448