1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Interplay MVE Video Decoder 3cabdff1aSopenharmony_ci * Copyright (C) 2003 The FFmpeg project 4cabdff1aSopenharmony_ci * 5cabdff1aSopenharmony_ci * This file is part of FFmpeg. 6cabdff1aSopenharmony_ci * 7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 11cabdff1aSopenharmony_ci * 12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15cabdff1aSopenharmony_ci * Lesser General Public License for more details. 16cabdff1aSopenharmony_ci * 17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20cabdff1aSopenharmony_ci */ 21cabdff1aSopenharmony_ci 22cabdff1aSopenharmony_ci/** 23cabdff1aSopenharmony_ci * @file 24cabdff1aSopenharmony_ci * Interplay MVE Video Decoder by Mike Melanson (melanson@pcisys.net) 25cabdff1aSopenharmony_ci * For more information about the Interplay MVE format, visit: 26cabdff1aSopenharmony_ci * http://www.pcisys.net/~melanson/codecs/interplay-mve.txt 27cabdff1aSopenharmony_ci * This code is written in such a way that the identifiers match up 28cabdff1aSopenharmony_ci * with the encoding descriptions in the document. 29cabdff1aSopenharmony_ci * 30cabdff1aSopenharmony_ci * This decoder presently only supports a PAL8 output colorspace. 31cabdff1aSopenharmony_ci * 32cabdff1aSopenharmony_ci * An Interplay video frame consists of 2 parts: The decoding map and 33cabdff1aSopenharmony_ci * the video data. A demuxer must load these 2 parts together in a single 34cabdff1aSopenharmony_ci * buffer before sending it through the stream to this decoder. 35cabdff1aSopenharmony_ci */ 36cabdff1aSopenharmony_ci 37cabdff1aSopenharmony_ci#include <stdio.h> 38cabdff1aSopenharmony_ci#include <stdlib.h> 39cabdff1aSopenharmony_ci#include <string.h> 40cabdff1aSopenharmony_ci 41cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h" 42cabdff1aSopenharmony_ci 43cabdff1aSopenharmony_ci#define BITSTREAM_READER_LE 44cabdff1aSopenharmony_ci#include "avcodec.h" 45cabdff1aSopenharmony_ci#include "bytestream.h" 46cabdff1aSopenharmony_ci#include "codec_internal.h" 47cabdff1aSopenharmony_ci#include "decode.h" 48cabdff1aSopenharmony_ci#include "get_bits.h" 49cabdff1aSopenharmony_ci#include "hpeldsp.h" 50cabdff1aSopenharmony_ci#include "internal.h" 51cabdff1aSopenharmony_ci 52cabdff1aSopenharmony_ci#define PALETTE_COUNT 256 53cabdff1aSopenharmony_ci 54cabdff1aSopenharmony_citypedef struct IpvideoContext { 55cabdff1aSopenharmony_ci 56cabdff1aSopenharmony_ci AVCodecContext *avctx; 57cabdff1aSopenharmony_ci HpelDSPContext hdsp; 58cabdff1aSopenharmony_ci AVFrame *second_last_frame; 59cabdff1aSopenharmony_ci AVFrame *last_frame; 60cabdff1aSopenharmony_ci 61cabdff1aSopenharmony_ci /* For format 0x10 */ 62cabdff1aSopenharmony_ci AVFrame *cur_decode_frame; 63cabdff1aSopenharmony_ci AVFrame *prev_decode_frame; 64cabdff1aSopenharmony_ci 65cabdff1aSopenharmony_ci const unsigned char *decoding_map; 66cabdff1aSopenharmony_ci int decoding_map_size; 67cabdff1aSopenharmony_ci const unsigned char *skip_map; 68cabdff1aSopenharmony_ci int skip_map_size; 69cabdff1aSopenharmony_ci 70cabdff1aSopenharmony_ci int is_16bpp; 71cabdff1aSopenharmony_ci GetByteContext stream_ptr, mv_ptr; 72cabdff1aSopenharmony_ci unsigned char *pixel_ptr; 73cabdff1aSopenharmony_ci int line_inc; 74cabdff1aSopenharmony_ci int stride; 75cabdff1aSopenharmony_ci int upper_motion_limit_offset; 76cabdff1aSopenharmony_ci 77cabdff1aSopenharmony_ci uint32_t pal[256]; 78cabdff1aSopenharmony_ci} IpvideoContext; 79cabdff1aSopenharmony_ci 80cabdff1aSopenharmony_cistatic int copy_from(IpvideoContext *s, AVFrame *src, AVFrame *dst, int delta_x, int delta_y) 81cabdff1aSopenharmony_ci{ 82cabdff1aSopenharmony_ci int width = dst->width; 83cabdff1aSopenharmony_ci int current_offset = s->pixel_ptr - dst->data[0]; 84cabdff1aSopenharmony_ci int x = (current_offset % dst->linesize[0]) / (1 + s->is_16bpp); 85cabdff1aSopenharmony_ci int y = current_offset / dst->linesize[0]; 86cabdff1aSopenharmony_ci int dx = delta_x + x - ((delta_x + x >= width) - (delta_x + x < 0)) * width; 87cabdff1aSopenharmony_ci int dy = delta_y + y + (delta_x + x >= width) - (delta_x + x < 0); 88cabdff1aSopenharmony_ci int motion_offset = dy * src->linesize[0] + dx * (1 + s->is_16bpp); 89cabdff1aSopenharmony_ci 90cabdff1aSopenharmony_ci if (motion_offset < 0) { 91cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "motion offset < 0 (%d)\n", motion_offset); 92cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 93cabdff1aSopenharmony_ci } else if (motion_offset > s->upper_motion_limit_offset) { 94cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "motion offset above limit (%d >= %d)\n", 95cabdff1aSopenharmony_ci motion_offset, s->upper_motion_limit_offset); 96cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 97cabdff1aSopenharmony_ci } 98cabdff1aSopenharmony_ci if (!src->data[0]) { 99cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "Invalid decode type, corrupted header?\n"); 100cabdff1aSopenharmony_ci return AVERROR(EINVAL); 101cabdff1aSopenharmony_ci } 102cabdff1aSopenharmony_ci s->hdsp.put_pixels_tab[!s->is_16bpp][0](s->pixel_ptr, src->data[0] + motion_offset, 103cabdff1aSopenharmony_ci dst->linesize[0], 8); 104cabdff1aSopenharmony_ci return 0; 105cabdff1aSopenharmony_ci} 106cabdff1aSopenharmony_ci 107cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0x0(IpvideoContext *s, AVFrame *frame) 108cabdff1aSopenharmony_ci{ 109cabdff1aSopenharmony_ci return copy_from(s, s->last_frame, frame, 0, 0); 110cabdff1aSopenharmony_ci} 111cabdff1aSopenharmony_ci 112cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0x1(IpvideoContext *s, AVFrame *frame) 113cabdff1aSopenharmony_ci{ 114cabdff1aSopenharmony_ci return copy_from(s, s->second_last_frame, frame, 0, 0); 115cabdff1aSopenharmony_ci} 116cabdff1aSopenharmony_ci 117cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0x2(IpvideoContext *s, AVFrame *frame) 118cabdff1aSopenharmony_ci{ 119cabdff1aSopenharmony_ci unsigned char B; 120cabdff1aSopenharmony_ci int x, y; 121cabdff1aSopenharmony_ci 122cabdff1aSopenharmony_ci /* copy block from 2 frames ago using a motion vector; need 1 more byte */ 123cabdff1aSopenharmony_ci if (!s->is_16bpp) { 124cabdff1aSopenharmony_ci B = bytestream2_get_byte(&s->stream_ptr); 125cabdff1aSopenharmony_ci } else { 126cabdff1aSopenharmony_ci B = bytestream2_get_byte(&s->mv_ptr); 127cabdff1aSopenharmony_ci } 128cabdff1aSopenharmony_ci 129cabdff1aSopenharmony_ci if (B < 56) { 130cabdff1aSopenharmony_ci x = 8 + (B % 7); 131cabdff1aSopenharmony_ci y = B / 7; 132cabdff1aSopenharmony_ci } else { 133cabdff1aSopenharmony_ci x = -14 + ((B - 56) % 29); 134cabdff1aSopenharmony_ci y = 8 + ((B - 56) / 29); 135cabdff1aSopenharmony_ci } 136cabdff1aSopenharmony_ci 137cabdff1aSopenharmony_ci ff_tlog(s->avctx, "motion byte = %d, (x, y) = (%d, %d)\n", B, x, y); 138cabdff1aSopenharmony_ci return copy_from(s, s->second_last_frame, frame, x, y); 139cabdff1aSopenharmony_ci} 140cabdff1aSopenharmony_ci 141cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0x3(IpvideoContext *s, AVFrame *frame) 142cabdff1aSopenharmony_ci{ 143cabdff1aSopenharmony_ci unsigned char B; 144cabdff1aSopenharmony_ci int x, y; 145cabdff1aSopenharmony_ci 146cabdff1aSopenharmony_ci /* copy 8x8 block from current frame from an up/left block */ 147cabdff1aSopenharmony_ci 148cabdff1aSopenharmony_ci /* need 1 more byte for motion */ 149cabdff1aSopenharmony_ci if (!s->is_16bpp) { 150cabdff1aSopenharmony_ci B = bytestream2_get_byte(&s->stream_ptr); 151cabdff1aSopenharmony_ci } else { 152cabdff1aSopenharmony_ci B = bytestream2_get_byte(&s->mv_ptr); 153cabdff1aSopenharmony_ci } 154cabdff1aSopenharmony_ci 155cabdff1aSopenharmony_ci if (B < 56) { 156cabdff1aSopenharmony_ci x = -(8 + (B % 7)); 157cabdff1aSopenharmony_ci y = -(B / 7); 158cabdff1aSopenharmony_ci } else { 159cabdff1aSopenharmony_ci x = -(-14 + ((B - 56) % 29)); 160cabdff1aSopenharmony_ci y = -( 8 + ((B - 56) / 29)); 161cabdff1aSopenharmony_ci } 162cabdff1aSopenharmony_ci 163cabdff1aSopenharmony_ci ff_tlog(s->avctx, "motion byte = %d, (x, y) = (%d, %d)\n", B, x, y); 164cabdff1aSopenharmony_ci return copy_from(s, frame, frame, x, y); 165cabdff1aSopenharmony_ci} 166cabdff1aSopenharmony_ci 167cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0x4(IpvideoContext *s, AVFrame *frame) 168cabdff1aSopenharmony_ci{ 169cabdff1aSopenharmony_ci int x, y; 170cabdff1aSopenharmony_ci unsigned char B, BL, BH; 171cabdff1aSopenharmony_ci 172cabdff1aSopenharmony_ci /* copy a block from the previous frame; need 1 more byte */ 173cabdff1aSopenharmony_ci if (!s->is_16bpp) { 174cabdff1aSopenharmony_ci B = bytestream2_get_byte(&s->stream_ptr); 175cabdff1aSopenharmony_ci } else { 176cabdff1aSopenharmony_ci B = bytestream2_get_byte(&s->mv_ptr); 177cabdff1aSopenharmony_ci } 178cabdff1aSopenharmony_ci 179cabdff1aSopenharmony_ci BL = B & 0x0F; 180cabdff1aSopenharmony_ci BH = (B >> 4) & 0x0F; 181cabdff1aSopenharmony_ci x = -8 + BL; 182cabdff1aSopenharmony_ci y = -8 + BH; 183cabdff1aSopenharmony_ci 184cabdff1aSopenharmony_ci ff_tlog(s->avctx, "motion byte = %d, (x, y) = (%d, %d)\n", B, x, y); 185cabdff1aSopenharmony_ci return copy_from(s, s->last_frame, frame, x, y); 186cabdff1aSopenharmony_ci} 187cabdff1aSopenharmony_ci 188cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0x5(IpvideoContext *s, AVFrame *frame) 189cabdff1aSopenharmony_ci{ 190cabdff1aSopenharmony_ci signed char x, y; 191cabdff1aSopenharmony_ci 192cabdff1aSopenharmony_ci /* copy a block from the previous frame using an expanded range; 193cabdff1aSopenharmony_ci * need 2 more bytes */ 194cabdff1aSopenharmony_ci x = bytestream2_get_byte(&s->stream_ptr); 195cabdff1aSopenharmony_ci y = bytestream2_get_byte(&s->stream_ptr); 196cabdff1aSopenharmony_ci 197cabdff1aSopenharmony_ci ff_tlog(s->avctx, "motion bytes = %d, %d\n", x, y); 198cabdff1aSopenharmony_ci return copy_from(s, s->last_frame, frame, x, y); 199cabdff1aSopenharmony_ci} 200cabdff1aSopenharmony_ci 201cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0x6(IpvideoContext *s, AVFrame *frame) 202cabdff1aSopenharmony_ci{ 203cabdff1aSopenharmony_ci /* mystery opcode? skip multiple blocks? */ 204cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "Help! Mystery opcode 0x6 seen\n"); 205cabdff1aSopenharmony_ci 206cabdff1aSopenharmony_ci /* report success */ 207cabdff1aSopenharmony_ci return 0; 208cabdff1aSopenharmony_ci} 209cabdff1aSopenharmony_ci 210cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0x7(IpvideoContext *s, AVFrame *frame) 211cabdff1aSopenharmony_ci{ 212cabdff1aSopenharmony_ci int x, y; 213cabdff1aSopenharmony_ci unsigned char P[2]; 214cabdff1aSopenharmony_ci unsigned int flags; 215cabdff1aSopenharmony_ci 216cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&s->stream_ptr) < 4) { 217cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "too little data for opcode 0x7\n"); 218cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 219cabdff1aSopenharmony_ci } 220cabdff1aSopenharmony_ci 221cabdff1aSopenharmony_ci /* 2-color encoding */ 222cabdff1aSopenharmony_ci P[0] = bytestream2_get_byte(&s->stream_ptr); 223cabdff1aSopenharmony_ci P[1] = bytestream2_get_byte(&s->stream_ptr); 224cabdff1aSopenharmony_ci 225cabdff1aSopenharmony_ci if (P[0] <= P[1]) { 226cabdff1aSopenharmony_ci 227cabdff1aSopenharmony_ci /* need 8 more bytes from the stream */ 228cabdff1aSopenharmony_ci for (y = 0; y < 8; y++) { 229cabdff1aSopenharmony_ci flags = bytestream2_get_byte(&s->stream_ptr) | 0x100; 230cabdff1aSopenharmony_ci for (; flags != 1; flags >>= 1) 231cabdff1aSopenharmony_ci *s->pixel_ptr++ = P[flags & 1]; 232cabdff1aSopenharmony_ci s->pixel_ptr += s->line_inc; 233cabdff1aSopenharmony_ci } 234cabdff1aSopenharmony_ci 235cabdff1aSopenharmony_ci } else { 236cabdff1aSopenharmony_ci 237cabdff1aSopenharmony_ci /* need 2 more bytes from the stream */ 238cabdff1aSopenharmony_ci flags = bytestream2_get_le16(&s->stream_ptr); 239cabdff1aSopenharmony_ci for (y = 0; y < 8; y += 2) { 240cabdff1aSopenharmony_ci for (x = 0; x < 8; x += 2, flags >>= 1) { 241cabdff1aSopenharmony_ci s->pixel_ptr[x ] = 242cabdff1aSopenharmony_ci s->pixel_ptr[x + 1 ] = 243cabdff1aSopenharmony_ci s->pixel_ptr[x + s->stride] = 244cabdff1aSopenharmony_ci s->pixel_ptr[x + 1 + s->stride] = P[flags & 1]; 245cabdff1aSopenharmony_ci } 246cabdff1aSopenharmony_ci s->pixel_ptr += s->stride * 2; 247cabdff1aSopenharmony_ci } 248cabdff1aSopenharmony_ci } 249cabdff1aSopenharmony_ci 250cabdff1aSopenharmony_ci /* report success */ 251cabdff1aSopenharmony_ci return 0; 252cabdff1aSopenharmony_ci} 253cabdff1aSopenharmony_ci 254cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0x8(IpvideoContext *s, AVFrame *frame) 255cabdff1aSopenharmony_ci{ 256cabdff1aSopenharmony_ci int x, y; 257cabdff1aSopenharmony_ci unsigned char P[4]; 258cabdff1aSopenharmony_ci unsigned int flags = 0; 259cabdff1aSopenharmony_ci 260cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&s->stream_ptr) < 12) { 261cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "too little data for opcode 0x8\n"); 262cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 263cabdff1aSopenharmony_ci } 264cabdff1aSopenharmony_ci 265cabdff1aSopenharmony_ci /* 2-color encoding for each 4x4 quadrant, or 2-color encoding on 266cabdff1aSopenharmony_ci * either top and bottom or left and right halves */ 267cabdff1aSopenharmony_ci P[0] = bytestream2_get_byte(&s->stream_ptr); 268cabdff1aSopenharmony_ci P[1] = bytestream2_get_byte(&s->stream_ptr); 269cabdff1aSopenharmony_ci 270cabdff1aSopenharmony_ci if (P[0] <= P[1]) { 271cabdff1aSopenharmony_ci for (y = 0; y < 16; y++) { 272cabdff1aSopenharmony_ci // new values for each 4x4 block 273cabdff1aSopenharmony_ci if (!(y & 3)) { 274cabdff1aSopenharmony_ci if (y) { 275cabdff1aSopenharmony_ci P[0] = bytestream2_get_byte(&s->stream_ptr); 276cabdff1aSopenharmony_ci P[1] = bytestream2_get_byte(&s->stream_ptr); 277cabdff1aSopenharmony_ci } 278cabdff1aSopenharmony_ci flags = bytestream2_get_le16(&s->stream_ptr); 279cabdff1aSopenharmony_ci } 280cabdff1aSopenharmony_ci 281cabdff1aSopenharmony_ci for (x = 0; x < 4; x++, flags >>= 1) 282cabdff1aSopenharmony_ci *s->pixel_ptr++ = P[flags & 1]; 283cabdff1aSopenharmony_ci s->pixel_ptr += s->stride - 4; 284cabdff1aSopenharmony_ci // switch to right half 285cabdff1aSopenharmony_ci if (y == 7) s->pixel_ptr -= 8 * s->stride - 4; 286cabdff1aSopenharmony_ci } 287cabdff1aSopenharmony_ci 288cabdff1aSopenharmony_ci } else { 289cabdff1aSopenharmony_ci flags = bytestream2_get_le32(&s->stream_ptr); 290cabdff1aSopenharmony_ci P[2] = bytestream2_get_byte(&s->stream_ptr); 291cabdff1aSopenharmony_ci P[3] = bytestream2_get_byte(&s->stream_ptr); 292cabdff1aSopenharmony_ci 293cabdff1aSopenharmony_ci if (P[2] <= P[3]) { 294cabdff1aSopenharmony_ci 295cabdff1aSopenharmony_ci /* vertical split; left & right halves are 2-color encoded */ 296cabdff1aSopenharmony_ci 297cabdff1aSopenharmony_ci for (y = 0; y < 16; y++) { 298cabdff1aSopenharmony_ci for (x = 0; x < 4; x++, flags >>= 1) 299cabdff1aSopenharmony_ci *s->pixel_ptr++ = P[flags & 1]; 300cabdff1aSopenharmony_ci s->pixel_ptr += s->stride - 4; 301cabdff1aSopenharmony_ci // switch to right half 302cabdff1aSopenharmony_ci if (y == 7) { 303cabdff1aSopenharmony_ci s->pixel_ptr -= 8 * s->stride - 4; 304cabdff1aSopenharmony_ci P[0] = P[2]; 305cabdff1aSopenharmony_ci P[1] = P[3]; 306cabdff1aSopenharmony_ci flags = bytestream2_get_le32(&s->stream_ptr); 307cabdff1aSopenharmony_ci } 308cabdff1aSopenharmony_ci } 309cabdff1aSopenharmony_ci 310cabdff1aSopenharmony_ci } else { 311cabdff1aSopenharmony_ci 312cabdff1aSopenharmony_ci /* horizontal split; top & bottom halves are 2-color encoded */ 313cabdff1aSopenharmony_ci 314cabdff1aSopenharmony_ci for (y = 0; y < 8; y++) { 315cabdff1aSopenharmony_ci if (y == 4) { 316cabdff1aSopenharmony_ci P[0] = P[2]; 317cabdff1aSopenharmony_ci P[1] = P[3]; 318cabdff1aSopenharmony_ci flags = bytestream2_get_le32(&s->stream_ptr); 319cabdff1aSopenharmony_ci } 320cabdff1aSopenharmony_ci 321cabdff1aSopenharmony_ci for (x = 0; x < 8; x++, flags >>= 1) 322cabdff1aSopenharmony_ci *s->pixel_ptr++ = P[flags & 1]; 323cabdff1aSopenharmony_ci s->pixel_ptr += s->line_inc; 324cabdff1aSopenharmony_ci } 325cabdff1aSopenharmony_ci } 326cabdff1aSopenharmony_ci } 327cabdff1aSopenharmony_ci 328cabdff1aSopenharmony_ci /* report success */ 329cabdff1aSopenharmony_ci return 0; 330cabdff1aSopenharmony_ci} 331cabdff1aSopenharmony_ci 332cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0x9(IpvideoContext *s, AVFrame *frame) 333cabdff1aSopenharmony_ci{ 334cabdff1aSopenharmony_ci int x, y; 335cabdff1aSopenharmony_ci unsigned char P[4]; 336cabdff1aSopenharmony_ci 337cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&s->stream_ptr) < 8) { 338cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "too little data for opcode 0x9\n"); 339cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 340cabdff1aSopenharmony_ci } 341cabdff1aSopenharmony_ci 342cabdff1aSopenharmony_ci /* 4-color encoding */ 343cabdff1aSopenharmony_ci bytestream2_get_buffer(&s->stream_ptr, P, 4); 344cabdff1aSopenharmony_ci 345cabdff1aSopenharmony_ci if (P[0] <= P[1]) { 346cabdff1aSopenharmony_ci if (P[2] <= P[3]) { 347cabdff1aSopenharmony_ci 348cabdff1aSopenharmony_ci /* 1 of 4 colors for each pixel, need 16 more bytes */ 349cabdff1aSopenharmony_ci for (y = 0; y < 8; y++) { 350cabdff1aSopenharmony_ci /* get the next set of 8 2-bit flags */ 351cabdff1aSopenharmony_ci int flags = bytestream2_get_le16(&s->stream_ptr); 352cabdff1aSopenharmony_ci for (x = 0; x < 8; x++, flags >>= 2) 353cabdff1aSopenharmony_ci *s->pixel_ptr++ = P[flags & 0x03]; 354cabdff1aSopenharmony_ci s->pixel_ptr += s->line_inc; 355cabdff1aSopenharmony_ci } 356cabdff1aSopenharmony_ci 357cabdff1aSopenharmony_ci } else { 358cabdff1aSopenharmony_ci uint32_t flags; 359cabdff1aSopenharmony_ci 360cabdff1aSopenharmony_ci /* 1 of 4 colors for each 2x2 block, need 4 more bytes */ 361cabdff1aSopenharmony_ci flags = bytestream2_get_le32(&s->stream_ptr); 362cabdff1aSopenharmony_ci 363cabdff1aSopenharmony_ci for (y = 0; y < 8; y += 2) { 364cabdff1aSopenharmony_ci for (x = 0; x < 8; x += 2, flags >>= 2) { 365cabdff1aSopenharmony_ci s->pixel_ptr[x ] = 366cabdff1aSopenharmony_ci s->pixel_ptr[x + 1 ] = 367cabdff1aSopenharmony_ci s->pixel_ptr[x + s->stride] = 368cabdff1aSopenharmony_ci s->pixel_ptr[x + 1 + s->stride] = P[flags & 0x03]; 369cabdff1aSopenharmony_ci } 370cabdff1aSopenharmony_ci s->pixel_ptr += s->stride * 2; 371cabdff1aSopenharmony_ci } 372cabdff1aSopenharmony_ci 373cabdff1aSopenharmony_ci } 374cabdff1aSopenharmony_ci } else { 375cabdff1aSopenharmony_ci uint64_t flags; 376cabdff1aSopenharmony_ci 377cabdff1aSopenharmony_ci /* 1 of 4 colors for each 2x1 or 1x2 block, need 8 more bytes */ 378cabdff1aSopenharmony_ci flags = bytestream2_get_le64(&s->stream_ptr); 379cabdff1aSopenharmony_ci if (P[2] <= P[3]) { 380cabdff1aSopenharmony_ci for (y = 0; y < 8; y++) { 381cabdff1aSopenharmony_ci for (x = 0; x < 8; x += 2, flags >>= 2) { 382cabdff1aSopenharmony_ci s->pixel_ptr[x ] = 383cabdff1aSopenharmony_ci s->pixel_ptr[x + 1] = P[flags & 0x03]; 384cabdff1aSopenharmony_ci } 385cabdff1aSopenharmony_ci s->pixel_ptr += s->stride; 386cabdff1aSopenharmony_ci } 387cabdff1aSopenharmony_ci } else { 388cabdff1aSopenharmony_ci for (y = 0; y < 8; y += 2) { 389cabdff1aSopenharmony_ci for (x = 0; x < 8; x++, flags >>= 2) { 390cabdff1aSopenharmony_ci s->pixel_ptr[x ] = 391cabdff1aSopenharmony_ci s->pixel_ptr[x + s->stride] = P[flags & 0x03]; 392cabdff1aSopenharmony_ci } 393cabdff1aSopenharmony_ci s->pixel_ptr += s->stride * 2; 394cabdff1aSopenharmony_ci } 395cabdff1aSopenharmony_ci } 396cabdff1aSopenharmony_ci } 397cabdff1aSopenharmony_ci 398cabdff1aSopenharmony_ci /* report success */ 399cabdff1aSopenharmony_ci return 0; 400cabdff1aSopenharmony_ci} 401cabdff1aSopenharmony_ci 402cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0xA(IpvideoContext *s, AVFrame *frame) 403cabdff1aSopenharmony_ci{ 404cabdff1aSopenharmony_ci int x, y; 405cabdff1aSopenharmony_ci unsigned char P[8]; 406cabdff1aSopenharmony_ci int flags = 0; 407cabdff1aSopenharmony_ci 408cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&s->stream_ptr) < 16) { 409cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "too little data for opcode 0xA\n"); 410cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 411cabdff1aSopenharmony_ci } 412cabdff1aSopenharmony_ci 413cabdff1aSopenharmony_ci bytestream2_get_buffer(&s->stream_ptr, P, 4); 414cabdff1aSopenharmony_ci 415cabdff1aSopenharmony_ci /* 4-color encoding for each 4x4 quadrant, or 4-color encoding on 416cabdff1aSopenharmony_ci * either top and bottom or left and right halves */ 417cabdff1aSopenharmony_ci if (P[0] <= P[1]) { 418cabdff1aSopenharmony_ci 419cabdff1aSopenharmony_ci /* 4-color encoding for each quadrant; need 32 bytes */ 420cabdff1aSopenharmony_ci for (y = 0; y < 16; y++) { 421cabdff1aSopenharmony_ci // new values for each 4x4 block 422cabdff1aSopenharmony_ci if (!(y & 3)) { 423cabdff1aSopenharmony_ci if (y) bytestream2_get_buffer(&s->stream_ptr, P, 4); 424cabdff1aSopenharmony_ci flags = bytestream2_get_le32(&s->stream_ptr); 425cabdff1aSopenharmony_ci } 426cabdff1aSopenharmony_ci 427cabdff1aSopenharmony_ci for (x = 0; x < 4; x++, flags >>= 2) 428cabdff1aSopenharmony_ci *s->pixel_ptr++ = P[flags & 0x03]; 429cabdff1aSopenharmony_ci 430cabdff1aSopenharmony_ci s->pixel_ptr += s->stride - 4; 431cabdff1aSopenharmony_ci // switch to right half 432cabdff1aSopenharmony_ci if (y == 7) s->pixel_ptr -= 8 * s->stride - 4; 433cabdff1aSopenharmony_ci } 434cabdff1aSopenharmony_ci 435cabdff1aSopenharmony_ci } else { 436cabdff1aSopenharmony_ci // vertical split? 437cabdff1aSopenharmony_ci int vert; 438cabdff1aSopenharmony_ci uint64_t flags = bytestream2_get_le64(&s->stream_ptr); 439cabdff1aSopenharmony_ci 440cabdff1aSopenharmony_ci bytestream2_get_buffer(&s->stream_ptr, P + 4, 4); 441cabdff1aSopenharmony_ci vert = P[4] <= P[5]; 442cabdff1aSopenharmony_ci 443cabdff1aSopenharmony_ci /* 4-color encoding for either left and right or top and bottom 444cabdff1aSopenharmony_ci * halves */ 445cabdff1aSopenharmony_ci 446cabdff1aSopenharmony_ci for (y = 0; y < 16; y++) { 447cabdff1aSopenharmony_ci for (x = 0; x < 4; x++, flags >>= 2) 448cabdff1aSopenharmony_ci *s->pixel_ptr++ = P[flags & 0x03]; 449cabdff1aSopenharmony_ci 450cabdff1aSopenharmony_ci if (vert) { 451cabdff1aSopenharmony_ci s->pixel_ptr += s->stride - 4; 452cabdff1aSopenharmony_ci // switch to right half 453cabdff1aSopenharmony_ci if (y == 7) s->pixel_ptr -= 8 * s->stride - 4; 454cabdff1aSopenharmony_ci } else if (y & 1) s->pixel_ptr += s->line_inc; 455cabdff1aSopenharmony_ci 456cabdff1aSopenharmony_ci // load values for second half 457cabdff1aSopenharmony_ci if (y == 7) { 458cabdff1aSopenharmony_ci memcpy(P, P + 4, 4); 459cabdff1aSopenharmony_ci flags = bytestream2_get_le64(&s->stream_ptr); 460cabdff1aSopenharmony_ci } 461cabdff1aSopenharmony_ci } 462cabdff1aSopenharmony_ci } 463cabdff1aSopenharmony_ci 464cabdff1aSopenharmony_ci /* report success */ 465cabdff1aSopenharmony_ci return 0; 466cabdff1aSopenharmony_ci} 467cabdff1aSopenharmony_ci 468cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0xB(IpvideoContext *s, AVFrame *frame) 469cabdff1aSopenharmony_ci{ 470cabdff1aSopenharmony_ci int y; 471cabdff1aSopenharmony_ci 472cabdff1aSopenharmony_ci /* 64-color encoding (each pixel in block is a different color) */ 473cabdff1aSopenharmony_ci for (y = 0; y < 8; y++) { 474cabdff1aSopenharmony_ci bytestream2_get_buffer(&s->stream_ptr, s->pixel_ptr, 8); 475cabdff1aSopenharmony_ci s->pixel_ptr += s->stride; 476cabdff1aSopenharmony_ci } 477cabdff1aSopenharmony_ci 478cabdff1aSopenharmony_ci /* report success */ 479cabdff1aSopenharmony_ci return 0; 480cabdff1aSopenharmony_ci} 481cabdff1aSopenharmony_ci 482cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0xC(IpvideoContext *s, AVFrame *frame) 483cabdff1aSopenharmony_ci{ 484cabdff1aSopenharmony_ci int x, y; 485cabdff1aSopenharmony_ci 486cabdff1aSopenharmony_ci /* 16-color block encoding: each 2x2 block is a different color */ 487cabdff1aSopenharmony_ci for (y = 0; y < 8; y += 2) { 488cabdff1aSopenharmony_ci for (x = 0; x < 8; x += 2) { 489cabdff1aSopenharmony_ci s->pixel_ptr[x ] = 490cabdff1aSopenharmony_ci s->pixel_ptr[x + 1 ] = 491cabdff1aSopenharmony_ci s->pixel_ptr[x + s->stride] = 492cabdff1aSopenharmony_ci s->pixel_ptr[x + 1 + s->stride] = bytestream2_get_byte(&s->stream_ptr); 493cabdff1aSopenharmony_ci } 494cabdff1aSopenharmony_ci s->pixel_ptr += s->stride * 2; 495cabdff1aSopenharmony_ci } 496cabdff1aSopenharmony_ci 497cabdff1aSopenharmony_ci /* report success */ 498cabdff1aSopenharmony_ci return 0; 499cabdff1aSopenharmony_ci} 500cabdff1aSopenharmony_ci 501cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0xD(IpvideoContext *s, AVFrame *frame) 502cabdff1aSopenharmony_ci{ 503cabdff1aSopenharmony_ci int y; 504cabdff1aSopenharmony_ci unsigned char P[2]; 505cabdff1aSopenharmony_ci 506cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&s->stream_ptr) < 4) { 507cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "too little data for opcode 0xD\n"); 508cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 509cabdff1aSopenharmony_ci } 510cabdff1aSopenharmony_ci 511cabdff1aSopenharmony_ci /* 4-color block encoding: each 4x4 block is a different color */ 512cabdff1aSopenharmony_ci for (y = 0; y < 8; y++) { 513cabdff1aSopenharmony_ci if (!(y & 3)) { 514cabdff1aSopenharmony_ci P[0] = bytestream2_get_byte(&s->stream_ptr); 515cabdff1aSopenharmony_ci P[1] = bytestream2_get_byte(&s->stream_ptr); 516cabdff1aSopenharmony_ci } 517cabdff1aSopenharmony_ci memset(s->pixel_ptr, P[0], 4); 518cabdff1aSopenharmony_ci memset(s->pixel_ptr + 4, P[1], 4); 519cabdff1aSopenharmony_ci s->pixel_ptr += s->stride; 520cabdff1aSopenharmony_ci } 521cabdff1aSopenharmony_ci 522cabdff1aSopenharmony_ci /* report success */ 523cabdff1aSopenharmony_ci return 0; 524cabdff1aSopenharmony_ci} 525cabdff1aSopenharmony_ci 526cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0xE(IpvideoContext *s, AVFrame *frame) 527cabdff1aSopenharmony_ci{ 528cabdff1aSopenharmony_ci int y; 529cabdff1aSopenharmony_ci unsigned char pix; 530cabdff1aSopenharmony_ci 531cabdff1aSopenharmony_ci /* 1-color encoding: the whole block is 1 solid color */ 532cabdff1aSopenharmony_ci pix = bytestream2_get_byte(&s->stream_ptr); 533cabdff1aSopenharmony_ci 534cabdff1aSopenharmony_ci for (y = 0; y < 8; y++) { 535cabdff1aSopenharmony_ci memset(s->pixel_ptr, pix, 8); 536cabdff1aSopenharmony_ci s->pixel_ptr += s->stride; 537cabdff1aSopenharmony_ci } 538cabdff1aSopenharmony_ci 539cabdff1aSopenharmony_ci /* report success */ 540cabdff1aSopenharmony_ci return 0; 541cabdff1aSopenharmony_ci} 542cabdff1aSopenharmony_ci 543cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0xF(IpvideoContext *s, AVFrame *frame) 544cabdff1aSopenharmony_ci{ 545cabdff1aSopenharmony_ci int x, y; 546cabdff1aSopenharmony_ci unsigned char sample[2]; 547cabdff1aSopenharmony_ci 548cabdff1aSopenharmony_ci /* dithered encoding */ 549cabdff1aSopenharmony_ci sample[0] = bytestream2_get_byte(&s->stream_ptr); 550cabdff1aSopenharmony_ci sample[1] = bytestream2_get_byte(&s->stream_ptr); 551cabdff1aSopenharmony_ci 552cabdff1aSopenharmony_ci for (y = 0; y < 8; y++) { 553cabdff1aSopenharmony_ci for (x = 0; x < 8; x += 2) { 554cabdff1aSopenharmony_ci *s->pixel_ptr++ = sample[ y & 1 ]; 555cabdff1aSopenharmony_ci *s->pixel_ptr++ = sample[!(y & 1)]; 556cabdff1aSopenharmony_ci } 557cabdff1aSopenharmony_ci s->pixel_ptr += s->line_inc; 558cabdff1aSopenharmony_ci } 559cabdff1aSopenharmony_ci 560cabdff1aSopenharmony_ci /* report success */ 561cabdff1aSopenharmony_ci return 0; 562cabdff1aSopenharmony_ci} 563cabdff1aSopenharmony_ci 564cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0x6_16(IpvideoContext *s, AVFrame *frame) 565cabdff1aSopenharmony_ci{ 566cabdff1aSopenharmony_ci signed char x, y; 567cabdff1aSopenharmony_ci 568cabdff1aSopenharmony_ci /* copy a block from the second last frame using an expanded range */ 569cabdff1aSopenharmony_ci x = bytestream2_get_byte(&s->stream_ptr); 570cabdff1aSopenharmony_ci y = bytestream2_get_byte(&s->stream_ptr); 571cabdff1aSopenharmony_ci 572cabdff1aSopenharmony_ci ff_tlog(s->avctx, "motion bytes = %d, %d\n", x, y); 573cabdff1aSopenharmony_ci return copy_from(s, s->second_last_frame, frame, x, y); 574cabdff1aSopenharmony_ci} 575cabdff1aSopenharmony_ci 576cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0x7_16(IpvideoContext *s, AVFrame *frame) 577cabdff1aSopenharmony_ci{ 578cabdff1aSopenharmony_ci int x, y; 579cabdff1aSopenharmony_ci uint16_t P[2]; 580cabdff1aSopenharmony_ci unsigned int flags; 581cabdff1aSopenharmony_ci uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr; 582cabdff1aSopenharmony_ci 583cabdff1aSopenharmony_ci /* 2-color encoding */ 584cabdff1aSopenharmony_ci P[0] = bytestream2_get_le16(&s->stream_ptr); 585cabdff1aSopenharmony_ci P[1] = bytestream2_get_le16(&s->stream_ptr); 586cabdff1aSopenharmony_ci 587cabdff1aSopenharmony_ci if (!(P[0] & 0x8000)) { 588cabdff1aSopenharmony_ci 589cabdff1aSopenharmony_ci for (y = 0; y < 8; y++) { 590cabdff1aSopenharmony_ci flags = bytestream2_get_byte(&s->stream_ptr) | 0x100; 591cabdff1aSopenharmony_ci for (; flags != 1; flags >>= 1) 592cabdff1aSopenharmony_ci *pixel_ptr++ = P[flags & 1]; 593cabdff1aSopenharmony_ci pixel_ptr += s->line_inc; 594cabdff1aSopenharmony_ci } 595cabdff1aSopenharmony_ci 596cabdff1aSopenharmony_ci } else { 597cabdff1aSopenharmony_ci 598cabdff1aSopenharmony_ci flags = bytestream2_get_le16(&s->stream_ptr); 599cabdff1aSopenharmony_ci for (y = 0; y < 8; y += 2) { 600cabdff1aSopenharmony_ci for (x = 0; x < 8; x += 2, flags >>= 1) { 601cabdff1aSopenharmony_ci pixel_ptr[x ] = 602cabdff1aSopenharmony_ci pixel_ptr[x + 1 ] = 603cabdff1aSopenharmony_ci pixel_ptr[x + s->stride] = 604cabdff1aSopenharmony_ci pixel_ptr[x + 1 + s->stride] = P[flags & 1]; 605cabdff1aSopenharmony_ci } 606cabdff1aSopenharmony_ci pixel_ptr += s->stride * 2; 607cabdff1aSopenharmony_ci } 608cabdff1aSopenharmony_ci } 609cabdff1aSopenharmony_ci 610cabdff1aSopenharmony_ci return 0; 611cabdff1aSopenharmony_ci} 612cabdff1aSopenharmony_ci 613cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0x8_16(IpvideoContext *s, AVFrame *frame) 614cabdff1aSopenharmony_ci{ 615cabdff1aSopenharmony_ci int x, y; 616cabdff1aSopenharmony_ci uint16_t P[4]; 617cabdff1aSopenharmony_ci unsigned int flags = 0; 618cabdff1aSopenharmony_ci uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr; 619cabdff1aSopenharmony_ci 620cabdff1aSopenharmony_ci /* 2-color encoding for each 4x4 quadrant, or 2-color encoding on 621cabdff1aSopenharmony_ci * either top and bottom or left and right halves */ 622cabdff1aSopenharmony_ci P[0] = bytestream2_get_le16(&s->stream_ptr); 623cabdff1aSopenharmony_ci P[1] = bytestream2_get_le16(&s->stream_ptr); 624cabdff1aSopenharmony_ci 625cabdff1aSopenharmony_ci if (!(P[0] & 0x8000)) { 626cabdff1aSopenharmony_ci 627cabdff1aSopenharmony_ci for (y = 0; y < 16; y++) { 628cabdff1aSopenharmony_ci // new values for each 4x4 block 629cabdff1aSopenharmony_ci if (!(y & 3)) { 630cabdff1aSopenharmony_ci if (y) { 631cabdff1aSopenharmony_ci P[0] = bytestream2_get_le16(&s->stream_ptr); 632cabdff1aSopenharmony_ci P[1] = bytestream2_get_le16(&s->stream_ptr); 633cabdff1aSopenharmony_ci } 634cabdff1aSopenharmony_ci flags = bytestream2_get_le16(&s->stream_ptr); 635cabdff1aSopenharmony_ci } 636cabdff1aSopenharmony_ci 637cabdff1aSopenharmony_ci for (x = 0; x < 4; x++, flags >>= 1) 638cabdff1aSopenharmony_ci *pixel_ptr++ = P[flags & 1]; 639cabdff1aSopenharmony_ci pixel_ptr += s->stride - 4; 640cabdff1aSopenharmony_ci // switch to right half 641cabdff1aSopenharmony_ci if (y == 7) pixel_ptr -= 8 * s->stride - 4; 642cabdff1aSopenharmony_ci } 643cabdff1aSopenharmony_ci 644cabdff1aSopenharmony_ci } else { 645cabdff1aSopenharmony_ci 646cabdff1aSopenharmony_ci flags = bytestream2_get_le32(&s->stream_ptr); 647cabdff1aSopenharmony_ci P[2] = bytestream2_get_le16(&s->stream_ptr); 648cabdff1aSopenharmony_ci P[3] = bytestream2_get_le16(&s->stream_ptr); 649cabdff1aSopenharmony_ci 650cabdff1aSopenharmony_ci if (!(P[2] & 0x8000)) { 651cabdff1aSopenharmony_ci 652cabdff1aSopenharmony_ci /* vertical split; left & right halves are 2-color encoded */ 653cabdff1aSopenharmony_ci 654cabdff1aSopenharmony_ci for (y = 0; y < 16; y++) { 655cabdff1aSopenharmony_ci for (x = 0; x < 4; x++, flags >>= 1) 656cabdff1aSopenharmony_ci *pixel_ptr++ = P[flags & 1]; 657cabdff1aSopenharmony_ci pixel_ptr += s->stride - 4; 658cabdff1aSopenharmony_ci // switch to right half 659cabdff1aSopenharmony_ci if (y == 7) { 660cabdff1aSopenharmony_ci pixel_ptr -= 8 * s->stride - 4; 661cabdff1aSopenharmony_ci P[0] = P[2]; 662cabdff1aSopenharmony_ci P[1] = P[3]; 663cabdff1aSopenharmony_ci flags = bytestream2_get_le32(&s->stream_ptr); 664cabdff1aSopenharmony_ci } 665cabdff1aSopenharmony_ci } 666cabdff1aSopenharmony_ci 667cabdff1aSopenharmony_ci } else { 668cabdff1aSopenharmony_ci 669cabdff1aSopenharmony_ci /* horizontal split; top & bottom halves are 2-color encoded */ 670cabdff1aSopenharmony_ci 671cabdff1aSopenharmony_ci for (y = 0; y < 8; y++) { 672cabdff1aSopenharmony_ci if (y == 4) { 673cabdff1aSopenharmony_ci P[0] = P[2]; 674cabdff1aSopenharmony_ci P[1] = P[3]; 675cabdff1aSopenharmony_ci flags = bytestream2_get_le32(&s->stream_ptr); 676cabdff1aSopenharmony_ci } 677cabdff1aSopenharmony_ci 678cabdff1aSopenharmony_ci for (x = 0; x < 8; x++, flags >>= 1) 679cabdff1aSopenharmony_ci *pixel_ptr++ = P[flags & 1]; 680cabdff1aSopenharmony_ci pixel_ptr += s->line_inc; 681cabdff1aSopenharmony_ci } 682cabdff1aSopenharmony_ci } 683cabdff1aSopenharmony_ci } 684cabdff1aSopenharmony_ci 685cabdff1aSopenharmony_ci /* report success */ 686cabdff1aSopenharmony_ci return 0; 687cabdff1aSopenharmony_ci} 688cabdff1aSopenharmony_ci 689cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0x9_16(IpvideoContext *s, AVFrame *frame) 690cabdff1aSopenharmony_ci{ 691cabdff1aSopenharmony_ci int x, y; 692cabdff1aSopenharmony_ci uint16_t P[4]; 693cabdff1aSopenharmony_ci uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr; 694cabdff1aSopenharmony_ci 695cabdff1aSopenharmony_ci /* 4-color encoding */ 696cabdff1aSopenharmony_ci for (x = 0; x < 4; x++) 697cabdff1aSopenharmony_ci P[x] = bytestream2_get_le16(&s->stream_ptr); 698cabdff1aSopenharmony_ci 699cabdff1aSopenharmony_ci if (!(P[0] & 0x8000)) { 700cabdff1aSopenharmony_ci if (!(P[2] & 0x8000)) { 701cabdff1aSopenharmony_ci 702cabdff1aSopenharmony_ci /* 1 of 4 colors for each pixel */ 703cabdff1aSopenharmony_ci for (y = 0; y < 8; y++) { 704cabdff1aSopenharmony_ci /* get the next set of 8 2-bit flags */ 705cabdff1aSopenharmony_ci int flags = bytestream2_get_le16(&s->stream_ptr); 706cabdff1aSopenharmony_ci for (x = 0; x < 8; x++, flags >>= 2) 707cabdff1aSopenharmony_ci *pixel_ptr++ = P[flags & 0x03]; 708cabdff1aSopenharmony_ci pixel_ptr += s->line_inc; 709cabdff1aSopenharmony_ci } 710cabdff1aSopenharmony_ci 711cabdff1aSopenharmony_ci } else { 712cabdff1aSopenharmony_ci uint32_t flags; 713cabdff1aSopenharmony_ci 714cabdff1aSopenharmony_ci /* 1 of 4 colors for each 2x2 block */ 715cabdff1aSopenharmony_ci flags = bytestream2_get_le32(&s->stream_ptr); 716cabdff1aSopenharmony_ci 717cabdff1aSopenharmony_ci for (y = 0; y < 8; y += 2) { 718cabdff1aSopenharmony_ci for (x = 0; x < 8; x += 2, flags >>= 2) { 719cabdff1aSopenharmony_ci pixel_ptr[x ] = 720cabdff1aSopenharmony_ci pixel_ptr[x + 1 ] = 721cabdff1aSopenharmony_ci pixel_ptr[x + s->stride] = 722cabdff1aSopenharmony_ci pixel_ptr[x + 1 + s->stride] = P[flags & 0x03]; 723cabdff1aSopenharmony_ci } 724cabdff1aSopenharmony_ci pixel_ptr += s->stride * 2; 725cabdff1aSopenharmony_ci } 726cabdff1aSopenharmony_ci 727cabdff1aSopenharmony_ci } 728cabdff1aSopenharmony_ci } else { 729cabdff1aSopenharmony_ci uint64_t flags; 730cabdff1aSopenharmony_ci 731cabdff1aSopenharmony_ci /* 1 of 4 colors for each 2x1 or 1x2 block */ 732cabdff1aSopenharmony_ci flags = bytestream2_get_le64(&s->stream_ptr); 733cabdff1aSopenharmony_ci if (!(P[2] & 0x8000)) { 734cabdff1aSopenharmony_ci for (y = 0; y < 8; y++) { 735cabdff1aSopenharmony_ci for (x = 0; x < 8; x += 2, flags >>= 2) { 736cabdff1aSopenharmony_ci pixel_ptr[x ] = 737cabdff1aSopenharmony_ci pixel_ptr[x + 1] = P[flags & 0x03]; 738cabdff1aSopenharmony_ci } 739cabdff1aSopenharmony_ci pixel_ptr += s->stride; 740cabdff1aSopenharmony_ci } 741cabdff1aSopenharmony_ci } else { 742cabdff1aSopenharmony_ci for (y = 0; y < 8; y += 2) { 743cabdff1aSopenharmony_ci for (x = 0; x < 8; x++, flags >>= 2) { 744cabdff1aSopenharmony_ci pixel_ptr[x ] = 745cabdff1aSopenharmony_ci pixel_ptr[x + s->stride] = P[flags & 0x03]; 746cabdff1aSopenharmony_ci } 747cabdff1aSopenharmony_ci pixel_ptr += s->stride * 2; 748cabdff1aSopenharmony_ci } 749cabdff1aSopenharmony_ci } 750cabdff1aSopenharmony_ci } 751cabdff1aSopenharmony_ci 752cabdff1aSopenharmony_ci /* report success */ 753cabdff1aSopenharmony_ci return 0; 754cabdff1aSopenharmony_ci} 755cabdff1aSopenharmony_ci 756cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0xA_16(IpvideoContext *s, AVFrame *frame) 757cabdff1aSopenharmony_ci{ 758cabdff1aSopenharmony_ci int x, y; 759cabdff1aSopenharmony_ci uint16_t P[8]; 760cabdff1aSopenharmony_ci int flags = 0; 761cabdff1aSopenharmony_ci uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr; 762cabdff1aSopenharmony_ci 763cabdff1aSopenharmony_ci for (x = 0; x < 4; x++) 764cabdff1aSopenharmony_ci P[x] = bytestream2_get_le16(&s->stream_ptr); 765cabdff1aSopenharmony_ci 766cabdff1aSopenharmony_ci /* 4-color encoding for each 4x4 quadrant, or 4-color encoding on 767cabdff1aSopenharmony_ci * either top and bottom or left and right halves */ 768cabdff1aSopenharmony_ci if (!(P[0] & 0x8000)) { 769cabdff1aSopenharmony_ci 770cabdff1aSopenharmony_ci /* 4-color encoding for each quadrant */ 771cabdff1aSopenharmony_ci for (y = 0; y < 16; y++) { 772cabdff1aSopenharmony_ci // new values for each 4x4 block 773cabdff1aSopenharmony_ci if (!(y & 3)) { 774cabdff1aSopenharmony_ci if (y) 775cabdff1aSopenharmony_ci for (x = 0; x < 4; x++) 776cabdff1aSopenharmony_ci P[x] = bytestream2_get_le16(&s->stream_ptr); 777cabdff1aSopenharmony_ci flags = bytestream2_get_le32(&s->stream_ptr); 778cabdff1aSopenharmony_ci } 779cabdff1aSopenharmony_ci 780cabdff1aSopenharmony_ci for (x = 0; x < 4; x++, flags >>= 2) 781cabdff1aSopenharmony_ci *pixel_ptr++ = P[flags & 0x03]; 782cabdff1aSopenharmony_ci 783cabdff1aSopenharmony_ci pixel_ptr += s->stride - 4; 784cabdff1aSopenharmony_ci // switch to right half 785cabdff1aSopenharmony_ci if (y == 7) pixel_ptr -= 8 * s->stride - 4; 786cabdff1aSopenharmony_ci } 787cabdff1aSopenharmony_ci 788cabdff1aSopenharmony_ci } else { 789cabdff1aSopenharmony_ci // vertical split? 790cabdff1aSopenharmony_ci int vert; 791cabdff1aSopenharmony_ci uint64_t flags = bytestream2_get_le64(&s->stream_ptr); 792cabdff1aSopenharmony_ci 793cabdff1aSopenharmony_ci for (x = 4; x < 8; x++) 794cabdff1aSopenharmony_ci P[x] = bytestream2_get_le16(&s->stream_ptr); 795cabdff1aSopenharmony_ci vert = !(P[4] & 0x8000); 796cabdff1aSopenharmony_ci 797cabdff1aSopenharmony_ci /* 4-color encoding for either left and right or top and bottom 798cabdff1aSopenharmony_ci * halves */ 799cabdff1aSopenharmony_ci 800cabdff1aSopenharmony_ci for (y = 0; y < 16; y++) { 801cabdff1aSopenharmony_ci for (x = 0; x < 4; x++, flags >>= 2) 802cabdff1aSopenharmony_ci *pixel_ptr++ = P[flags & 0x03]; 803cabdff1aSopenharmony_ci 804cabdff1aSopenharmony_ci if (vert) { 805cabdff1aSopenharmony_ci pixel_ptr += s->stride - 4; 806cabdff1aSopenharmony_ci // switch to right half 807cabdff1aSopenharmony_ci if (y == 7) pixel_ptr -= 8 * s->stride - 4; 808cabdff1aSopenharmony_ci } else if (y & 1) pixel_ptr += s->line_inc; 809cabdff1aSopenharmony_ci 810cabdff1aSopenharmony_ci // load values for second half 811cabdff1aSopenharmony_ci if (y == 7) { 812cabdff1aSopenharmony_ci memcpy(P, P + 4, 8); 813cabdff1aSopenharmony_ci flags = bytestream2_get_le64(&s->stream_ptr); 814cabdff1aSopenharmony_ci } 815cabdff1aSopenharmony_ci } 816cabdff1aSopenharmony_ci } 817cabdff1aSopenharmony_ci 818cabdff1aSopenharmony_ci /* report success */ 819cabdff1aSopenharmony_ci return 0; 820cabdff1aSopenharmony_ci} 821cabdff1aSopenharmony_ci 822cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0xB_16(IpvideoContext *s, AVFrame *frame) 823cabdff1aSopenharmony_ci{ 824cabdff1aSopenharmony_ci int x, y; 825cabdff1aSopenharmony_ci uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr; 826cabdff1aSopenharmony_ci 827cabdff1aSopenharmony_ci /* 64-color encoding (each pixel in block is a different color) */ 828cabdff1aSopenharmony_ci for (y = 0; y < 8; y++) { 829cabdff1aSopenharmony_ci for (x = 0; x < 8; x++) 830cabdff1aSopenharmony_ci pixel_ptr[x] = bytestream2_get_le16(&s->stream_ptr); 831cabdff1aSopenharmony_ci pixel_ptr += s->stride; 832cabdff1aSopenharmony_ci } 833cabdff1aSopenharmony_ci 834cabdff1aSopenharmony_ci /* report success */ 835cabdff1aSopenharmony_ci return 0; 836cabdff1aSopenharmony_ci} 837cabdff1aSopenharmony_ci 838cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0xC_16(IpvideoContext *s, AVFrame *frame) 839cabdff1aSopenharmony_ci{ 840cabdff1aSopenharmony_ci int x, y; 841cabdff1aSopenharmony_ci uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr; 842cabdff1aSopenharmony_ci 843cabdff1aSopenharmony_ci /* 16-color block encoding: each 2x2 block is a different color */ 844cabdff1aSopenharmony_ci for (y = 0; y < 8; y += 2) { 845cabdff1aSopenharmony_ci for (x = 0; x < 8; x += 2) { 846cabdff1aSopenharmony_ci pixel_ptr[x ] = 847cabdff1aSopenharmony_ci pixel_ptr[x + 1 ] = 848cabdff1aSopenharmony_ci pixel_ptr[x + s->stride] = 849cabdff1aSopenharmony_ci pixel_ptr[x + 1 + s->stride] = bytestream2_get_le16(&s->stream_ptr); 850cabdff1aSopenharmony_ci } 851cabdff1aSopenharmony_ci pixel_ptr += s->stride * 2; 852cabdff1aSopenharmony_ci } 853cabdff1aSopenharmony_ci 854cabdff1aSopenharmony_ci /* report success */ 855cabdff1aSopenharmony_ci return 0; 856cabdff1aSopenharmony_ci} 857cabdff1aSopenharmony_ci 858cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0xD_16(IpvideoContext *s, AVFrame *frame) 859cabdff1aSopenharmony_ci{ 860cabdff1aSopenharmony_ci int x, y; 861cabdff1aSopenharmony_ci uint16_t P[2]; 862cabdff1aSopenharmony_ci uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr; 863cabdff1aSopenharmony_ci 864cabdff1aSopenharmony_ci /* 4-color block encoding: each 4x4 block is a different color */ 865cabdff1aSopenharmony_ci for (y = 0; y < 8; y++) { 866cabdff1aSopenharmony_ci if (!(y & 3)) { 867cabdff1aSopenharmony_ci P[0] = bytestream2_get_le16(&s->stream_ptr); 868cabdff1aSopenharmony_ci P[1] = bytestream2_get_le16(&s->stream_ptr); 869cabdff1aSopenharmony_ci } 870cabdff1aSopenharmony_ci for (x = 0; x < 8; x++) 871cabdff1aSopenharmony_ci pixel_ptr[x] = P[x >> 2]; 872cabdff1aSopenharmony_ci pixel_ptr += s->stride; 873cabdff1aSopenharmony_ci } 874cabdff1aSopenharmony_ci 875cabdff1aSopenharmony_ci /* report success */ 876cabdff1aSopenharmony_ci return 0; 877cabdff1aSopenharmony_ci} 878cabdff1aSopenharmony_ci 879cabdff1aSopenharmony_cistatic int ipvideo_decode_block_opcode_0xE_16(IpvideoContext *s, AVFrame *frame) 880cabdff1aSopenharmony_ci{ 881cabdff1aSopenharmony_ci int x, y; 882cabdff1aSopenharmony_ci uint16_t pix; 883cabdff1aSopenharmony_ci uint16_t *pixel_ptr = (uint16_t*)s->pixel_ptr; 884cabdff1aSopenharmony_ci 885cabdff1aSopenharmony_ci /* 1-color encoding: the whole block is 1 solid color */ 886cabdff1aSopenharmony_ci pix = bytestream2_get_le16(&s->stream_ptr); 887cabdff1aSopenharmony_ci 888cabdff1aSopenharmony_ci for (y = 0; y < 8; y++) { 889cabdff1aSopenharmony_ci for (x = 0; x < 8; x++) 890cabdff1aSopenharmony_ci pixel_ptr[x] = pix; 891cabdff1aSopenharmony_ci pixel_ptr += s->stride; 892cabdff1aSopenharmony_ci } 893cabdff1aSopenharmony_ci 894cabdff1aSopenharmony_ci /* report success */ 895cabdff1aSopenharmony_ci return 0; 896cabdff1aSopenharmony_ci} 897cabdff1aSopenharmony_ci 898cabdff1aSopenharmony_cistatic int (* const ipvideo_decode_block[])(IpvideoContext *s, AVFrame *frame) = { 899cabdff1aSopenharmony_ci ipvideo_decode_block_opcode_0x0, ipvideo_decode_block_opcode_0x1, 900cabdff1aSopenharmony_ci ipvideo_decode_block_opcode_0x2, ipvideo_decode_block_opcode_0x3, 901cabdff1aSopenharmony_ci ipvideo_decode_block_opcode_0x4, ipvideo_decode_block_opcode_0x5, 902cabdff1aSopenharmony_ci ipvideo_decode_block_opcode_0x6, ipvideo_decode_block_opcode_0x7, 903cabdff1aSopenharmony_ci ipvideo_decode_block_opcode_0x8, ipvideo_decode_block_opcode_0x9, 904cabdff1aSopenharmony_ci ipvideo_decode_block_opcode_0xA, ipvideo_decode_block_opcode_0xB, 905cabdff1aSopenharmony_ci ipvideo_decode_block_opcode_0xC, ipvideo_decode_block_opcode_0xD, 906cabdff1aSopenharmony_ci ipvideo_decode_block_opcode_0xE, ipvideo_decode_block_opcode_0xF, 907cabdff1aSopenharmony_ci}; 908cabdff1aSopenharmony_ci 909cabdff1aSopenharmony_cistatic int (* const ipvideo_decode_block16[])(IpvideoContext *s, AVFrame *frame) = { 910cabdff1aSopenharmony_ci ipvideo_decode_block_opcode_0x0, ipvideo_decode_block_opcode_0x1, 911cabdff1aSopenharmony_ci ipvideo_decode_block_opcode_0x2, ipvideo_decode_block_opcode_0x3, 912cabdff1aSopenharmony_ci ipvideo_decode_block_opcode_0x4, ipvideo_decode_block_opcode_0x5, 913cabdff1aSopenharmony_ci ipvideo_decode_block_opcode_0x6_16, ipvideo_decode_block_opcode_0x7_16, 914cabdff1aSopenharmony_ci ipvideo_decode_block_opcode_0x8_16, ipvideo_decode_block_opcode_0x9_16, 915cabdff1aSopenharmony_ci ipvideo_decode_block_opcode_0xA_16, ipvideo_decode_block_opcode_0xB_16, 916cabdff1aSopenharmony_ci ipvideo_decode_block_opcode_0xC_16, ipvideo_decode_block_opcode_0xD_16, 917cabdff1aSopenharmony_ci ipvideo_decode_block_opcode_0xE_16, ipvideo_decode_block_opcode_0x1, 918cabdff1aSopenharmony_ci}; 919cabdff1aSopenharmony_ci 920cabdff1aSopenharmony_cistatic void ipvideo_format_06_firstpass(IpvideoContext *s, AVFrame *frame, int16_t opcode) 921cabdff1aSopenharmony_ci{ 922cabdff1aSopenharmony_ci int line; 923cabdff1aSopenharmony_ci 924cabdff1aSopenharmony_ci if (!opcode) { 925cabdff1aSopenharmony_ci for (line = 0; line < 8; ++line) { 926cabdff1aSopenharmony_ci bytestream2_get_buffer(&s->stream_ptr, s->pixel_ptr, 8); 927cabdff1aSopenharmony_ci s->pixel_ptr += s->stride; 928cabdff1aSopenharmony_ci } 929cabdff1aSopenharmony_ci } else { 930cabdff1aSopenharmony_ci /* Don't try to copy second_last_frame data on the first frames */ 931cabdff1aSopenharmony_ci if (s->avctx->frame_number > 2) 932cabdff1aSopenharmony_ci copy_from(s, s->second_last_frame, frame, 0, 0); 933cabdff1aSopenharmony_ci } 934cabdff1aSopenharmony_ci} 935cabdff1aSopenharmony_ci 936cabdff1aSopenharmony_cistatic void ipvideo_format_06_secondpass(IpvideoContext *s, AVFrame *frame, int16_t opcode) 937cabdff1aSopenharmony_ci{ 938cabdff1aSopenharmony_ci int off_x, off_y; 939cabdff1aSopenharmony_ci 940cabdff1aSopenharmony_ci if (opcode < 0) { 941cabdff1aSopenharmony_ci off_x = ((uint16_t)opcode - 0xC000) % frame->width; 942cabdff1aSopenharmony_ci off_y = ((uint16_t)opcode - 0xC000) / frame->width; 943cabdff1aSopenharmony_ci copy_from(s, s->last_frame, frame, off_x, off_y); 944cabdff1aSopenharmony_ci } else if (opcode > 0) { 945cabdff1aSopenharmony_ci off_x = ((uint16_t)opcode - 0x4000) % frame->width; 946cabdff1aSopenharmony_ci off_y = ((uint16_t)opcode - 0x4000) / frame->width; 947cabdff1aSopenharmony_ci copy_from(s, frame, frame, off_x, off_y); 948cabdff1aSopenharmony_ci } 949cabdff1aSopenharmony_ci} 950cabdff1aSopenharmony_ci 951cabdff1aSopenharmony_cistatic void (* const ipvideo_format_06_passes[])(IpvideoContext *s, AVFrame *frame, int16_t op) = { 952cabdff1aSopenharmony_ci ipvideo_format_06_firstpass, ipvideo_format_06_secondpass, 953cabdff1aSopenharmony_ci}; 954cabdff1aSopenharmony_ci 955cabdff1aSopenharmony_cistatic void ipvideo_decode_format_06_opcodes(IpvideoContext *s, AVFrame *frame) 956cabdff1aSopenharmony_ci{ 957cabdff1aSopenharmony_ci int pass, x, y; 958cabdff1aSopenharmony_ci int16_t opcode; 959cabdff1aSopenharmony_ci GetByteContext decoding_map_ptr; 960cabdff1aSopenharmony_ci 961cabdff1aSopenharmony_ci /* this is PAL8, so make the palette available */ 962cabdff1aSopenharmony_ci memcpy(frame->data[1], s->pal, AVPALETTE_SIZE); 963cabdff1aSopenharmony_ci s->stride = frame->linesize[0]; 964cabdff1aSopenharmony_ci 965cabdff1aSopenharmony_ci s->line_inc = s->stride - 8; 966cabdff1aSopenharmony_ci s->upper_motion_limit_offset = (s->avctx->height - 8) * frame->linesize[0] 967cabdff1aSopenharmony_ci + (s->avctx->width - 8) * (1 + s->is_16bpp); 968cabdff1aSopenharmony_ci 969cabdff1aSopenharmony_ci bytestream2_init(&decoding_map_ptr, s->decoding_map, s->decoding_map_size); 970cabdff1aSopenharmony_ci 971cabdff1aSopenharmony_ci for (pass = 0; pass < 2; ++pass) { 972cabdff1aSopenharmony_ci bytestream2_seek(&decoding_map_ptr, 0, SEEK_SET); 973cabdff1aSopenharmony_ci for (y = 0; y < s->avctx->height; y += 8) { 974cabdff1aSopenharmony_ci for (x = 0; x < s->avctx->width; x += 8) { 975cabdff1aSopenharmony_ci opcode = bytestream2_get_le16(&decoding_map_ptr); 976cabdff1aSopenharmony_ci 977cabdff1aSopenharmony_ci ff_tlog(s->avctx, 978cabdff1aSopenharmony_ci " block @ (%3d, %3d): opcode 0x%X, data ptr offset %d\n", 979cabdff1aSopenharmony_ci x, y, opcode, bytestream2_tell(&s->stream_ptr)); 980cabdff1aSopenharmony_ci 981cabdff1aSopenharmony_ci s->pixel_ptr = frame->data[0] + x + y * frame->linesize[0]; 982cabdff1aSopenharmony_ci ipvideo_format_06_passes[pass](s, frame, opcode); 983cabdff1aSopenharmony_ci } 984cabdff1aSopenharmony_ci } 985cabdff1aSopenharmony_ci } 986cabdff1aSopenharmony_ci 987cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&s->stream_ptr) > 1) { 988cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_DEBUG, 989cabdff1aSopenharmony_ci "decode finished with %d bytes left over\n", 990cabdff1aSopenharmony_ci bytestream2_get_bytes_left(&s->stream_ptr)); 991cabdff1aSopenharmony_ci } 992cabdff1aSopenharmony_ci} 993cabdff1aSopenharmony_ci 994cabdff1aSopenharmony_cistatic void ipvideo_format_10_firstpass(IpvideoContext *s, AVFrame *frame, int16_t opcode) 995cabdff1aSopenharmony_ci{ 996cabdff1aSopenharmony_ci int line; 997cabdff1aSopenharmony_ci 998cabdff1aSopenharmony_ci if (!opcode) { 999cabdff1aSopenharmony_ci for (line = 0; line < 8; ++line) { 1000cabdff1aSopenharmony_ci bytestream2_get_buffer(&s->stream_ptr, s->pixel_ptr, 8); 1001cabdff1aSopenharmony_ci s->pixel_ptr += s->stride; 1002cabdff1aSopenharmony_ci } 1003cabdff1aSopenharmony_ci } 1004cabdff1aSopenharmony_ci} 1005cabdff1aSopenharmony_ci 1006cabdff1aSopenharmony_cistatic void ipvideo_format_10_secondpass(IpvideoContext *s, AVFrame *frame, int16_t opcode) 1007cabdff1aSopenharmony_ci{ 1008cabdff1aSopenharmony_ci int off_x, off_y; 1009cabdff1aSopenharmony_ci 1010cabdff1aSopenharmony_ci if (opcode < 0) { 1011cabdff1aSopenharmony_ci off_x = ((uint16_t)opcode - 0xC000) % s->cur_decode_frame->width; 1012cabdff1aSopenharmony_ci off_y = ((uint16_t)opcode - 0xC000) / s->cur_decode_frame->width; 1013cabdff1aSopenharmony_ci copy_from(s, s->prev_decode_frame, s->cur_decode_frame, off_x, off_y); 1014cabdff1aSopenharmony_ci } else if (opcode > 0) { 1015cabdff1aSopenharmony_ci off_x = ((uint16_t)opcode - 0x4000) % s->cur_decode_frame->width; 1016cabdff1aSopenharmony_ci off_y = ((uint16_t)opcode - 0x4000) / s->cur_decode_frame->width; 1017cabdff1aSopenharmony_ci copy_from(s, s->cur_decode_frame, s->cur_decode_frame, off_x, off_y); 1018cabdff1aSopenharmony_ci } 1019cabdff1aSopenharmony_ci} 1020cabdff1aSopenharmony_ci 1021cabdff1aSopenharmony_cistatic void (* const ipvideo_format_10_passes[])(IpvideoContext *s, AVFrame *frame, int16_t op) = { 1022cabdff1aSopenharmony_ci ipvideo_format_10_firstpass, ipvideo_format_10_secondpass, 1023cabdff1aSopenharmony_ci}; 1024cabdff1aSopenharmony_ci 1025cabdff1aSopenharmony_cistatic void ipvideo_decode_format_10_opcodes(IpvideoContext *s, AVFrame *frame) 1026cabdff1aSopenharmony_ci{ 1027cabdff1aSopenharmony_ci int pass, x, y, changed_block; 1028cabdff1aSopenharmony_ci int16_t opcode, skip; 1029cabdff1aSopenharmony_ci GetByteContext decoding_map_ptr; 1030cabdff1aSopenharmony_ci GetByteContext skip_map_ptr; 1031cabdff1aSopenharmony_ci 1032cabdff1aSopenharmony_ci bytestream2_skip(&s->stream_ptr, 14); /* data starts 14 bytes in */ 1033cabdff1aSopenharmony_ci 1034cabdff1aSopenharmony_ci /* this is PAL8, so make the palette available */ 1035cabdff1aSopenharmony_ci memcpy(frame->data[1], s->pal, AVPALETTE_SIZE); 1036cabdff1aSopenharmony_ci s->stride = frame->linesize[0]; 1037cabdff1aSopenharmony_ci 1038cabdff1aSopenharmony_ci s->line_inc = s->stride - 8; 1039cabdff1aSopenharmony_ci s->upper_motion_limit_offset = (s->avctx->height - 8) * frame->linesize[0] 1040cabdff1aSopenharmony_ci + (s->avctx->width - 8) * (1 + s->is_16bpp); 1041cabdff1aSopenharmony_ci 1042cabdff1aSopenharmony_ci bytestream2_init(&decoding_map_ptr, s->decoding_map, s->decoding_map_size); 1043cabdff1aSopenharmony_ci bytestream2_init(&skip_map_ptr, s->skip_map, s->skip_map_size); 1044cabdff1aSopenharmony_ci 1045cabdff1aSopenharmony_ci for (pass = 0; pass < 2; ++pass) { 1046cabdff1aSopenharmony_ci bytestream2_seek(&decoding_map_ptr, 0, SEEK_SET); 1047cabdff1aSopenharmony_ci bytestream2_seek(&skip_map_ptr, 0, SEEK_SET); 1048cabdff1aSopenharmony_ci skip = bytestream2_get_le16(&skip_map_ptr); 1049cabdff1aSopenharmony_ci 1050cabdff1aSopenharmony_ci for (y = 0; y < s->avctx->height; y += 8) { 1051cabdff1aSopenharmony_ci for (x = 0; x < s->avctx->width; x += 8) { 1052cabdff1aSopenharmony_ci s->pixel_ptr = s->cur_decode_frame->data[0] + x + y * s->cur_decode_frame->linesize[0]; 1053cabdff1aSopenharmony_ci 1054cabdff1aSopenharmony_ci while (skip <= 0) { 1055cabdff1aSopenharmony_ci if (skip != -0x8000 && skip) { 1056cabdff1aSopenharmony_ci opcode = bytestream2_get_le16(&decoding_map_ptr); 1057cabdff1aSopenharmony_ci ipvideo_format_10_passes[pass](s, frame, opcode); 1058cabdff1aSopenharmony_ci break; 1059cabdff1aSopenharmony_ci } 1060cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&skip_map_ptr) < 2) 1061cabdff1aSopenharmony_ci return; 1062cabdff1aSopenharmony_ci skip = bytestream2_get_le16(&skip_map_ptr); 1063cabdff1aSopenharmony_ci } 1064cabdff1aSopenharmony_ci skip *= 2; 1065cabdff1aSopenharmony_ci } 1066cabdff1aSopenharmony_ci } 1067cabdff1aSopenharmony_ci } 1068cabdff1aSopenharmony_ci 1069cabdff1aSopenharmony_ci bytestream2_seek(&skip_map_ptr, 0, SEEK_SET); 1070cabdff1aSopenharmony_ci skip = bytestream2_get_le16(&skip_map_ptr); 1071cabdff1aSopenharmony_ci for (y = 0; y < s->avctx->height; y += 8) { 1072cabdff1aSopenharmony_ci for (x = 0; x < s->avctx->width; x += 8) { 1073cabdff1aSopenharmony_ci changed_block = 0; 1074cabdff1aSopenharmony_ci s->pixel_ptr = frame->data[0] + x + y*frame->linesize[0]; 1075cabdff1aSopenharmony_ci 1076cabdff1aSopenharmony_ci while (skip <= 0) { 1077cabdff1aSopenharmony_ci if (skip != -0x8000 && skip) { 1078cabdff1aSopenharmony_ci changed_block = 1; 1079cabdff1aSopenharmony_ci break; 1080cabdff1aSopenharmony_ci } 1081cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&skip_map_ptr) < 2) 1082cabdff1aSopenharmony_ci return; 1083cabdff1aSopenharmony_ci skip = bytestream2_get_le16(&skip_map_ptr); 1084cabdff1aSopenharmony_ci } 1085cabdff1aSopenharmony_ci 1086cabdff1aSopenharmony_ci if (changed_block) { 1087cabdff1aSopenharmony_ci copy_from(s, s->cur_decode_frame, frame, 0, 0); 1088cabdff1aSopenharmony_ci } else { 1089cabdff1aSopenharmony_ci /* Don't try to copy last_frame data on the first frame */ 1090cabdff1aSopenharmony_ci if (s->avctx->frame_number) 1091cabdff1aSopenharmony_ci copy_from(s, s->last_frame, frame, 0, 0); 1092cabdff1aSopenharmony_ci } 1093cabdff1aSopenharmony_ci skip *= 2; 1094cabdff1aSopenharmony_ci } 1095cabdff1aSopenharmony_ci } 1096cabdff1aSopenharmony_ci 1097cabdff1aSopenharmony_ci FFSWAP(AVFrame*, s->prev_decode_frame, s->cur_decode_frame); 1098cabdff1aSopenharmony_ci 1099cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&s->stream_ptr) > 1) { 1100cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_DEBUG, 1101cabdff1aSopenharmony_ci "decode finished with %d bytes left over\n", 1102cabdff1aSopenharmony_ci bytestream2_get_bytes_left(&s->stream_ptr)); 1103cabdff1aSopenharmony_ci } 1104cabdff1aSopenharmony_ci} 1105cabdff1aSopenharmony_ci 1106cabdff1aSopenharmony_cistatic void ipvideo_decode_format_11_opcodes(IpvideoContext *s, AVFrame *frame) 1107cabdff1aSopenharmony_ci{ 1108cabdff1aSopenharmony_ci int x, y; 1109cabdff1aSopenharmony_ci unsigned char opcode; 1110cabdff1aSopenharmony_ci int ret; 1111cabdff1aSopenharmony_ci GetBitContext gb; 1112cabdff1aSopenharmony_ci 1113cabdff1aSopenharmony_ci bytestream2_skip(&s->stream_ptr, 14); /* data starts 14 bytes in */ 1114cabdff1aSopenharmony_ci if (!s->is_16bpp) { 1115cabdff1aSopenharmony_ci /* this is PAL8, so make the palette available */ 1116cabdff1aSopenharmony_ci memcpy(frame->data[1], s->pal, AVPALETTE_SIZE); 1117cabdff1aSopenharmony_ci 1118cabdff1aSopenharmony_ci s->stride = frame->linesize[0]; 1119cabdff1aSopenharmony_ci } else { 1120cabdff1aSopenharmony_ci s->stride = frame->linesize[0] >> 1; 1121cabdff1aSopenharmony_ci s->mv_ptr = s->stream_ptr; 1122cabdff1aSopenharmony_ci bytestream2_skip(&s->mv_ptr, bytestream2_get_le16(&s->stream_ptr)); 1123cabdff1aSopenharmony_ci } 1124cabdff1aSopenharmony_ci s->line_inc = s->stride - 8; 1125cabdff1aSopenharmony_ci s->upper_motion_limit_offset = (s->avctx->height - 8) * frame->linesize[0] 1126cabdff1aSopenharmony_ci + (s->avctx->width - 8) * (1 + s->is_16bpp); 1127cabdff1aSopenharmony_ci 1128cabdff1aSopenharmony_ci init_get_bits(&gb, s->decoding_map, s->decoding_map_size * 8); 1129cabdff1aSopenharmony_ci for (y = 0; y < s->avctx->height; y += 8) { 1130cabdff1aSopenharmony_ci for (x = 0; x < s->avctx->width; x += 8) { 1131cabdff1aSopenharmony_ci if (get_bits_left(&gb) < 4) 1132cabdff1aSopenharmony_ci return; 1133cabdff1aSopenharmony_ci opcode = get_bits(&gb, 4); 1134cabdff1aSopenharmony_ci 1135cabdff1aSopenharmony_ci ff_tlog(s->avctx, 1136cabdff1aSopenharmony_ci " block @ (%3d, %3d): encoding 0x%X, data ptr offset %d\n", 1137cabdff1aSopenharmony_ci x, y, opcode, bytestream2_tell(&s->stream_ptr)); 1138cabdff1aSopenharmony_ci 1139cabdff1aSopenharmony_ci if (!s->is_16bpp) { 1140cabdff1aSopenharmony_ci s->pixel_ptr = frame->data[0] + x 1141cabdff1aSopenharmony_ci + y*frame->linesize[0]; 1142cabdff1aSopenharmony_ci ret = ipvideo_decode_block[opcode](s, frame); 1143cabdff1aSopenharmony_ci } else { 1144cabdff1aSopenharmony_ci s->pixel_ptr = frame->data[0] + x*2 1145cabdff1aSopenharmony_ci + y*frame->linesize[0]; 1146cabdff1aSopenharmony_ci ret = ipvideo_decode_block16[opcode](s, frame); 1147cabdff1aSopenharmony_ci } 1148cabdff1aSopenharmony_ci if (ret != 0) { 1149cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "decode problem on frame %d, @ block (%d, %d)\n", 1150cabdff1aSopenharmony_ci s->avctx->frame_number, x, y); 1151cabdff1aSopenharmony_ci return; 1152cabdff1aSopenharmony_ci } 1153cabdff1aSopenharmony_ci } 1154cabdff1aSopenharmony_ci } 1155cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&s->stream_ptr) > 1) { 1156cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_DEBUG, 1157cabdff1aSopenharmony_ci "decode finished with %d bytes left over\n", 1158cabdff1aSopenharmony_ci bytestream2_get_bytes_left(&s->stream_ptr)); 1159cabdff1aSopenharmony_ci } 1160cabdff1aSopenharmony_ci} 1161cabdff1aSopenharmony_ci 1162cabdff1aSopenharmony_cistatic av_cold int ipvideo_decode_init(AVCodecContext *avctx) 1163cabdff1aSopenharmony_ci{ 1164cabdff1aSopenharmony_ci IpvideoContext *s = avctx->priv_data; 1165cabdff1aSopenharmony_ci 1166cabdff1aSopenharmony_ci s->avctx = avctx; 1167cabdff1aSopenharmony_ci 1168cabdff1aSopenharmony_ci s->is_16bpp = avctx->bits_per_coded_sample == 16; 1169cabdff1aSopenharmony_ci avctx->pix_fmt = s->is_16bpp ? AV_PIX_FMT_RGB555 : AV_PIX_FMT_PAL8; 1170cabdff1aSopenharmony_ci 1171cabdff1aSopenharmony_ci ff_hpeldsp_init(&s->hdsp, avctx->flags); 1172cabdff1aSopenharmony_ci 1173cabdff1aSopenharmony_ci s->last_frame = av_frame_alloc(); 1174cabdff1aSopenharmony_ci s->second_last_frame = av_frame_alloc(); 1175cabdff1aSopenharmony_ci s->cur_decode_frame = av_frame_alloc(); 1176cabdff1aSopenharmony_ci s->prev_decode_frame = av_frame_alloc(); 1177cabdff1aSopenharmony_ci if (!s->last_frame || !s->second_last_frame || 1178cabdff1aSopenharmony_ci !s->cur_decode_frame || !s->prev_decode_frame) { 1179cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 1180cabdff1aSopenharmony_ci } 1181cabdff1aSopenharmony_ci 1182cabdff1aSopenharmony_ci s->cur_decode_frame->width = avctx->width; 1183cabdff1aSopenharmony_ci s->prev_decode_frame->width = avctx->width; 1184cabdff1aSopenharmony_ci s->cur_decode_frame->height = avctx->height; 1185cabdff1aSopenharmony_ci s->prev_decode_frame->height = avctx->height; 1186cabdff1aSopenharmony_ci s->cur_decode_frame->format = avctx->pix_fmt; 1187cabdff1aSopenharmony_ci s->prev_decode_frame->format = avctx->pix_fmt; 1188cabdff1aSopenharmony_ci 1189cabdff1aSopenharmony_ci return 0; 1190cabdff1aSopenharmony_ci} 1191cabdff1aSopenharmony_ci 1192cabdff1aSopenharmony_cistatic int ipvideo_decode_frame(AVCodecContext *avctx, AVFrame *frame, 1193cabdff1aSopenharmony_ci int *got_frame, AVPacket *avpkt) 1194cabdff1aSopenharmony_ci{ 1195cabdff1aSopenharmony_ci const uint8_t *buf = avpkt->data; 1196cabdff1aSopenharmony_ci int buf_size = avpkt->size; 1197cabdff1aSopenharmony_ci IpvideoContext *s = avctx->priv_data; 1198cabdff1aSopenharmony_ci int ret; 1199cabdff1aSopenharmony_ci int send_buffer; 1200cabdff1aSopenharmony_ci int frame_format; 1201cabdff1aSopenharmony_ci int video_data_size; 1202cabdff1aSopenharmony_ci 1203cabdff1aSopenharmony_ci if (av_packet_get_side_data(avpkt, AV_PKT_DATA_PARAM_CHANGE, NULL)) { 1204cabdff1aSopenharmony_ci av_frame_unref(s->last_frame); 1205cabdff1aSopenharmony_ci av_frame_unref(s->second_last_frame); 1206cabdff1aSopenharmony_ci av_frame_unref(s->cur_decode_frame); 1207cabdff1aSopenharmony_ci av_frame_unref(s->prev_decode_frame); 1208cabdff1aSopenharmony_ci } 1209cabdff1aSopenharmony_ci 1210cabdff1aSopenharmony_ci if (!s->cur_decode_frame->data[0]) { 1211cabdff1aSopenharmony_ci ret = ff_get_buffer(avctx, s->cur_decode_frame, 0); 1212cabdff1aSopenharmony_ci if (ret < 0) 1213cabdff1aSopenharmony_ci return ret; 1214cabdff1aSopenharmony_ci 1215cabdff1aSopenharmony_ci ret = ff_get_buffer(avctx, s->prev_decode_frame, 0); 1216cabdff1aSopenharmony_ci if (ret < 0) { 1217cabdff1aSopenharmony_ci av_frame_unref(s->cur_decode_frame); 1218cabdff1aSopenharmony_ci return ret; 1219cabdff1aSopenharmony_ci } 1220cabdff1aSopenharmony_ci } 1221cabdff1aSopenharmony_ci 1222cabdff1aSopenharmony_ci if (buf_size < 8) 1223cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1224cabdff1aSopenharmony_ci 1225cabdff1aSopenharmony_ci frame_format = AV_RL8(buf); 1226cabdff1aSopenharmony_ci send_buffer = AV_RL8(buf + 1); 1227cabdff1aSopenharmony_ci video_data_size = AV_RL16(buf + 2); 1228cabdff1aSopenharmony_ci s->decoding_map_size = AV_RL16(buf + 4); 1229cabdff1aSopenharmony_ci s->skip_map_size = AV_RL16(buf + 6); 1230cabdff1aSopenharmony_ci 1231cabdff1aSopenharmony_ci switch (frame_format) { 1232cabdff1aSopenharmony_ci case 0x06: 1233cabdff1aSopenharmony_ci if (s->decoding_map_size) { 1234cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Decoding map for format 0x06\n"); 1235cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1236cabdff1aSopenharmony_ci } 1237cabdff1aSopenharmony_ci 1238cabdff1aSopenharmony_ci if (s->skip_map_size) { 1239cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Skip map for format 0x06\n"); 1240cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1241cabdff1aSopenharmony_ci } 1242cabdff1aSopenharmony_ci 1243cabdff1aSopenharmony_ci if (s->is_16bpp) { 1244cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Video format 0x06 does not support 16bpp movies\n"); 1245cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1246cabdff1aSopenharmony_ci } 1247cabdff1aSopenharmony_ci 1248cabdff1aSopenharmony_ci /* Decoding map for 0x06 frame format is at the top of pixeldata */ 1249cabdff1aSopenharmony_ci s->decoding_map_size = ((s->avctx->width / 8) * (s->avctx->height / 8)) * 2; 1250cabdff1aSopenharmony_ci s->decoding_map = buf + 8 + 14; /* 14 bits of op data */ 1251cabdff1aSopenharmony_ci video_data_size -= s->decoding_map_size + 14; 1252cabdff1aSopenharmony_ci if (video_data_size <= 0 || s->decoding_map_size == 0) 1253cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1254cabdff1aSopenharmony_ci 1255cabdff1aSopenharmony_ci if (buf_size < 8 + s->decoding_map_size + 14 + video_data_size) 1256cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1257cabdff1aSopenharmony_ci 1258cabdff1aSopenharmony_ci bytestream2_init(&s->stream_ptr, buf + 8 + s->decoding_map_size + 14, video_data_size); 1259cabdff1aSopenharmony_ci 1260cabdff1aSopenharmony_ci break; 1261cabdff1aSopenharmony_ci 1262cabdff1aSopenharmony_ci case 0x10: 1263cabdff1aSopenharmony_ci if (! s->decoding_map_size) { 1264cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Empty decoding map for format 0x10\n"); 1265cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1266cabdff1aSopenharmony_ci } 1267cabdff1aSopenharmony_ci 1268cabdff1aSopenharmony_ci if (! s->skip_map_size) { 1269cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Empty skip map for format 0x10\n"); 1270cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1271cabdff1aSopenharmony_ci } 1272cabdff1aSopenharmony_ci 1273cabdff1aSopenharmony_ci if (s->is_16bpp) { 1274cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Video format 0x10 does not support 16bpp movies\n"); 1275cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1276cabdff1aSopenharmony_ci } 1277cabdff1aSopenharmony_ci 1278cabdff1aSopenharmony_ci if (buf_size < 8 + video_data_size + s->decoding_map_size + s->skip_map_size) 1279cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1280cabdff1aSopenharmony_ci 1281cabdff1aSopenharmony_ci bytestream2_init(&s->stream_ptr, buf + 8, video_data_size); 1282cabdff1aSopenharmony_ci s->decoding_map = buf + 8 + video_data_size; 1283cabdff1aSopenharmony_ci s->skip_map = buf + 8 + video_data_size + s->decoding_map_size; 1284cabdff1aSopenharmony_ci 1285cabdff1aSopenharmony_ci break; 1286cabdff1aSopenharmony_ci 1287cabdff1aSopenharmony_ci case 0x11: 1288cabdff1aSopenharmony_ci if (! s->decoding_map_size) { 1289cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Empty decoding map for format 0x11\n"); 1290cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1291cabdff1aSopenharmony_ci } 1292cabdff1aSopenharmony_ci 1293cabdff1aSopenharmony_ci if (s->skip_map_size) { 1294cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Skip map for format 0x11\n"); 1295cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1296cabdff1aSopenharmony_ci } 1297cabdff1aSopenharmony_ci 1298cabdff1aSopenharmony_ci if (buf_size < 8 + video_data_size + s->decoding_map_size) 1299cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1300cabdff1aSopenharmony_ci 1301cabdff1aSopenharmony_ci bytestream2_init(&s->stream_ptr, buf + 8, video_data_size); 1302cabdff1aSopenharmony_ci s->decoding_map = buf + 8 + video_data_size; 1303cabdff1aSopenharmony_ci 1304cabdff1aSopenharmony_ci break; 1305cabdff1aSopenharmony_ci 1306cabdff1aSopenharmony_ci default: 1307cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Frame type 0x%02X unsupported\n", frame_format); 1308cabdff1aSopenharmony_ci } 1309cabdff1aSopenharmony_ci 1310cabdff1aSopenharmony_ci /* ensure we can't overread the packet */ 1311cabdff1aSopenharmony_ci if (buf_size < 8 + s->decoding_map_size + video_data_size + s->skip_map_size) { 1312cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Invalid IP packet size\n"); 1313cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1314cabdff1aSopenharmony_ci } 1315cabdff1aSopenharmony_ci 1316cabdff1aSopenharmony_ci if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0) 1317cabdff1aSopenharmony_ci return ret; 1318cabdff1aSopenharmony_ci 1319cabdff1aSopenharmony_ci if (!s->is_16bpp) { 1320cabdff1aSopenharmony_ci frame->palette_has_changed = ff_copy_palette(s->pal, avpkt, avctx); 1321cabdff1aSopenharmony_ci } 1322cabdff1aSopenharmony_ci 1323cabdff1aSopenharmony_ci switch (frame_format) { 1324cabdff1aSopenharmony_ci case 0x06: 1325cabdff1aSopenharmony_ci ipvideo_decode_format_06_opcodes(s, frame); 1326cabdff1aSopenharmony_ci break; 1327cabdff1aSopenharmony_ci case 0x10: 1328cabdff1aSopenharmony_ci ipvideo_decode_format_10_opcodes(s, frame); 1329cabdff1aSopenharmony_ci break; 1330cabdff1aSopenharmony_ci case 0x11: 1331cabdff1aSopenharmony_ci ipvideo_decode_format_11_opcodes(s, frame); 1332cabdff1aSopenharmony_ci break; 1333cabdff1aSopenharmony_ci } 1334cabdff1aSopenharmony_ci 1335cabdff1aSopenharmony_ci *got_frame = send_buffer; 1336cabdff1aSopenharmony_ci 1337cabdff1aSopenharmony_ci /* shuffle frames */ 1338cabdff1aSopenharmony_ci av_frame_unref(s->second_last_frame); 1339cabdff1aSopenharmony_ci FFSWAP(AVFrame*, s->second_last_frame, s->last_frame); 1340cabdff1aSopenharmony_ci if ((ret = av_frame_ref(s->last_frame, frame)) < 0) 1341cabdff1aSopenharmony_ci return ret; 1342cabdff1aSopenharmony_ci 1343cabdff1aSopenharmony_ci /* report that the buffer was completely consumed */ 1344cabdff1aSopenharmony_ci return buf_size; 1345cabdff1aSopenharmony_ci} 1346cabdff1aSopenharmony_ci 1347cabdff1aSopenharmony_cistatic av_cold int ipvideo_decode_end(AVCodecContext *avctx) 1348cabdff1aSopenharmony_ci{ 1349cabdff1aSopenharmony_ci IpvideoContext *s = avctx->priv_data; 1350cabdff1aSopenharmony_ci 1351cabdff1aSopenharmony_ci av_frame_free(&s->last_frame); 1352cabdff1aSopenharmony_ci av_frame_free(&s->second_last_frame); 1353cabdff1aSopenharmony_ci av_frame_free(&s->cur_decode_frame); 1354cabdff1aSopenharmony_ci av_frame_free(&s->prev_decode_frame); 1355cabdff1aSopenharmony_ci 1356cabdff1aSopenharmony_ci return 0; 1357cabdff1aSopenharmony_ci} 1358cabdff1aSopenharmony_ci 1359cabdff1aSopenharmony_ciconst FFCodec ff_interplay_video_decoder = { 1360cabdff1aSopenharmony_ci .p.name = "interplayvideo", 1361cabdff1aSopenharmony_ci .p.long_name = NULL_IF_CONFIG_SMALL("Interplay MVE video"), 1362cabdff1aSopenharmony_ci .p.type = AVMEDIA_TYPE_VIDEO, 1363cabdff1aSopenharmony_ci .p.id = AV_CODEC_ID_INTERPLAY_VIDEO, 1364cabdff1aSopenharmony_ci .priv_data_size = sizeof(IpvideoContext), 1365cabdff1aSopenharmony_ci .init = ipvideo_decode_init, 1366cabdff1aSopenharmony_ci .close = ipvideo_decode_end, 1367cabdff1aSopenharmony_ci FF_CODEC_DECODE_CB(ipvideo_decode_frame), 1368cabdff1aSopenharmony_ci .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_PARAM_CHANGE, 1369cabdff1aSopenharmony_ci .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, 1370cabdff1aSopenharmony_ci}; 1371