1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * LucasArts Smush video decoder 3cabdff1aSopenharmony_ci * Copyright (c) 2006 Cyril Zorin 4cabdff1aSopenharmony_ci * Copyright (c) 2011 Konstantin Shishkov 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/avassert.h" 24cabdff1aSopenharmony_ci#include "libavutil/bswap.h" 25cabdff1aSopenharmony_ci#include "libavutil/imgutils.h" 26cabdff1aSopenharmony_ci 27cabdff1aSopenharmony_ci#include "avcodec.h" 28cabdff1aSopenharmony_ci#include "bytestream.h" 29cabdff1aSopenharmony_ci#include "copy_block.h" 30cabdff1aSopenharmony_ci#include "codec_internal.h" 31cabdff1aSopenharmony_ci#include "internal.h" 32cabdff1aSopenharmony_ci 33cabdff1aSopenharmony_ci#define NGLYPHS 256 34cabdff1aSopenharmony_ci#define GLYPH_COORD_VECT_SIZE 16 35cabdff1aSopenharmony_ci#define PALETTE_SIZE 256 36cabdff1aSopenharmony_ci#define PALETTE_DELTA 768 37cabdff1aSopenharmony_ci 38cabdff1aSopenharmony_cistatic const int8_t glyph4_x[GLYPH_COORD_VECT_SIZE] = { 39cabdff1aSopenharmony_ci 0, 1, 2, 3, 3, 3, 3, 2, 1, 0, 0, 0, 1, 2, 2, 1 40cabdff1aSopenharmony_ci}; 41cabdff1aSopenharmony_ci 42cabdff1aSopenharmony_cistatic const int8_t glyph4_y[GLYPH_COORD_VECT_SIZE] = { 43cabdff1aSopenharmony_ci 0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 2, 1, 1, 1, 2, 2 44cabdff1aSopenharmony_ci}; 45cabdff1aSopenharmony_ci 46cabdff1aSopenharmony_cistatic const int8_t glyph8_x[GLYPH_COORD_VECT_SIZE] = { 47cabdff1aSopenharmony_ci 0, 2, 5, 7, 7, 7, 7, 7, 7, 5, 2, 0, 0, 0, 0, 0 48cabdff1aSopenharmony_ci}; 49cabdff1aSopenharmony_ci 50cabdff1aSopenharmony_cistatic const int8_t glyph8_y[GLYPH_COORD_VECT_SIZE] = { 51cabdff1aSopenharmony_ci 0, 0, 0, 0, 1, 3, 4, 6, 7, 7, 7, 7, 6, 4, 3, 1 52cabdff1aSopenharmony_ci}; 53cabdff1aSopenharmony_ci 54cabdff1aSopenharmony_cistatic const int8_t motion_vectors[256][2] = { 55cabdff1aSopenharmony_ci { 0, 0 }, { -1, -43 }, { 6, -43 }, { -9, -42 }, { 13, -41 }, 56cabdff1aSopenharmony_ci { -16, -40 }, { 19, -39 }, { -23, -36 }, { 26, -34 }, { -2, -33 }, 57cabdff1aSopenharmony_ci { 4, -33 }, { -29, -32 }, { -9, -32 }, { 11, -31 }, { -16, -29 }, 58cabdff1aSopenharmony_ci { 32, -29 }, { 18, -28 }, { -34, -26 }, { -22, -25 }, { -1, -25 }, 59cabdff1aSopenharmony_ci { 3, -25 }, { -7, -24 }, { 8, -24 }, { 24, -23 }, { 36, -23 }, 60cabdff1aSopenharmony_ci { -12, -22 }, { 13, -21 }, { -38, -20 }, { 0, -20 }, { -27, -19 }, 61cabdff1aSopenharmony_ci { -4, -19 }, { 4, -19 }, { -17, -18 }, { -8, -17 }, { 8, -17 }, 62cabdff1aSopenharmony_ci { 18, -17 }, { 28, -17 }, { 39, -17 }, { -12, -15 }, { 12, -15 }, 63cabdff1aSopenharmony_ci { -21, -14 }, { -1, -14 }, { 1, -14 }, { -41, -13 }, { -5, -13 }, 64cabdff1aSopenharmony_ci { 5, -13 }, { 21, -13 }, { -31, -12 }, { -15, -11 }, { -8, -11 }, 65cabdff1aSopenharmony_ci { 8, -11 }, { 15, -11 }, { -2, -10 }, { 1, -10 }, { 31, -10 }, 66cabdff1aSopenharmony_ci { -23, -9 }, { -11, -9 }, { -5, -9 }, { 4, -9 }, { 11, -9 }, 67cabdff1aSopenharmony_ci { 42, -9 }, { 6, -8 }, { 24, -8 }, { -18, -7 }, { -7, -7 }, 68cabdff1aSopenharmony_ci { -3, -7 }, { -1, -7 }, { 2, -7 }, { 18, -7 }, { -43, -6 }, 69cabdff1aSopenharmony_ci { -13, -6 }, { -4, -6 }, { 4, -6 }, { 8, -6 }, { -33, -5 }, 70cabdff1aSopenharmony_ci { -9, -5 }, { -2, -5 }, { 0, -5 }, { 2, -5 }, { 5, -5 }, 71cabdff1aSopenharmony_ci { 13, -5 }, { -25, -4 }, { -6, -4 }, { -3, -4 }, { 3, -4 }, 72cabdff1aSopenharmony_ci { 9, -4 }, { -19, -3 }, { -7, -3 }, { -4, -3 }, { -2, -3 }, 73cabdff1aSopenharmony_ci { -1, -3 }, { 0, -3 }, { 1, -3 }, { 2, -3 }, { 4, -3 }, 74cabdff1aSopenharmony_ci { 6, -3 }, { 33, -3 }, { -14, -2 }, { -10, -2 }, { -5, -2 }, 75cabdff1aSopenharmony_ci { -3, -2 }, { -2, -2 }, { -1, -2 }, { 0, -2 }, { 1, -2 }, 76cabdff1aSopenharmony_ci { 2, -2 }, { 3, -2 }, { 5, -2 }, { 7, -2 }, { 14, -2 }, 77cabdff1aSopenharmony_ci { 19, -2 }, { 25, -2 }, { 43, -2 }, { -7, -1 }, { -3, -1 }, 78cabdff1aSopenharmony_ci { -2, -1 }, { -1, -1 }, { 0, -1 }, { 1, -1 }, { 2, -1 }, 79cabdff1aSopenharmony_ci { 3, -1 }, { 10, -1 }, { -5, 0 }, { -3, 0 }, { -2, 0 }, 80cabdff1aSopenharmony_ci { -1, 0 }, { 1, 0 }, { 2, 0 }, { 3, 0 }, { 5, 0 }, 81cabdff1aSopenharmony_ci { 7, 0 }, { -10, 1 }, { -7, 1 }, { -3, 1 }, { -2, 1 }, 82cabdff1aSopenharmony_ci { -1, 1 }, { 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1 }, 83cabdff1aSopenharmony_ci { -43, 2 }, { -25, 2 }, { -19, 2 }, { -14, 2 }, { -5, 2 }, 84cabdff1aSopenharmony_ci { -3, 2 }, { -2, 2 }, { -1, 2 }, { 0, 2 }, { 1, 2 }, 85cabdff1aSopenharmony_ci { 2, 2 }, { 3, 2 }, { 5, 2 }, { 7, 2 }, { 10, 2 }, 86cabdff1aSopenharmony_ci { 14, 2 }, { -33, 3 }, { -6, 3 }, { -4, 3 }, { -2, 3 }, 87cabdff1aSopenharmony_ci { -1, 3 }, { 0, 3 }, { 1, 3 }, { 2, 3 }, { 4, 3 }, 88cabdff1aSopenharmony_ci { 19, 3 }, { -9, 4 }, { -3, 4 }, { 3, 4 }, { 7, 4 }, 89cabdff1aSopenharmony_ci { 25, 4 }, { -13, 5 }, { -5, 5 }, { -2, 5 }, { 0, 5 }, 90cabdff1aSopenharmony_ci { 2, 5 }, { 5, 5 }, { 9, 5 }, { 33, 5 }, { -8, 6 }, 91cabdff1aSopenharmony_ci { -4, 6 }, { 4, 6 }, { 13, 6 }, { 43, 6 }, { -18, 7 }, 92cabdff1aSopenharmony_ci { -2, 7 }, { 0, 7 }, { 2, 7 }, { 7, 7 }, { 18, 7 }, 93cabdff1aSopenharmony_ci { -24, 8 }, { -6, 8 }, { -42, 9 }, { -11, 9 }, { -4, 9 }, 94cabdff1aSopenharmony_ci { 5, 9 }, { 11, 9 }, { 23, 9 }, { -31, 10 }, { -1, 10 }, 95cabdff1aSopenharmony_ci { 2, 10 }, { -15, 11 }, { -8, 11 }, { 8, 11 }, { 15, 11 }, 96cabdff1aSopenharmony_ci { 31, 12 }, { -21, 13 }, { -5, 13 }, { 5, 13 }, { 41, 13 }, 97cabdff1aSopenharmony_ci { -1, 14 }, { 1, 14 }, { 21, 14 }, { -12, 15 }, { 12, 15 }, 98cabdff1aSopenharmony_ci { -39, 17 }, { -28, 17 }, { -18, 17 }, { -8, 17 }, { 8, 17 }, 99cabdff1aSopenharmony_ci { 17, 18 }, { -4, 19 }, { 0, 19 }, { 4, 19 }, { 27, 19 }, 100cabdff1aSopenharmony_ci { 38, 20 }, { -13, 21 }, { 12, 22 }, { -36, 23 }, { -24, 23 }, 101cabdff1aSopenharmony_ci { -8, 24 }, { 7, 24 }, { -3, 25 }, { 1, 25 }, { 22, 25 }, 102cabdff1aSopenharmony_ci { 34, 26 }, { -18, 28 }, { -32, 29 }, { 16, 29 }, { -11, 31 }, 103cabdff1aSopenharmony_ci { 9, 32 }, { 29, 32 }, { -4, 33 }, { 2, 33 }, { -26, 34 }, 104cabdff1aSopenharmony_ci { 23, 36 }, { -19, 39 }, { 16, 40 }, { -13, 41 }, { 9, 42 }, 105cabdff1aSopenharmony_ci { -6, 43 }, { 1, 43 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, 106cabdff1aSopenharmony_ci}; 107cabdff1aSopenharmony_ci 108cabdff1aSopenharmony_cistatic const int8_t c37_mv[] = { 109cabdff1aSopenharmony_ci 0, 0, 1, 0, 2, 0, 3, 0, 5, 0, 110cabdff1aSopenharmony_ci 8, 0, 13, 0, 21, 0, -1, 0, -2, 0, 111cabdff1aSopenharmony_ci -3, 0, -5, 0, -8, 0, -13, 0, -17, 0, 112cabdff1aSopenharmony_ci -21, 0, 0, 1, 1, 1, 2, 1, 3, 1, 113cabdff1aSopenharmony_ci 5, 1, 8, 1, 13, 1, 21, 1, -1, 1, 114cabdff1aSopenharmony_ci -2, 1, -3, 1, -5, 1, -8, 1, -13, 1, 115cabdff1aSopenharmony_ci -17, 1, -21, 1, 0, 2, 1, 2, 2, 2, 116cabdff1aSopenharmony_ci 3, 2, 5, 2, 8, 2, 13, 2, 21, 2, 117cabdff1aSopenharmony_ci -1, 2, -2, 2, -3, 2, -5, 2, -8, 2, 118cabdff1aSopenharmony_ci -13, 2, -17, 2, -21, 2, 0, 3, 1, 3, 119cabdff1aSopenharmony_ci 2, 3, 3, 3, 5, 3, 8, 3, 13, 3, 120cabdff1aSopenharmony_ci 21, 3, -1, 3, -2, 3, -3, 3, -5, 3, 121cabdff1aSopenharmony_ci -8, 3, -13, 3, -17, 3, -21, 3, 0, 5, 122cabdff1aSopenharmony_ci 1, 5, 2, 5, 3, 5, 5, 5, 8, 5, 123cabdff1aSopenharmony_ci 13, 5, 21, 5, -1, 5, -2, 5, -3, 5, 124cabdff1aSopenharmony_ci -5, 5, -8, 5, -13, 5, -17, 5, -21, 5, 125cabdff1aSopenharmony_ci 0, 8, 1, 8, 2, 8, 3, 8, 5, 8, 126cabdff1aSopenharmony_ci 8, 8, 13, 8, 21, 8, -1, 8, -2, 8, 127cabdff1aSopenharmony_ci -3, 8, -5, 8, -8, 8, -13, 8, -17, 8, 128cabdff1aSopenharmony_ci -21, 8, 0, 13, 1, 13, 2, 13, 3, 13, 129cabdff1aSopenharmony_ci 5, 13, 8, 13, 13, 13, 21, 13, -1, 13, 130cabdff1aSopenharmony_ci -2, 13, -3, 13, -5, 13, -8, 13, -13, 13, 131cabdff1aSopenharmony_ci -17, 13, -21, 13, 0, 21, 1, 21, 2, 21, 132cabdff1aSopenharmony_ci 3, 21, 5, 21, 8, 21, 13, 21, 21, 21, 133cabdff1aSopenharmony_ci -1, 21, -2, 21, -3, 21, -5, 21, -8, 21, 134cabdff1aSopenharmony_ci -13, 21, -17, 21, -21, 21, 0, -1, 1, -1, 135cabdff1aSopenharmony_ci 2, -1, 3, -1, 5, -1, 8, -1, 13, -1, 136cabdff1aSopenharmony_ci 21, -1, -1, -1, -2, -1, -3, -1, -5, -1, 137cabdff1aSopenharmony_ci -8, -1, -13, -1, -17, -1, -21, -1, 0, -2, 138cabdff1aSopenharmony_ci 1, -2, 2, -2, 3, -2, 5, -2, 8, -2, 139cabdff1aSopenharmony_ci 13, -2, 21, -2, -1, -2, -2, -2, -3, -2, 140cabdff1aSopenharmony_ci -5, -2, -8, -2, -13, -2, -17, -2, -21, -2, 141cabdff1aSopenharmony_ci 0, -3, 1, -3, 2, -3, 3, -3, 5, -3, 142cabdff1aSopenharmony_ci 8, -3, 13, -3, 21, -3, -1, -3, -2, -3, 143cabdff1aSopenharmony_ci -3, -3, -5, -3, -8, -3, -13, -3, -17, -3, 144cabdff1aSopenharmony_ci -21, -3, 0, -5, 1, -5, 2, -5, 3, -5, 145cabdff1aSopenharmony_ci 5, -5, 8, -5, 13, -5, 21, -5, -1, -5, 146cabdff1aSopenharmony_ci -2, -5, -3, -5, -5, -5, -8, -5, -13, -5, 147cabdff1aSopenharmony_ci -17, -5, -21, -5, 0, -8, 1, -8, 2, -8, 148cabdff1aSopenharmony_ci 3, -8, 5, -8, 8, -8, 13, -8, 21, -8, 149cabdff1aSopenharmony_ci -1, -8, -2, -8, -3, -8, -5, -8, -8, -8, 150cabdff1aSopenharmony_ci -13, -8, -17, -8, -21, -8, 0, -13, 1, -13, 151cabdff1aSopenharmony_ci 2, -13, 3, -13, 5, -13, 8, -13, 13, -13, 152cabdff1aSopenharmony_ci 21, -13, -1, -13, -2, -13, -3, -13, -5, -13, 153cabdff1aSopenharmony_ci -8, -13, -13, -13, -17, -13, -21, -13, 0, -17, 154cabdff1aSopenharmony_ci 1, -17, 2, -17, 3, -17, 5, -17, 8, -17, 155cabdff1aSopenharmony_ci 13, -17, 21, -17, -1, -17, -2, -17, -3, -17, 156cabdff1aSopenharmony_ci -5, -17, -8, -17, -13, -17, -17, -17, -21, -17, 157cabdff1aSopenharmony_ci 0, -21, 1, -21, 2, -21, 3, -21, 5, -21, 158cabdff1aSopenharmony_ci 8, -21, 13, -21, 21, -21, -1, -21, -2, -21, 159cabdff1aSopenharmony_ci -3, -21, -5, -21, -8, -21, -13, -21, -17, -21, 160cabdff1aSopenharmony_ci 0, 0, -8, -29, 8, -29, -18, -25, 17, -25, 161cabdff1aSopenharmony_ci 0, -23, -6, -22, 6, -22, -13, -19, 12, -19, 162cabdff1aSopenharmony_ci 0, -18, 25, -18, -25, -17, -5, -17, 5, -17, 163cabdff1aSopenharmony_ci -10, -15, 10, -15, 0, -14, -4, -13, 4, -13, 164cabdff1aSopenharmony_ci 19, -13, -19, -12, -8, -11, -2, -11, 0, -11, 165cabdff1aSopenharmony_ci 2, -11, 8, -11, -15, -10, -4, -10, 4, -10, 166cabdff1aSopenharmony_ci 15, -10, -6, -9, -1, -9, 1, -9, 6, -9, 167cabdff1aSopenharmony_ci -29, -8, -11, -8, -8, -8, -3, -8, 3, -8, 168cabdff1aSopenharmony_ci 8, -8, 11, -8, 29, -8, -5, -7, -2, -7, 169cabdff1aSopenharmony_ci 0, -7, 2, -7, 5, -7, -22, -6, -9, -6, 170cabdff1aSopenharmony_ci -6, -6, -3, -6, -1, -6, 1, -6, 3, -6, 171cabdff1aSopenharmony_ci 6, -6, 9, -6, 22, -6, -17, -5, -7, -5, 172cabdff1aSopenharmony_ci -4, -5, -2, -5, 0, -5, 2, -5, 4, -5, 173cabdff1aSopenharmony_ci 7, -5, 17, -5, -13, -4, -10, -4, -5, -4, 174cabdff1aSopenharmony_ci -3, -4, -1, -4, 0, -4, 1, -4, 3, -4, 175cabdff1aSopenharmony_ci 5, -4, 10, -4, 13, -4, -8, -3, -6, -3, 176cabdff1aSopenharmony_ci -4, -3, -3, -3, -2, -3, -1, -3, 0, -3, 177cabdff1aSopenharmony_ci 1, -3, 2, -3, 4, -3, 6, -3, 8, -3, 178cabdff1aSopenharmony_ci -11, -2, -7, -2, -5, -2, -3, -2, -2, -2, 179cabdff1aSopenharmony_ci -1, -2, 0, -2, 1, -2, 2, -2, 3, -2, 180cabdff1aSopenharmony_ci 5, -2, 7, -2, 11, -2, -9, -1, -6, -1, 181cabdff1aSopenharmony_ci -4, -1, -3, -1, -2, -1, -1, -1, 0, -1, 182cabdff1aSopenharmony_ci 1, -1, 2, -1, 3, -1, 4, -1, 6, -1, 183cabdff1aSopenharmony_ci 9, -1, -31, 0, -23, 0, -18, 0, -14, 0, 184cabdff1aSopenharmony_ci -11, 0, -7, 0, -5, 0, -4, 0, -3, 0, 185cabdff1aSopenharmony_ci -2, 0, -1, 0, 0, -31, 1, 0, 2, 0, 186cabdff1aSopenharmony_ci 3, 0, 4, 0, 5, 0, 7, 0, 11, 0, 187cabdff1aSopenharmony_ci 14, 0, 18, 0, 23, 0, 31, 0, -9, 1, 188cabdff1aSopenharmony_ci -6, 1, -4, 1, -3, 1, -2, 1, -1, 1, 189cabdff1aSopenharmony_ci 0, 1, 1, 1, 2, 1, 3, 1, 4, 1, 190cabdff1aSopenharmony_ci 6, 1, 9, 1, -11, 2, -7, 2, -5, 2, 191cabdff1aSopenharmony_ci -3, 2, -2, 2, -1, 2, 0, 2, 1, 2, 192cabdff1aSopenharmony_ci 2, 2, 3, 2, 5, 2, 7, 2, 11, 2, 193cabdff1aSopenharmony_ci -8, 3, -6, 3, -4, 3, -2, 3, -1, 3, 194cabdff1aSopenharmony_ci 0, 3, 1, 3, 2, 3, 3, 3, 4, 3, 195cabdff1aSopenharmony_ci 6, 3, 8, 3, -13, 4, -10, 4, -5, 4, 196cabdff1aSopenharmony_ci -3, 4, -1, 4, 0, 4, 1, 4, 3, 4, 197cabdff1aSopenharmony_ci 5, 4, 10, 4, 13, 4, -17, 5, -7, 5, 198cabdff1aSopenharmony_ci -4, 5, -2, 5, 0, 5, 2, 5, 4, 5, 199cabdff1aSopenharmony_ci 7, 5, 17, 5, -22, 6, -9, 6, -6, 6, 200cabdff1aSopenharmony_ci -3, 6, -1, 6, 1, 6, 3, 6, 6, 6, 201cabdff1aSopenharmony_ci 9, 6, 22, 6, -5, 7, -2, 7, 0, 7, 202cabdff1aSopenharmony_ci 2, 7, 5, 7, -29, 8, -11, 8, -8, 8, 203cabdff1aSopenharmony_ci -3, 8, 3, 8, 8, 8, 11, 8, 29, 8, 204cabdff1aSopenharmony_ci -6, 9, -1, 9, 1, 9, 6, 9, -15, 10, 205cabdff1aSopenharmony_ci -4, 10, 4, 10, 15, 10, -8, 11, -2, 11, 206cabdff1aSopenharmony_ci 0, 11, 2, 11, 8, 11, 19, 12, -19, 13, 207cabdff1aSopenharmony_ci -4, 13, 4, 13, 0, 14, -10, 15, 10, 15, 208cabdff1aSopenharmony_ci -5, 17, 5, 17, 25, 17, -25, 18, 0, 18, 209cabdff1aSopenharmony_ci -12, 19, 13, 19, -6, 22, 6, 22, 0, 23, 210cabdff1aSopenharmony_ci -17, 25, 18, 25, -8, 29, 8, 29, 0, 31, 211cabdff1aSopenharmony_ci 0, 0, -6, -22, 6, -22, -13, -19, 12, -19, 212cabdff1aSopenharmony_ci 0, -18, -5, -17, 5, -17, -10, -15, 10, -15, 213cabdff1aSopenharmony_ci 0, -14, -4, -13, 4, -13, 19, -13, -19, -12, 214cabdff1aSopenharmony_ci -8, -11, -2, -11, 0, -11, 2, -11, 8, -11, 215cabdff1aSopenharmony_ci -15, -10, -4, -10, 4, -10, 15, -10, -6, -9, 216cabdff1aSopenharmony_ci -1, -9, 1, -9, 6, -9, -11, -8, -8, -8, 217cabdff1aSopenharmony_ci -3, -8, 0, -8, 3, -8, 8, -8, 11, -8, 218cabdff1aSopenharmony_ci -5, -7, -2, -7, 0, -7, 2, -7, 5, -7, 219cabdff1aSopenharmony_ci -22, -6, -9, -6, -6, -6, -3, -6, -1, -6, 220cabdff1aSopenharmony_ci 1, -6, 3, -6, 6, -6, 9, -6, 22, -6, 221cabdff1aSopenharmony_ci -17, -5, -7, -5, -4, -5, -2, -5, -1, -5, 222cabdff1aSopenharmony_ci 0, -5, 1, -5, 2, -5, 4, -5, 7, -5, 223cabdff1aSopenharmony_ci 17, -5, -13, -4, -10, -4, -5, -4, -3, -4, 224cabdff1aSopenharmony_ci -2, -4, -1, -4, 0, -4, 1, -4, 2, -4, 225cabdff1aSopenharmony_ci 3, -4, 5, -4, 10, -4, 13, -4, -8, -3, 226cabdff1aSopenharmony_ci -6, -3, -4, -3, -3, -3, -2, -3, -1, -3, 227cabdff1aSopenharmony_ci 0, -3, 1, -3, 2, -3, 3, -3, 4, -3, 228cabdff1aSopenharmony_ci 6, -3, 8, -3, -11, -2, -7, -2, -5, -2, 229cabdff1aSopenharmony_ci -4, -2, -3, -2, -2, -2, -1, -2, 0, -2, 230cabdff1aSopenharmony_ci 1, -2, 2, -2, 3, -2, 4, -2, 5, -2, 231cabdff1aSopenharmony_ci 7, -2, 11, -2, -9, -1, -6, -1, -5, -1, 232cabdff1aSopenharmony_ci -4, -1, -3, -1, -2, -1, -1, -1, 0, -1, 233cabdff1aSopenharmony_ci 1, -1, 2, -1, 3, -1, 4, -1, 5, -1, 234cabdff1aSopenharmony_ci 6, -1, 9, -1, -23, 0, -18, 0, -14, 0, 235cabdff1aSopenharmony_ci -11, 0, -7, 0, -5, 0, -4, 0, -3, 0, 236cabdff1aSopenharmony_ci -2, 0, -1, 0, 0, -23, 1, 0, 2, 0, 237cabdff1aSopenharmony_ci 3, 0, 4, 0, 5, 0, 7, 0, 11, 0, 238cabdff1aSopenharmony_ci 14, 0, 18, 0, 23, 0, -9, 1, -6, 1, 239cabdff1aSopenharmony_ci -5, 1, -4, 1, -3, 1, -2, 1, -1, 1, 240cabdff1aSopenharmony_ci 0, 1, 1, 1, 2, 1, 3, 1, 4, 1, 241cabdff1aSopenharmony_ci 5, 1, 6, 1, 9, 1, -11, 2, -7, 2, 242cabdff1aSopenharmony_ci -5, 2, -4, 2, -3, 2, -2, 2, -1, 2, 243cabdff1aSopenharmony_ci 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 244cabdff1aSopenharmony_ci 5, 2, 7, 2, 11, 2, -8, 3, -6, 3, 245cabdff1aSopenharmony_ci -4, 3, -3, 3, -2, 3, -1, 3, 0, 3, 246cabdff1aSopenharmony_ci 1, 3, 2, 3, 3, 3, 4, 3, 6, 3, 247cabdff1aSopenharmony_ci 8, 3, -13, 4, -10, 4, -5, 4, -3, 4, 248cabdff1aSopenharmony_ci -2, 4, -1, 4, 0, 4, 1, 4, 2, 4, 249cabdff1aSopenharmony_ci 3, 4, 5, 4, 10, 4, 13, 4, -17, 5, 250cabdff1aSopenharmony_ci -7, 5, -4, 5, -2, 5, -1, 5, 0, 5, 251cabdff1aSopenharmony_ci 1, 5, 2, 5, 4, 5, 7, 5, 17, 5, 252cabdff1aSopenharmony_ci -22, 6, -9, 6, -6, 6, -3, 6, -1, 6, 253cabdff1aSopenharmony_ci 1, 6, 3, 6, 6, 6, 9, 6, 22, 6, 254cabdff1aSopenharmony_ci -5, 7, -2, 7, 0, 7, 2, 7, 5, 7, 255cabdff1aSopenharmony_ci -11, 8, -8, 8, -3, 8, 0, 8, 3, 8, 256cabdff1aSopenharmony_ci 8, 8, 11, 8, -6, 9, -1, 9, 1, 9, 257cabdff1aSopenharmony_ci 6, 9, -15, 10, -4, 10, 4, 10, 15, 10, 258cabdff1aSopenharmony_ci -8, 11, -2, 11, 0, 11, 2, 11, 8, 11, 259cabdff1aSopenharmony_ci 19, 12, -19, 13, -4, 13, 4, 13, 0, 14, 260cabdff1aSopenharmony_ci -10, 15, 10, 15, -5, 17, 5, 17, 0, 18, 261cabdff1aSopenharmony_ci -12, 19, 13, 19, -6, 22, 6, 22, 0, 23, 262cabdff1aSopenharmony_ci}; 263cabdff1aSopenharmony_ci 264cabdff1aSopenharmony_citypedef struct SANMVideoContext { 265cabdff1aSopenharmony_ci AVCodecContext *avctx; 266cabdff1aSopenharmony_ci GetByteContext gb; 267cabdff1aSopenharmony_ci 268cabdff1aSopenharmony_ci int version, subversion; 269cabdff1aSopenharmony_ci uint32_t pal[PALETTE_SIZE]; 270cabdff1aSopenharmony_ci int16_t delta_pal[PALETTE_DELTA]; 271cabdff1aSopenharmony_ci 272cabdff1aSopenharmony_ci ptrdiff_t pitch; 273cabdff1aSopenharmony_ci int width, height; 274cabdff1aSopenharmony_ci int aligned_width, aligned_height; 275cabdff1aSopenharmony_ci int prev_seq; 276cabdff1aSopenharmony_ci 277cabdff1aSopenharmony_ci AVFrame *frame; 278cabdff1aSopenharmony_ci uint16_t *frm0, *frm1, *frm2; 279cabdff1aSopenharmony_ci uint8_t *stored_frame; 280cabdff1aSopenharmony_ci uint32_t frm0_size, frm1_size, frm2_size; 281cabdff1aSopenharmony_ci uint32_t stored_frame_size; 282cabdff1aSopenharmony_ci 283cabdff1aSopenharmony_ci uint8_t *rle_buf; 284cabdff1aSopenharmony_ci unsigned int rle_buf_size; 285cabdff1aSopenharmony_ci 286cabdff1aSopenharmony_ci int rotate_code; 287cabdff1aSopenharmony_ci 288cabdff1aSopenharmony_ci long npixels, buf_size; 289cabdff1aSopenharmony_ci 290cabdff1aSopenharmony_ci uint16_t codebook[256]; 291cabdff1aSopenharmony_ci uint16_t small_codebook[4]; 292cabdff1aSopenharmony_ci 293cabdff1aSopenharmony_ci int8_t p4x4glyphs[NGLYPHS][16]; 294cabdff1aSopenharmony_ci int8_t p8x8glyphs[NGLYPHS][64]; 295cabdff1aSopenharmony_ci} SANMVideoContext; 296cabdff1aSopenharmony_ci 297cabdff1aSopenharmony_citypedef struct SANMFrameHeader { 298cabdff1aSopenharmony_ci int seq_num, codec, rotate_code, rle_output_size; 299cabdff1aSopenharmony_ci 300cabdff1aSopenharmony_ci uint16_t bg_color; 301cabdff1aSopenharmony_ci uint32_t width, height; 302cabdff1aSopenharmony_ci} SANMFrameHeader; 303cabdff1aSopenharmony_ci 304cabdff1aSopenharmony_cienum GlyphEdge { 305cabdff1aSopenharmony_ci LEFT_EDGE, 306cabdff1aSopenharmony_ci TOP_EDGE, 307cabdff1aSopenharmony_ci RIGHT_EDGE, 308cabdff1aSopenharmony_ci BOTTOM_EDGE, 309cabdff1aSopenharmony_ci NO_EDGE 310cabdff1aSopenharmony_ci}; 311cabdff1aSopenharmony_ci 312cabdff1aSopenharmony_cienum GlyphDir { 313cabdff1aSopenharmony_ci DIR_LEFT, 314cabdff1aSopenharmony_ci DIR_UP, 315cabdff1aSopenharmony_ci DIR_RIGHT, 316cabdff1aSopenharmony_ci DIR_DOWN, 317cabdff1aSopenharmony_ci NO_DIR 318cabdff1aSopenharmony_ci}; 319cabdff1aSopenharmony_ci 320cabdff1aSopenharmony_ci/** 321cabdff1aSopenharmony_ci * Return enum GlyphEdge of box where point (x, y) lies. 322cabdff1aSopenharmony_ci * 323cabdff1aSopenharmony_ci * @param x x point coordinate 324cabdff1aSopenharmony_ci * @param y y point coordinate 325cabdff1aSopenharmony_ci * @param edge_size box width/height. 326cabdff1aSopenharmony_ci */ 327cabdff1aSopenharmony_cistatic enum GlyphEdge which_edge(int x, int y, int edge_size) 328cabdff1aSopenharmony_ci{ 329cabdff1aSopenharmony_ci const int edge_max = edge_size - 1; 330cabdff1aSopenharmony_ci 331cabdff1aSopenharmony_ci if (!y) 332cabdff1aSopenharmony_ci return BOTTOM_EDGE; 333cabdff1aSopenharmony_ci else if (y == edge_max) 334cabdff1aSopenharmony_ci return TOP_EDGE; 335cabdff1aSopenharmony_ci else if (!x) 336cabdff1aSopenharmony_ci return LEFT_EDGE; 337cabdff1aSopenharmony_ci else if (x == edge_max) 338cabdff1aSopenharmony_ci return RIGHT_EDGE; 339cabdff1aSopenharmony_ci else 340cabdff1aSopenharmony_ci return NO_EDGE; 341cabdff1aSopenharmony_ci} 342cabdff1aSopenharmony_ci 343cabdff1aSopenharmony_cistatic enum GlyphDir which_direction(enum GlyphEdge edge0, enum GlyphEdge edge1) 344cabdff1aSopenharmony_ci{ 345cabdff1aSopenharmony_ci if ((edge0 == LEFT_EDGE && edge1 == RIGHT_EDGE) || 346cabdff1aSopenharmony_ci (edge1 == LEFT_EDGE && edge0 == RIGHT_EDGE) || 347cabdff1aSopenharmony_ci (edge0 == BOTTOM_EDGE && edge1 != TOP_EDGE) || 348cabdff1aSopenharmony_ci (edge1 == BOTTOM_EDGE && edge0 != TOP_EDGE)) 349cabdff1aSopenharmony_ci return DIR_UP; 350cabdff1aSopenharmony_ci else if ((edge0 == TOP_EDGE && edge1 != BOTTOM_EDGE) || 351cabdff1aSopenharmony_ci (edge1 == TOP_EDGE && edge0 != BOTTOM_EDGE)) 352cabdff1aSopenharmony_ci return DIR_DOWN; 353cabdff1aSopenharmony_ci else if ((edge0 == LEFT_EDGE && edge1 != RIGHT_EDGE) || 354cabdff1aSopenharmony_ci (edge1 == LEFT_EDGE && edge0 != RIGHT_EDGE)) 355cabdff1aSopenharmony_ci return DIR_LEFT; 356cabdff1aSopenharmony_ci else if ((edge0 == TOP_EDGE && edge1 == BOTTOM_EDGE) || 357cabdff1aSopenharmony_ci (edge1 == TOP_EDGE && edge0 == BOTTOM_EDGE) || 358cabdff1aSopenharmony_ci (edge0 == RIGHT_EDGE && edge1 != LEFT_EDGE) || 359cabdff1aSopenharmony_ci (edge1 == RIGHT_EDGE && edge0 != LEFT_EDGE)) 360cabdff1aSopenharmony_ci return DIR_RIGHT; 361cabdff1aSopenharmony_ci 362cabdff1aSopenharmony_ci return NO_DIR; 363cabdff1aSopenharmony_ci} 364cabdff1aSopenharmony_ci 365cabdff1aSopenharmony_ci/* Interpolate two points. */ 366cabdff1aSopenharmony_cistatic void interp_point(int8_t *points, int x0, int y0, int x1, int y1, 367cabdff1aSopenharmony_ci int pos, int npoints) 368cabdff1aSopenharmony_ci{ 369cabdff1aSopenharmony_ci if (npoints) { 370cabdff1aSopenharmony_ci points[0] = (x0 * pos + x1 * (npoints - pos) + (npoints >> 1)) / npoints; 371cabdff1aSopenharmony_ci points[1] = (y0 * pos + y1 * (npoints - pos) + (npoints >> 1)) / npoints; 372cabdff1aSopenharmony_ci } else { 373cabdff1aSopenharmony_ci points[0] = x0; 374cabdff1aSopenharmony_ci points[1] = y0; 375cabdff1aSopenharmony_ci } 376cabdff1aSopenharmony_ci} 377cabdff1aSopenharmony_ci 378cabdff1aSopenharmony_ci/** 379cabdff1aSopenharmony_ci * Construct glyphs by iterating through vector coordinates. 380cabdff1aSopenharmony_ci * 381cabdff1aSopenharmony_ci * @param pglyphs pointer to table where glyphs are stored 382cabdff1aSopenharmony_ci * @param xvec pointer to x component of vector coordinates 383cabdff1aSopenharmony_ci * @param yvec pointer to y component of vector coordinates 384cabdff1aSopenharmony_ci * @param side_length glyph width/height. 385cabdff1aSopenharmony_ci */ 386cabdff1aSopenharmony_cistatic void make_glyphs(int8_t *pglyphs, const int8_t *xvec, const int8_t *yvec, 387cabdff1aSopenharmony_ci const int side_length) 388cabdff1aSopenharmony_ci{ 389cabdff1aSopenharmony_ci const int glyph_size = side_length * side_length; 390cabdff1aSopenharmony_ci int8_t *pglyph = pglyphs; 391cabdff1aSopenharmony_ci 392cabdff1aSopenharmony_ci int i, j; 393cabdff1aSopenharmony_ci for (i = 0; i < GLYPH_COORD_VECT_SIZE; i++) { 394cabdff1aSopenharmony_ci int x0 = xvec[i]; 395cabdff1aSopenharmony_ci int y0 = yvec[i]; 396cabdff1aSopenharmony_ci enum GlyphEdge edge0 = which_edge(x0, y0, side_length); 397cabdff1aSopenharmony_ci 398cabdff1aSopenharmony_ci for (j = 0; j < GLYPH_COORD_VECT_SIZE; j++, pglyph += glyph_size) { 399cabdff1aSopenharmony_ci int x1 = xvec[j]; 400cabdff1aSopenharmony_ci int y1 = yvec[j]; 401cabdff1aSopenharmony_ci enum GlyphEdge edge1 = which_edge(x1, y1, side_length); 402cabdff1aSopenharmony_ci enum GlyphDir dir = which_direction(edge0, edge1); 403cabdff1aSopenharmony_ci int npoints = FFMAX(FFABS(x1 - x0), FFABS(y1 - y0)); 404cabdff1aSopenharmony_ci int ipoint; 405cabdff1aSopenharmony_ci 406cabdff1aSopenharmony_ci for (ipoint = 0; ipoint <= npoints; ipoint++) { 407cabdff1aSopenharmony_ci int8_t point[2]; 408cabdff1aSopenharmony_ci int irow, icol; 409cabdff1aSopenharmony_ci 410cabdff1aSopenharmony_ci interp_point(point, x0, y0, x1, y1, ipoint, npoints); 411cabdff1aSopenharmony_ci 412cabdff1aSopenharmony_ci switch (dir) { 413cabdff1aSopenharmony_ci case DIR_UP: 414cabdff1aSopenharmony_ci for (irow = point[1]; irow >= 0; irow--) 415cabdff1aSopenharmony_ci pglyph[point[0] + irow * side_length] = 1; 416cabdff1aSopenharmony_ci break; 417cabdff1aSopenharmony_ci 418cabdff1aSopenharmony_ci case DIR_DOWN: 419cabdff1aSopenharmony_ci for (irow = point[1]; irow < side_length; irow++) 420cabdff1aSopenharmony_ci pglyph[point[0] + irow * side_length] = 1; 421cabdff1aSopenharmony_ci break; 422cabdff1aSopenharmony_ci 423cabdff1aSopenharmony_ci case DIR_LEFT: 424cabdff1aSopenharmony_ci for (icol = point[0]; icol >= 0; icol--) 425cabdff1aSopenharmony_ci pglyph[icol + point[1] * side_length] = 1; 426cabdff1aSopenharmony_ci break; 427cabdff1aSopenharmony_ci 428cabdff1aSopenharmony_ci case DIR_RIGHT: 429cabdff1aSopenharmony_ci for (icol = point[0]; icol < side_length; icol++) 430cabdff1aSopenharmony_ci pglyph[icol + point[1] * side_length] = 1; 431cabdff1aSopenharmony_ci break; 432cabdff1aSopenharmony_ci } 433cabdff1aSopenharmony_ci } 434cabdff1aSopenharmony_ci } 435cabdff1aSopenharmony_ci } 436cabdff1aSopenharmony_ci} 437cabdff1aSopenharmony_ci 438cabdff1aSopenharmony_cistatic void init_sizes(SANMVideoContext *ctx, int width, int height) 439cabdff1aSopenharmony_ci{ 440cabdff1aSopenharmony_ci ctx->width = width; 441cabdff1aSopenharmony_ci ctx->height = height; 442cabdff1aSopenharmony_ci ctx->npixels = width * height; 443cabdff1aSopenharmony_ci 444cabdff1aSopenharmony_ci ctx->aligned_width = FFALIGN(width, 8); 445cabdff1aSopenharmony_ci ctx->aligned_height = FFALIGN(height, 8); 446cabdff1aSopenharmony_ci 447cabdff1aSopenharmony_ci ctx->buf_size = ctx->aligned_width * ctx->aligned_height * sizeof(ctx->frm0[0]); 448cabdff1aSopenharmony_ci ctx->pitch = width; 449cabdff1aSopenharmony_ci} 450cabdff1aSopenharmony_ci 451cabdff1aSopenharmony_cistatic void destroy_buffers(SANMVideoContext *ctx) 452cabdff1aSopenharmony_ci{ 453cabdff1aSopenharmony_ci av_freep(&ctx->frm0); 454cabdff1aSopenharmony_ci av_freep(&ctx->frm1); 455cabdff1aSopenharmony_ci av_freep(&ctx->frm2); 456cabdff1aSopenharmony_ci av_freep(&ctx->stored_frame); 457cabdff1aSopenharmony_ci av_freep(&ctx->rle_buf); 458cabdff1aSopenharmony_ci ctx->frm0_size = 459cabdff1aSopenharmony_ci ctx->frm1_size = 460cabdff1aSopenharmony_ci ctx->frm2_size = 0; 461cabdff1aSopenharmony_ci init_sizes(ctx, 0, 0); 462cabdff1aSopenharmony_ci} 463cabdff1aSopenharmony_ci 464cabdff1aSopenharmony_cistatic av_cold int init_buffers(SANMVideoContext *ctx) 465cabdff1aSopenharmony_ci{ 466cabdff1aSopenharmony_ci av_fast_padded_mallocz(&ctx->frm0, &ctx->frm0_size, ctx->buf_size); 467cabdff1aSopenharmony_ci av_fast_padded_mallocz(&ctx->frm1, &ctx->frm1_size, ctx->buf_size); 468cabdff1aSopenharmony_ci av_fast_padded_mallocz(&ctx->frm2, &ctx->frm2_size, ctx->buf_size); 469cabdff1aSopenharmony_ci if (!ctx->version) 470cabdff1aSopenharmony_ci av_fast_padded_mallocz(&ctx->stored_frame, 471cabdff1aSopenharmony_ci &ctx->stored_frame_size, ctx->buf_size); 472cabdff1aSopenharmony_ci 473cabdff1aSopenharmony_ci if (!ctx->frm0 || !ctx->frm1 || !ctx->frm2 || 474cabdff1aSopenharmony_ci (!ctx->stored_frame && !ctx->version)) { 475cabdff1aSopenharmony_ci destroy_buffers(ctx); 476cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 477cabdff1aSopenharmony_ci } 478cabdff1aSopenharmony_ci 479cabdff1aSopenharmony_ci return 0; 480cabdff1aSopenharmony_ci} 481cabdff1aSopenharmony_ci 482cabdff1aSopenharmony_cistatic void rotate_bufs(SANMVideoContext *ctx, int rotate_code) 483cabdff1aSopenharmony_ci{ 484cabdff1aSopenharmony_ci if (rotate_code == 2) 485cabdff1aSopenharmony_ci FFSWAP(uint16_t*, ctx->frm1, ctx->frm2); 486cabdff1aSopenharmony_ci FFSWAP(uint16_t*, ctx->frm2, ctx->frm0); 487cabdff1aSopenharmony_ci} 488cabdff1aSopenharmony_ci 489cabdff1aSopenharmony_cistatic av_cold int decode_init(AVCodecContext *avctx) 490cabdff1aSopenharmony_ci{ 491cabdff1aSopenharmony_ci SANMVideoContext *ctx = avctx->priv_data; 492cabdff1aSopenharmony_ci 493cabdff1aSopenharmony_ci ctx->avctx = avctx; 494cabdff1aSopenharmony_ci ctx->version = !avctx->extradata_size; 495cabdff1aSopenharmony_ci // early sanity check before allocations to avoid need for deallocation code. 496cabdff1aSopenharmony_ci if (!ctx->version && avctx->extradata_size < 1026) { 497cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Not enough extradata.\n"); 498cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 499cabdff1aSopenharmony_ci } 500cabdff1aSopenharmony_ci 501cabdff1aSopenharmony_ci avctx->pix_fmt = ctx->version ? AV_PIX_FMT_RGB565 : AV_PIX_FMT_PAL8; 502cabdff1aSopenharmony_ci 503cabdff1aSopenharmony_ci init_sizes(ctx, avctx->width, avctx->height); 504cabdff1aSopenharmony_ci if (init_buffers(ctx)) { 505cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Error allocating buffers.\n"); 506cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 507cabdff1aSopenharmony_ci } 508cabdff1aSopenharmony_ci 509cabdff1aSopenharmony_ci make_glyphs(ctx->p4x4glyphs[0], glyph4_x, glyph4_y, 4); 510cabdff1aSopenharmony_ci make_glyphs(ctx->p8x8glyphs[0], glyph8_x, glyph8_y, 8); 511cabdff1aSopenharmony_ci 512cabdff1aSopenharmony_ci if (!ctx->version) { 513cabdff1aSopenharmony_ci int i; 514cabdff1aSopenharmony_ci 515cabdff1aSopenharmony_ci ctx->subversion = AV_RL16(avctx->extradata); 516cabdff1aSopenharmony_ci for (i = 0; i < PALETTE_SIZE; i++) 517cabdff1aSopenharmony_ci ctx->pal[i] = 0xFFU << 24 | AV_RL32(avctx->extradata + 2 + i * 4); 518cabdff1aSopenharmony_ci } 519cabdff1aSopenharmony_ci 520cabdff1aSopenharmony_ci return 0; 521cabdff1aSopenharmony_ci} 522cabdff1aSopenharmony_ci 523cabdff1aSopenharmony_cistatic av_cold int decode_end(AVCodecContext *avctx) 524cabdff1aSopenharmony_ci{ 525cabdff1aSopenharmony_ci SANMVideoContext *ctx = avctx->priv_data; 526cabdff1aSopenharmony_ci 527cabdff1aSopenharmony_ci destroy_buffers(ctx); 528cabdff1aSopenharmony_ci 529cabdff1aSopenharmony_ci return 0; 530cabdff1aSopenharmony_ci} 531cabdff1aSopenharmony_ci 532cabdff1aSopenharmony_cistatic int rle_decode(SANMVideoContext *ctx, uint8_t *dst, const int out_size) 533cabdff1aSopenharmony_ci{ 534cabdff1aSopenharmony_ci int opcode, color, run_len, left = out_size; 535cabdff1aSopenharmony_ci 536cabdff1aSopenharmony_ci while (left > 0) { 537cabdff1aSopenharmony_ci opcode = bytestream2_get_byte(&ctx->gb); 538cabdff1aSopenharmony_ci run_len = (opcode >> 1) + 1; 539cabdff1aSopenharmony_ci if (run_len > left || bytestream2_get_bytes_left(&ctx->gb) <= 0) 540cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 541cabdff1aSopenharmony_ci 542cabdff1aSopenharmony_ci if (opcode & 1) { 543cabdff1aSopenharmony_ci color = bytestream2_get_byte(&ctx->gb); 544cabdff1aSopenharmony_ci memset(dst, color, run_len); 545cabdff1aSopenharmony_ci } else { 546cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&ctx->gb) < run_len) 547cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 548cabdff1aSopenharmony_ci bytestream2_get_bufferu(&ctx->gb, dst, run_len); 549cabdff1aSopenharmony_ci } 550cabdff1aSopenharmony_ci 551cabdff1aSopenharmony_ci dst += run_len; 552cabdff1aSopenharmony_ci left -= run_len; 553cabdff1aSopenharmony_ci } 554cabdff1aSopenharmony_ci 555cabdff1aSopenharmony_ci return 0; 556cabdff1aSopenharmony_ci} 557cabdff1aSopenharmony_ci 558cabdff1aSopenharmony_cistatic int old_codec1(SANMVideoContext *ctx, int top, 559cabdff1aSopenharmony_ci int left, int width, int height) 560cabdff1aSopenharmony_ci{ 561cabdff1aSopenharmony_ci uint8_t *dst = ((uint8_t *)ctx->frm0) + left + top * ctx->pitch; 562cabdff1aSopenharmony_ci int i, j, len, flag, code, val, pos, end; 563cabdff1aSopenharmony_ci 564cabdff1aSopenharmony_ci for (i = 0; i < height; i++) { 565cabdff1aSopenharmony_ci pos = 0; 566cabdff1aSopenharmony_ci 567cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&ctx->gb) < 2) 568cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 569cabdff1aSopenharmony_ci 570cabdff1aSopenharmony_ci len = bytestream2_get_le16u(&ctx->gb); 571cabdff1aSopenharmony_ci end = bytestream2_tell(&ctx->gb) + len; 572cabdff1aSopenharmony_ci 573cabdff1aSopenharmony_ci while (bytestream2_tell(&ctx->gb) < end) { 574cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&ctx->gb) < 2) 575cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 576cabdff1aSopenharmony_ci 577cabdff1aSopenharmony_ci code = bytestream2_get_byteu(&ctx->gb); 578cabdff1aSopenharmony_ci flag = code & 1; 579cabdff1aSopenharmony_ci code = (code >> 1) + 1; 580cabdff1aSopenharmony_ci if (pos + code > width) 581cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 582cabdff1aSopenharmony_ci if (flag) { 583cabdff1aSopenharmony_ci val = bytestream2_get_byteu(&ctx->gb); 584cabdff1aSopenharmony_ci if (val) 585cabdff1aSopenharmony_ci memset(dst + pos, val, code); 586cabdff1aSopenharmony_ci pos += code; 587cabdff1aSopenharmony_ci } else { 588cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&ctx->gb) < code) 589cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 590cabdff1aSopenharmony_ci for (j = 0; j < code; j++) { 591cabdff1aSopenharmony_ci val = bytestream2_get_byteu(&ctx->gb); 592cabdff1aSopenharmony_ci if (val) 593cabdff1aSopenharmony_ci dst[pos] = val; 594cabdff1aSopenharmony_ci pos++; 595cabdff1aSopenharmony_ci } 596cabdff1aSopenharmony_ci } 597cabdff1aSopenharmony_ci } 598cabdff1aSopenharmony_ci dst += ctx->pitch; 599cabdff1aSopenharmony_ci } 600cabdff1aSopenharmony_ci ctx->rotate_code = 0; 601cabdff1aSopenharmony_ci 602cabdff1aSopenharmony_ci return 0; 603cabdff1aSopenharmony_ci} 604cabdff1aSopenharmony_ci 605cabdff1aSopenharmony_cistatic inline void codec37_mv(uint8_t *dst, const uint8_t *src, 606cabdff1aSopenharmony_ci int height, int stride, int x, int y) 607cabdff1aSopenharmony_ci{ 608cabdff1aSopenharmony_ci int pos, i, j; 609cabdff1aSopenharmony_ci 610cabdff1aSopenharmony_ci pos = x + y * stride; 611cabdff1aSopenharmony_ci for (j = 0; j < 4; j++) { 612cabdff1aSopenharmony_ci for (i = 0; i < 4; i++) { 613cabdff1aSopenharmony_ci if ((pos + i) < 0 || (pos + i) >= height * stride) 614cabdff1aSopenharmony_ci dst[i] = 0; 615cabdff1aSopenharmony_ci else 616cabdff1aSopenharmony_ci dst[i] = src[i]; 617cabdff1aSopenharmony_ci } 618cabdff1aSopenharmony_ci dst += stride; 619cabdff1aSopenharmony_ci src += stride; 620cabdff1aSopenharmony_ci pos += stride; 621cabdff1aSopenharmony_ci } 622cabdff1aSopenharmony_ci} 623cabdff1aSopenharmony_ci 624cabdff1aSopenharmony_cistatic int old_codec37(SANMVideoContext *ctx, int top, 625cabdff1aSopenharmony_ci int left, int width, int height) 626cabdff1aSopenharmony_ci{ 627cabdff1aSopenharmony_ci ptrdiff_t stride = ctx->pitch; 628cabdff1aSopenharmony_ci int i, j, k, t; 629cabdff1aSopenharmony_ci uint8_t *dst, *prev; 630cabdff1aSopenharmony_ci int skip_run = 0; 631cabdff1aSopenharmony_ci int compr = bytestream2_get_byte(&ctx->gb); 632cabdff1aSopenharmony_ci int mvoff = bytestream2_get_byte(&ctx->gb); 633cabdff1aSopenharmony_ci int seq = bytestream2_get_le16(&ctx->gb); 634cabdff1aSopenharmony_ci uint32_t decoded_size = bytestream2_get_le32(&ctx->gb); 635cabdff1aSopenharmony_ci int flags; 636cabdff1aSopenharmony_ci 637cabdff1aSopenharmony_ci bytestream2_skip(&ctx->gb, 4); 638cabdff1aSopenharmony_ci flags = bytestream2_get_byte(&ctx->gb); 639cabdff1aSopenharmony_ci bytestream2_skip(&ctx->gb, 3); 640cabdff1aSopenharmony_ci 641cabdff1aSopenharmony_ci if (decoded_size > ctx->height * stride - left - top * stride) { 642cabdff1aSopenharmony_ci decoded_size = ctx->height * stride - left - top * stride; 643cabdff1aSopenharmony_ci av_log(ctx->avctx, AV_LOG_WARNING, "Decoded size is too large.\n"); 644cabdff1aSopenharmony_ci } 645cabdff1aSopenharmony_ci 646cabdff1aSopenharmony_ci ctx->rotate_code = 0; 647cabdff1aSopenharmony_ci 648cabdff1aSopenharmony_ci if (((seq & 1) || !(flags & 1)) && (compr && compr != 2)) 649cabdff1aSopenharmony_ci rotate_bufs(ctx, 1); 650cabdff1aSopenharmony_ci 651cabdff1aSopenharmony_ci dst = ((uint8_t*)ctx->frm0) + left + top * stride; 652cabdff1aSopenharmony_ci prev = ((uint8_t*)ctx->frm2) + left + top * stride; 653cabdff1aSopenharmony_ci 654cabdff1aSopenharmony_ci if (mvoff > 2) { 655cabdff1aSopenharmony_ci av_log(ctx->avctx, AV_LOG_ERROR, "Invalid motion base value %d.\n", mvoff); 656cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 657cabdff1aSopenharmony_ci } 658cabdff1aSopenharmony_ci 659cabdff1aSopenharmony_ci switch (compr) { 660cabdff1aSopenharmony_ci case 0: 661cabdff1aSopenharmony_ci for (i = 0; i < height; i++) { 662cabdff1aSopenharmony_ci bytestream2_get_buffer(&ctx->gb, dst, width); 663cabdff1aSopenharmony_ci dst += stride; 664cabdff1aSopenharmony_ci } 665cabdff1aSopenharmony_ci memset(ctx->frm1, 0, ctx->height * stride); 666cabdff1aSopenharmony_ci memset(ctx->frm2, 0, ctx->height * stride); 667cabdff1aSopenharmony_ci break; 668cabdff1aSopenharmony_ci case 2: 669cabdff1aSopenharmony_ci if (rle_decode(ctx, dst, decoded_size)) 670cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 671cabdff1aSopenharmony_ci memset(ctx->frm1, 0, ctx->frm1_size); 672cabdff1aSopenharmony_ci memset(ctx->frm2, 0, ctx->frm2_size); 673cabdff1aSopenharmony_ci break; 674cabdff1aSopenharmony_ci case 3: 675cabdff1aSopenharmony_ci case 4: 676cabdff1aSopenharmony_ci if (flags & 4) { 677cabdff1aSopenharmony_ci for (j = 0; j < height; j += 4) { 678cabdff1aSopenharmony_ci for (i = 0; i < width; i += 4) { 679cabdff1aSopenharmony_ci int code; 680cabdff1aSopenharmony_ci if (skip_run) { 681cabdff1aSopenharmony_ci skip_run--; 682cabdff1aSopenharmony_ci copy_block4(dst + i, prev + i, stride, stride, 4); 683cabdff1aSopenharmony_ci continue; 684cabdff1aSopenharmony_ci } 685cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&ctx->gb) < 1) 686cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 687cabdff1aSopenharmony_ci code = bytestream2_get_byteu(&ctx->gb); 688cabdff1aSopenharmony_ci switch (code) { 689cabdff1aSopenharmony_ci case 0xFF: 690cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&ctx->gb) < 16) 691cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 692cabdff1aSopenharmony_ci for (k = 0; k < 4; k++) 693cabdff1aSopenharmony_ci bytestream2_get_bufferu(&ctx->gb, dst + i + k * stride, 4); 694cabdff1aSopenharmony_ci break; 695cabdff1aSopenharmony_ci case 0xFE: 696cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&ctx->gb) < 4) 697cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 698cabdff1aSopenharmony_ci for (k = 0; k < 4; k++) 699cabdff1aSopenharmony_ci memset(dst + i + k * stride, bytestream2_get_byteu(&ctx->gb), 4); 700cabdff1aSopenharmony_ci break; 701cabdff1aSopenharmony_ci case 0xFD: 702cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&ctx->gb) < 1) 703cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 704cabdff1aSopenharmony_ci t = bytestream2_get_byteu(&ctx->gb); 705cabdff1aSopenharmony_ci for (k = 0; k < 4; k++) 706cabdff1aSopenharmony_ci memset(dst + i + k * stride, t, 4); 707cabdff1aSopenharmony_ci break; 708cabdff1aSopenharmony_ci default: 709cabdff1aSopenharmony_ci if (compr == 4 && !code) { 710cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&ctx->gb) < 1) 711cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 712cabdff1aSopenharmony_ci skip_run = bytestream2_get_byteu(&ctx->gb) + 1; 713cabdff1aSopenharmony_ci i -= 4; 714cabdff1aSopenharmony_ci } else { 715cabdff1aSopenharmony_ci int mx, my; 716cabdff1aSopenharmony_ci 717cabdff1aSopenharmony_ci mx = c37_mv[(mvoff * 255 + code) * 2]; 718cabdff1aSopenharmony_ci my = c37_mv[(mvoff * 255 + code) * 2 + 1]; 719cabdff1aSopenharmony_ci codec37_mv(dst + i, prev + i + mx + my * stride, 720cabdff1aSopenharmony_ci ctx->height, stride, i + mx, j + my); 721cabdff1aSopenharmony_ci } 722cabdff1aSopenharmony_ci } 723cabdff1aSopenharmony_ci } 724cabdff1aSopenharmony_ci dst += stride * 4; 725cabdff1aSopenharmony_ci prev += stride * 4; 726cabdff1aSopenharmony_ci } 727cabdff1aSopenharmony_ci } else { 728cabdff1aSopenharmony_ci for (j = 0; j < height; j += 4) { 729cabdff1aSopenharmony_ci for (i = 0; i < width; i += 4) { 730cabdff1aSopenharmony_ci int code; 731cabdff1aSopenharmony_ci if (skip_run) { 732cabdff1aSopenharmony_ci skip_run--; 733cabdff1aSopenharmony_ci copy_block4(dst + i, prev + i, stride, stride, 4); 734cabdff1aSopenharmony_ci continue; 735cabdff1aSopenharmony_ci } 736cabdff1aSopenharmony_ci code = bytestream2_get_byte(&ctx->gb); 737cabdff1aSopenharmony_ci if (code == 0xFF) { 738cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&ctx->gb) < 16) 739cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 740cabdff1aSopenharmony_ci for (k = 0; k < 4; k++) 741cabdff1aSopenharmony_ci bytestream2_get_bufferu(&ctx->gb, dst + i + k * stride, 4); 742cabdff1aSopenharmony_ci } else if (compr == 4 && !code) { 743cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&ctx->gb) < 1) 744cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 745cabdff1aSopenharmony_ci skip_run = bytestream2_get_byteu(&ctx->gb) + 1; 746cabdff1aSopenharmony_ci i -= 4; 747cabdff1aSopenharmony_ci } else { 748cabdff1aSopenharmony_ci int mx, my; 749cabdff1aSopenharmony_ci 750cabdff1aSopenharmony_ci mx = c37_mv[(mvoff * 255 + code) * 2]; 751cabdff1aSopenharmony_ci my = c37_mv[(mvoff * 255 + code) * 2 + 1]; 752cabdff1aSopenharmony_ci codec37_mv(dst + i, prev + i + mx + my * stride, 753cabdff1aSopenharmony_ci ctx->height, stride, i + mx, j + my); 754cabdff1aSopenharmony_ci } 755cabdff1aSopenharmony_ci } 756cabdff1aSopenharmony_ci dst += stride * 4; 757cabdff1aSopenharmony_ci prev += stride * 4; 758cabdff1aSopenharmony_ci } 759cabdff1aSopenharmony_ci } 760cabdff1aSopenharmony_ci break; 761cabdff1aSopenharmony_ci default: 762cabdff1aSopenharmony_ci avpriv_report_missing_feature(ctx->avctx, 763cabdff1aSopenharmony_ci "Subcodec 37 compression %d", compr); 764cabdff1aSopenharmony_ci return AVERROR_PATCHWELCOME; 765cabdff1aSopenharmony_ci } 766cabdff1aSopenharmony_ci 767cabdff1aSopenharmony_ci return 0; 768cabdff1aSopenharmony_ci} 769cabdff1aSopenharmony_ci 770cabdff1aSopenharmony_cistatic int process_block(SANMVideoContext *ctx, uint8_t *dst, uint8_t *prev1, 771cabdff1aSopenharmony_ci uint8_t *prev2, int stride, int tbl, int size) 772cabdff1aSopenharmony_ci{ 773cabdff1aSopenharmony_ci int code, k, t; 774cabdff1aSopenharmony_ci uint8_t colors[2]; 775cabdff1aSopenharmony_ci int8_t *pglyph; 776cabdff1aSopenharmony_ci 777cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&ctx->gb) < 1) 778cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 779cabdff1aSopenharmony_ci 780cabdff1aSopenharmony_ci code = bytestream2_get_byteu(&ctx->gb); 781cabdff1aSopenharmony_ci if (code >= 0xF8) { 782cabdff1aSopenharmony_ci switch (code) { 783cabdff1aSopenharmony_ci case 0xFF: 784cabdff1aSopenharmony_ci if (size == 2) { 785cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&ctx->gb) < 4) 786cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 787cabdff1aSopenharmony_ci dst[0] = bytestream2_get_byteu(&ctx->gb); 788cabdff1aSopenharmony_ci dst[1] = bytestream2_get_byteu(&ctx->gb); 789cabdff1aSopenharmony_ci dst[0 + stride] = bytestream2_get_byteu(&ctx->gb); 790cabdff1aSopenharmony_ci dst[1 + stride] = bytestream2_get_byteu(&ctx->gb); 791cabdff1aSopenharmony_ci } else { 792cabdff1aSopenharmony_ci size >>= 1; 793cabdff1aSopenharmony_ci if (process_block(ctx, dst, prev1, prev2, stride, tbl, size)) 794cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 795cabdff1aSopenharmony_ci if (process_block(ctx, dst + size, prev1 + size, prev2 + size, 796cabdff1aSopenharmony_ci stride, tbl, size)) 797cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 798cabdff1aSopenharmony_ci dst += size * stride; 799cabdff1aSopenharmony_ci prev1 += size * stride; 800cabdff1aSopenharmony_ci prev2 += size * stride; 801cabdff1aSopenharmony_ci if (process_block(ctx, dst, prev1, prev2, stride, tbl, size)) 802cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 803cabdff1aSopenharmony_ci if (process_block(ctx, dst + size, prev1 + size, prev2 + size, 804cabdff1aSopenharmony_ci stride, tbl, size)) 805cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 806cabdff1aSopenharmony_ci } 807cabdff1aSopenharmony_ci break; 808cabdff1aSopenharmony_ci case 0xFE: 809cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&ctx->gb) < 1) 810cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 811cabdff1aSopenharmony_ci 812cabdff1aSopenharmony_ci t = bytestream2_get_byteu(&ctx->gb); 813cabdff1aSopenharmony_ci for (k = 0; k < size; k++) 814cabdff1aSopenharmony_ci memset(dst + k * stride, t, size); 815cabdff1aSopenharmony_ci break; 816cabdff1aSopenharmony_ci case 0xFD: 817cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&ctx->gb) < 3) 818cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 819cabdff1aSopenharmony_ci 820cabdff1aSopenharmony_ci code = bytestream2_get_byteu(&ctx->gb); 821cabdff1aSopenharmony_ci pglyph = (size == 8) ? ctx->p8x8glyphs[code] : ctx->p4x4glyphs[code]; 822cabdff1aSopenharmony_ci bytestream2_get_bufferu(&ctx->gb, colors, 2); 823cabdff1aSopenharmony_ci 824cabdff1aSopenharmony_ci for (k = 0; k < size; k++) 825cabdff1aSopenharmony_ci for (t = 0; t < size; t++) 826cabdff1aSopenharmony_ci dst[t + k * stride] = colors[!*pglyph++]; 827cabdff1aSopenharmony_ci break; 828cabdff1aSopenharmony_ci case 0xFC: 829cabdff1aSopenharmony_ci for (k = 0; k < size; k++) 830cabdff1aSopenharmony_ci memcpy(dst + k * stride, prev1 + k * stride, size); 831cabdff1aSopenharmony_ci break; 832cabdff1aSopenharmony_ci default: 833cabdff1aSopenharmony_ci k = bytestream2_tell(&ctx->gb); 834cabdff1aSopenharmony_ci bytestream2_seek(&ctx->gb, tbl + (code & 7), SEEK_SET); 835cabdff1aSopenharmony_ci t = bytestream2_get_byte(&ctx->gb); 836cabdff1aSopenharmony_ci bytestream2_seek(&ctx->gb, k, SEEK_SET); 837cabdff1aSopenharmony_ci for (k = 0; k < size; k++) 838cabdff1aSopenharmony_ci memset(dst + k * stride, t, size); 839cabdff1aSopenharmony_ci } 840cabdff1aSopenharmony_ci } else { 841cabdff1aSopenharmony_ci int mx = motion_vectors[code][0]; 842cabdff1aSopenharmony_ci int my = motion_vectors[code][1]; 843cabdff1aSopenharmony_ci int index = prev2 - (const uint8_t *)ctx->frm2; 844cabdff1aSopenharmony_ci 845cabdff1aSopenharmony_ci av_assert2(index >= 0 && index < (ctx->buf_size >> 1)); 846cabdff1aSopenharmony_ci 847cabdff1aSopenharmony_ci if (index < -mx - my * stride || 848cabdff1aSopenharmony_ci (ctx->buf_size >> 1) - index < mx + size + (my + size - 1) * stride) { 849cabdff1aSopenharmony_ci av_log(ctx->avctx, AV_LOG_ERROR, "MV is invalid.\n"); 850cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 851cabdff1aSopenharmony_ci } 852cabdff1aSopenharmony_ci 853cabdff1aSopenharmony_ci for (k = 0; k < size; k++) 854cabdff1aSopenharmony_ci memcpy(dst + k * stride, prev2 + mx + (my + k) * stride, size); 855cabdff1aSopenharmony_ci } 856cabdff1aSopenharmony_ci 857cabdff1aSopenharmony_ci return 0; 858cabdff1aSopenharmony_ci} 859cabdff1aSopenharmony_ci 860cabdff1aSopenharmony_cistatic int old_codec47(SANMVideoContext *ctx, int top, 861cabdff1aSopenharmony_ci int left, int width, int height) 862cabdff1aSopenharmony_ci{ 863cabdff1aSopenharmony_ci uint32_t decoded_size; 864cabdff1aSopenharmony_ci int i, j; 865cabdff1aSopenharmony_ci ptrdiff_t stride = ctx->pitch; 866cabdff1aSopenharmony_ci uint8_t *dst = (uint8_t *)ctx->frm0 + left + top * stride; 867cabdff1aSopenharmony_ci uint8_t *prev1 = (uint8_t *)ctx->frm1; 868cabdff1aSopenharmony_ci uint8_t *prev2 = (uint8_t *)ctx->frm2; 869cabdff1aSopenharmony_ci int tbl_pos = bytestream2_tell(&ctx->gb); 870cabdff1aSopenharmony_ci int seq = bytestream2_get_le16(&ctx->gb); 871cabdff1aSopenharmony_ci int compr = bytestream2_get_byte(&ctx->gb); 872cabdff1aSopenharmony_ci int new_rot = bytestream2_get_byte(&ctx->gb); 873cabdff1aSopenharmony_ci int skip = bytestream2_get_byte(&ctx->gb); 874cabdff1aSopenharmony_ci 875cabdff1aSopenharmony_ci bytestream2_skip(&ctx->gb, 9); 876cabdff1aSopenharmony_ci decoded_size = bytestream2_get_le32(&ctx->gb); 877cabdff1aSopenharmony_ci bytestream2_skip(&ctx->gb, 8); 878cabdff1aSopenharmony_ci 879cabdff1aSopenharmony_ci if (decoded_size > ctx->height * stride - left - top * stride) { 880cabdff1aSopenharmony_ci decoded_size = ctx->height * stride - left - top * stride; 881cabdff1aSopenharmony_ci av_log(ctx->avctx, AV_LOG_WARNING, "Decoded size is too large.\n"); 882cabdff1aSopenharmony_ci } 883cabdff1aSopenharmony_ci 884cabdff1aSopenharmony_ci if (skip & 1) 885cabdff1aSopenharmony_ci bytestream2_skip(&ctx->gb, 0x8080); 886cabdff1aSopenharmony_ci if (!seq) { 887cabdff1aSopenharmony_ci ctx->prev_seq = -1; 888cabdff1aSopenharmony_ci memset(prev1, 0, ctx->height * stride); 889cabdff1aSopenharmony_ci memset(prev2, 0, ctx->height * stride); 890cabdff1aSopenharmony_ci } 891cabdff1aSopenharmony_ci 892cabdff1aSopenharmony_ci switch (compr) { 893cabdff1aSopenharmony_ci case 0: 894cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&ctx->gb) < width * height) 895cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 896cabdff1aSopenharmony_ci for (j = 0; j < height; j++) { 897cabdff1aSopenharmony_ci bytestream2_get_bufferu(&ctx->gb, dst, width); 898cabdff1aSopenharmony_ci dst += stride; 899cabdff1aSopenharmony_ci } 900cabdff1aSopenharmony_ci break; 901cabdff1aSopenharmony_ci case 1: 902cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&ctx->gb) < ((width + 1) >> 1) * ((height + 1) >> 1)) 903cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 904cabdff1aSopenharmony_ci for (j = 0; j < height; j += 2) { 905cabdff1aSopenharmony_ci for (i = 0; i < width; i += 2) { 906cabdff1aSopenharmony_ci dst[i] = 907cabdff1aSopenharmony_ci dst[i + 1] = 908cabdff1aSopenharmony_ci dst[stride + i] = 909cabdff1aSopenharmony_ci dst[stride + i + 1] = bytestream2_get_byteu(&ctx->gb); 910cabdff1aSopenharmony_ci } 911cabdff1aSopenharmony_ci dst += stride * 2; 912cabdff1aSopenharmony_ci } 913cabdff1aSopenharmony_ci break; 914cabdff1aSopenharmony_ci case 2: 915cabdff1aSopenharmony_ci if (seq == ctx->prev_seq + 1) { 916cabdff1aSopenharmony_ci for (j = 0; j < height; j += 8) { 917cabdff1aSopenharmony_ci for (i = 0; i < width; i += 8) 918cabdff1aSopenharmony_ci if (process_block(ctx, dst + i, prev1 + i, prev2 + i, stride, 919cabdff1aSopenharmony_ci tbl_pos + 8, 8)) 920cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 921cabdff1aSopenharmony_ci dst += stride * 8; 922cabdff1aSopenharmony_ci prev1 += stride * 8; 923cabdff1aSopenharmony_ci prev2 += stride * 8; 924cabdff1aSopenharmony_ci } 925cabdff1aSopenharmony_ci } 926cabdff1aSopenharmony_ci break; 927cabdff1aSopenharmony_ci case 3: 928cabdff1aSopenharmony_ci memcpy(ctx->frm0, ctx->frm2, ctx->pitch * ctx->height); 929cabdff1aSopenharmony_ci break; 930cabdff1aSopenharmony_ci case 4: 931cabdff1aSopenharmony_ci memcpy(ctx->frm0, ctx->frm1, ctx->pitch * ctx->height); 932cabdff1aSopenharmony_ci break; 933cabdff1aSopenharmony_ci case 5: 934cabdff1aSopenharmony_ci if (rle_decode(ctx, dst, decoded_size)) 935cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 936cabdff1aSopenharmony_ci break; 937cabdff1aSopenharmony_ci default: 938cabdff1aSopenharmony_ci avpriv_report_missing_feature(ctx->avctx, 939cabdff1aSopenharmony_ci "Subcodec 47 compression %d", compr); 940cabdff1aSopenharmony_ci return AVERROR_PATCHWELCOME; 941cabdff1aSopenharmony_ci } 942cabdff1aSopenharmony_ci if (seq == ctx->prev_seq + 1) 943cabdff1aSopenharmony_ci ctx->rotate_code = new_rot; 944cabdff1aSopenharmony_ci else 945cabdff1aSopenharmony_ci ctx->rotate_code = 0; 946cabdff1aSopenharmony_ci ctx->prev_seq = seq; 947cabdff1aSopenharmony_ci 948cabdff1aSopenharmony_ci return 0; 949cabdff1aSopenharmony_ci} 950cabdff1aSopenharmony_ci 951cabdff1aSopenharmony_cistatic int process_frame_obj(SANMVideoContext *ctx) 952cabdff1aSopenharmony_ci{ 953cabdff1aSopenharmony_ci uint16_t codec = bytestream2_get_le16u(&ctx->gb); 954cabdff1aSopenharmony_ci uint16_t left = bytestream2_get_le16u(&ctx->gb); 955cabdff1aSopenharmony_ci uint16_t top = bytestream2_get_le16u(&ctx->gb); 956cabdff1aSopenharmony_ci uint16_t w = bytestream2_get_le16u(&ctx->gb); 957cabdff1aSopenharmony_ci uint16_t h = bytestream2_get_le16u(&ctx->gb); 958cabdff1aSopenharmony_ci 959cabdff1aSopenharmony_ci if (!w || !h) { 960cabdff1aSopenharmony_ci av_log(ctx->avctx, AV_LOG_ERROR, "Dimensions are invalid.\n"); 961cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 962cabdff1aSopenharmony_ci } 963cabdff1aSopenharmony_ci 964cabdff1aSopenharmony_ci if (ctx->width < left + w || ctx->height < top + h) { 965cabdff1aSopenharmony_ci int ret = ff_set_dimensions(ctx->avctx, FFMAX(left + w, ctx->width), 966cabdff1aSopenharmony_ci FFMAX(top + h, ctx->height)); 967cabdff1aSopenharmony_ci if (ret < 0) 968cabdff1aSopenharmony_ci return ret; 969cabdff1aSopenharmony_ci init_sizes(ctx, FFMAX(left + w, ctx->width), 970cabdff1aSopenharmony_ci FFMAX(top + h, ctx->height)); 971cabdff1aSopenharmony_ci if (init_buffers(ctx)) { 972cabdff1aSopenharmony_ci av_log(ctx->avctx, AV_LOG_ERROR, "Error resizing buffers.\n"); 973cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 974cabdff1aSopenharmony_ci } 975cabdff1aSopenharmony_ci } 976cabdff1aSopenharmony_ci bytestream2_skip(&ctx->gb, 4); 977cabdff1aSopenharmony_ci 978cabdff1aSopenharmony_ci switch (codec) { 979cabdff1aSopenharmony_ci case 1: 980cabdff1aSopenharmony_ci case 3: 981cabdff1aSopenharmony_ci return old_codec1(ctx, top, left, w, h); 982cabdff1aSopenharmony_ci case 37: 983cabdff1aSopenharmony_ci return old_codec37(ctx, top, left, w, h); 984cabdff1aSopenharmony_ci case 47: 985cabdff1aSopenharmony_ci return old_codec47(ctx, top, left, w, h); 986cabdff1aSopenharmony_ci default: 987cabdff1aSopenharmony_ci avpriv_request_sample(ctx->avctx, "Subcodec %d", codec); 988cabdff1aSopenharmony_ci return AVERROR_PATCHWELCOME; 989cabdff1aSopenharmony_ci } 990cabdff1aSopenharmony_ci} 991cabdff1aSopenharmony_ci 992cabdff1aSopenharmony_cistatic int decode_0(SANMVideoContext *ctx) 993cabdff1aSopenharmony_ci{ 994cabdff1aSopenharmony_ci uint16_t *frm = ctx->frm0; 995cabdff1aSopenharmony_ci int x, y; 996cabdff1aSopenharmony_ci 997cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&ctx->gb) < ctx->width * ctx->height * 2) { 998cabdff1aSopenharmony_ci av_log(ctx->avctx, AV_LOG_ERROR, "Insufficient data for raw frame.\n"); 999cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1000cabdff1aSopenharmony_ci } 1001cabdff1aSopenharmony_ci for (y = 0; y < ctx->height; y++) { 1002cabdff1aSopenharmony_ci for (x = 0; x < ctx->width; x++) 1003cabdff1aSopenharmony_ci frm[x] = bytestream2_get_le16u(&ctx->gb); 1004cabdff1aSopenharmony_ci frm += ctx->pitch; 1005cabdff1aSopenharmony_ci } 1006cabdff1aSopenharmony_ci return 0; 1007cabdff1aSopenharmony_ci} 1008cabdff1aSopenharmony_ci 1009cabdff1aSopenharmony_cistatic int decode_nop(SANMVideoContext *ctx) 1010cabdff1aSopenharmony_ci{ 1011cabdff1aSopenharmony_ci avpriv_request_sample(ctx->avctx, "Unknown/unsupported compression type"); 1012cabdff1aSopenharmony_ci return AVERROR_PATCHWELCOME; 1013cabdff1aSopenharmony_ci} 1014cabdff1aSopenharmony_ci 1015cabdff1aSopenharmony_cistatic void copy_block(uint16_t *pdest, uint16_t *psrc, int block_size, ptrdiff_t pitch) 1016cabdff1aSopenharmony_ci{ 1017cabdff1aSopenharmony_ci uint8_t *dst = (uint8_t *)pdest; 1018cabdff1aSopenharmony_ci uint8_t *src = (uint8_t *)psrc; 1019cabdff1aSopenharmony_ci ptrdiff_t stride = pitch * 2; 1020cabdff1aSopenharmony_ci 1021cabdff1aSopenharmony_ci switch (block_size) { 1022cabdff1aSopenharmony_ci case 2: 1023cabdff1aSopenharmony_ci copy_block4(dst, src, stride, stride, 2); 1024cabdff1aSopenharmony_ci break; 1025cabdff1aSopenharmony_ci case 4: 1026cabdff1aSopenharmony_ci copy_block8(dst, src, stride, stride, 4); 1027cabdff1aSopenharmony_ci break; 1028cabdff1aSopenharmony_ci case 8: 1029cabdff1aSopenharmony_ci copy_block16(dst, src, stride, stride, 8); 1030cabdff1aSopenharmony_ci break; 1031cabdff1aSopenharmony_ci } 1032cabdff1aSopenharmony_ci} 1033cabdff1aSopenharmony_ci 1034cabdff1aSopenharmony_cistatic void fill_block(uint16_t *pdest, uint16_t color, int block_size, ptrdiff_t pitch) 1035cabdff1aSopenharmony_ci{ 1036cabdff1aSopenharmony_ci int x, y; 1037cabdff1aSopenharmony_ci 1038cabdff1aSopenharmony_ci pitch -= block_size; 1039cabdff1aSopenharmony_ci for (y = 0; y < block_size; y++, pdest += pitch) 1040cabdff1aSopenharmony_ci for (x = 0; x < block_size; x++) 1041cabdff1aSopenharmony_ci *pdest++ = color; 1042cabdff1aSopenharmony_ci} 1043cabdff1aSopenharmony_ci 1044cabdff1aSopenharmony_cistatic int draw_glyph(SANMVideoContext *ctx, uint16_t *dst, int index, 1045cabdff1aSopenharmony_ci uint16_t fg_color, uint16_t bg_color, int block_size, 1046cabdff1aSopenharmony_ci ptrdiff_t pitch) 1047cabdff1aSopenharmony_ci{ 1048cabdff1aSopenharmony_ci int8_t *pglyph; 1049cabdff1aSopenharmony_ci uint16_t colors[2] = { fg_color, bg_color }; 1050cabdff1aSopenharmony_ci int x, y; 1051cabdff1aSopenharmony_ci 1052cabdff1aSopenharmony_ci if (index >= NGLYPHS) { 1053cabdff1aSopenharmony_ci av_log(ctx->avctx, AV_LOG_ERROR, "Ignoring nonexistent glyph #%u.\n", index); 1054cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1055cabdff1aSopenharmony_ci } 1056cabdff1aSopenharmony_ci 1057cabdff1aSopenharmony_ci pglyph = block_size == 8 ? ctx->p8x8glyphs[index] : ctx->p4x4glyphs[index]; 1058cabdff1aSopenharmony_ci pitch -= block_size; 1059cabdff1aSopenharmony_ci 1060cabdff1aSopenharmony_ci for (y = 0; y < block_size; y++, dst += pitch) 1061cabdff1aSopenharmony_ci for (x = 0; x < block_size; x++) 1062cabdff1aSopenharmony_ci *dst++ = colors[*pglyph++]; 1063cabdff1aSopenharmony_ci return 0; 1064cabdff1aSopenharmony_ci} 1065cabdff1aSopenharmony_ci 1066cabdff1aSopenharmony_cistatic int opcode_0xf7(SANMVideoContext *ctx, int cx, int cy, int block_size, ptrdiff_t pitch) 1067cabdff1aSopenharmony_ci{ 1068cabdff1aSopenharmony_ci uint16_t *dst = ctx->frm0 + cx + cy * ctx->pitch; 1069cabdff1aSopenharmony_ci 1070cabdff1aSopenharmony_ci if (block_size == 2) { 1071cabdff1aSopenharmony_ci uint32_t indices; 1072cabdff1aSopenharmony_ci 1073cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&ctx->gb) < 4) 1074cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1075cabdff1aSopenharmony_ci 1076cabdff1aSopenharmony_ci indices = bytestream2_get_le32u(&ctx->gb); 1077cabdff1aSopenharmony_ci dst[0] = ctx->codebook[indices & 0xFF]; 1078cabdff1aSopenharmony_ci indices >>= 8; 1079cabdff1aSopenharmony_ci dst[1] = ctx->codebook[indices & 0xFF]; 1080cabdff1aSopenharmony_ci indices >>= 8; 1081cabdff1aSopenharmony_ci dst[pitch] = ctx->codebook[indices & 0xFF]; 1082cabdff1aSopenharmony_ci indices >>= 8; 1083cabdff1aSopenharmony_ci dst[pitch + 1] = ctx->codebook[indices & 0xFF]; 1084cabdff1aSopenharmony_ci } else { 1085cabdff1aSopenharmony_ci uint16_t fgcolor, bgcolor; 1086cabdff1aSopenharmony_ci int glyph; 1087cabdff1aSopenharmony_ci 1088cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&ctx->gb) < 3) 1089cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1090cabdff1aSopenharmony_ci 1091cabdff1aSopenharmony_ci glyph = bytestream2_get_byteu(&ctx->gb); 1092cabdff1aSopenharmony_ci bgcolor = ctx->codebook[bytestream2_get_byteu(&ctx->gb)]; 1093cabdff1aSopenharmony_ci fgcolor = ctx->codebook[bytestream2_get_byteu(&ctx->gb)]; 1094cabdff1aSopenharmony_ci 1095cabdff1aSopenharmony_ci draw_glyph(ctx, dst, glyph, fgcolor, bgcolor, block_size, pitch); 1096cabdff1aSopenharmony_ci } 1097cabdff1aSopenharmony_ci return 0; 1098cabdff1aSopenharmony_ci} 1099cabdff1aSopenharmony_ci 1100cabdff1aSopenharmony_cistatic int opcode_0xf8(SANMVideoContext *ctx, int cx, int cy, int block_size, ptrdiff_t pitch) 1101cabdff1aSopenharmony_ci{ 1102cabdff1aSopenharmony_ci uint16_t *dst = ctx->frm0 + cx + cy * ctx->pitch; 1103cabdff1aSopenharmony_ci 1104cabdff1aSopenharmony_ci if (block_size == 2) { 1105cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&ctx->gb) < 8) 1106cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1107cabdff1aSopenharmony_ci 1108cabdff1aSopenharmony_ci dst[0] = bytestream2_get_le16u(&ctx->gb); 1109cabdff1aSopenharmony_ci dst[1] = bytestream2_get_le16u(&ctx->gb); 1110cabdff1aSopenharmony_ci dst[pitch] = bytestream2_get_le16u(&ctx->gb); 1111cabdff1aSopenharmony_ci dst[pitch + 1] = bytestream2_get_le16u(&ctx->gb); 1112cabdff1aSopenharmony_ci } else { 1113cabdff1aSopenharmony_ci uint16_t fgcolor, bgcolor; 1114cabdff1aSopenharmony_ci int glyph; 1115cabdff1aSopenharmony_ci 1116cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&ctx->gb) < 5) 1117cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1118cabdff1aSopenharmony_ci 1119cabdff1aSopenharmony_ci glyph = bytestream2_get_byteu(&ctx->gb); 1120cabdff1aSopenharmony_ci bgcolor = bytestream2_get_le16u(&ctx->gb); 1121cabdff1aSopenharmony_ci fgcolor = bytestream2_get_le16u(&ctx->gb); 1122cabdff1aSopenharmony_ci 1123cabdff1aSopenharmony_ci draw_glyph(ctx, dst, glyph, fgcolor, bgcolor, block_size, pitch); 1124cabdff1aSopenharmony_ci } 1125cabdff1aSopenharmony_ci return 0; 1126cabdff1aSopenharmony_ci} 1127cabdff1aSopenharmony_ci 1128cabdff1aSopenharmony_cistatic int good_mvec(SANMVideoContext *ctx, int cx, int cy, int mx, int my, 1129cabdff1aSopenharmony_ci int block_size) 1130cabdff1aSopenharmony_ci{ 1131cabdff1aSopenharmony_ci int start_pos = cx + mx + (cy + my) * ctx->pitch; 1132cabdff1aSopenharmony_ci int end_pos = start_pos + (block_size - 1) * (ctx->pitch + 1); 1133cabdff1aSopenharmony_ci 1134cabdff1aSopenharmony_ci int good = start_pos >= 0 && end_pos < (ctx->buf_size >> 1); 1135cabdff1aSopenharmony_ci 1136cabdff1aSopenharmony_ci if (!good) 1137cabdff1aSopenharmony_ci av_log(ctx->avctx, AV_LOG_ERROR, 1138cabdff1aSopenharmony_ci "Ignoring invalid motion vector (%i, %i)->(%u, %u), block size = %u\n", 1139cabdff1aSopenharmony_ci cx + mx, cy + my, cx, cy, block_size); 1140cabdff1aSopenharmony_ci 1141cabdff1aSopenharmony_ci return good; 1142cabdff1aSopenharmony_ci} 1143cabdff1aSopenharmony_ci 1144cabdff1aSopenharmony_cistatic int codec2subblock(SANMVideoContext *ctx, int cx, int cy, int blk_size) 1145cabdff1aSopenharmony_ci{ 1146cabdff1aSopenharmony_ci int16_t mx, my, index; 1147cabdff1aSopenharmony_ci int opcode; 1148cabdff1aSopenharmony_ci 1149cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&ctx->gb) < 1) 1150cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1151cabdff1aSopenharmony_ci 1152cabdff1aSopenharmony_ci opcode = bytestream2_get_byteu(&ctx->gb); 1153cabdff1aSopenharmony_ci 1154cabdff1aSopenharmony_ci switch (opcode) { 1155cabdff1aSopenharmony_ci default: 1156cabdff1aSopenharmony_ci mx = motion_vectors[opcode][0]; 1157cabdff1aSopenharmony_ci my = motion_vectors[opcode][1]; 1158cabdff1aSopenharmony_ci 1159cabdff1aSopenharmony_ci if (good_mvec(ctx, cx, cy, mx, my, blk_size)) { 1160cabdff1aSopenharmony_ci copy_block(ctx->frm0 + cx + ctx->pitch * cy, 1161cabdff1aSopenharmony_ci ctx->frm2 + cx + mx + ctx->pitch * (cy + my), 1162cabdff1aSopenharmony_ci blk_size, ctx->pitch); 1163cabdff1aSopenharmony_ci } 1164cabdff1aSopenharmony_ci break; 1165cabdff1aSopenharmony_ci case 0xF5: 1166cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&ctx->gb) < 2) 1167cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1168cabdff1aSopenharmony_ci index = bytestream2_get_le16u(&ctx->gb); 1169cabdff1aSopenharmony_ci 1170cabdff1aSopenharmony_ci mx = index % ctx->width; 1171cabdff1aSopenharmony_ci my = index / ctx->width; 1172cabdff1aSopenharmony_ci 1173cabdff1aSopenharmony_ci if (good_mvec(ctx, cx, cy, mx, my, blk_size)) { 1174cabdff1aSopenharmony_ci copy_block(ctx->frm0 + cx + ctx->pitch * cy, 1175cabdff1aSopenharmony_ci ctx->frm2 + cx + mx + ctx->pitch * (cy + my), 1176cabdff1aSopenharmony_ci blk_size, ctx->pitch); 1177cabdff1aSopenharmony_ci } 1178cabdff1aSopenharmony_ci break; 1179cabdff1aSopenharmony_ci case 0xF6: 1180cabdff1aSopenharmony_ci copy_block(ctx->frm0 + cx + ctx->pitch * cy, 1181cabdff1aSopenharmony_ci ctx->frm1 + cx + ctx->pitch * cy, 1182cabdff1aSopenharmony_ci blk_size, ctx->pitch); 1183cabdff1aSopenharmony_ci break; 1184cabdff1aSopenharmony_ci case 0xF7: 1185cabdff1aSopenharmony_ci opcode_0xf7(ctx, cx, cy, blk_size, ctx->pitch); 1186cabdff1aSopenharmony_ci break; 1187cabdff1aSopenharmony_ci 1188cabdff1aSopenharmony_ci case 0xF8: 1189cabdff1aSopenharmony_ci opcode_0xf8(ctx, cx, cy, blk_size, ctx->pitch); 1190cabdff1aSopenharmony_ci break; 1191cabdff1aSopenharmony_ci case 0xF9: 1192cabdff1aSopenharmony_ci case 0xFA: 1193cabdff1aSopenharmony_ci case 0xFB: 1194cabdff1aSopenharmony_ci case 0xFC: 1195cabdff1aSopenharmony_ci fill_block(ctx->frm0 + cx + cy * ctx->pitch, 1196cabdff1aSopenharmony_ci ctx->small_codebook[opcode - 0xf9], blk_size, ctx->pitch); 1197cabdff1aSopenharmony_ci break; 1198cabdff1aSopenharmony_ci case 0xFD: 1199cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&ctx->gb) < 1) 1200cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1201cabdff1aSopenharmony_ci fill_block(ctx->frm0 + cx + cy * ctx->pitch, 1202cabdff1aSopenharmony_ci ctx->codebook[bytestream2_get_byteu(&ctx->gb)], blk_size, ctx->pitch); 1203cabdff1aSopenharmony_ci break; 1204cabdff1aSopenharmony_ci case 0xFE: 1205cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&ctx->gb) < 2) 1206cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1207cabdff1aSopenharmony_ci fill_block(ctx->frm0 + cx + cy * ctx->pitch, 1208cabdff1aSopenharmony_ci bytestream2_get_le16u(&ctx->gb), blk_size, ctx->pitch); 1209cabdff1aSopenharmony_ci break; 1210cabdff1aSopenharmony_ci case 0xFF: 1211cabdff1aSopenharmony_ci if (blk_size == 2) { 1212cabdff1aSopenharmony_ci opcode_0xf8(ctx, cx, cy, blk_size, ctx->pitch); 1213cabdff1aSopenharmony_ci } else { 1214cabdff1aSopenharmony_ci blk_size >>= 1; 1215cabdff1aSopenharmony_ci if (codec2subblock(ctx, cx, cy, blk_size)) 1216cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1217cabdff1aSopenharmony_ci if (codec2subblock(ctx, cx + blk_size, cy, blk_size)) 1218cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1219cabdff1aSopenharmony_ci if (codec2subblock(ctx, cx, cy + blk_size, blk_size)) 1220cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1221cabdff1aSopenharmony_ci if (codec2subblock(ctx, cx + blk_size, cy + blk_size, blk_size)) 1222cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1223cabdff1aSopenharmony_ci } 1224cabdff1aSopenharmony_ci break; 1225cabdff1aSopenharmony_ci } 1226cabdff1aSopenharmony_ci return 0; 1227cabdff1aSopenharmony_ci} 1228cabdff1aSopenharmony_ci 1229cabdff1aSopenharmony_cistatic int decode_2(SANMVideoContext *ctx) 1230cabdff1aSopenharmony_ci{ 1231cabdff1aSopenharmony_ci int cx, cy, ret; 1232cabdff1aSopenharmony_ci 1233cabdff1aSopenharmony_ci for (cy = 0; cy < ctx->aligned_height; cy += 8) 1234cabdff1aSopenharmony_ci for (cx = 0; cx < ctx->aligned_width; cx += 8) 1235cabdff1aSopenharmony_ci if (ret = codec2subblock(ctx, cx, cy, 8)) 1236cabdff1aSopenharmony_ci return ret; 1237cabdff1aSopenharmony_ci 1238cabdff1aSopenharmony_ci return 0; 1239cabdff1aSopenharmony_ci} 1240cabdff1aSopenharmony_ci 1241cabdff1aSopenharmony_cistatic int decode_3(SANMVideoContext *ctx) 1242cabdff1aSopenharmony_ci{ 1243cabdff1aSopenharmony_ci memcpy(ctx->frm0, ctx->frm2, ctx->frm2_size); 1244cabdff1aSopenharmony_ci return 0; 1245cabdff1aSopenharmony_ci} 1246cabdff1aSopenharmony_ci 1247cabdff1aSopenharmony_cistatic int decode_4(SANMVideoContext *ctx) 1248cabdff1aSopenharmony_ci{ 1249cabdff1aSopenharmony_ci memcpy(ctx->frm0, ctx->frm1, ctx->frm1_size); 1250cabdff1aSopenharmony_ci return 0; 1251cabdff1aSopenharmony_ci} 1252cabdff1aSopenharmony_ci 1253cabdff1aSopenharmony_cistatic int decode_5(SANMVideoContext *ctx) 1254cabdff1aSopenharmony_ci{ 1255cabdff1aSopenharmony_ci#if HAVE_BIGENDIAN 1256cabdff1aSopenharmony_ci uint16_t *frm; 1257cabdff1aSopenharmony_ci int npixels; 1258cabdff1aSopenharmony_ci#endif 1259cabdff1aSopenharmony_ci uint8_t *dst = (uint8_t*)ctx->frm0; 1260cabdff1aSopenharmony_ci 1261cabdff1aSopenharmony_ci if (rle_decode(ctx, dst, ctx->buf_size)) 1262cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1263cabdff1aSopenharmony_ci 1264cabdff1aSopenharmony_ci#if HAVE_BIGENDIAN 1265cabdff1aSopenharmony_ci npixels = ctx->npixels; 1266cabdff1aSopenharmony_ci frm = ctx->frm0; 1267cabdff1aSopenharmony_ci while (npixels--) { 1268cabdff1aSopenharmony_ci *frm = av_bswap16(*frm); 1269cabdff1aSopenharmony_ci frm++; 1270cabdff1aSopenharmony_ci } 1271cabdff1aSopenharmony_ci#endif 1272cabdff1aSopenharmony_ci 1273cabdff1aSopenharmony_ci return 0; 1274cabdff1aSopenharmony_ci} 1275cabdff1aSopenharmony_ci 1276cabdff1aSopenharmony_cistatic int decode_6(SANMVideoContext *ctx) 1277cabdff1aSopenharmony_ci{ 1278cabdff1aSopenharmony_ci int npixels = ctx->npixels; 1279cabdff1aSopenharmony_ci uint16_t *frm = ctx->frm0; 1280cabdff1aSopenharmony_ci 1281cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&ctx->gb) < npixels) { 1282cabdff1aSopenharmony_ci av_log(ctx->avctx, AV_LOG_ERROR, "Insufficient data for frame.\n"); 1283cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1284cabdff1aSopenharmony_ci } 1285cabdff1aSopenharmony_ci while (npixels--) 1286cabdff1aSopenharmony_ci *frm++ = ctx->codebook[bytestream2_get_byteu(&ctx->gb)]; 1287cabdff1aSopenharmony_ci 1288cabdff1aSopenharmony_ci return 0; 1289cabdff1aSopenharmony_ci} 1290cabdff1aSopenharmony_ci 1291cabdff1aSopenharmony_cistatic int decode_8(SANMVideoContext *ctx) 1292cabdff1aSopenharmony_ci{ 1293cabdff1aSopenharmony_ci uint16_t *pdest = ctx->frm0; 1294cabdff1aSopenharmony_ci uint8_t *rsrc; 1295cabdff1aSopenharmony_ci long npixels = ctx->npixels; 1296cabdff1aSopenharmony_ci 1297cabdff1aSopenharmony_ci av_fast_malloc(&ctx->rle_buf, &ctx->rle_buf_size, npixels); 1298cabdff1aSopenharmony_ci if (!ctx->rle_buf) { 1299cabdff1aSopenharmony_ci av_log(ctx->avctx, AV_LOG_ERROR, "RLE buffer allocation failed.\n"); 1300cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 1301cabdff1aSopenharmony_ci } 1302cabdff1aSopenharmony_ci rsrc = ctx->rle_buf; 1303cabdff1aSopenharmony_ci 1304cabdff1aSopenharmony_ci if (rle_decode(ctx, rsrc, npixels)) 1305cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1306cabdff1aSopenharmony_ci 1307cabdff1aSopenharmony_ci while (npixels--) 1308cabdff1aSopenharmony_ci *pdest++ = ctx->codebook[*rsrc++]; 1309cabdff1aSopenharmony_ci 1310cabdff1aSopenharmony_ci return 0; 1311cabdff1aSopenharmony_ci} 1312cabdff1aSopenharmony_ci 1313cabdff1aSopenharmony_citypedef int (*frm_decoder)(SANMVideoContext *ctx); 1314cabdff1aSopenharmony_ci 1315cabdff1aSopenharmony_cistatic const frm_decoder v1_decoders[] = { 1316cabdff1aSopenharmony_ci decode_0, decode_nop, decode_2, decode_3, decode_4, decode_5, 1317cabdff1aSopenharmony_ci decode_6, decode_nop, decode_8 1318cabdff1aSopenharmony_ci}; 1319cabdff1aSopenharmony_ci 1320cabdff1aSopenharmony_cistatic int read_frame_header(SANMVideoContext *ctx, SANMFrameHeader *hdr) 1321cabdff1aSopenharmony_ci{ 1322cabdff1aSopenharmony_ci int i, ret; 1323cabdff1aSopenharmony_ci 1324cabdff1aSopenharmony_ci if ((ret = bytestream2_get_bytes_left(&ctx->gb)) < 560) { 1325cabdff1aSopenharmony_ci av_log(ctx->avctx, AV_LOG_ERROR, "Input frame too short (%d bytes).\n", 1326cabdff1aSopenharmony_ci ret); 1327cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1328cabdff1aSopenharmony_ci } 1329cabdff1aSopenharmony_ci bytestream2_skip(&ctx->gb, 8); // skip pad 1330cabdff1aSopenharmony_ci 1331cabdff1aSopenharmony_ci hdr->width = bytestream2_get_le32u(&ctx->gb); 1332cabdff1aSopenharmony_ci hdr->height = bytestream2_get_le32u(&ctx->gb); 1333cabdff1aSopenharmony_ci 1334cabdff1aSopenharmony_ci if (hdr->width != ctx->width || hdr->height != ctx->height) { 1335cabdff1aSopenharmony_ci avpriv_report_missing_feature(ctx->avctx, "Variable size frames"); 1336cabdff1aSopenharmony_ci return AVERROR_PATCHWELCOME; 1337cabdff1aSopenharmony_ci } 1338cabdff1aSopenharmony_ci 1339cabdff1aSopenharmony_ci hdr->seq_num = bytestream2_get_le16u(&ctx->gb); 1340cabdff1aSopenharmony_ci hdr->codec = bytestream2_get_byteu(&ctx->gb); 1341cabdff1aSopenharmony_ci hdr->rotate_code = bytestream2_get_byteu(&ctx->gb); 1342cabdff1aSopenharmony_ci 1343cabdff1aSopenharmony_ci bytestream2_skip(&ctx->gb, 4); // skip pad 1344cabdff1aSopenharmony_ci 1345cabdff1aSopenharmony_ci for (i = 0; i < 4; i++) 1346cabdff1aSopenharmony_ci ctx->small_codebook[i] = bytestream2_get_le16u(&ctx->gb); 1347cabdff1aSopenharmony_ci hdr->bg_color = bytestream2_get_le16u(&ctx->gb); 1348cabdff1aSopenharmony_ci 1349cabdff1aSopenharmony_ci bytestream2_skip(&ctx->gb, 2); // skip pad 1350cabdff1aSopenharmony_ci 1351cabdff1aSopenharmony_ci hdr->rle_output_size = bytestream2_get_le32u(&ctx->gb); 1352cabdff1aSopenharmony_ci for (i = 0; i < 256; i++) 1353cabdff1aSopenharmony_ci ctx->codebook[i] = bytestream2_get_le16u(&ctx->gb); 1354cabdff1aSopenharmony_ci 1355cabdff1aSopenharmony_ci bytestream2_skip(&ctx->gb, 8); // skip pad 1356cabdff1aSopenharmony_ci 1357cabdff1aSopenharmony_ci return 0; 1358cabdff1aSopenharmony_ci} 1359cabdff1aSopenharmony_ci 1360cabdff1aSopenharmony_cistatic void fill_frame(uint16_t *pbuf, int buf_size, uint16_t color) 1361cabdff1aSopenharmony_ci{ 1362cabdff1aSopenharmony_ci if (buf_size--) { 1363cabdff1aSopenharmony_ci *pbuf++ = color; 1364cabdff1aSopenharmony_ci av_memcpy_backptr((uint8_t*)pbuf, 2, 2*buf_size); 1365cabdff1aSopenharmony_ci } 1366cabdff1aSopenharmony_ci} 1367cabdff1aSopenharmony_ci 1368cabdff1aSopenharmony_cistatic int copy_output(SANMVideoContext *ctx, SANMFrameHeader *hdr) 1369cabdff1aSopenharmony_ci{ 1370cabdff1aSopenharmony_ci uint8_t *dst; 1371cabdff1aSopenharmony_ci const uint8_t *src = (uint8_t*) ctx->frm0; 1372cabdff1aSopenharmony_ci int ret, height = ctx->height; 1373cabdff1aSopenharmony_ci ptrdiff_t dstpitch, srcpitch = ctx->pitch * (hdr ? sizeof(ctx->frm0[0]) : 1); 1374cabdff1aSopenharmony_ci 1375cabdff1aSopenharmony_ci if ((ret = ff_get_buffer(ctx->avctx, ctx->frame, 0)) < 0) 1376cabdff1aSopenharmony_ci return ret; 1377cabdff1aSopenharmony_ci 1378cabdff1aSopenharmony_ci dst = ctx->frame->data[0]; 1379cabdff1aSopenharmony_ci dstpitch = ctx->frame->linesize[0]; 1380cabdff1aSopenharmony_ci 1381cabdff1aSopenharmony_ci while (height--) { 1382cabdff1aSopenharmony_ci memcpy(dst, src, srcpitch); 1383cabdff1aSopenharmony_ci src += srcpitch; 1384cabdff1aSopenharmony_ci dst += dstpitch; 1385cabdff1aSopenharmony_ci } 1386cabdff1aSopenharmony_ci 1387cabdff1aSopenharmony_ci return 0; 1388cabdff1aSopenharmony_ci} 1389cabdff1aSopenharmony_ci 1390cabdff1aSopenharmony_cistatic int decode_frame(AVCodecContext *avctx, AVFrame *frame, 1391cabdff1aSopenharmony_ci int *got_frame_ptr, AVPacket *pkt) 1392cabdff1aSopenharmony_ci{ 1393cabdff1aSopenharmony_ci SANMVideoContext *ctx = avctx->priv_data; 1394cabdff1aSopenharmony_ci int i, ret; 1395cabdff1aSopenharmony_ci 1396cabdff1aSopenharmony_ci ctx->frame = frame; 1397cabdff1aSopenharmony_ci bytestream2_init(&ctx->gb, pkt->data, pkt->size); 1398cabdff1aSopenharmony_ci 1399cabdff1aSopenharmony_ci if (!ctx->version) { 1400cabdff1aSopenharmony_ci int to_store = 0; 1401cabdff1aSopenharmony_ci 1402cabdff1aSopenharmony_ci while (bytestream2_get_bytes_left(&ctx->gb) >= 8) { 1403cabdff1aSopenharmony_ci uint32_t sig, size; 1404cabdff1aSopenharmony_ci int pos; 1405cabdff1aSopenharmony_ci 1406cabdff1aSopenharmony_ci sig = bytestream2_get_be32u(&ctx->gb); 1407cabdff1aSopenharmony_ci size = bytestream2_get_be32u(&ctx->gb); 1408cabdff1aSopenharmony_ci pos = bytestream2_tell(&ctx->gb); 1409cabdff1aSopenharmony_ci 1410cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&ctx->gb) < size) { 1411cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Incorrect chunk size %"PRIu32".\n", size); 1412cabdff1aSopenharmony_ci break; 1413cabdff1aSopenharmony_ci } 1414cabdff1aSopenharmony_ci switch (sig) { 1415cabdff1aSopenharmony_ci case MKBETAG('N', 'P', 'A', 'L'): 1416cabdff1aSopenharmony_ci if (size != PALETTE_SIZE * 3) { 1417cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, 1418cabdff1aSopenharmony_ci "Incorrect palette block size %"PRIu32".\n", size); 1419cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1420cabdff1aSopenharmony_ci } 1421cabdff1aSopenharmony_ci for (i = 0; i < PALETTE_SIZE; i++) 1422cabdff1aSopenharmony_ci ctx->pal[i] = 0xFFU << 24 | bytestream2_get_be24u(&ctx->gb); 1423cabdff1aSopenharmony_ci break; 1424cabdff1aSopenharmony_ci case MKBETAG('F', 'O', 'B', 'J'): 1425cabdff1aSopenharmony_ci if (size < 16) 1426cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1427cabdff1aSopenharmony_ci if (ret = process_frame_obj(ctx)) 1428cabdff1aSopenharmony_ci return ret; 1429cabdff1aSopenharmony_ci break; 1430cabdff1aSopenharmony_ci case MKBETAG('X', 'P', 'A', 'L'): 1431cabdff1aSopenharmony_ci if (size == 6 || size == 4) { 1432cabdff1aSopenharmony_ci uint8_t tmp[3]; 1433cabdff1aSopenharmony_ci int j; 1434cabdff1aSopenharmony_ci 1435cabdff1aSopenharmony_ci for (i = 0; i < PALETTE_SIZE; i++) { 1436cabdff1aSopenharmony_ci for (j = 0; j < 3; j++) { 1437cabdff1aSopenharmony_ci int t = (ctx->pal[i] >> (16 - j * 8)) & 0xFF; 1438cabdff1aSopenharmony_ci tmp[j] = av_clip_uint8((t * 129 + ctx->delta_pal[i * 3 + j]) >> 7); 1439cabdff1aSopenharmony_ci } 1440cabdff1aSopenharmony_ci ctx->pal[i] = 0xFFU << 24 | AV_RB24(tmp); 1441cabdff1aSopenharmony_ci } 1442cabdff1aSopenharmony_ci } else { 1443cabdff1aSopenharmony_ci if (size < PALETTE_DELTA * 2 + 4) { 1444cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, 1445cabdff1aSopenharmony_ci "Incorrect palette change block size %"PRIu32".\n", 1446cabdff1aSopenharmony_ci size); 1447cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1448cabdff1aSopenharmony_ci } 1449cabdff1aSopenharmony_ci bytestream2_skipu(&ctx->gb, 4); 1450cabdff1aSopenharmony_ci for (i = 0; i < PALETTE_DELTA; i++) 1451cabdff1aSopenharmony_ci ctx->delta_pal[i] = bytestream2_get_le16u(&ctx->gb); 1452cabdff1aSopenharmony_ci if (size >= PALETTE_DELTA * 5 + 4) { 1453cabdff1aSopenharmony_ci for (i = 0; i < PALETTE_SIZE; i++) 1454cabdff1aSopenharmony_ci ctx->pal[i] = 0xFFU << 24 | bytestream2_get_be24u(&ctx->gb); 1455cabdff1aSopenharmony_ci } else { 1456cabdff1aSopenharmony_ci memset(ctx->pal, 0, sizeof(ctx->pal)); 1457cabdff1aSopenharmony_ci } 1458cabdff1aSopenharmony_ci } 1459cabdff1aSopenharmony_ci break; 1460cabdff1aSopenharmony_ci case MKBETAG('S', 'T', 'O', 'R'): 1461cabdff1aSopenharmony_ci to_store = 1; 1462cabdff1aSopenharmony_ci break; 1463cabdff1aSopenharmony_ci case MKBETAG('F', 'T', 'C', 'H'): 1464cabdff1aSopenharmony_ci memcpy(ctx->frm0, ctx->stored_frame, ctx->buf_size); 1465cabdff1aSopenharmony_ci break; 1466cabdff1aSopenharmony_ci default: 1467cabdff1aSopenharmony_ci bytestream2_skip(&ctx->gb, size); 1468cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_DEBUG, 1469cabdff1aSopenharmony_ci "Unknown/unsupported chunk %"PRIx32".\n", sig); 1470cabdff1aSopenharmony_ci break; 1471cabdff1aSopenharmony_ci } 1472cabdff1aSopenharmony_ci 1473cabdff1aSopenharmony_ci bytestream2_seek(&ctx->gb, pos + size, SEEK_SET); 1474cabdff1aSopenharmony_ci if (size & 1) 1475cabdff1aSopenharmony_ci bytestream2_skip(&ctx->gb, 1); 1476cabdff1aSopenharmony_ci } 1477cabdff1aSopenharmony_ci if (to_store) 1478cabdff1aSopenharmony_ci memcpy(ctx->stored_frame, ctx->frm0, ctx->buf_size); 1479cabdff1aSopenharmony_ci if ((ret = copy_output(ctx, NULL))) 1480cabdff1aSopenharmony_ci return ret; 1481cabdff1aSopenharmony_ci memcpy(ctx->frame->data[1], ctx->pal, 1024); 1482cabdff1aSopenharmony_ci } else { 1483cabdff1aSopenharmony_ci SANMFrameHeader header; 1484cabdff1aSopenharmony_ci 1485cabdff1aSopenharmony_ci if ((ret = read_frame_header(ctx, &header))) 1486cabdff1aSopenharmony_ci return ret; 1487cabdff1aSopenharmony_ci 1488cabdff1aSopenharmony_ci ctx->rotate_code = header.rotate_code; 1489cabdff1aSopenharmony_ci if ((ctx->frame->key_frame = !header.seq_num)) { 1490cabdff1aSopenharmony_ci ctx->frame->pict_type = AV_PICTURE_TYPE_I; 1491cabdff1aSopenharmony_ci fill_frame(ctx->frm1, ctx->npixels, header.bg_color); 1492cabdff1aSopenharmony_ci fill_frame(ctx->frm2, ctx->npixels, header.bg_color); 1493cabdff1aSopenharmony_ci } else { 1494cabdff1aSopenharmony_ci ctx->frame->pict_type = AV_PICTURE_TYPE_P; 1495cabdff1aSopenharmony_ci } 1496cabdff1aSopenharmony_ci 1497cabdff1aSopenharmony_ci if (header.codec < FF_ARRAY_ELEMS(v1_decoders)) { 1498cabdff1aSopenharmony_ci if ((ret = v1_decoders[header.codec](ctx))) { 1499cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, 1500cabdff1aSopenharmony_ci "Subcodec %d: error decoding frame.\n", header.codec); 1501cabdff1aSopenharmony_ci return ret; 1502cabdff1aSopenharmony_ci } 1503cabdff1aSopenharmony_ci } else { 1504cabdff1aSopenharmony_ci avpriv_request_sample(avctx, "Subcodec %d", header.codec); 1505cabdff1aSopenharmony_ci return AVERROR_PATCHWELCOME; 1506cabdff1aSopenharmony_ci } 1507cabdff1aSopenharmony_ci 1508cabdff1aSopenharmony_ci if ((ret = copy_output(ctx, &header))) 1509cabdff1aSopenharmony_ci return ret; 1510cabdff1aSopenharmony_ci } 1511cabdff1aSopenharmony_ci if (ctx->rotate_code) 1512cabdff1aSopenharmony_ci rotate_bufs(ctx, ctx->rotate_code); 1513cabdff1aSopenharmony_ci 1514cabdff1aSopenharmony_ci *got_frame_ptr = 1; 1515cabdff1aSopenharmony_ci 1516cabdff1aSopenharmony_ci return pkt->size; 1517cabdff1aSopenharmony_ci} 1518cabdff1aSopenharmony_ci 1519cabdff1aSopenharmony_ciconst FFCodec ff_sanm_decoder = { 1520cabdff1aSopenharmony_ci .p.name = "sanm", 1521cabdff1aSopenharmony_ci .p.long_name = NULL_IF_CONFIG_SMALL("LucasArts SANM/Smush video"), 1522cabdff1aSopenharmony_ci .p.type = AVMEDIA_TYPE_VIDEO, 1523cabdff1aSopenharmony_ci .p.id = AV_CODEC_ID_SANM, 1524cabdff1aSopenharmony_ci .priv_data_size = sizeof(SANMVideoContext), 1525cabdff1aSopenharmony_ci .init = decode_init, 1526cabdff1aSopenharmony_ci .close = decode_end, 1527cabdff1aSopenharmony_ci FF_CODEC_DECODE_CB(decode_frame), 1528cabdff1aSopenharmony_ci .p.capabilities = AV_CODEC_CAP_DR1, 1529cabdff1aSopenharmony_ci .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, 1530cabdff1aSopenharmony_ci}; 1531