1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * FM Screen Capture Codec decoder 3cabdff1aSopenharmony_ci * 4cabdff1aSopenharmony_ci * Copyright (c) 2017 Paul B Mahol 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 <stdio.h> 24cabdff1aSopenharmony_ci#include <stdlib.h> 25cabdff1aSopenharmony_ci#include <string.h> 26cabdff1aSopenharmony_ci 27cabdff1aSopenharmony_ci#include "avcodec.h" 28cabdff1aSopenharmony_ci#include "bytestream.h" 29cabdff1aSopenharmony_ci#include "codec_internal.h" 30cabdff1aSopenharmony_ci#include "internal.h" 31cabdff1aSopenharmony_ci 32cabdff1aSopenharmony_ci#define BLOCK_HEIGHT 112u 33cabdff1aSopenharmony_ci#define BLOCK_WIDTH 84u 34cabdff1aSopenharmony_ci 35cabdff1aSopenharmony_citypedef struct InterBlock { 36cabdff1aSopenharmony_ci int w, h; 37cabdff1aSopenharmony_ci int size; 38cabdff1aSopenharmony_ci int xor; 39cabdff1aSopenharmony_ci} InterBlock; 40cabdff1aSopenharmony_ci 41cabdff1aSopenharmony_citypedef struct FMVCContext { 42cabdff1aSopenharmony_ci GetByteContext gb; 43cabdff1aSopenharmony_ci PutByteContext pb; 44cabdff1aSopenharmony_ci uint8_t *buffer; 45cabdff1aSopenharmony_ci size_t buffer_size; 46cabdff1aSopenharmony_ci uint8_t *pbuffer; 47cabdff1aSopenharmony_ci size_t pbuffer_size; 48cabdff1aSopenharmony_ci ptrdiff_t stride; 49cabdff1aSopenharmony_ci int bpp; 50cabdff1aSopenharmony_ci int yb, xb; 51cabdff1aSopenharmony_ci InterBlock *blocks; 52cabdff1aSopenharmony_ci unsigned nb_blocks; 53cabdff1aSopenharmony_ci} FMVCContext; 54cabdff1aSopenharmony_ci 55cabdff1aSopenharmony_cistatic int decode_type2(GetByteContext *gb, PutByteContext *pb) 56cabdff1aSopenharmony_ci{ 57cabdff1aSopenharmony_ci unsigned repeat = 0, first = 1, opcode = 0; 58cabdff1aSopenharmony_ci int i, len, pos; 59cabdff1aSopenharmony_ci 60cabdff1aSopenharmony_ci while (bytestream2_get_bytes_left(gb) > 0) { 61cabdff1aSopenharmony_ci GetByteContext gbc; 62cabdff1aSopenharmony_ci 63cabdff1aSopenharmony_ci while (bytestream2_get_bytes_left(gb) > 0) { 64cabdff1aSopenharmony_ci if (first) { 65cabdff1aSopenharmony_ci first = 0; 66cabdff1aSopenharmony_ci if (bytestream2_peek_byte(gb) > 17) { 67cabdff1aSopenharmony_ci len = bytestream2_get_byte(gb) - 17; 68cabdff1aSopenharmony_ci if (len < 4) { 69cabdff1aSopenharmony_ci do { 70cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(gb)); 71cabdff1aSopenharmony_ci --len; 72cabdff1aSopenharmony_ci } while (len); 73cabdff1aSopenharmony_ci opcode = bytestream2_peek_byte(gb); 74cabdff1aSopenharmony_ci continue; 75cabdff1aSopenharmony_ci } else { 76cabdff1aSopenharmony_ci do { 77cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(gb)); 78cabdff1aSopenharmony_ci --len; 79cabdff1aSopenharmony_ci } while (len); 80cabdff1aSopenharmony_ci opcode = bytestream2_peek_byte(gb); 81cabdff1aSopenharmony_ci if (opcode < 0x10) { 82cabdff1aSopenharmony_ci bytestream2_skip(gb, 1); 83cabdff1aSopenharmony_ci pos = - (opcode >> 2) - 4 * bytestream2_get_byte(gb) - 2049; 84cabdff1aSopenharmony_ci 85cabdff1aSopenharmony_ci bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start); 86cabdff1aSopenharmony_ci bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET); 87cabdff1aSopenharmony_ci 88cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); 89cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); 90cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); 91cabdff1aSopenharmony_ci len = opcode & 3; 92cabdff1aSopenharmony_ci if (!len) { 93cabdff1aSopenharmony_ci repeat = 1; 94cabdff1aSopenharmony_ci } else { 95cabdff1aSopenharmony_ci do { 96cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(gb)); 97cabdff1aSopenharmony_ci --len; 98cabdff1aSopenharmony_ci } while (len); 99cabdff1aSopenharmony_ci opcode = bytestream2_peek_byte(gb); 100cabdff1aSopenharmony_ci } 101cabdff1aSopenharmony_ci continue; 102cabdff1aSopenharmony_ci } 103cabdff1aSopenharmony_ci } 104cabdff1aSopenharmony_ci repeat = 0; 105cabdff1aSopenharmony_ci } 106cabdff1aSopenharmony_ci repeat = 1; 107cabdff1aSopenharmony_ci } 108cabdff1aSopenharmony_ci if (repeat) { 109cabdff1aSopenharmony_ci repeat = 0; 110cabdff1aSopenharmony_ci opcode = bytestream2_peek_byte(gb); 111cabdff1aSopenharmony_ci if (opcode < 0x10) { 112cabdff1aSopenharmony_ci bytestream2_skip(gb, 1); 113cabdff1aSopenharmony_ci if (!opcode) { 114cabdff1aSopenharmony_ci if (!bytestream2_peek_byte(gb)) { 115cabdff1aSopenharmony_ci do { 116cabdff1aSopenharmony_ci bytestream2_skip(gb, 1); 117cabdff1aSopenharmony_ci opcode += 255; 118cabdff1aSopenharmony_ci } while (!bytestream2_peek_byte(gb) && bytestream2_get_bytes_left(gb) > 0); 119cabdff1aSopenharmony_ci } 120cabdff1aSopenharmony_ci opcode += bytestream2_get_byte(gb) + 15; 121cabdff1aSopenharmony_ci } 122cabdff1aSopenharmony_ci bytestream2_put_le32(pb, bytestream2_get_le32(gb)); 123cabdff1aSopenharmony_ci for (i = opcode - 1; i > 0; --i) 124cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(gb)); 125cabdff1aSopenharmony_ci opcode = bytestream2_peek_byte(gb); 126cabdff1aSopenharmony_ci if (opcode < 0x10) { 127cabdff1aSopenharmony_ci bytestream2_skip(gb, 1); 128cabdff1aSopenharmony_ci pos = - (opcode >> 2) - 4 * bytestream2_get_byte(gb) - 2049; 129cabdff1aSopenharmony_ci 130cabdff1aSopenharmony_ci bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start); 131cabdff1aSopenharmony_ci bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET); 132cabdff1aSopenharmony_ci 133cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); 134cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); 135cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); 136cabdff1aSopenharmony_ci len = opcode & 3; 137cabdff1aSopenharmony_ci if (!len) { 138cabdff1aSopenharmony_ci repeat = 1; 139cabdff1aSopenharmony_ci } else { 140cabdff1aSopenharmony_ci do { 141cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(gb)); 142cabdff1aSopenharmony_ci --len; 143cabdff1aSopenharmony_ci } while (len); 144cabdff1aSopenharmony_ci opcode = bytestream2_peek_byte(gb); 145cabdff1aSopenharmony_ci } 146cabdff1aSopenharmony_ci continue; 147cabdff1aSopenharmony_ci } 148cabdff1aSopenharmony_ci } 149cabdff1aSopenharmony_ci } 150cabdff1aSopenharmony_ci 151cabdff1aSopenharmony_ci if (opcode >= 0x40) { 152cabdff1aSopenharmony_ci bytestream2_skip(gb, 1); 153cabdff1aSopenharmony_ci pos = - ((opcode >> 2) & 7) - 1 - 8 * bytestream2_get_byte(gb); 154cabdff1aSopenharmony_ci len = (opcode >> 5) - 1; 155cabdff1aSopenharmony_ci 156cabdff1aSopenharmony_ci bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start); 157cabdff1aSopenharmony_ci bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET); 158cabdff1aSopenharmony_ci 159cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); 160cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); 161cabdff1aSopenharmony_ci do { 162cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); 163cabdff1aSopenharmony_ci --len; 164cabdff1aSopenharmony_ci } while (len); 165cabdff1aSopenharmony_ci 166cabdff1aSopenharmony_ci len = opcode & 3; 167cabdff1aSopenharmony_ci 168cabdff1aSopenharmony_ci if (!len) { 169cabdff1aSopenharmony_ci repeat = 1; 170cabdff1aSopenharmony_ci } else { 171cabdff1aSopenharmony_ci do { 172cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(gb)); 173cabdff1aSopenharmony_ci --len; 174cabdff1aSopenharmony_ci } while (len); 175cabdff1aSopenharmony_ci opcode = bytestream2_peek_byte(gb); 176cabdff1aSopenharmony_ci } 177cabdff1aSopenharmony_ci continue; 178cabdff1aSopenharmony_ci } else if (opcode < 0x20) { 179cabdff1aSopenharmony_ci break; 180cabdff1aSopenharmony_ci } 181cabdff1aSopenharmony_ci len = opcode & 0x1F; 182cabdff1aSopenharmony_ci bytestream2_skip(gb, 1); 183cabdff1aSopenharmony_ci if (!len) { 184cabdff1aSopenharmony_ci if (!bytestream2_peek_byte(gb)) { 185cabdff1aSopenharmony_ci do { 186cabdff1aSopenharmony_ci bytestream2_skip(gb, 1); 187cabdff1aSopenharmony_ci len += 255; 188cabdff1aSopenharmony_ci } while (!bytestream2_peek_byte(gb) && bytestream2_get_bytes_left(gb) > 0); 189cabdff1aSopenharmony_ci } 190cabdff1aSopenharmony_ci len += bytestream2_get_byte(gb) + 31; 191cabdff1aSopenharmony_ci } 192cabdff1aSopenharmony_ci i = bytestream2_get_le16(gb); 193cabdff1aSopenharmony_ci pos = - (i >> 2) - 1; 194cabdff1aSopenharmony_ci 195cabdff1aSopenharmony_ci bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start); 196cabdff1aSopenharmony_ci bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET); 197cabdff1aSopenharmony_ci 198cabdff1aSopenharmony_ci if (len < 6 || bytestream2_tell_p(pb) - bytestream2_tell(&gbc) < 4) { 199cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); 200cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); 201cabdff1aSopenharmony_ci do { 202cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); 203cabdff1aSopenharmony_ci --len; 204cabdff1aSopenharmony_ci } while (len); 205cabdff1aSopenharmony_ci } else { 206cabdff1aSopenharmony_ci bytestream2_put_le32(pb, bytestream2_get_le32(&gbc)); 207cabdff1aSopenharmony_ci for (len = len - 2; len; --len) 208cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); 209cabdff1aSopenharmony_ci } 210cabdff1aSopenharmony_ci len = i & 3; 211cabdff1aSopenharmony_ci if (!len) { 212cabdff1aSopenharmony_ci repeat = 1; 213cabdff1aSopenharmony_ci } else { 214cabdff1aSopenharmony_ci do { 215cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(gb)); 216cabdff1aSopenharmony_ci --len; 217cabdff1aSopenharmony_ci } while (len); 218cabdff1aSopenharmony_ci opcode = bytestream2_peek_byte(gb); 219cabdff1aSopenharmony_ci } 220cabdff1aSopenharmony_ci } 221cabdff1aSopenharmony_ci bytestream2_skip(gb, 1); 222cabdff1aSopenharmony_ci if (opcode < 0x10) { 223cabdff1aSopenharmony_ci pos = -(opcode >> 2) - 1 - 4 * bytestream2_get_byte(gb); 224cabdff1aSopenharmony_ci 225cabdff1aSopenharmony_ci bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start); 226cabdff1aSopenharmony_ci bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET); 227cabdff1aSopenharmony_ci 228cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); 229cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); 230cabdff1aSopenharmony_ci len = opcode & 3; 231cabdff1aSopenharmony_ci if (!len) { 232cabdff1aSopenharmony_ci repeat = 1; 233cabdff1aSopenharmony_ci } else { 234cabdff1aSopenharmony_ci do { 235cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(gb)); 236cabdff1aSopenharmony_ci --len; 237cabdff1aSopenharmony_ci } while (len); 238cabdff1aSopenharmony_ci opcode = bytestream2_peek_byte(gb); 239cabdff1aSopenharmony_ci } 240cabdff1aSopenharmony_ci continue; 241cabdff1aSopenharmony_ci } 242cabdff1aSopenharmony_ci len = opcode & 7; 243cabdff1aSopenharmony_ci if (!len) { 244cabdff1aSopenharmony_ci if (!bytestream2_peek_byte(gb)) { 245cabdff1aSopenharmony_ci do { 246cabdff1aSopenharmony_ci bytestream2_skip(gb, 1); 247cabdff1aSopenharmony_ci len += 255; 248cabdff1aSopenharmony_ci } while (!bytestream2_peek_byte(gb) && bytestream2_get_bytes_left(gb) > 0); 249cabdff1aSopenharmony_ci } 250cabdff1aSopenharmony_ci len += bytestream2_get_byte(gb) + 7; 251cabdff1aSopenharmony_ci } 252cabdff1aSopenharmony_ci i = bytestream2_get_le16(gb); 253cabdff1aSopenharmony_ci pos = bytestream2_tell_p(pb) - 2048 * (opcode & 8); 254cabdff1aSopenharmony_ci pos = pos - (i >> 2); 255cabdff1aSopenharmony_ci if (pos == bytestream2_tell_p(pb)) 256cabdff1aSopenharmony_ci break; 257cabdff1aSopenharmony_ci 258cabdff1aSopenharmony_ci pos = pos - 0x4000; 259cabdff1aSopenharmony_ci bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start); 260cabdff1aSopenharmony_ci bytestream2_seek(&gbc, pos, SEEK_SET); 261cabdff1aSopenharmony_ci 262cabdff1aSopenharmony_ci if (len < 6 || bytestream2_tell_p(pb) - bytestream2_tell(&gbc) < 4) { 263cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); 264cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); 265cabdff1aSopenharmony_ci do { 266cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); 267cabdff1aSopenharmony_ci --len; 268cabdff1aSopenharmony_ci } while (len); 269cabdff1aSopenharmony_ci } else { 270cabdff1aSopenharmony_ci bytestream2_put_le32(pb, bytestream2_get_le32(&gbc)); 271cabdff1aSopenharmony_ci for (len = len - 2; len; --len) 272cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); 273cabdff1aSopenharmony_ci } 274cabdff1aSopenharmony_ci 275cabdff1aSopenharmony_ci len = i & 3; 276cabdff1aSopenharmony_ci if (!len) { 277cabdff1aSopenharmony_ci repeat = 1; 278cabdff1aSopenharmony_ci } else { 279cabdff1aSopenharmony_ci do { 280cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(gb)); 281cabdff1aSopenharmony_ci --len; 282cabdff1aSopenharmony_ci } while (len); 283cabdff1aSopenharmony_ci opcode = bytestream2_peek_byte(gb); 284cabdff1aSopenharmony_ci } 285cabdff1aSopenharmony_ci } 286cabdff1aSopenharmony_ci 287cabdff1aSopenharmony_ci return 0; 288cabdff1aSopenharmony_ci} 289cabdff1aSopenharmony_ci 290cabdff1aSopenharmony_cistatic int decode_type1(GetByteContext *gb, PutByteContext *pb) 291cabdff1aSopenharmony_ci{ 292cabdff1aSopenharmony_ci unsigned opcode = 0, len; 293cabdff1aSopenharmony_ci int high = 0; 294cabdff1aSopenharmony_ci int i, pos; 295cabdff1aSopenharmony_ci 296cabdff1aSopenharmony_ci while (bytestream2_get_bytes_left(gb) > 0) { 297cabdff1aSopenharmony_ci GetByteContext gbc; 298cabdff1aSopenharmony_ci 299cabdff1aSopenharmony_ci while (bytestream2_get_bytes_left(gb) > 0) { 300cabdff1aSopenharmony_ci while (bytestream2_get_bytes_left(gb) > 0) { 301cabdff1aSopenharmony_ci opcode = bytestream2_get_byte(gb); 302cabdff1aSopenharmony_ci high = opcode >= 0x20; 303cabdff1aSopenharmony_ci if (high) 304cabdff1aSopenharmony_ci break; 305cabdff1aSopenharmony_ci if (opcode) 306cabdff1aSopenharmony_ci break; 307cabdff1aSopenharmony_ci opcode = bytestream2_get_byte(gb); 308cabdff1aSopenharmony_ci if (opcode < 0xF8) { 309cabdff1aSopenharmony_ci opcode += 32; 310cabdff1aSopenharmony_ci break; 311cabdff1aSopenharmony_ci } 312cabdff1aSopenharmony_ci i = opcode - 0xF8; 313cabdff1aSopenharmony_ci if (i) { 314cabdff1aSopenharmony_ci len = 256; 315cabdff1aSopenharmony_ci do { 316cabdff1aSopenharmony_ci len *= 2; 317cabdff1aSopenharmony_ci --i; 318cabdff1aSopenharmony_ci } while (i); 319cabdff1aSopenharmony_ci } else { 320cabdff1aSopenharmony_ci len = 280; 321cabdff1aSopenharmony_ci } 322cabdff1aSopenharmony_ci do { 323cabdff1aSopenharmony_ci bytestream2_put_le32(pb, bytestream2_get_le32(gb)); 324cabdff1aSopenharmony_ci bytestream2_put_le32(pb, bytestream2_get_le32(gb)); 325cabdff1aSopenharmony_ci len -= 8; 326cabdff1aSopenharmony_ci } while (len && bytestream2_get_bytes_left(gb) > 0); 327cabdff1aSopenharmony_ci } 328cabdff1aSopenharmony_ci 329cabdff1aSopenharmony_ci if (!high) { 330cabdff1aSopenharmony_ci do { 331cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(gb)); 332cabdff1aSopenharmony_ci --opcode; 333cabdff1aSopenharmony_ci } while (opcode && bytestream2_get_bytes_left(gb) > 0); 334cabdff1aSopenharmony_ci 335cabdff1aSopenharmony_ci while (bytestream2_get_bytes_left(gb) > 0) { 336cabdff1aSopenharmony_ci GetByteContext gbc; 337cabdff1aSopenharmony_ci 338cabdff1aSopenharmony_ci opcode = bytestream2_get_byte(gb); 339cabdff1aSopenharmony_ci if (opcode >= 0x20) 340cabdff1aSopenharmony_ci break; 341cabdff1aSopenharmony_ci bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start); 342cabdff1aSopenharmony_ci 343cabdff1aSopenharmony_ci pos = -(opcode | 32 * bytestream2_get_byte(gb)) - 1; 344cabdff1aSopenharmony_ci bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET); 345cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); 346cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); 347cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); 348cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(gb)); 349cabdff1aSopenharmony_ci } 350cabdff1aSopenharmony_ci } 351cabdff1aSopenharmony_ci high = 0; 352cabdff1aSopenharmony_ci if (opcode < 0x40) 353cabdff1aSopenharmony_ci break; 354cabdff1aSopenharmony_ci bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start); 355cabdff1aSopenharmony_ci pos = (-((opcode & 0x1F) | 32 * bytestream2_get_byte(gb)) - 1); 356cabdff1aSopenharmony_ci bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET); 357cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); 358cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); 359cabdff1aSopenharmony_ci len = (opcode >> 5) - 1; 360cabdff1aSopenharmony_ci do { 361cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); 362cabdff1aSopenharmony_ci --len; 363cabdff1aSopenharmony_ci } while (len && bytestream2_get_bytes_left(&gbc) > 0); 364cabdff1aSopenharmony_ci } 365cabdff1aSopenharmony_ci len = opcode & 0x1F; 366cabdff1aSopenharmony_ci if (!len) { 367cabdff1aSopenharmony_ci if (!bytestream2_peek_byte(gb)) { 368cabdff1aSopenharmony_ci do { 369cabdff1aSopenharmony_ci bytestream2_skip(gb, 1); 370cabdff1aSopenharmony_ci len += 255; 371cabdff1aSopenharmony_ci } while (!bytestream2_peek_byte(gb) && bytestream2_get_bytes_left(gb) > 0); 372cabdff1aSopenharmony_ci } 373cabdff1aSopenharmony_ci len += bytestream2_get_byte(gb) + 31; 374cabdff1aSopenharmony_ci } 375cabdff1aSopenharmony_ci pos = -bytestream2_get_byte(gb); 376cabdff1aSopenharmony_ci bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start); 377cabdff1aSopenharmony_ci bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos - (bytestream2_get_byte(gb) << 8), SEEK_SET); 378cabdff1aSopenharmony_ci if (bytestream2_tell_p(pb) == bytestream2_tell(&gbc)) 379cabdff1aSopenharmony_ci break; 380cabdff1aSopenharmony_ci if (len < 5 || bytestream2_tell_p(pb) - bytestream2_tell(&gbc) < 4) { 381cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); 382cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); 383cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); 384cabdff1aSopenharmony_ci } else { 385cabdff1aSopenharmony_ci bytestream2_put_le32(pb, bytestream2_get_le32(&gbc)); 386cabdff1aSopenharmony_ci len--; 387cabdff1aSopenharmony_ci } 388cabdff1aSopenharmony_ci do { 389cabdff1aSopenharmony_ci bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); 390cabdff1aSopenharmony_ci len--; 391cabdff1aSopenharmony_ci } while (len && bytestream2_get_bytes_left(&gbc) > 0); 392cabdff1aSopenharmony_ci } 393cabdff1aSopenharmony_ci 394cabdff1aSopenharmony_ci return 0; 395cabdff1aSopenharmony_ci} 396cabdff1aSopenharmony_ci 397cabdff1aSopenharmony_cistatic int decode_frame(AVCodecContext *avctx, AVFrame *frame, 398cabdff1aSopenharmony_ci int *got_frame, AVPacket *avpkt) 399cabdff1aSopenharmony_ci{ 400cabdff1aSopenharmony_ci FMVCContext *s = avctx->priv_data; 401cabdff1aSopenharmony_ci GetByteContext *gb = &s->gb; 402cabdff1aSopenharmony_ci PutByteContext *pb = &s->pb; 403cabdff1aSopenharmony_ci int ret, y, x; 404cabdff1aSopenharmony_ci int key_frame; 405cabdff1aSopenharmony_ci 406cabdff1aSopenharmony_ci if (avpkt->size < 8) 407cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 408cabdff1aSopenharmony_ci 409cabdff1aSopenharmony_ci bytestream2_init(gb, avpkt->data, avpkt->size); 410cabdff1aSopenharmony_ci bytestream2_skip(gb, 2); 411cabdff1aSopenharmony_ci 412cabdff1aSopenharmony_ci key_frame = !!bytestream2_get_le16(gb); 413cabdff1aSopenharmony_ci 414cabdff1aSopenharmony_ci if (key_frame) { 415cabdff1aSopenharmony_ci const uint8_t *src; 416cabdff1aSopenharmony_ci unsigned type, size; 417cabdff1aSopenharmony_ci uint8_t *dst; 418cabdff1aSopenharmony_ci 419cabdff1aSopenharmony_ci type = bytestream2_get_le16(gb); 420cabdff1aSopenharmony_ci size = bytestream2_get_le16(gb); 421cabdff1aSopenharmony_ci if (size > bytestream2_get_bytes_left(gb)) 422cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 423cabdff1aSopenharmony_ci 424cabdff1aSopenharmony_ci bytestream2_init_writer(pb, s->buffer, s->buffer_size); 425cabdff1aSopenharmony_ci if (type == 1) { 426cabdff1aSopenharmony_ci decode_type1(gb, pb); 427cabdff1aSopenharmony_ci } else if (type == 2){ 428cabdff1aSopenharmony_ci decode_type2(gb, pb); 429cabdff1aSopenharmony_ci } else { 430cabdff1aSopenharmony_ci avpriv_report_missing_feature(avctx, "Compression type %d", type); 431cabdff1aSopenharmony_ci return AVERROR_PATCHWELCOME; 432cabdff1aSopenharmony_ci } 433cabdff1aSopenharmony_ci 434cabdff1aSopenharmony_ci if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) 435cabdff1aSopenharmony_ci return ret; 436cabdff1aSopenharmony_ci 437cabdff1aSopenharmony_ci frame->key_frame = 1; 438cabdff1aSopenharmony_ci frame->pict_type = AV_PICTURE_TYPE_I; 439cabdff1aSopenharmony_ci 440cabdff1aSopenharmony_ci src = s->buffer; 441cabdff1aSopenharmony_ci dst = frame->data[0] + (avctx->height - 1) * frame->linesize[0]; 442cabdff1aSopenharmony_ci for (y = 0; y < avctx->height; y++) { 443cabdff1aSopenharmony_ci memcpy(dst, src, avctx->width * s->bpp); 444cabdff1aSopenharmony_ci dst -= frame->linesize[0]; 445cabdff1aSopenharmony_ci src += s->stride * 4; 446cabdff1aSopenharmony_ci if (bytestream2_tell_p(pb) < y*s->stride * 4) 447cabdff1aSopenharmony_ci break; 448cabdff1aSopenharmony_ci } 449cabdff1aSopenharmony_ci } else { 450cabdff1aSopenharmony_ci unsigned block, nb_blocks; 451cabdff1aSopenharmony_ci int type, k, l; 452cabdff1aSopenharmony_ci uint8_t *ssrc, *ddst; 453cabdff1aSopenharmony_ci const uint32_t *src; 454cabdff1aSopenharmony_ci uint32_t *dst; 455cabdff1aSopenharmony_ci 456cabdff1aSopenharmony_ci for (block = 0; block < s->nb_blocks; block++) 457cabdff1aSopenharmony_ci s->blocks[block].xor = 0; 458cabdff1aSopenharmony_ci 459cabdff1aSopenharmony_ci nb_blocks = bytestream2_get_le16(gb); 460cabdff1aSopenharmony_ci if (nb_blocks > s->nb_blocks) 461cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 462cabdff1aSopenharmony_ci 463cabdff1aSopenharmony_ci bytestream2_init_writer(pb, s->pbuffer, s->pbuffer_size); 464cabdff1aSopenharmony_ci 465cabdff1aSopenharmony_ci type = bytestream2_get_le16(gb); 466cabdff1aSopenharmony_ci for (block = 0; block < nb_blocks; block++) { 467cabdff1aSopenharmony_ci unsigned size, offset; 468cabdff1aSopenharmony_ci int start = 0; 469cabdff1aSopenharmony_ci 470cabdff1aSopenharmony_ci offset = bytestream2_get_le16(gb); 471cabdff1aSopenharmony_ci if (offset >= s->nb_blocks) 472cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 473cabdff1aSopenharmony_ci 474cabdff1aSopenharmony_ci size = bytestream2_get_le16(gb); 475cabdff1aSopenharmony_ci if (size > bytestream2_get_bytes_left(gb)) 476cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 477cabdff1aSopenharmony_ci 478cabdff1aSopenharmony_ci start = bytestream2_tell_p(pb); 479cabdff1aSopenharmony_ci if (type == 1) { 480cabdff1aSopenharmony_ci decode_type1(gb, pb); 481cabdff1aSopenharmony_ci } else if (type == 2){ 482cabdff1aSopenharmony_ci decode_type2(gb, pb); 483cabdff1aSopenharmony_ci } else { 484cabdff1aSopenharmony_ci avpriv_report_missing_feature(avctx, "Compression type %d", type); 485cabdff1aSopenharmony_ci return AVERROR_PATCHWELCOME; 486cabdff1aSopenharmony_ci } 487cabdff1aSopenharmony_ci 488cabdff1aSopenharmony_ci if (s->blocks[offset].size * 4 != bytestream2_tell_p(pb) - start) 489cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 490cabdff1aSopenharmony_ci 491cabdff1aSopenharmony_ci s->blocks[offset].xor = 1; 492cabdff1aSopenharmony_ci } 493cabdff1aSopenharmony_ci 494cabdff1aSopenharmony_ci src = (const uint32_t *)s->pbuffer; 495cabdff1aSopenharmony_ci dst = (uint32_t *)s->buffer; 496cabdff1aSopenharmony_ci 497cabdff1aSopenharmony_ci for (block = 0, y = 0; y < s->yb; y++) { 498cabdff1aSopenharmony_ci int block_h = s->blocks[block].h; 499cabdff1aSopenharmony_ci uint32_t *rect = dst; 500cabdff1aSopenharmony_ci 501cabdff1aSopenharmony_ci for (x = 0; x < s->xb; x++) { 502cabdff1aSopenharmony_ci int block_w = s->blocks[block].w; 503cabdff1aSopenharmony_ci uint32_t *row = dst; 504cabdff1aSopenharmony_ci 505cabdff1aSopenharmony_ci block_h = s->blocks[block].h; 506cabdff1aSopenharmony_ci if (s->blocks[block].xor) { 507cabdff1aSopenharmony_ci for (k = 0; k < block_h; k++) { 508cabdff1aSopenharmony_ci uint32_t *column = dst; 509cabdff1aSopenharmony_ci for (l = 0; l < block_w; l++) 510cabdff1aSopenharmony_ci *dst++ ^= *src++; 511cabdff1aSopenharmony_ci dst = &column[s->stride]; 512cabdff1aSopenharmony_ci } 513cabdff1aSopenharmony_ci } 514cabdff1aSopenharmony_ci dst = &row[block_w]; 515cabdff1aSopenharmony_ci ++block; 516cabdff1aSopenharmony_ci } 517cabdff1aSopenharmony_ci dst = &rect[block_h * s->stride]; 518cabdff1aSopenharmony_ci } 519cabdff1aSopenharmony_ci 520cabdff1aSopenharmony_ci if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) 521cabdff1aSopenharmony_ci return ret; 522cabdff1aSopenharmony_ci 523cabdff1aSopenharmony_ci frame->key_frame = 0; 524cabdff1aSopenharmony_ci frame->pict_type = AV_PICTURE_TYPE_P; 525cabdff1aSopenharmony_ci 526cabdff1aSopenharmony_ci ssrc = s->buffer; 527cabdff1aSopenharmony_ci ddst = frame->data[0] + (avctx->height - 1) * frame->linesize[0]; 528cabdff1aSopenharmony_ci for (y = 0; y < avctx->height; y++) { 529cabdff1aSopenharmony_ci memcpy(ddst, ssrc, avctx->width * s->bpp); 530cabdff1aSopenharmony_ci ddst -= frame->linesize[0]; 531cabdff1aSopenharmony_ci ssrc += s->stride * 4; 532cabdff1aSopenharmony_ci } 533cabdff1aSopenharmony_ci } 534cabdff1aSopenharmony_ci 535cabdff1aSopenharmony_ci *got_frame = 1; 536cabdff1aSopenharmony_ci 537cabdff1aSopenharmony_ci return avpkt->size; 538cabdff1aSopenharmony_ci} 539cabdff1aSopenharmony_ci 540cabdff1aSopenharmony_cistatic av_cold int decode_init(AVCodecContext *avctx) 541cabdff1aSopenharmony_ci{ 542cabdff1aSopenharmony_ci FMVCContext *s = avctx->priv_data; 543cabdff1aSopenharmony_ci int i, j, m, block = 0, h = BLOCK_HEIGHT, w = BLOCK_WIDTH; 544cabdff1aSopenharmony_ci 545cabdff1aSopenharmony_ci switch (avctx->bits_per_coded_sample) { 546cabdff1aSopenharmony_ci case 16: 547cabdff1aSopenharmony_ci avctx->pix_fmt = AV_PIX_FMT_RGB555LE; 548cabdff1aSopenharmony_ci break; 549cabdff1aSopenharmony_ci case 24: 550cabdff1aSopenharmony_ci avctx->pix_fmt = AV_PIX_FMT_BGR24; 551cabdff1aSopenharmony_ci break; 552cabdff1aSopenharmony_ci case 32: 553cabdff1aSopenharmony_ci avctx->pix_fmt = AV_PIX_FMT_BGRA; 554cabdff1aSopenharmony_ci break; 555cabdff1aSopenharmony_ci default: 556cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Unsupported bitdepth %i\n", 557cabdff1aSopenharmony_ci avctx->bits_per_coded_sample); 558cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 559cabdff1aSopenharmony_ci } 560cabdff1aSopenharmony_ci 561cabdff1aSopenharmony_ci s->stride = (avctx->width * avctx->bits_per_coded_sample + 31) / 32; 562cabdff1aSopenharmony_ci s->xb = s->stride / BLOCK_WIDTH; 563cabdff1aSopenharmony_ci m = s->stride % BLOCK_WIDTH; 564cabdff1aSopenharmony_ci if (m) { 565cabdff1aSopenharmony_ci if (m < 37) { 566cabdff1aSopenharmony_ci w = m + BLOCK_WIDTH; 567cabdff1aSopenharmony_ci } else { 568cabdff1aSopenharmony_ci w = m; 569cabdff1aSopenharmony_ci s->xb++; 570cabdff1aSopenharmony_ci } 571cabdff1aSopenharmony_ci } 572cabdff1aSopenharmony_ci 573cabdff1aSopenharmony_ci s->yb = avctx->height / BLOCK_HEIGHT; 574cabdff1aSopenharmony_ci m = avctx->height % BLOCK_HEIGHT; 575cabdff1aSopenharmony_ci if (m) { 576cabdff1aSopenharmony_ci if (m < 49) { 577cabdff1aSopenharmony_ci h = m + BLOCK_HEIGHT; 578cabdff1aSopenharmony_ci } else { 579cabdff1aSopenharmony_ci h = m; 580cabdff1aSopenharmony_ci s->yb++; 581cabdff1aSopenharmony_ci } 582cabdff1aSopenharmony_ci } 583cabdff1aSopenharmony_ci 584cabdff1aSopenharmony_ci s->nb_blocks = s->xb * s->yb; 585cabdff1aSopenharmony_ci if (!s->nb_blocks) 586cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 587cabdff1aSopenharmony_ci s->blocks = av_calloc(s->nb_blocks, sizeof(*s->blocks)); 588cabdff1aSopenharmony_ci if (!s->blocks) 589cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 590cabdff1aSopenharmony_ci 591cabdff1aSopenharmony_ci for (i = 0; i < s->yb; i++) { 592cabdff1aSopenharmony_ci for (j = 0; j < s->xb; j++) { 593cabdff1aSopenharmony_ci if (i != (s->yb - 1) || j != (s->xb - 1)) { 594cabdff1aSopenharmony_ci if (i == s->yb - 1) { 595cabdff1aSopenharmony_ci s->blocks[block].w = BLOCK_WIDTH; 596cabdff1aSopenharmony_ci s->blocks[block].h = h; 597cabdff1aSopenharmony_ci s->blocks[block].size = BLOCK_WIDTH * h; 598cabdff1aSopenharmony_ci } else if (j == s->xb - 1) { 599cabdff1aSopenharmony_ci s->blocks[block].w = w; 600cabdff1aSopenharmony_ci s->blocks[block].h = BLOCK_HEIGHT; 601cabdff1aSopenharmony_ci s->blocks[block].size = BLOCK_HEIGHT * w; 602cabdff1aSopenharmony_ci } else { 603cabdff1aSopenharmony_ci s->blocks[block].w = BLOCK_WIDTH; 604cabdff1aSopenharmony_ci s->blocks[block].h = BLOCK_HEIGHT; 605cabdff1aSopenharmony_ci s->blocks[block].size = BLOCK_WIDTH * BLOCK_HEIGHT; 606cabdff1aSopenharmony_ci } 607cabdff1aSopenharmony_ci } else { 608cabdff1aSopenharmony_ci s->blocks[block].w = w; 609cabdff1aSopenharmony_ci s->blocks[block].h = h; 610cabdff1aSopenharmony_ci s->blocks[block].size = w * h; 611cabdff1aSopenharmony_ci } 612cabdff1aSopenharmony_ci block++; 613cabdff1aSopenharmony_ci } 614cabdff1aSopenharmony_ci } 615cabdff1aSopenharmony_ci 616cabdff1aSopenharmony_ci s->bpp = avctx->bits_per_coded_sample >> 3; 617cabdff1aSopenharmony_ci s->buffer_size = avctx->width * avctx->height * 4; 618cabdff1aSopenharmony_ci s->pbuffer_size = avctx->width * avctx->height * 4; 619cabdff1aSopenharmony_ci s->buffer = av_mallocz(s->buffer_size); 620cabdff1aSopenharmony_ci s->pbuffer = av_mallocz(s->pbuffer_size); 621cabdff1aSopenharmony_ci if (!s->buffer || !s->pbuffer) 622cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 623cabdff1aSopenharmony_ci 624cabdff1aSopenharmony_ci return 0; 625cabdff1aSopenharmony_ci} 626cabdff1aSopenharmony_ci 627cabdff1aSopenharmony_cistatic av_cold int decode_close(AVCodecContext *avctx) 628cabdff1aSopenharmony_ci{ 629cabdff1aSopenharmony_ci FMVCContext *s = avctx->priv_data; 630cabdff1aSopenharmony_ci 631cabdff1aSopenharmony_ci av_freep(&s->buffer); 632cabdff1aSopenharmony_ci av_freep(&s->pbuffer); 633cabdff1aSopenharmony_ci av_freep(&s->blocks); 634cabdff1aSopenharmony_ci 635cabdff1aSopenharmony_ci return 0; 636cabdff1aSopenharmony_ci} 637cabdff1aSopenharmony_ci 638cabdff1aSopenharmony_ciconst FFCodec ff_fmvc_decoder = { 639cabdff1aSopenharmony_ci .p.name = "fmvc", 640cabdff1aSopenharmony_ci .p.long_name = NULL_IF_CONFIG_SMALL("FM Screen Capture Codec"), 641cabdff1aSopenharmony_ci .p.type = AVMEDIA_TYPE_VIDEO, 642cabdff1aSopenharmony_ci .p.id = AV_CODEC_ID_FMVC, 643cabdff1aSopenharmony_ci .priv_data_size = sizeof(FMVCContext), 644cabdff1aSopenharmony_ci .init = decode_init, 645cabdff1aSopenharmony_ci .close = decode_close, 646cabdff1aSopenharmony_ci FF_CODEC_DECODE_CB(decode_frame), 647cabdff1aSopenharmony_ci .p.capabilities = AV_CODEC_CAP_DR1, 648cabdff1aSopenharmony_ci .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | 649cabdff1aSopenharmony_ci FF_CODEC_CAP_INIT_CLEANUP, 650cabdff1aSopenharmony_ci}; 651