1/* 2 * Gryphon's Anim Compressor decoder 3 * Copyright (c) 2019 Paul B Mahol 4 * 5 * This file is part of FFmpeg. 6 * 7 * FFmpeg is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * FFmpeg is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with FFmpeg; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22#include <stdio.h> 23#include <stdlib.h> 24#include <string.h> 25 26#include "libavutil/imgutils.h" 27#include "libavutil/internal.h" 28#include "libavutil/intreadwrite.h" 29 30#include "avcodec.h" 31#include "bytestream.h" 32#include "codec_internal.h" 33#include "internal.h" 34 35typedef struct ARBCContext { 36 GetByteContext gb; 37 38 AVFrame *prev_frame; 39} ARBCContext; 40 41static int fill_tile4(AVCodecContext *avctx, int color, AVFrame *frame) 42{ 43 ARBCContext *s = avctx->priv_data; 44 GetByteContext *gb = &s->gb; 45 int nb_tiles = bytestream2_get_le16(gb); 46 int h = avctx->height - 1; 47 int pixels_overwritten = 0; 48 49 if ((avctx->width / 4 + 1) * (avctx->height / 4 + 1) < nb_tiles) 50 return 0; 51 52 for (int i = 0; i < nb_tiles; i++) { 53 int y = bytestream2_get_byte(gb); 54 int x = bytestream2_get_byte(gb); 55 uint16_t mask = bytestream2_get_le16(gb); 56 int start_y = y * 4, start_x = x * 4; 57 int end_y = start_y + 4, end_x = start_x + 4; 58 59 for (int j = start_y; j < end_y; j++) { 60 for (int k = start_x; k < end_x; k++) { 61 if (mask & 0x8000) { 62 if (j >= avctx->height || k >= avctx->width) { 63 mask = mask << 1; 64 continue; 65 } 66 AV_WB24(&frame->data[0][frame->linesize[0] * (h - j) + 3 * k], color); 67 pixels_overwritten ++; 68 } 69 mask = mask << 1; 70 } 71 } 72 } 73 return pixels_overwritten; 74} 75 76static int fill_tileX(AVCodecContext *avctx, int tile_width, int tile_height, 77 int color, AVFrame *frame) 78{ 79 ARBCContext *s = avctx->priv_data; 80 GetByteContext *gb = &s->gb; 81 const int step_h = tile_height / 4; 82 const int step_w = tile_width / 4; 83 int nb_tiles = bytestream2_get_le16(gb); 84 int h = avctx->height - 1; 85 int pixels_overwritten = 0; 86 87 if ((avctx->width / tile_width + 1) * (avctx->height / tile_height + 1) < nb_tiles) 88 return 0; 89 90 for (int i = 0; i < nb_tiles; i++) { 91 int y = bytestream2_get_byte(gb); 92 int x = bytestream2_get_byte(gb); 93 uint16_t mask = bytestream2_get_le16(gb); 94 int start_y = y * tile_height, start_x = x * tile_width; 95 int end_y = start_y + tile_height, end_x = start_x + tile_width; 96 97 if (start_x >= avctx->width || start_y >= avctx->height) 98 continue; 99 100 for (int j = start_y; j < end_y; j += step_h) { 101 for (int k = start_x; k < end_x; k += step_w) { 102 if (mask & 0x8000U) { 103 for (int m = 0; m < step_h; m++) { 104 for (int n = 0; n < step_w; n++) { 105 if (j + m >= avctx->height || k + n >= avctx->width) 106 continue; 107 AV_WB24(&frame->data[0][frame->linesize[0] * (h - (j + m)) + 3 * (k + n)], color); 108 } 109 } 110 pixels_overwritten += FFMIN(step_h, avctx->height - j) * FFMIN(step_w, avctx->width - k); 111 } 112 mask = mask << 1; 113 } 114 } 115 } 116 return pixels_overwritten; 117} 118 119static int decode_frame(AVCodecContext *avctx, AVFrame *frame, 120 int *got_frame, AVPacket *avpkt) 121{ 122 ARBCContext *s = avctx->priv_data; 123 int ret, nb_segments; 124 int prev_pixels = avctx->width * avctx->height; 125 126 if (avpkt->size < 10) 127 return AVERROR_INVALIDDATA; 128 129 bytestream2_init(&s->gb, avpkt->data, avpkt->size); 130 bytestream2_skip(&s->gb, 8); 131 nb_segments = bytestream2_get_le16(&s->gb); 132 if (nb_segments == 0) 133 return avpkt->size; 134 135 if (7 * nb_segments > bytestream2_get_bytes_left(&s->gb)) 136 return AVERROR_INVALIDDATA; 137 138 if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0) 139 return ret; 140 141 if (s->prev_frame->data[0]) { 142 ret = av_frame_copy(frame, s->prev_frame); 143 if (ret < 0) 144 return ret; 145 } 146 147 for (int i = 0; i < nb_segments; i++) { 148 int resolution_flag; 149 int fill; 150 151 if (bytestream2_get_bytes_left(&s->gb) <= 0) 152 return AVERROR_INVALIDDATA; 153 154 fill = bytestream2_get_byte(&s->gb) << 16; 155 bytestream2_skip(&s->gb, 1); 156 fill |= bytestream2_get_byte(&s->gb) << 8; 157 bytestream2_skip(&s->gb, 1); 158 fill |= bytestream2_get_byte(&s->gb) << 0; 159 bytestream2_skip(&s->gb, 1); 160 resolution_flag = bytestream2_get_byte(&s->gb); 161 162 if (resolution_flag & 0x10) 163 prev_pixels -= fill_tileX(avctx, 1024, 1024, fill, frame); 164 if (resolution_flag & 0x08) 165 prev_pixels -= fill_tileX(avctx, 256, 256, fill, frame); 166 if (resolution_flag & 0x04) 167 prev_pixels -= fill_tileX(avctx, 64, 64, fill, frame); 168 if (resolution_flag & 0x02) 169 prev_pixels -= fill_tileX(avctx, 16, 16, fill, frame); 170 if (resolution_flag & 0x01) 171 prev_pixels -= fill_tile4(avctx, fill, frame); 172 } 173 174 av_frame_unref(s->prev_frame); 175 if ((ret = av_frame_ref(s->prev_frame, frame)) < 0) 176 return ret; 177 178 frame->pict_type = prev_pixels <= 0 ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P; 179 frame->key_frame = prev_pixels <= 0; 180 *got_frame = 1; 181 182 return avpkt->size; 183} 184 185static av_cold int decode_init(AVCodecContext *avctx) 186{ 187 ARBCContext *s = avctx->priv_data; 188 189 avctx->pix_fmt = AV_PIX_FMT_RGB24; 190 191 s->prev_frame = av_frame_alloc(); 192 if (!s->prev_frame) 193 return AVERROR(ENOMEM); 194 195 return 0; 196} 197 198static void decode_flush(AVCodecContext *avctx) 199{ 200 ARBCContext *s = avctx->priv_data; 201 202 av_frame_unref(s->prev_frame); 203} 204 205static av_cold int decode_close(AVCodecContext *avctx) 206{ 207 ARBCContext *s = avctx->priv_data; 208 209 av_frame_free(&s->prev_frame); 210 211 return 0; 212} 213 214const FFCodec ff_arbc_decoder = { 215 .p.name = "arbc", 216 .p.long_name = NULL_IF_CONFIG_SMALL("Gryphon's Anim Compressor"), 217 .p.type = AVMEDIA_TYPE_VIDEO, 218 .p.id = AV_CODEC_ID_ARBC, 219 .priv_data_size = sizeof(ARBCContext), 220 .init = decode_init, 221 FF_CODEC_DECODE_CB(decode_frame), 222 .flush = decode_flush, 223 .close = decode_close, 224 .p.capabilities = AV_CODEC_CAP_DR1, 225 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, 226}; 227