1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * FLI/FLC Animation Video Decoder 3cabdff1aSopenharmony_ci * Copyright (C) 2003, 2004 The FFmpeg project 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 * Autodesk Animator FLI/FLC Video Decoder 25cabdff1aSopenharmony_ci * by Mike Melanson (melanson@pcisys.net) 26cabdff1aSopenharmony_ci * for more information on the .fli/.flc file format and all of its many 27cabdff1aSopenharmony_ci * variations, visit: 28cabdff1aSopenharmony_ci * http://www.compuphase.com/flic.htm 29cabdff1aSopenharmony_ci * 30cabdff1aSopenharmony_ci * This decoder outputs PAL8/RGB555/RGB565/BGR24. To use this decoder, be 31cabdff1aSopenharmony_ci * sure that your demuxer sends the FLI file header to the decoder via 32cabdff1aSopenharmony_ci * the extradata chunk in AVCodecContext. The chunk should be 128 bytes 33cabdff1aSopenharmony_ci * large. The only exception is for FLI files from the game "Magic Carpet", 34cabdff1aSopenharmony_ci * in which the header is only 12 bytes. 35cabdff1aSopenharmony_ci */ 36cabdff1aSopenharmony_ci 37cabdff1aSopenharmony_ci#include <stdio.h> 38cabdff1aSopenharmony_ci#include <stdlib.h> 39cabdff1aSopenharmony_ci#include <string.h> 40cabdff1aSopenharmony_ci 41cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h" 42cabdff1aSopenharmony_ci#include "avcodec.h" 43cabdff1aSopenharmony_ci#include "bytestream.h" 44cabdff1aSopenharmony_ci#include "codec_internal.h" 45cabdff1aSopenharmony_ci#include "internal.h" 46cabdff1aSopenharmony_ci#include "mathops.h" 47cabdff1aSopenharmony_ci 48cabdff1aSopenharmony_ci#define FLI_256_COLOR 4 49cabdff1aSopenharmony_ci#define FLI_DELTA 7 50cabdff1aSopenharmony_ci#define FLI_COLOR 11 51cabdff1aSopenharmony_ci#define FLI_LC 12 52cabdff1aSopenharmony_ci#define FLI_BLACK 13 53cabdff1aSopenharmony_ci#define FLI_BRUN 15 54cabdff1aSopenharmony_ci#define FLI_COPY 16 55cabdff1aSopenharmony_ci#define FLI_MINI 18 56cabdff1aSopenharmony_ci#define FLI_DTA_BRUN 25 57cabdff1aSopenharmony_ci#define FLI_DTA_COPY 26 58cabdff1aSopenharmony_ci#define FLI_DTA_LC 27 59cabdff1aSopenharmony_ci 60cabdff1aSopenharmony_ci#define FLI_TYPE_CODE (0xAF11) 61cabdff1aSopenharmony_ci#define FLC_FLX_TYPE_CODE (0xAF12) 62cabdff1aSopenharmony_ci#define FLC_DTA_TYPE_CODE (0xAF44) /* Marks an "Extended FLC" comes from Dave's Targa Animator (DTA) */ 63cabdff1aSopenharmony_ci#define FLC_MAGIC_CARPET_SYNTHETIC_TYPE_CODE (0xAF13) 64cabdff1aSopenharmony_ci 65cabdff1aSopenharmony_ci#define CHECK_PIXEL_PTR(n) \ 66cabdff1aSopenharmony_ci if (pixel_ptr + n > pixel_limit) { \ 67cabdff1aSopenharmony_ci av_log (s->avctx, AV_LOG_ERROR, "Invalid pixel_ptr = %d > pixel_limit = %d\n", \ 68cabdff1aSopenharmony_ci pixel_ptr + n, pixel_limit); \ 69cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; \ 70cabdff1aSopenharmony_ci } \ 71cabdff1aSopenharmony_ci 72cabdff1aSopenharmony_citypedef struct FlicDecodeContext { 73cabdff1aSopenharmony_ci AVCodecContext *avctx; 74cabdff1aSopenharmony_ci AVFrame *frame; 75cabdff1aSopenharmony_ci 76cabdff1aSopenharmony_ci unsigned int palette[256]; 77cabdff1aSopenharmony_ci int new_palette; 78cabdff1aSopenharmony_ci int fli_type; /* either 0xAF11 or 0xAF12, affects palette resolution */ 79cabdff1aSopenharmony_ci} FlicDecodeContext; 80cabdff1aSopenharmony_ci 81cabdff1aSopenharmony_cistatic av_cold int flic_decode_init(AVCodecContext *avctx) 82cabdff1aSopenharmony_ci{ 83cabdff1aSopenharmony_ci FlicDecodeContext *s = avctx->priv_data; 84cabdff1aSopenharmony_ci unsigned char *fli_header = (unsigned char *)avctx->extradata; 85cabdff1aSopenharmony_ci int depth; 86cabdff1aSopenharmony_ci 87cabdff1aSopenharmony_ci if (avctx->extradata_size != 0 && 88cabdff1aSopenharmony_ci avctx->extradata_size != 12 && 89cabdff1aSopenharmony_ci avctx->extradata_size != 128 && 90cabdff1aSopenharmony_ci avctx->extradata_size != 256 && 91cabdff1aSopenharmony_ci avctx->extradata_size != 904 && 92cabdff1aSopenharmony_ci avctx->extradata_size != 1024) { 93cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Unexpected extradata size %d\n", avctx->extradata_size); 94cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 95cabdff1aSopenharmony_ci } 96cabdff1aSopenharmony_ci 97cabdff1aSopenharmony_ci s->avctx = avctx; 98cabdff1aSopenharmony_ci 99cabdff1aSopenharmony_ci if (s->avctx->extradata_size == 12) { 100cabdff1aSopenharmony_ci /* special case for magic carpet FLIs */ 101cabdff1aSopenharmony_ci s->fli_type = FLC_MAGIC_CARPET_SYNTHETIC_TYPE_CODE; 102cabdff1aSopenharmony_ci depth = 8; 103cabdff1aSopenharmony_ci } else if (avctx->extradata_size == 1024) { 104cabdff1aSopenharmony_ci uint8_t *ptr = avctx->extradata; 105cabdff1aSopenharmony_ci int i; 106cabdff1aSopenharmony_ci 107cabdff1aSopenharmony_ci for (i = 0; i < 256; i++) { 108cabdff1aSopenharmony_ci s->palette[i] = AV_RL32(ptr); 109cabdff1aSopenharmony_ci ptr += 4; 110cabdff1aSopenharmony_ci } 111cabdff1aSopenharmony_ci depth = 8; 112cabdff1aSopenharmony_ci /* FLI in MOV, see e.g. FFmpeg trac issue #626 */ 113cabdff1aSopenharmony_ci } else if (avctx->extradata_size == 0 || 114cabdff1aSopenharmony_ci avctx->extradata_size == 256 || 115cabdff1aSopenharmony_ci /* see FFmpeg ticket #1234 */ 116cabdff1aSopenharmony_ci avctx->extradata_size == 904) { 117cabdff1aSopenharmony_ci s->fli_type = FLI_TYPE_CODE; 118cabdff1aSopenharmony_ci depth = 8; 119cabdff1aSopenharmony_ci } else { 120cabdff1aSopenharmony_ci s->fli_type = AV_RL16(&fli_header[4]); 121cabdff1aSopenharmony_ci depth = AV_RL16(&fli_header[12]); 122cabdff1aSopenharmony_ci } 123cabdff1aSopenharmony_ci 124cabdff1aSopenharmony_ci if (depth == 0) { 125cabdff1aSopenharmony_ci depth = 8; /* Some FLC generators set depth to zero, when they mean 8Bpp. Fix up here */ 126cabdff1aSopenharmony_ci } 127cabdff1aSopenharmony_ci 128cabdff1aSopenharmony_ci if ((s->fli_type == FLC_FLX_TYPE_CODE) && (depth == 16)) { 129cabdff1aSopenharmony_ci depth = 15; /* Original Autodesk FLX's say the depth is 16Bpp when it is really 15Bpp */ 130cabdff1aSopenharmony_ci } 131cabdff1aSopenharmony_ci 132cabdff1aSopenharmony_ci switch (depth) { 133cabdff1aSopenharmony_ci case 8 : avctx->pix_fmt = AV_PIX_FMT_PAL8; break; 134cabdff1aSopenharmony_ci case 15 : avctx->pix_fmt = AV_PIX_FMT_RGB555; break; 135cabdff1aSopenharmony_ci case 16 : avctx->pix_fmt = AV_PIX_FMT_RGB565; break; 136cabdff1aSopenharmony_ci case 24 : avctx->pix_fmt = AV_PIX_FMT_BGR24; break; 137cabdff1aSopenharmony_ci default : 138cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Unknown FLC/FLX depth of %d Bpp is unsupported.\n",depth); 139cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 140cabdff1aSopenharmony_ci } 141cabdff1aSopenharmony_ci 142cabdff1aSopenharmony_ci s->frame = av_frame_alloc(); 143cabdff1aSopenharmony_ci if (!s->frame) 144cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 145cabdff1aSopenharmony_ci 146cabdff1aSopenharmony_ci s->new_palette = 0; 147cabdff1aSopenharmony_ci 148cabdff1aSopenharmony_ci return 0; 149cabdff1aSopenharmony_ci} 150cabdff1aSopenharmony_ci 151cabdff1aSopenharmony_cistatic int flic_decode_frame_8BPP(AVCodecContext *avctx, 152cabdff1aSopenharmony_ci AVFrame *rframe, int *got_frame, 153cabdff1aSopenharmony_ci const uint8_t *buf, int buf_size) 154cabdff1aSopenharmony_ci{ 155cabdff1aSopenharmony_ci FlicDecodeContext *s = avctx->priv_data; 156cabdff1aSopenharmony_ci 157cabdff1aSopenharmony_ci GetByteContext g2; 158cabdff1aSopenharmony_ci int pixel_ptr; 159cabdff1aSopenharmony_ci int palette_ptr; 160cabdff1aSopenharmony_ci unsigned char palette_idx1; 161cabdff1aSopenharmony_ci unsigned char palette_idx2; 162cabdff1aSopenharmony_ci 163cabdff1aSopenharmony_ci unsigned int frame_size; 164cabdff1aSopenharmony_ci int num_chunks; 165cabdff1aSopenharmony_ci 166cabdff1aSopenharmony_ci unsigned int chunk_size; 167cabdff1aSopenharmony_ci int chunk_type; 168cabdff1aSopenharmony_ci 169cabdff1aSopenharmony_ci int i, j, ret; 170cabdff1aSopenharmony_ci 171cabdff1aSopenharmony_ci int color_packets; 172cabdff1aSopenharmony_ci int color_changes; 173cabdff1aSopenharmony_ci int color_shift; 174cabdff1aSopenharmony_ci unsigned char r, g, b; 175cabdff1aSopenharmony_ci 176cabdff1aSopenharmony_ci int lines; 177cabdff1aSopenharmony_ci int compressed_lines; 178cabdff1aSopenharmony_ci int starting_line; 179cabdff1aSopenharmony_ci int line_packets; 180cabdff1aSopenharmony_ci int y_ptr; 181cabdff1aSopenharmony_ci int byte_run; 182cabdff1aSopenharmony_ci int pixel_skip; 183cabdff1aSopenharmony_ci int pixel_countdown; 184cabdff1aSopenharmony_ci unsigned char *pixels; 185cabdff1aSopenharmony_ci unsigned int pixel_limit; 186cabdff1aSopenharmony_ci 187cabdff1aSopenharmony_ci bytestream2_init(&g2, buf, buf_size); 188cabdff1aSopenharmony_ci 189cabdff1aSopenharmony_ci if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0) 190cabdff1aSopenharmony_ci return ret; 191cabdff1aSopenharmony_ci 192cabdff1aSopenharmony_ci pixels = s->frame->data[0]; 193cabdff1aSopenharmony_ci pixel_limit = s->avctx->height * s->frame->linesize[0]; 194cabdff1aSopenharmony_ci if (buf_size < 16 || buf_size > INT_MAX - (3 * 256 + AV_INPUT_BUFFER_PADDING_SIZE)) 195cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 196cabdff1aSopenharmony_ci frame_size = bytestream2_get_le32(&g2); 197cabdff1aSopenharmony_ci if (frame_size > buf_size) 198cabdff1aSopenharmony_ci frame_size = buf_size; 199cabdff1aSopenharmony_ci bytestream2_skip(&g2, 2); /* skip the magic number */ 200cabdff1aSopenharmony_ci num_chunks = bytestream2_get_le16(&g2); 201cabdff1aSopenharmony_ci bytestream2_skip(&g2, 8); /* skip padding */ 202cabdff1aSopenharmony_ci 203cabdff1aSopenharmony_ci if (frame_size < 16) 204cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 205cabdff1aSopenharmony_ci 206cabdff1aSopenharmony_ci frame_size -= 16; 207cabdff1aSopenharmony_ci 208cabdff1aSopenharmony_ci /* iterate through the chunks */ 209cabdff1aSopenharmony_ci while ((frame_size >= 6) && (num_chunks > 0) && 210cabdff1aSopenharmony_ci bytestream2_get_bytes_left(&g2) >= 4) { 211cabdff1aSopenharmony_ci int stream_ptr_after_chunk; 212cabdff1aSopenharmony_ci chunk_size = bytestream2_get_le32(&g2); 213cabdff1aSopenharmony_ci if (chunk_size > frame_size) { 214cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_WARNING, 215cabdff1aSopenharmony_ci "Invalid chunk_size = %u > frame_size = %u\n", chunk_size, frame_size); 216cabdff1aSopenharmony_ci chunk_size = frame_size; 217cabdff1aSopenharmony_ci } 218cabdff1aSopenharmony_ci stream_ptr_after_chunk = bytestream2_tell(&g2) - 4 + chunk_size; 219cabdff1aSopenharmony_ci 220cabdff1aSopenharmony_ci chunk_type = bytestream2_get_le16(&g2); 221cabdff1aSopenharmony_ci 222cabdff1aSopenharmony_ci switch (chunk_type) { 223cabdff1aSopenharmony_ci case FLI_256_COLOR: 224cabdff1aSopenharmony_ci case FLI_COLOR: 225cabdff1aSopenharmony_ci /* check special case: If this file is from the Magic Carpet 226cabdff1aSopenharmony_ci * game and uses 6-bit colors even though it reports 256-color 227cabdff1aSopenharmony_ci * chunks in a 0xAF12-type file (fli_type is set to 0xAF13 during 228cabdff1aSopenharmony_ci * initialization) */ 229cabdff1aSopenharmony_ci if ((chunk_type == FLI_256_COLOR) && (s->fli_type != FLC_MAGIC_CARPET_SYNTHETIC_TYPE_CODE)) 230cabdff1aSopenharmony_ci color_shift = 0; 231cabdff1aSopenharmony_ci else 232cabdff1aSopenharmony_ci color_shift = 2; 233cabdff1aSopenharmony_ci /* set up the palette */ 234cabdff1aSopenharmony_ci color_packets = bytestream2_get_le16(&g2); 235cabdff1aSopenharmony_ci palette_ptr = 0; 236cabdff1aSopenharmony_ci for (i = 0; i < color_packets; i++) { 237cabdff1aSopenharmony_ci /* first byte is how many colors to skip */ 238cabdff1aSopenharmony_ci palette_ptr += bytestream2_get_byte(&g2); 239cabdff1aSopenharmony_ci 240cabdff1aSopenharmony_ci /* next byte indicates how many entries to change */ 241cabdff1aSopenharmony_ci color_changes = bytestream2_get_byte(&g2); 242cabdff1aSopenharmony_ci 243cabdff1aSopenharmony_ci /* if there are 0 color changes, there are actually 256 */ 244cabdff1aSopenharmony_ci if (color_changes == 0) 245cabdff1aSopenharmony_ci color_changes = 256; 246cabdff1aSopenharmony_ci 247cabdff1aSopenharmony_ci if (bytestream2_tell(&g2) + color_changes * 3 > stream_ptr_after_chunk) 248cabdff1aSopenharmony_ci break; 249cabdff1aSopenharmony_ci 250cabdff1aSopenharmony_ci for (j = 0; j < color_changes; j++) { 251cabdff1aSopenharmony_ci unsigned int entry; 252cabdff1aSopenharmony_ci 253cabdff1aSopenharmony_ci /* wrap around, for good measure */ 254cabdff1aSopenharmony_ci if ((unsigned)palette_ptr >= 256) 255cabdff1aSopenharmony_ci palette_ptr = 0; 256cabdff1aSopenharmony_ci 257cabdff1aSopenharmony_ci r = bytestream2_get_byte(&g2) << color_shift; 258cabdff1aSopenharmony_ci g = bytestream2_get_byte(&g2) << color_shift; 259cabdff1aSopenharmony_ci b = bytestream2_get_byte(&g2) << color_shift; 260cabdff1aSopenharmony_ci entry = 0xFFU << 24 | r << 16 | g << 8 | b; 261cabdff1aSopenharmony_ci if (color_shift == 2) 262cabdff1aSopenharmony_ci entry |= entry >> 6 & 0x30303; 263cabdff1aSopenharmony_ci if (s->palette[palette_ptr] != entry) 264cabdff1aSopenharmony_ci s->new_palette = 1; 265cabdff1aSopenharmony_ci s->palette[palette_ptr++] = entry; 266cabdff1aSopenharmony_ci } 267cabdff1aSopenharmony_ci } 268cabdff1aSopenharmony_ci break; 269cabdff1aSopenharmony_ci 270cabdff1aSopenharmony_ci case FLI_DELTA: 271cabdff1aSopenharmony_ci y_ptr = 0; 272cabdff1aSopenharmony_ci compressed_lines = bytestream2_get_le16(&g2); 273cabdff1aSopenharmony_ci while (compressed_lines > 0) { 274cabdff1aSopenharmony_ci if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk) 275cabdff1aSopenharmony_ci break; 276cabdff1aSopenharmony_ci if (y_ptr > pixel_limit) 277cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 278cabdff1aSopenharmony_ci line_packets = sign_extend(bytestream2_get_le16(&g2), 16); 279cabdff1aSopenharmony_ci if ((line_packets & 0xC000) == 0xC000) { 280cabdff1aSopenharmony_ci // line skip opcode 281cabdff1aSopenharmony_ci line_packets = -line_packets; 282cabdff1aSopenharmony_ci if (line_packets > s->avctx->height) 283cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 284cabdff1aSopenharmony_ci y_ptr += line_packets * s->frame->linesize[0]; 285cabdff1aSopenharmony_ci } else if ((line_packets & 0xC000) == 0x4000) { 286cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Undefined opcode (%x) in DELTA_FLI\n", line_packets); 287cabdff1aSopenharmony_ci } else if ((line_packets & 0xC000) == 0x8000) { 288cabdff1aSopenharmony_ci // "last byte" opcode 289cabdff1aSopenharmony_ci pixel_ptr= y_ptr + s->frame->linesize[0] - 1; 290cabdff1aSopenharmony_ci CHECK_PIXEL_PTR(0); 291cabdff1aSopenharmony_ci pixels[pixel_ptr] = line_packets & 0xff; 292cabdff1aSopenharmony_ci } else { 293cabdff1aSopenharmony_ci compressed_lines--; 294cabdff1aSopenharmony_ci pixel_ptr = y_ptr; 295cabdff1aSopenharmony_ci CHECK_PIXEL_PTR(0); 296cabdff1aSopenharmony_ci pixel_countdown = s->avctx->width; 297cabdff1aSopenharmony_ci for (i = 0; i < line_packets; i++) { 298cabdff1aSopenharmony_ci if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk) 299cabdff1aSopenharmony_ci break; 300cabdff1aSopenharmony_ci /* account for the skip bytes */ 301cabdff1aSopenharmony_ci pixel_skip = bytestream2_get_byte(&g2); 302cabdff1aSopenharmony_ci pixel_ptr += pixel_skip; 303cabdff1aSopenharmony_ci pixel_countdown -= pixel_skip; 304cabdff1aSopenharmony_ci byte_run = sign_extend(bytestream2_get_byte(&g2), 8); 305cabdff1aSopenharmony_ci if (byte_run < 0) { 306cabdff1aSopenharmony_ci byte_run = -byte_run; 307cabdff1aSopenharmony_ci palette_idx1 = bytestream2_get_byte(&g2); 308cabdff1aSopenharmony_ci palette_idx2 = bytestream2_get_byte(&g2); 309cabdff1aSopenharmony_ci CHECK_PIXEL_PTR(byte_run * 2); 310cabdff1aSopenharmony_ci for (j = 0; j < byte_run; j++, pixel_countdown -= 2) { 311cabdff1aSopenharmony_ci pixels[pixel_ptr++] = palette_idx1; 312cabdff1aSopenharmony_ci pixels[pixel_ptr++] = palette_idx2; 313cabdff1aSopenharmony_ci } 314cabdff1aSopenharmony_ci } else { 315cabdff1aSopenharmony_ci CHECK_PIXEL_PTR(byte_run * 2); 316cabdff1aSopenharmony_ci if (bytestream2_tell(&g2) + byte_run * 2 > stream_ptr_after_chunk) 317cabdff1aSopenharmony_ci break; 318cabdff1aSopenharmony_ci for (j = 0; j < byte_run * 2; j++, pixel_countdown--) { 319cabdff1aSopenharmony_ci pixels[pixel_ptr++] = bytestream2_get_byte(&g2); 320cabdff1aSopenharmony_ci } 321cabdff1aSopenharmony_ci } 322cabdff1aSopenharmony_ci } 323cabdff1aSopenharmony_ci 324cabdff1aSopenharmony_ci y_ptr += s->frame->linesize[0]; 325cabdff1aSopenharmony_ci } 326cabdff1aSopenharmony_ci } 327cabdff1aSopenharmony_ci break; 328cabdff1aSopenharmony_ci 329cabdff1aSopenharmony_ci case FLI_LC: 330cabdff1aSopenharmony_ci /* line compressed */ 331cabdff1aSopenharmony_ci starting_line = bytestream2_get_le16(&g2); 332cabdff1aSopenharmony_ci if (starting_line >= s->avctx->height) 333cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 334cabdff1aSopenharmony_ci y_ptr = 0; 335cabdff1aSopenharmony_ci y_ptr += starting_line * s->frame->linesize[0]; 336cabdff1aSopenharmony_ci 337cabdff1aSopenharmony_ci compressed_lines = bytestream2_get_le16(&g2); 338cabdff1aSopenharmony_ci while (compressed_lines > 0) { 339cabdff1aSopenharmony_ci pixel_ptr = y_ptr; 340cabdff1aSopenharmony_ci CHECK_PIXEL_PTR(0); 341cabdff1aSopenharmony_ci pixel_countdown = s->avctx->width; 342cabdff1aSopenharmony_ci if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) 343cabdff1aSopenharmony_ci break; 344cabdff1aSopenharmony_ci line_packets = bytestream2_get_byte(&g2); 345cabdff1aSopenharmony_ci if (line_packets > 0) { 346cabdff1aSopenharmony_ci for (i = 0; i < line_packets; i++) { 347cabdff1aSopenharmony_ci /* account for the skip bytes */ 348cabdff1aSopenharmony_ci if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) 349cabdff1aSopenharmony_ci break; 350cabdff1aSopenharmony_ci pixel_skip = bytestream2_get_byte(&g2); 351cabdff1aSopenharmony_ci pixel_ptr += pixel_skip; 352cabdff1aSopenharmony_ci pixel_countdown -= pixel_skip; 353cabdff1aSopenharmony_ci byte_run = sign_extend(bytestream2_get_byte(&g2),8); 354cabdff1aSopenharmony_ci if (byte_run > 0) { 355cabdff1aSopenharmony_ci CHECK_PIXEL_PTR(byte_run); 356cabdff1aSopenharmony_ci if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk) 357cabdff1aSopenharmony_ci break; 358cabdff1aSopenharmony_ci for (j = 0; j < byte_run; j++, pixel_countdown--) { 359cabdff1aSopenharmony_ci pixels[pixel_ptr++] = bytestream2_get_byte(&g2); 360cabdff1aSopenharmony_ci } 361cabdff1aSopenharmony_ci } else if (byte_run < 0) { 362cabdff1aSopenharmony_ci byte_run = -byte_run; 363cabdff1aSopenharmony_ci palette_idx1 = bytestream2_get_byte(&g2); 364cabdff1aSopenharmony_ci CHECK_PIXEL_PTR(byte_run); 365cabdff1aSopenharmony_ci for (j = 0; j < byte_run; j++, pixel_countdown--) { 366cabdff1aSopenharmony_ci pixels[pixel_ptr++] = palette_idx1; 367cabdff1aSopenharmony_ci } 368cabdff1aSopenharmony_ci } 369cabdff1aSopenharmony_ci } 370cabdff1aSopenharmony_ci } 371cabdff1aSopenharmony_ci 372cabdff1aSopenharmony_ci y_ptr += s->frame->linesize[0]; 373cabdff1aSopenharmony_ci compressed_lines--; 374cabdff1aSopenharmony_ci } 375cabdff1aSopenharmony_ci break; 376cabdff1aSopenharmony_ci 377cabdff1aSopenharmony_ci case FLI_BLACK: 378cabdff1aSopenharmony_ci /* set the whole frame to color 0 (which is usually black) */ 379cabdff1aSopenharmony_ci memset(pixels, 0, 380cabdff1aSopenharmony_ci s->frame->linesize[0] * s->avctx->height); 381cabdff1aSopenharmony_ci break; 382cabdff1aSopenharmony_ci 383cabdff1aSopenharmony_ci case FLI_BRUN: 384cabdff1aSopenharmony_ci /* Byte run compression: This chunk type only occurs in the first 385cabdff1aSopenharmony_ci * FLI frame and it will update the entire frame. */ 386cabdff1aSopenharmony_ci y_ptr = 0; 387cabdff1aSopenharmony_ci for (lines = 0; lines < s->avctx->height; lines++) { 388cabdff1aSopenharmony_ci pixel_ptr = y_ptr; 389cabdff1aSopenharmony_ci /* disregard the line packets; instead, iterate through all 390cabdff1aSopenharmony_ci * pixels on a row */ 391cabdff1aSopenharmony_ci bytestream2_skip(&g2, 1); 392cabdff1aSopenharmony_ci pixel_countdown = s->avctx->width; 393cabdff1aSopenharmony_ci while (pixel_countdown > 0) { 394cabdff1aSopenharmony_ci if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) 395cabdff1aSopenharmony_ci break; 396cabdff1aSopenharmony_ci byte_run = sign_extend(bytestream2_get_byte(&g2), 8); 397cabdff1aSopenharmony_ci if (!byte_run) { 398cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Invalid byte run value.\n"); 399cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 400cabdff1aSopenharmony_ci } 401cabdff1aSopenharmony_ci 402cabdff1aSopenharmony_ci if (byte_run > 0) { 403cabdff1aSopenharmony_ci palette_idx1 = bytestream2_get_byte(&g2); 404cabdff1aSopenharmony_ci CHECK_PIXEL_PTR(byte_run); 405cabdff1aSopenharmony_ci for (j = 0; j < byte_run; j++) { 406cabdff1aSopenharmony_ci pixels[pixel_ptr++] = palette_idx1; 407cabdff1aSopenharmony_ci pixel_countdown--; 408cabdff1aSopenharmony_ci if (pixel_countdown < 0) 409cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n", 410cabdff1aSopenharmony_ci pixel_countdown, lines); 411cabdff1aSopenharmony_ci } 412cabdff1aSopenharmony_ci } else { /* copy bytes if byte_run < 0 */ 413cabdff1aSopenharmony_ci byte_run = -byte_run; 414cabdff1aSopenharmony_ci CHECK_PIXEL_PTR(byte_run); 415cabdff1aSopenharmony_ci if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk) 416cabdff1aSopenharmony_ci break; 417cabdff1aSopenharmony_ci for (j = 0; j < byte_run; j++) { 418cabdff1aSopenharmony_ci pixels[pixel_ptr++] = bytestream2_get_byte(&g2); 419cabdff1aSopenharmony_ci pixel_countdown--; 420cabdff1aSopenharmony_ci if (pixel_countdown < 0) 421cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n", 422cabdff1aSopenharmony_ci pixel_countdown, lines); 423cabdff1aSopenharmony_ci } 424cabdff1aSopenharmony_ci } 425cabdff1aSopenharmony_ci } 426cabdff1aSopenharmony_ci 427cabdff1aSopenharmony_ci y_ptr += s->frame->linesize[0]; 428cabdff1aSopenharmony_ci } 429cabdff1aSopenharmony_ci break; 430cabdff1aSopenharmony_ci 431cabdff1aSopenharmony_ci case FLI_COPY: 432cabdff1aSopenharmony_ci /* copy the chunk (uncompressed frame) */ 433cabdff1aSopenharmony_ci if (chunk_size - 6 != FFALIGN(s->avctx->width, 4) * s->avctx->height) { 434cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "In chunk FLI_COPY : source data (%d bytes) " \ 435cabdff1aSopenharmony_ci "has incorrect size, skipping chunk\n", chunk_size - 6); 436cabdff1aSopenharmony_ci bytestream2_skip(&g2, chunk_size - 6); 437cabdff1aSopenharmony_ci } else { 438cabdff1aSopenharmony_ci for (y_ptr = 0; y_ptr < s->frame->linesize[0] * s->avctx->height; 439cabdff1aSopenharmony_ci y_ptr += s->frame->linesize[0]) { 440cabdff1aSopenharmony_ci bytestream2_get_buffer(&g2, &pixels[y_ptr], 441cabdff1aSopenharmony_ci s->avctx->width); 442cabdff1aSopenharmony_ci if (s->avctx->width & 3) 443cabdff1aSopenharmony_ci bytestream2_skip(&g2, 4 - (s->avctx->width & 3)); 444cabdff1aSopenharmony_ci } 445cabdff1aSopenharmony_ci } 446cabdff1aSopenharmony_ci break; 447cabdff1aSopenharmony_ci 448cabdff1aSopenharmony_ci case FLI_MINI: 449cabdff1aSopenharmony_ci /* some sort of a thumbnail? disregard this chunk... */ 450cabdff1aSopenharmony_ci break; 451cabdff1aSopenharmony_ci 452cabdff1aSopenharmony_ci default: 453cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Unrecognized chunk type: %d\n", chunk_type); 454cabdff1aSopenharmony_ci break; 455cabdff1aSopenharmony_ci } 456cabdff1aSopenharmony_ci 457cabdff1aSopenharmony_ci if (stream_ptr_after_chunk - bytestream2_tell(&g2) >= 0) { 458cabdff1aSopenharmony_ci bytestream2_skip(&g2, stream_ptr_after_chunk - bytestream2_tell(&g2)); 459cabdff1aSopenharmony_ci } else { 460cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Chunk overread\n"); 461cabdff1aSopenharmony_ci break; 462cabdff1aSopenharmony_ci } 463cabdff1aSopenharmony_ci 464cabdff1aSopenharmony_ci frame_size -= chunk_size; 465cabdff1aSopenharmony_ci num_chunks--; 466cabdff1aSopenharmony_ci } 467cabdff1aSopenharmony_ci 468cabdff1aSopenharmony_ci /* by the end of the chunk, the stream ptr should equal the frame 469cabdff1aSopenharmony_ci * size (minus 1 or 2, possibly); if it doesn't, issue a warning */ 470cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&g2) > 2) 471cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Processed FLI chunk where chunk size = %d " \ 472cabdff1aSopenharmony_ci "and final chunk ptr = %d\n", buf_size, 473cabdff1aSopenharmony_ci buf_size - bytestream2_get_bytes_left(&g2)); 474cabdff1aSopenharmony_ci 475cabdff1aSopenharmony_ci /* make the palette available on the way out */ 476cabdff1aSopenharmony_ci memcpy(s->frame->data[1], s->palette, AVPALETTE_SIZE); 477cabdff1aSopenharmony_ci if (s->new_palette) { 478cabdff1aSopenharmony_ci s->frame->palette_has_changed = 1; 479cabdff1aSopenharmony_ci s->new_palette = 0; 480cabdff1aSopenharmony_ci } 481cabdff1aSopenharmony_ci 482cabdff1aSopenharmony_ci if ((ret = av_frame_ref(rframe, s->frame)) < 0) 483cabdff1aSopenharmony_ci return ret; 484cabdff1aSopenharmony_ci 485cabdff1aSopenharmony_ci *got_frame = 1; 486cabdff1aSopenharmony_ci 487cabdff1aSopenharmony_ci return buf_size; 488cabdff1aSopenharmony_ci} 489cabdff1aSopenharmony_ci 490cabdff1aSopenharmony_cistatic int flic_decode_frame_15_16BPP(AVCodecContext *avctx, 491cabdff1aSopenharmony_ci AVFrame *rframe, int *got_frame, 492cabdff1aSopenharmony_ci const uint8_t *buf, int buf_size) 493cabdff1aSopenharmony_ci{ 494cabdff1aSopenharmony_ci /* Note, the only difference between the 15Bpp and 16Bpp */ 495cabdff1aSopenharmony_ci /* Format is the pixel format, the packets are processed the same. */ 496cabdff1aSopenharmony_ci FlicDecodeContext *s = avctx->priv_data; 497cabdff1aSopenharmony_ci 498cabdff1aSopenharmony_ci GetByteContext g2; 499cabdff1aSopenharmony_ci int pixel_ptr; 500cabdff1aSopenharmony_ci unsigned char palette_idx1; 501cabdff1aSopenharmony_ci 502cabdff1aSopenharmony_ci unsigned int frame_size; 503cabdff1aSopenharmony_ci int num_chunks; 504cabdff1aSopenharmony_ci 505cabdff1aSopenharmony_ci unsigned int chunk_size; 506cabdff1aSopenharmony_ci int chunk_type; 507cabdff1aSopenharmony_ci 508cabdff1aSopenharmony_ci int i, j, ret; 509cabdff1aSopenharmony_ci 510cabdff1aSopenharmony_ci int lines; 511cabdff1aSopenharmony_ci int compressed_lines; 512cabdff1aSopenharmony_ci int line_packets; 513cabdff1aSopenharmony_ci int y_ptr; 514cabdff1aSopenharmony_ci int byte_run; 515cabdff1aSopenharmony_ci int pixel_skip; 516cabdff1aSopenharmony_ci int pixel_countdown; 517cabdff1aSopenharmony_ci unsigned char *pixels; 518cabdff1aSopenharmony_ci int pixel; 519cabdff1aSopenharmony_ci unsigned int pixel_limit; 520cabdff1aSopenharmony_ci 521cabdff1aSopenharmony_ci bytestream2_init(&g2, buf, buf_size); 522cabdff1aSopenharmony_ci 523cabdff1aSopenharmony_ci if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0) 524cabdff1aSopenharmony_ci return ret; 525cabdff1aSopenharmony_ci 526cabdff1aSopenharmony_ci pixels = s->frame->data[0]; 527cabdff1aSopenharmony_ci pixel_limit = s->avctx->height * s->frame->linesize[0]; 528cabdff1aSopenharmony_ci 529cabdff1aSopenharmony_ci frame_size = bytestream2_get_le32(&g2); 530cabdff1aSopenharmony_ci bytestream2_skip(&g2, 2); /* skip the magic number */ 531cabdff1aSopenharmony_ci num_chunks = bytestream2_get_le16(&g2); 532cabdff1aSopenharmony_ci bytestream2_skip(&g2, 8); /* skip padding */ 533cabdff1aSopenharmony_ci if (frame_size > buf_size) 534cabdff1aSopenharmony_ci frame_size = buf_size; 535cabdff1aSopenharmony_ci 536cabdff1aSopenharmony_ci if (frame_size < 16) 537cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 538cabdff1aSopenharmony_ci frame_size -= 16; 539cabdff1aSopenharmony_ci 540cabdff1aSopenharmony_ci /* iterate through the chunks */ 541cabdff1aSopenharmony_ci while ((frame_size > 0) && (num_chunks > 0) && 542cabdff1aSopenharmony_ci bytestream2_get_bytes_left(&g2) >= 4) { 543cabdff1aSopenharmony_ci int stream_ptr_after_chunk; 544cabdff1aSopenharmony_ci chunk_size = bytestream2_get_le32(&g2); 545cabdff1aSopenharmony_ci if (chunk_size > frame_size) { 546cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_WARNING, 547cabdff1aSopenharmony_ci "Invalid chunk_size = %u > frame_size = %u\n", chunk_size, frame_size); 548cabdff1aSopenharmony_ci chunk_size = frame_size; 549cabdff1aSopenharmony_ci } 550cabdff1aSopenharmony_ci stream_ptr_after_chunk = bytestream2_tell(&g2) - 4 + chunk_size; 551cabdff1aSopenharmony_ci 552cabdff1aSopenharmony_ci chunk_type = bytestream2_get_le16(&g2); 553cabdff1aSopenharmony_ci 554cabdff1aSopenharmony_ci 555cabdff1aSopenharmony_ci switch (chunk_type) { 556cabdff1aSopenharmony_ci case FLI_256_COLOR: 557cabdff1aSopenharmony_ci case FLI_COLOR: 558cabdff1aSopenharmony_ci /* For some reason, it seems that non-palettized flics do 559cabdff1aSopenharmony_ci * include one of these chunks in their first frame. 560cabdff1aSopenharmony_ci * Why I do not know, it seems rather extraneous. */ 561cabdff1aSopenharmony_ci ff_dlog(avctx, 562cabdff1aSopenharmony_ci "Unexpected Palette chunk %d in non-palettized FLC\n", 563cabdff1aSopenharmony_ci chunk_type); 564cabdff1aSopenharmony_ci bytestream2_skip(&g2, chunk_size - 6); 565cabdff1aSopenharmony_ci break; 566cabdff1aSopenharmony_ci 567cabdff1aSopenharmony_ci case FLI_DELTA: 568cabdff1aSopenharmony_ci case FLI_DTA_LC: 569cabdff1aSopenharmony_ci y_ptr = 0; 570cabdff1aSopenharmony_ci compressed_lines = bytestream2_get_le16(&g2); 571cabdff1aSopenharmony_ci while (compressed_lines > 0) { 572cabdff1aSopenharmony_ci if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk) 573cabdff1aSopenharmony_ci break; 574cabdff1aSopenharmony_ci if (y_ptr > pixel_limit) 575cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 576cabdff1aSopenharmony_ci line_packets = sign_extend(bytestream2_get_le16(&g2), 16); 577cabdff1aSopenharmony_ci if (line_packets < 0) { 578cabdff1aSopenharmony_ci line_packets = -line_packets; 579cabdff1aSopenharmony_ci if (line_packets > s->avctx->height) 580cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 581cabdff1aSopenharmony_ci y_ptr += line_packets * s->frame->linesize[0]; 582cabdff1aSopenharmony_ci } else { 583cabdff1aSopenharmony_ci compressed_lines--; 584cabdff1aSopenharmony_ci pixel_ptr = y_ptr; 585cabdff1aSopenharmony_ci CHECK_PIXEL_PTR(0); 586cabdff1aSopenharmony_ci pixel_countdown = s->avctx->width; 587cabdff1aSopenharmony_ci for (i = 0; i < line_packets; i++) { 588cabdff1aSopenharmony_ci /* account for the skip bytes */ 589cabdff1aSopenharmony_ci if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk) 590cabdff1aSopenharmony_ci break; 591cabdff1aSopenharmony_ci pixel_skip = bytestream2_get_byte(&g2); 592cabdff1aSopenharmony_ci pixel_ptr += (pixel_skip*2); /* Pixel is 2 bytes wide */ 593cabdff1aSopenharmony_ci pixel_countdown -= pixel_skip; 594cabdff1aSopenharmony_ci byte_run = sign_extend(bytestream2_get_byte(&g2), 8); 595cabdff1aSopenharmony_ci if (byte_run < 0) { 596cabdff1aSopenharmony_ci byte_run = -byte_run; 597cabdff1aSopenharmony_ci pixel = bytestream2_get_le16(&g2); 598cabdff1aSopenharmony_ci CHECK_PIXEL_PTR(2 * byte_run); 599cabdff1aSopenharmony_ci for (j = 0; j < byte_run; j++, pixel_countdown -= 2) { 600cabdff1aSopenharmony_ci *((signed short*)(&pixels[pixel_ptr])) = pixel; 601cabdff1aSopenharmony_ci pixel_ptr += 2; 602cabdff1aSopenharmony_ci } 603cabdff1aSopenharmony_ci } else { 604cabdff1aSopenharmony_ci if (bytestream2_tell(&g2) + 2*byte_run > stream_ptr_after_chunk) 605cabdff1aSopenharmony_ci break; 606cabdff1aSopenharmony_ci CHECK_PIXEL_PTR(2 * byte_run); 607cabdff1aSopenharmony_ci for (j = 0; j < byte_run; j++, pixel_countdown--) { 608cabdff1aSopenharmony_ci *((signed short*)(&pixels[pixel_ptr])) = bytestream2_get_le16(&g2); 609cabdff1aSopenharmony_ci pixel_ptr += 2; 610cabdff1aSopenharmony_ci } 611cabdff1aSopenharmony_ci } 612cabdff1aSopenharmony_ci } 613cabdff1aSopenharmony_ci 614cabdff1aSopenharmony_ci y_ptr += s->frame->linesize[0]; 615cabdff1aSopenharmony_ci } 616cabdff1aSopenharmony_ci } 617cabdff1aSopenharmony_ci break; 618cabdff1aSopenharmony_ci 619cabdff1aSopenharmony_ci case FLI_LC: 620cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Unexpected FLI_LC chunk in non-palettized FLC\n"); 621cabdff1aSopenharmony_ci bytestream2_skip(&g2, chunk_size - 6); 622cabdff1aSopenharmony_ci break; 623cabdff1aSopenharmony_ci 624cabdff1aSopenharmony_ci case FLI_BLACK: 625cabdff1aSopenharmony_ci /* set the whole frame to 0x0000 which is black in both 15Bpp and 16Bpp modes. */ 626cabdff1aSopenharmony_ci memset(pixels, 0x0000, 627cabdff1aSopenharmony_ci s->frame->linesize[0] * s->avctx->height); 628cabdff1aSopenharmony_ci break; 629cabdff1aSopenharmony_ci 630cabdff1aSopenharmony_ci case FLI_BRUN: 631cabdff1aSopenharmony_ci y_ptr = 0; 632cabdff1aSopenharmony_ci for (lines = 0; lines < s->avctx->height; lines++) { 633cabdff1aSopenharmony_ci pixel_ptr = y_ptr; 634cabdff1aSopenharmony_ci /* disregard the line packets; instead, iterate through all 635cabdff1aSopenharmony_ci * pixels on a row */ 636cabdff1aSopenharmony_ci bytestream2_skip(&g2, 1); 637cabdff1aSopenharmony_ci pixel_countdown = (s->avctx->width * 2); 638cabdff1aSopenharmony_ci 639cabdff1aSopenharmony_ci while (pixel_countdown > 0) { 640cabdff1aSopenharmony_ci if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) 641cabdff1aSopenharmony_ci break; 642cabdff1aSopenharmony_ci byte_run = sign_extend(bytestream2_get_byte(&g2), 8); 643cabdff1aSopenharmony_ci if (byte_run > 0) { 644cabdff1aSopenharmony_ci palette_idx1 = bytestream2_get_byte(&g2); 645cabdff1aSopenharmony_ci CHECK_PIXEL_PTR(byte_run); 646cabdff1aSopenharmony_ci for (j = 0; j < byte_run; j++) { 647cabdff1aSopenharmony_ci pixels[pixel_ptr++] = palette_idx1; 648cabdff1aSopenharmony_ci pixel_countdown--; 649cabdff1aSopenharmony_ci if (pixel_countdown < 0) 650cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) (linea%d)\n", 651cabdff1aSopenharmony_ci pixel_countdown, lines); 652cabdff1aSopenharmony_ci } 653cabdff1aSopenharmony_ci } else { /* copy bytes if byte_run < 0 */ 654cabdff1aSopenharmony_ci byte_run = -byte_run; 655cabdff1aSopenharmony_ci if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk) 656cabdff1aSopenharmony_ci break; 657cabdff1aSopenharmony_ci CHECK_PIXEL_PTR(byte_run); 658cabdff1aSopenharmony_ci for (j = 0; j < byte_run; j++) { 659cabdff1aSopenharmony_ci palette_idx1 = bytestream2_get_byte(&g2); 660cabdff1aSopenharmony_ci pixels[pixel_ptr++] = palette_idx1; 661cabdff1aSopenharmony_ci pixel_countdown--; 662cabdff1aSopenharmony_ci if (pixel_countdown < 0) 663cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n", 664cabdff1aSopenharmony_ci pixel_countdown, lines); 665cabdff1aSopenharmony_ci } 666cabdff1aSopenharmony_ci } 667cabdff1aSopenharmony_ci } 668cabdff1aSopenharmony_ci 669cabdff1aSopenharmony_ci /* Now FLX is strange, in that it is "byte" as opposed to "pixel" run length compressed. 670cabdff1aSopenharmony_ci * This does not give us any good opportunity to perform word endian conversion 671cabdff1aSopenharmony_ci * during decompression. So if it is required (i.e., this is not a LE target, we do 672cabdff1aSopenharmony_ci * a second pass over the line here, swapping the bytes. 673cabdff1aSopenharmony_ci */ 674cabdff1aSopenharmony_ci#if HAVE_BIGENDIAN 675cabdff1aSopenharmony_ci pixel_ptr = y_ptr; 676cabdff1aSopenharmony_ci pixel_countdown = s->avctx->width; 677cabdff1aSopenharmony_ci while (pixel_countdown > 0) { 678cabdff1aSopenharmony_ci *((signed short*)(&pixels[pixel_ptr])) = AV_RL16(&buf[pixel_ptr]); 679cabdff1aSopenharmony_ci pixel_ptr += 2; 680cabdff1aSopenharmony_ci } 681cabdff1aSopenharmony_ci#endif 682cabdff1aSopenharmony_ci y_ptr += s->frame->linesize[0]; 683cabdff1aSopenharmony_ci } 684cabdff1aSopenharmony_ci break; 685cabdff1aSopenharmony_ci 686cabdff1aSopenharmony_ci case FLI_DTA_BRUN: 687cabdff1aSopenharmony_ci y_ptr = 0; 688cabdff1aSopenharmony_ci for (lines = 0; lines < s->avctx->height; lines++) { 689cabdff1aSopenharmony_ci pixel_ptr = y_ptr; 690cabdff1aSopenharmony_ci /* disregard the line packets; instead, iterate through all 691cabdff1aSopenharmony_ci * pixels on a row */ 692cabdff1aSopenharmony_ci bytestream2_skip(&g2, 1); 693cabdff1aSopenharmony_ci pixel_countdown = s->avctx->width; /* Width is in pixels, not bytes */ 694cabdff1aSopenharmony_ci 695cabdff1aSopenharmony_ci while (pixel_countdown > 0) { 696cabdff1aSopenharmony_ci if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) 697cabdff1aSopenharmony_ci break; 698cabdff1aSopenharmony_ci byte_run = sign_extend(bytestream2_get_byte(&g2), 8); 699cabdff1aSopenharmony_ci if (byte_run > 0) { 700cabdff1aSopenharmony_ci pixel = bytestream2_get_le16(&g2); 701cabdff1aSopenharmony_ci CHECK_PIXEL_PTR(2 * byte_run); 702cabdff1aSopenharmony_ci for (j = 0; j < byte_run; j++) { 703cabdff1aSopenharmony_ci *((signed short*)(&pixels[pixel_ptr])) = pixel; 704cabdff1aSopenharmony_ci pixel_ptr += 2; 705cabdff1aSopenharmony_ci pixel_countdown--; 706cabdff1aSopenharmony_ci if (pixel_countdown < 0) 707cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n", 708cabdff1aSopenharmony_ci pixel_countdown); 709cabdff1aSopenharmony_ci } 710cabdff1aSopenharmony_ci } else { /* copy pixels if byte_run < 0 */ 711cabdff1aSopenharmony_ci byte_run = -byte_run; 712cabdff1aSopenharmony_ci if (bytestream2_tell(&g2) + 2 * byte_run > stream_ptr_after_chunk) 713cabdff1aSopenharmony_ci break; 714cabdff1aSopenharmony_ci CHECK_PIXEL_PTR(2 * byte_run); 715cabdff1aSopenharmony_ci for (j = 0; j < byte_run; j++) { 716cabdff1aSopenharmony_ci *((signed short*)(&pixels[pixel_ptr])) = bytestream2_get_le16(&g2); 717cabdff1aSopenharmony_ci pixel_ptr += 2; 718cabdff1aSopenharmony_ci pixel_countdown--; 719cabdff1aSopenharmony_ci if (pixel_countdown < 0) 720cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n", 721cabdff1aSopenharmony_ci pixel_countdown); 722cabdff1aSopenharmony_ci } 723cabdff1aSopenharmony_ci } 724cabdff1aSopenharmony_ci } 725cabdff1aSopenharmony_ci 726cabdff1aSopenharmony_ci y_ptr += s->frame->linesize[0]; 727cabdff1aSopenharmony_ci } 728cabdff1aSopenharmony_ci break; 729cabdff1aSopenharmony_ci 730cabdff1aSopenharmony_ci case FLI_COPY: 731cabdff1aSopenharmony_ci case FLI_DTA_COPY: 732cabdff1aSopenharmony_ci /* copy the chunk (uncompressed frame) */ 733cabdff1aSopenharmony_ci if (chunk_size - 6 > (unsigned int)(FFALIGN(s->avctx->width, 2) * s->avctx->height)*2) { 734cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "In chunk FLI_COPY : source data (%d bytes) " \ 735cabdff1aSopenharmony_ci "bigger than image, skipping chunk\n", chunk_size - 6); 736cabdff1aSopenharmony_ci bytestream2_skip(&g2, chunk_size - 6); 737cabdff1aSopenharmony_ci } else { 738cabdff1aSopenharmony_ci 739cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&g2) < 2 * s->avctx->width * s->avctx->height ) 740cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 741cabdff1aSopenharmony_ci for (y_ptr = 0; y_ptr < s->frame->linesize[0] * s->avctx->height; 742cabdff1aSopenharmony_ci y_ptr += s->frame->linesize[0]) { 743cabdff1aSopenharmony_ci 744cabdff1aSopenharmony_ci pixel_countdown = s->avctx->width; 745cabdff1aSopenharmony_ci pixel_ptr = 0; 746cabdff1aSopenharmony_ci while (pixel_countdown > 0) { 747cabdff1aSopenharmony_ci *((signed short*)(&pixels[y_ptr + pixel_ptr])) = bytestream2_get_le16(&g2); 748cabdff1aSopenharmony_ci pixel_ptr += 2; 749cabdff1aSopenharmony_ci pixel_countdown--; 750cabdff1aSopenharmony_ci } 751cabdff1aSopenharmony_ci if (s->avctx->width & 1) 752cabdff1aSopenharmony_ci bytestream2_skip(&g2, 2); 753cabdff1aSopenharmony_ci } 754cabdff1aSopenharmony_ci } 755cabdff1aSopenharmony_ci break; 756cabdff1aSopenharmony_ci 757cabdff1aSopenharmony_ci case FLI_MINI: 758cabdff1aSopenharmony_ci /* some sort of a thumbnail? disregard this chunk... */ 759cabdff1aSopenharmony_ci bytestream2_skip(&g2, chunk_size - 6); 760cabdff1aSopenharmony_ci break; 761cabdff1aSopenharmony_ci 762cabdff1aSopenharmony_ci default: 763cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Unrecognized chunk type: %d\n", chunk_type); 764cabdff1aSopenharmony_ci break; 765cabdff1aSopenharmony_ci } 766cabdff1aSopenharmony_ci 767cabdff1aSopenharmony_ci if (stream_ptr_after_chunk - bytestream2_tell(&g2) >= 0) { 768cabdff1aSopenharmony_ci bytestream2_skip(&g2, stream_ptr_after_chunk - bytestream2_tell(&g2)); 769cabdff1aSopenharmony_ci } else { 770cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Chunk overread\n"); 771cabdff1aSopenharmony_ci break; 772cabdff1aSopenharmony_ci } 773cabdff1aSopenharmony_ci 774cabdff1aSopenharmony_ci frame_size -= chunk_size; 775cabdff1aSopenharmony_ci num_chunks--; 776cabdff1aSopenharmony_ci } 777cabdff1aSopenharmony_ci 778cabdff1aSopenharmony_ci /* by the end of the chunk, the stream ptr should equal the frame 779cabdff1aSopenharmony_ci * size (minus 1, possibly); if it doesn't, issue a warning */ 780cabdff1aSopenharmony_ci if ((bytestream2_get_bytes_left(&g2) != 0) && (bytestream2_get_bytes_left(&g2) != 1)) 781cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Processed FLI chunk where chunk size = %d " \ 782cabdff1aSopenharmony_ci "and final chunk ptr = %d\n", buf_size, bytestream2_tell(&g2)); 783cabdff1aSopenharmony_ci 784cabdff1aSopenharmony_ci if ((ret = av_frame_ref(rframe, s->frame)) < 0) 785cabdff1aSopenharmony_ci return ret; 786cabdff1aSopenharmony_ci 787cabdff1aSopenharmony_ci *got_frame = 1; 788cabdff1aSopenharmony_ci 789cabdff1aSopenharmony_ci return buf_size; 790cabdff1aSopenharmony_ci} 791cabdff1aSopenharmony_ci 792cabdff1aSopenharmony_cistatic int flic_decode_frame_24BPP(AVCodecContext *avctx, 793cabdff1aSopenharmony_ci AVFrame *rframe, int *got_frame, 794cabdff1aSopenharmony_ci const uint8_t *buf, int buf_size) 795cabdff1aSopenharmony_ci{ 796cabdff1aSopenharmony_ci FlicDecodeContext *s = avctx->priv_data; 797cabdff1aSopenharmony_ci 798cabdff1aSopenharmony_ci GetByteContext g2; 799cabdff1aSopenharmony_ci int pixel_ptr; 800cabdff1aSopenharmony_ci unsigned char palette_idx1; 801cabdff1aSopenharmony_ci 802cabdff1aSopenharmony_ci unsigned int frame_size; 803cabdff1aSopenharmony_ci int num_chunks; 804cabdff1aSopenharmony_ci 805cabdff1aSopenharmony_ci unsigned int chunk_size; 806cabdff1aSopenharmony_ci int chunk_type; 807cabdff1aSopenharmony_ci 808cabdff1aSopenharmony_ci int i, j, ret; 809cabdff1aSopenharmony_ci 810cabdff1aSopenharmony_ci int lines; 811cabdff1aSopenharmony_ci int compressed_lines; 812cabdff1aSopenharmony_ci int line_packets; 813cabdff1aSopenharmony_ci int y_ptr; 814cabdff1aSopenharmony_ci int byte_run; 815cabdff1aSopenharmony_ci int pixel_skip; 816cabdff1aSopenharmony_ci int pixel_countdown; 817cabdff1aSopenharmony_ci unsigned char *pixels; 818cabdff1aSopenharmony_ci int pixel; 819cabdff1aSopenharmony_ci unsigned int pixel_limit; 820cabdff1aSopenharmony_ci 821cabdff1aSopenharmony_ci bytestream2_init(&g2, buf, buf_size); 822cabdff1aSopenharmony_ci 823cabdff1aSopenharmony_ci if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0) 824cabdff1aSopenharmony_ci return ret; 825cabdff1aSopenharmony_ci 826cabdff1aSopenharmony_ci pixels = s->frame->data[0]; 827cabdff1aSopenharmony_ci pixel_limit = s->avctx->height * s->frame->linesize[0]; 828cabdff1aSopenharmony_ci 829cabdff1aSopenharmony_ci frame_size = bytestream2_get_le32(&g2); 830cabdff1aSopenharmony_ci bytestream2_skip(&g2, 2); /* skip the magic number */ 831cabdff1aSopenharmony_ci num_chunks = bytestream2_get_le16(&g2); 832cabdff1aSopenharmony_ci bytestream2_skip(&g2, 8); /* skip padding */ 833cabdff1aSopenharmony_ci if (frame_size > buf_size) 834cabdff1aSopenharmony_ci frame_size = buf_size; 835cabdff1aSopenharmony_ci 836cabdff1aSopenharmony_ci if (frame_size < 16) 837cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 838cabdff1aSopenharmony_ci frame_size -= 16; 839cabdff1aSopenharmony_ci 840cabdff1aSopenharmony_ci /* iterate through the chunks */ 841cabdff1aSopenharmony_ci while ((frame_size > 0) && (num_chunks > 0) && 842cabdff1aSopenharmony_ci bytestream2_get_bytes_left(&g2) >= 4) { 843cabdff1aSopenharmony_ci int stream_ptr_after_chunk; 844cabdff1aSopenharmony_ci chunk_size = bytestream2_get_le32(&g2); 845cabdff1aSopenharmony_ci if (chunk_size > frame_size) { 846cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_WARNING, 847cabdff1aSopenharmony_ci "Invalid chunk_size = %u > frame_size = %u\n", chunk_size, frame_size); 848cabdff1aSopenharmony_ci chunk_size = frame_size; 849cabdff1aSopenharmony_ci } 850cabdff1aSopenharmony_ci stream_ptr_after_chunk = bytestream2_tell(&g2) - 4 + chunk_size; 851cabdff1aSopenharmony_ci 852cabdff1aSopenharmony_ci chunk_type = bytestream2_get_le16(&g2); 853cabdff1aSopenharmony_ci 854cabdff1aSopenharmony_ci 855cabdff1aSopenharmony_ci switch (chunk_type) { 856cabdff1aSopenharmony_ci case FLI_256_COLOR: 857cabdff1aSopenharmony_ci case FLI_COLOR: 858cabdff1aSopenharmony_ci /* For some reason, it seems that non-palettized flics do 859cabdff1aSopenharmony_ci * include one of these chunks in their first frame. 860cabdff1aSopenharmony_ci * Why I do not know, it seems rather extraneous. */ 861cabdff1aSopenharmony_ci ff_dlog(avctx, 862cabdff1aSopenharmony_ci "Unexpected Palette chunk %d in non-palettized FLC\n", 863cabdff1aSopenharmony_ci chunk_type); 864cabdff1aSopenharmony_ci bytestream2_skip(&g2, chunk_size - 6); 865cabdff1aSopenharmony_ci break; 866cabdff1aSopenharmony_ci 867cabdff1aSopenharmony_ci case FLI_DELTA: 868cabdff1aSopenharmony_ci case FLI_DTA_LC: 869cabdff1aSopenharmony_ci y_ptr = 0; 870cabdff1aSopenharmony_ci compressed_lines = bytestream2_get_le16(&g2); 871cabdff1aSopenharmony_ci while (compressed_lines > 0) { 872cabdff1aSopenharmony_ci if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk) 873cabdff1aSopenharmony_ci break; 874cabdff1aSopenharmony_ci if (y_ptr > pixel_limit) 875cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 876cabdff1aSopenharmony_ci line_packets = sign_extend(bytestream2_get_le16(&g2), 16); 877cabdff1aSopenharmony_ci if (line_packets < 0) { 878cabdff1aSopenharmony_ci line_packets = -line_packets; 879cabdff1aSopenharmony_ci if (line_packets > s->avctx->height) 880cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 881cabdff1aSopenharmony_ci y_ptr += line_packets * s->frame->linesize[0]; 882cabdff1aSopenharmony_ci } else { 883cabdff1aSopenharmony_ci compressed_lines--; 884cabdff1aSopenharmony_ci pixel_ptr = y_ptr; 885cabdff1aSopenharmony_ci CHECK_PIXEL_PTR(0); 886cabdff1aSopenharmony_ci pixel_countdown = s->avctx->width; 887cabdff1aSopenharmony_ci for (i = 0; i < line_packets; i++) { 888cabdff1aSopenharmony_ci /* account for the skip bytes */ 889cabdff1aSopenharmony_ci if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk) 890cabdff1aSopenharmony_ci break; 891cabdff1aSopenharmony_ci pixel_skip = bytestream2_get_byte(&g2); 892cabdff1aSopenharmony_ci pixel_ptr += (pixel_skip*3); /* Pixel is 3 bytes wide */ 893cabdff1aSopenharmony_ci pixel_countdown -= pixel_skip; 894cabdff1aSopenharmony_ci byte_run = sign_extend(bytestream2_get_byte(&g2), 8); 895cabdff1aSopenharmony_ci if (byte_run < 0) { 896cabdff1aSopenharmony_ci byte_run = -byte_run; 897cabdff1aSopenharmony_ci pixel = bytestream2_get_le24(&g2); 898cabdff1aSopenharmony_ci CHECK_PIXEL_PTR(3 * byte_run); 899cabdff1aSopenharmony_ci for (j = 0; j < byte_run; j++, pixel_countdown -= 1) { 900cabdff1aSopenharmony_ci AV_WL24(&pixels[pixel_ptr], pixel); 901cabdff1aSopenharmony_ci pixel_ptr += 3; 902cabdff1aSopenharmony_ci } 903cabdff1aSopenharmony_ci } else { 904cabdff1aSopenharmony_ci if (bytestream2_tell(&g2) + 2*byte_run > stream_ptr_after_chunk) 905cabdff1aSopenharmony_ci break; 906cabdff1aSopenharmony_ci CHECK_PIXEL_PTR(3 * byte_run); 907cabdff1aSopenharmony_ci for (j = 0; j < byte_run; j++, pixel_countdown--) { 908cabdff1aSopenharmony_ci pixel = bytestream2_get_le24(&g2); 909cabdff1aSopenharmony_ci AV_WL24(&pixels[pixel_ptr], pixel); 910cabdff1aSopenharmony_ci pixel_ptr += 3; 911cabdff1aSopenharmony_ci } 912cabdff1aSopenharmony_ci } 913cabdff1aSopenharmony_ci } 914cabdff1aSopenharmony_ci 915cabdff1aSopenharmony_ci y_ptr += s->frame->linesize[0]; 916cabdff1aSopenharmony_ci } 917cabdff1aSopenharmony_ci } 918cabdff1aSopenharmony_ci break; 919cabdff1aSopenharmony_ci 920cabdff1aSopenharmony_ci case FLI_LC: 921cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Unexpected FLI_LC chunk in non-palettized FLC\n"); 922cabdff1aSopenharmony_ci bytestream2_skip(&g2, chunk_size - 6); 923cabdff1aSopenharmony_ci break; 924cabdff1aSopenharmony_ci 925cabdff1aSopenharmony_ci case FLI_BLACK: 926cabdff1aSopenharmony_ci /* set the whole frame to 0x00 which is black for 24 bit mode. */ 927cabdff1aSopenharmony_ci memset(pixels, 0x00, 928cabdff1aSopenharmony_ci s->frame->linesize[0] * s->avctx->height); 929cabdff1aSopenharmony_ci break; 930cabdff1aSopenharmony_ci 931cabdff1aSopenharmony_ci case FLI_BRUN: 932cabdff1aSopenharmony_ci y_ptr = 0; 933cabdff1aSopenharmony_ci for (lines = 0; lines < s->avctx->height; lines++) { 934cabdff1aSopenharmony_ci pixel_ptr = y_ptr; 935cabdff1aSopenharmony_ci /* disregard the line packets; instead, iterate through all 936cabdff1aSopenharmony_ci * pixels on a row */ 937cabdff1aSopenharmony_ci bytestream2_skip(&g2, 1); 938cabdff1aSopenharmony_ci pixel_countdown = (s->avctx->width * 3); 939cabdff1aSopenharmony_ci 940cabdff1aSopenharmony_ci while (pixel_countdown > 0) { 941cabdff1aSopenharmony_ci if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) 942cabdff1aSopenharmony_ci break; 943cabdff1aSopenharmony_ci byte_run = sign_extend(bytestream2_get_byte(&g2), 8); 944cabdff1aSopenharmony_ci if (byte_run > 0) { 945cabdff1aSopenharmony_ci palette_idx1 = bytestream2_get_byte(&g2); 946cabdff1aSopenharmony_ci CHECK_PIXEL_PTR(byte_run); 947cabdff1aSopenharmony_ci for (j = 0; j < byte_run; j++) { 948cabdff1aSopenharmony_ci pixels[pixel_ptr++] = palette_idx1; 949cabdff1aSopenharmony_ci pixel_countdown--; 950cabdff1aSopenharmony_ci if (pixel_countdown < 0) 951cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) (linea%d)\n", 952cabdff1aSopenharmony_ci pixel_countdown, lines); 953cabdff1aSopenharmony_ci } 954cabdff1aSopenharmony_ci } else { /* copy bytes if byte_run < 0 */ 955cabdff1aSopenharmony_ci byte_run = -byte_run; 956cabdff1aSopenharmony_ci if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk) 957cabdff1aSopenharmony_ci break; 958cabdff1aSopenharmony_ci CHECK_PIXEL_PTR(byte_run); 959cabdff1aSopenharmony_ci for (j = 0; j < byte_run; j++) { 960cabdff1aSopenharmony_ci palette_idx1 = bytestream2_get_byte(&g2); 961cabdff1aSopenharmony_ci pixels[pixel_ptr++] = palette_idx1; 962cabdff1aSopenharmony_ci pixel_countdown--; 963cabdff1aSopenharmony_ci if (pixel_countdown < 0) 964cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n", 965cabdff1aSopenharmony_ci pixel_countdown, lines); 966cabdff1aSopenharmony_ci } 967cabdff1aSopenharmony_ci } 968cabdff1aSopenharmony_ci } 969cabdff1aSopenharmony_ci 970cabdff1aSopenharmony_ci y_ptr += s->frame->linesize[0]; 971cabdff1aSopenharmony_ci } 972cabdff1aSopenharmony_ci break; 973cabdff1aSopenharmony_ci 974cabdff1aSopenharmony_ci case FLI_DTA_BRUN: 975cabdff1aSopenharmony_ci y_ptr = 0; 976cabdff1aSopenharmony_ci for (lines = 0; lines < s->avctx->height; lines++) { 977cabdff1aSopenharmony_ci pixel_ptr = y_ptr; 978cabdff1aSopenharmony_ci /* disregard the line packets; instead, iterate through all 979cabdff1aSopenharmony_ci * pixels on a row */ 980cabdff1aSopenharmony_ci bytestream2_skip(&g2, 1); 981cabdff1aSopenharmony_ci pixel_countdown = s->avctx->width; /* Width is in pixels, not bytes */ 982cabdff1aSopenharmony_ci 983cabdff1aSopenharmony_ci while (pixel_countdown > 0) { 984cabdff1aSopenharmony_ci if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk) 985cabdff1aSopenharmony_ci break; 986cabdff1aSopenharmony_ci byte_run = sign_extend(bytestream2_get_byte(&g2), 8); 987cabdff1aSopenharmony_ci if (byte_run > 0) { 988cabdff1aSopenharmony_ci pixel = bytestream2_get_le24(&g2); 989cabdff1aSopenharmony_ci CHECK_PIXEL_PTR(3 * byte_run); 990cabdff1aSopenharmony_ci for (j = 0; j < byte_run; j++) { 991cabdff1aSopenharmony_ci AV_WL24(pixels + pixel_ptr, pixel); 992cabdff1aSopenharmony_ci pixel_ptr += 3; 993cabdff1aSopenharmony_ci pixel_countdown--; 994cabdff1aSopenharmony_ci if (pixel_countdown < 0) 995cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n", 996cabdff1aSopenharmony_ci pixel_countdown); 997cabdff1aSopenharmony_ci } 998cabdff1aSopenharmony_ci } else { /* copy pixels if byte_run < 0 */ 999cabdff1aSopenharmony_ci byte_run = -byte_run; 1000cabdff1aSopenharmony_ci if (bytestream2_tell(&g2) + 3 * byte_run > stream_ptr_after_chunk) 1001cabdff1aSopenharmony_ci break; 1002cabdff1aSopenharmony_ci CHECK_PIXEL_PTR(3 * byte_run); 1003cabdff1aSopenharmony_ci for (j = 0; j < byte_run; j++) { 1004cabdff1aSopenharmony_ci pixel = bytestream2_get_le24(&g2); 1005cabdff1aSopenharmony_ci AV_WL24(pixels + pixel_ptr, pixel); 1006cabdff1aSopenharmony_ci pixel_ptr += 3; 1007cabdff1aSopenharmony_ci pixel_countdown--; 1008cabdff1aSopenharmony_ci if (pixel_countdown < 0) 1009cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n", 1010cabdff1aSopenharmony_ci pixel_countdown); 1011cabdff1aSopenharmony_ci } 1012cabdff1aSopenharmony_ci } 1013cabdff1aSopenharmony_ci } 1014cabdff1aSopenharmony_ci 1015cabdff1aSopenharmony_ci y_ptr += s->frame->linesize[0]; 1016cabdff1aSopenharmony_ci } 1017cabdff1aSopenharmony_ci break; 1018cabdff1aSopenharmony_ci 1019cabdff1aSopenharmony_ci case FLI_COPY: 1020cabdff1aSopenharmony_ci case FLI_DTA_COPY: 1021cabdff1aSopenharmony_ci /* copy the chunk (uncompressed frame) */ 1022cabdff1aSopenharmony_ci if (chunk_size - 6 > (unsigned int)(FFALIGN(s->avctx->width, 2) * s->avctx->height)*3) { 1023cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "In chunk FLI_COPY : source data (%d bytes) " \ 1024cabdff1aSopenharmony_ci "bigger than image, skipping chunk\n", chunk_size - 6); 1025cabdff1aSopenharmony_ci bytestream2_skip(&g2, chunk_size - 6); 1026cabdff1aSopenharmony_ci } else { 1027cabdff1aSopenharmony_ci for (y_ptr = 0; y_ptr < s->frame->linesize[0] * s->avctx->height; 1028cabdff1aSopenharmony_ci y_ptr += s->frame->linesize[0]) { 1029cabdff1aSopenharmony_ci 1030cabdff1aSopenharmony_ci bytestream2_get_buffer(&g2, pixels + y_ptr, 3*s->avctx->width); 1031cabdff1aSopenharmony_ci if (s->avctx->width & 1) 1032cabdff1aSopenharmony_ci bytestream2_skip(&g2, 3); 1033cabdff1aSopenharmony_ci } 1034cabdff1aSopenharmony_ci } 1035cabdff1aSopenharmony_ci break; 1036cabdff1aSopenharmony_ci 1037cabdff1aSopenharmony_ci case FLI_MINI: 1038cabdff1aSopenharmony_ci /* some sort of a thumbnail? disregard this chunk... */ 1039cabdff1aSopenharmony_ci bytestream2_skip(&g2, chunk_size - 6); 1040cabdff1aSopenharmony_ci break; 1041cabdff1aSopenharmony_ci 1042cabdff1aSopenharmony_ci default: 1043cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Unrecognized chunk type: %d\n", chunk_type); 1044cabdff1aSopenharmony_ci break; 1045cabdff1aSopenharmony_ci } 1046cabdff1aSopenharmony_ci 1047cabdff1aSopenharmony_ci if (stream_ptr_after_chunk - bytestream2_tell(&g2) >= 0) { 1048cabdff1aSopenharmony_ci bytestream2_skip(&g2, stream_ptr_after_chunk - bytestream2_tell(&g2)); 1049cabdff1aSopenharmony_ci } else { 1050cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Chunk overread\n"); 1051cabdff1aSopenharmony_ci break; 1052cabdff1aSopenharmony_ci } 1053cabdff1aSopenharmony_ci 1054cabdff1aSopenharmony_ci frame_size -= chunk_size; 1055cabdff1aSopenharmony_ci num_chunks--; 1056cabdff1aSopenharmony_ci } 1057cabdff1aSopenharmony_ci 1058cabdff1aSopenharmony_ci /* by the end of the chunk, the stream ptr should equal the frame 1059cabdff1aSopenharmony_ci * size (minus 1, possibly); if it doesn't, issue a warning */ 1060cabdff1aSopenharmony_ci if ((bytestream2_get_bytes_left(&g2) != 0) && (bytestream2_get_bytes_left(&g2) != 1)) 1061cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Processed FLI chunk where chunk size = %d " \ 1062cabdff1aSopenharmony_ci "and final chunk ptr = %d\n", buf_size, bytestream2_tell(&g2)); 1063cabdff1aSopenharmony_ci 1064cabdff1aSopenharmony_ci if ((ret = av_frame_ref(rframe, s->frame)) < 0) 1065cabdff1aSopenharmony_ci return ret; 1066cabdff1aSopenharmony_ci 1067cabdff1aSopenharmony_ci *got_frame = 1; 1068cabdff1aSopenharmony_ci 1069cabdff1aSopenharmony_ci return buf_size; 1070cabdff1aSopenharmony_ci} 1071cabdff1aSopenharmony_ci 1072cabdff1aSopenharmony_cistatic int flic_decode_frame(AVCodecContext *avctx, AVFrame *frame, 1073cabdff1aSopenharmony_ci int *got_frame, AVPacket *avpkt) 1074cabdff1aSopenharmony_ci{ 1075cabdff1aSopenharmony_ci const uint8_t *buf = avpkt->data; 1076cabdff1aSopenharmony_ci int buf_size = avpkt->size; 1077cabdff1aSopenharmony_ci if (avctx->pix_fmt == AV_PIX_FMT_PAL8) { 1078cabdff1aSopenharmony_ci return flic_decode_frame_8BPP(avctx, frame, got_frame, 1079cabdff1aSopenharmony_ci buf, buf_size); 1080cabdff1aSopenharmony_ci } else if ((avctx->pix_fmt == AV_PIX_FMT_RGB555) || 1081cabdff1aSopenharmony_ci (avctx->pix_fmt == AV_PIX_FMT_RGB565)) { 1082cabdff1aSopenharmony_ci return flic_decode_frame_15_16BPP(avctx, frame, got_frame, 1083cabdff1aSopenharmony_ci buf, buf_size); 1084cabdff1aSopenharmony_ci } else if (avctx->pix_fmt == AV_PIX_FMT_BGR24) { 1085cabdff1aSopenharmony_ci return flic_decode_frame_24BPP(avctx, frame, got_frame, 1086cabdff1aSopenharmony_ci buf, buf_size); 1087cabdff1aSopenharmony_ci } 1088cabdff1aSopenharmony_ci 1089cabdff1aSopenharmony_ci /* Should not get here, ever as the pix_fmt is processed */ 1090cabdff1aSopenharmony_ci /* in flic_decode_init and the above if should deal with */ 1091cabdff1aSopenharmony_ci /* the finite set of possibilities allowable by here. */ 1092cabdff1aSopenharmony_ci /* But in case we do, just error out. */ 1093cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Unknown FLC format, my science cannot explain how this happened.\n"); 1094cabdff1aSopenharmony_ci return AVERROR_BUG; 1095cabdff1aSopenharmony_ci} 1096cabdff1aSopenharmony_ci 1097cabdff1aSopenharmony_ci 1098cabdff1aSopenharmony_cistatic av_cold int flic_decode_end(AVCodecContext *avctx) 1099cabdff1aSopenharmony_ci{ 1100cabdff1aSopenharmony_ci FlicDecodeContext *s = avctx->priv_data; 1101cabdff1aSopenharmony_ci 1102cabdff1aSopenharmony_ci av_frame_free(&s->frame); 1103cabdff1aSopenharmony_ci 1104cabdff1aSopenharmony_ci return 0; 1105cabdff1aSopenharmony_ci} 1106cabdff1aSopenharmony_ci 1107cabdff1aSopenharmony_ciconst FFCodec ff_flic_decoder = { 1108cabdff1aSopenharmony_ci .p.name = "flic", 1109cabdff1aSopenharmony_ci .p.long_name = NULL_IF_CONFIG_SMALL("Autodesk Animator Flic video"), 1110cabdff1aSopenharmony_ci .p.type = AVMEDIA_TYPE_VIDEO, 1111cabdff1aSopenharmony_ci .p.id = AV_CODEC_ID_FLIC, 1112cabdff1aSopenharmony_ci .priv_data_size = sizeof(FlicDecodeContext), 1113cabdff1aSopenharmony_ci .init = flic_decode_init, 1114cabdff1aSopenharmony_ci .close = flic_decode_end, 1115cabdff1aSopenharmony_ci FF_CODEC_DECODE_CB(flic_decode_frame), 1116cabdff1aSopenharmony_ci .p.capabilities = AV_CODEC_CAP_DR1, 1117cabdff1aSopenharmony_ci .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, 1118cabdff1aSopenharmony_ci}; 1119