1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Cryo Interactive Entertainment HNM4 video decoder 3cabdff1aSopenharmony_ci * 4cabdff1aSopenharmony_ci * Copyright (c) 2012 David Kment 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 <string.h> 24cabdff1aSopenharmony_ci 25cabdff1aSopenharmony_ci#include "libavutil/imgutils.h" 26cabdff1aSopenharmony_ci#include "libavutil/internal.h" 27cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h" 28cabdff1aSopenharmony_ci#include "libavutil/mem.h" 29cabdff1aSopenharmony_ci#include "avcodec.h" 30cabdff1aSopenharmony_ci#include "bytestream.h" 31cabdff1aSopenharmony_ci#include "codec_internal.h" 32cabdff1aSopenharmony_ci#include "internal.h" 33cabdff1aSopenharmony_ci 34cabdff1aSopenharmony_ci#define HNM4_CHUNK_ID_PL 19536 35cabdff1aSopenharmony_ci#define HNM4_CHUNK_ID_IZ 23113 36cabdff1aSopenharmony_ci#define HNM4_CHUNK_ID_IU 21833 37cabdff1aSopenharmony_ci#define HNM4_CHUNK_ID_SD 17491 38cabdff1aSopenharmony_ci 39cabdff1aSopenharmony_citypedef struct Hnm4VideoContext { 40cabdff1aSopenharmony_ci uint8_t version; 41cabdff1aSopenharmony_ci int width; 42cabdff1aSopenharmony_ci int height; 43cabdff1aSopenharmony_ci uint8_t *current; 44cabdff1aSopenharmony_ci uint8_t *previous; 45cabdff1aSopenharmony_ci uint8_t *buffer1; 46cabdff1aSopenharmony_ci uint8_t *buffer2; 47cabdff1aSopenharmony_ci uint8_t *processed; 48cabdff1aSopenharmony_ci uint32_t palette[256]; 49cabdff1aSopenharmony_ci} Hnm4VideoContext; 50cabdff1aSopenharmony_ci 51cabdff1aSopenharmony_cistatic int getbit(GetByteContext *gb, uint32_t *bitbuf, int *bits) 52cabdff1aSopenharmony_ci{ 53cabdff1aSopenharmony_ci int ret; 54cabdff1aSopenharmony_ci 55cabdff1aSopenharmony_ci if (!*bits) { 56cabdff1aSopenharmony_ci *bitbuf = bytestream2_get_le32(gb); 57cabdff1aSopenharmony_ci *bits = 32; 58cabdff1aSopenharmony_ci } 59cabdff1aSopenharmony_ci 60cabdff1aSopenharmony_ci ret = *bitbuf >> 31; 61cabdff1aSopenharmony_ci *bitbuf <<= 1; 62cabdff1aSopenharmony_ci (*bits)--; 63cabdff1aSopenharmony_ci 64cabdff1aSopenharmony_ci return ret; 65cabdff1aSopenharmony_ci} 66cabdff1aSopenharmony_ci 67cabdff1aSopenharmony_cistatic void unpack_intraframe(AVCodecContext *avctx, const uint8_t *src, 68cabdff1aSopenharmony_ci uint32_t size) 69cabdff1aSopenharmony_ci{ 70cabdff1aSopenharmony_ci Hnm4VideoContext *hnm = avctx->priv_data; 71cabdff1aSopenharmony_ci GetByteContext gb; 72cabdff1aSopenharmony_ci uint32_t bitbuf = 0, writeoffset = 0, count = 0; 73cabdff1aSopenharmony_ci uint16_t word; 74cabdff1aSopenharmony_ci int32_t offset; 75cabdff1aSopenharmony_ci int bits = 0; 76cabdff1aSopenharmony_ci 77cabdff1aSopenharmony_ci bytestream2_init(&gb, src, size); 78cabdff1aSopenharmony_ci 79cabdff1aSopenharmony_ci while (bytestream2_tell(&gb) < size) { 80cabdff1aSopenharmony_ci if (getbit(&gb, &bitbuf, &bits)) { 81cabdff1aSopenharmony_ci if (writeoffset >= hnm->width * hnm->height) { 82cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, 83cabdff1aSopenharmony_ci "Attempting to write out of bounds\n"); 84cabdff1aSopenharmony_ci break; 85cabdff1aSopenharmony_ci } 86cabdff1aSopenharmony_ci hnm->current[writeoffset++] = bytestream2_get_byte(&gb); 87cabdff1aSopenharmony_ci } else { 88cabdff1aSopenharmony_ci if (getbit(&gb, &bitbuf, &bits)) { 89cabdff1aSopenharmony_ci word = bytestream2_get_le16(&gb); 90cabdff1aSopenharmony_ci count = word & 0x07; 91cabdff1aSopenharmony_ci offset = (word >> 3) - 0x2000; 92cabdff1aSopenharmony_ci if (!count) 93cabdff1aSopenharmony_ci count = bytestream2_get_byte(&gb); 94cabdff1aSopenharmony_ci if (!count) 95cabdff1aSopenharmony_ci return; 96cabdff1aSopenharmony_ci } else { 97cabdff1aSopenharmony_ci count = getbit(&gb, &bitbuf, &bits) * 2; 98cabdff1aSopenharmony_ci count += getbit(&gb, &bitbuf, &bits); 99cabdff1aSopenharmony_ci offset = bytestream2_get_byte(&gb) - 0x0100; 100cabdff1aSopenharmony_ci } 101cabdff1aSopenharmony_ci count += 2; 102cabdff1aSopenharmony_ci offset += writeoffset; 103cabdff1aSopenharmony_ci if (offset < 0 || offset + count >= hnm->width * hnm->height) { 104cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n"); 105cabdff1aSopenharmony_ci break; 106cabdff1aSopenharmony_ci } else if (writeoffset + count >= hnm->width * hnm->height) { 107cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, 108cabdff1aSopenharmony_ci "Attempting to write out of bounds\n"); 109cabdff1aSopenharmony_ci break; 110cabdff1aSopenharmony_ci } 111cabdff1aSopenharmony_ci while (count--) { 112cabdff1aSopenharmony_ci hnm->current[writeoffset++] = hnm->current[offset++]; 113cabdff1aSopenharmony_ci } 114cabdff1aSopenharmony_ci } 115cabdff1aSopenharmony_ci } 116cabdff1aSopenharmony_ci} 117cabdff1aSopenharmony_ci 118cabdff1aSopenharmony_cistatic void postprocess_current_frame(AVCodecContext *avctx) 119cabdff1aSopenharmony_ci{ 120cabdff1aSopenharmony_ci Hnm4VideoContext *hnm = avctx->priv_data; 121cabdff1aSopenharmony_ci uint32_t x, y, src_y; 122cabdff1aSopenharmony_ci int width = hnm->width; 123cabdff1aSopenharmony_ci 124cabdff1aSopenharmony_ci for (y = 0; y < hnm->height; y++) { 125cabdff1aSopenharmony_ci uint8_t *dst = hnm->processed + y * width; 126cabdff1aSopenharmony_ci const uint8_t *src = hnm->current; 127cabdff1aSopenharmony_ci src_y = y - (y % 2); 128cabdff1aSopenharmony_ci src += src_y * width + (y % 2); 129cabdff1aSopenharmony_ci for (x = 0; x < width; x++) { 130cabdff1aSopenharmony_ci dst[x] = *src; 131cabdff1aSopenharmony_ci src += 2; 132cabdff1aSopenharmony_ci } 133cabdff1aSopenharmony_ci } 134cabdff1aSopenharmony_ci} 135cabdff1aSopenharmony_ci 136cabdff1aSopenharmony_cistatic void copy_processed_frame(AVCodecContext *avctx, AVFrame *frame) 137cabdff1aSopenharmony_ci{ 138cabdff1aSopenharmony_ci Hnm4VideoContext *hnm = avctx->priv_data; 139cabdff1aSopenharmony_ci uint8_t *src = hnm->processed; 140cabdff1aSopenharmony_ci uint8_t *dst = frame->data[0]; 141cabdff1aSopenharmony_ci int y; 142cabdff1aSopenharmony_ci 143cabdff1aSopenharmony_ci for (y = 0; y < hnm->height; y++) { 144cabdff1aSopenharmony_ci memcpy(dst, src, hnm->width); 145cabdff1aSopenharmony_ci src += hnm->width; 146cabdff1aSopenharmony_ci dst += frame->linesize[0]; 147cabdff1aSopenharmony_ci } 148cabdff1aSopenharmony_ci} 149cabdff1aSopenharmony_ci 150cabdff1aSopenharmony_cistatic int decode_interframe_v4(AVCodecContext *avctx, const uint8_t *src, uint32_t size) 151cabdff1aSopenharmony_ci{ 152cabdff1aSopenharmony_ci Hnm4VideoContext *hnm = avctx->priv_data; 153cabdff1aSopenharmony_ci GetByteContext gb; 154cabdff1aSopenharmony_ci uint32_t writeoffset = 0; 155cabdff1aSopenharmony_ci int count, left, offset; 156cabdff1aSopenharmony_ci uint8_t tag, previous, backline, backward, swap; 157cabdff1aSopenharmony_ci 158cabdff1aSopenharmony_ci bytestream2_init(&gb, src, size); 159cabdff1aSopenharmony_ci 160cabdff1aSopenharmony_ci while (bytestream2_tell(&gb) < size) { 161cabdff1aSopenharmony_ci count = bytestream2_peek_byte(&gb) & 0x1F; 162cabdff1aSopenharmony_ci if (count == 0) { 163cabdff1aSopenharmony_ci tag = bytestream2_get_byte(&gb) & 0xE0; 164cabdff1aSopenharmony_ci tag = tag >> 5; 165cabdff1aSopenharmony_ci 166cabdff1aSopenharmony_ci if (tag == 0) { 167cabdff1aSopenharmony_ci if (writeoffset + 2 > hnm->width * hnm->height) { 168cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "writeoffset out of bounds\n"); 169cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 170cabdff1aSopenharmony_ci } 171cabdff1aSopenharmony_ci hnm->current[writeoffset++] = bytestream2_get_byte(&gb); 172cabdff1aSopenharmony_ci hnm->current[writeoffset++] = bytestream2_get_byte(&gb); 173cabdff1aSopenharmony_ci } else if (tag == 1) { 174cabdff1aSopenharmony_ci writeoffset += bytestream2_get_byte(&gb) * 2; 175cabdff1aSopenharmony_ci } else if (tag == 2) { 176cabdff1aSopenharmony_ci count = bytestream2_get_le16(&gb); 177cabdff1aSopenharmony_ci count *= 2; 178cabdff1aSopenharmony_ci writeoffset += count; 179cabdff1aSopenharmony_ci } else if (tag == 3) { 180cabdff1aSopenharmony_ci count = bytestream2_get_byte(&gb) * 2; 181cabdff1aSopenharmony_ci if (writeoffset + count > hnm->width * hnm->height) { 182cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "writeoffset out of bounds\n"); 183cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 184cabdff1aSopenharmony_ci } 185cabdff1aSopenharmony_ci while (count > 0) { 186cabdff1aSopenharmony_ci hnm->current[writeoffset++] = bytestream2_peek_byte(&gb); 187cabdff1aSopenharmony_ci count--; 188cabdff1aSopenharmony_ci } 189cabdff1aSopenharmony_ci bytestream2_skip(&gb, 1); 190cabdff1aSopenharmony_ci } else { 191cabdff1aSopenharmony_ci break; 192cabdff1aSopenharmony_ci } 193cabdff1aSopenharmony_ci if (writeoffset > hnm->width * hnm->height) { 194cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "writeoffset out of bounds\n"); 195cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 196cabdff1aSopenharmony_ci } 197cabdff1aSopenharmony_ci } else { 198cabdff1aSopenharmony_ci previous = bytestream2_peek_byte(&gb) & 0x20; 199cabdff1aSopenharmony_ci backline = bytestream2_peek_byte(&gb) & 0x40; 200cabdff1aSopenharmony_ci backward = bytestream2_peek_byte(&gb) & 0x80; 201cabdff1aSopenharmony_ci bytestream2_skip(&gb, 1); 202cabdff1aSopenharmony_ci swap = bytestream2_peek_byte(&gb) & 0x01; 203cabdff1aSopenharmony_ci offset = bytestream2_get_le16(&gb); 204cabdff1aSopenharmony_ci offset = (offset >> 1) & 0x7FFF; 205cabdff1aSopenharmony_ci offset = writeoffset + (offset * 2) - 0x8000; 206cabdff1aSopenharmony_ci 207cabdff1aSopenharmony_ci left = count; 208cabdff1aSopenharmony_ci 209cabdff1aSopenharmony_ci if (!backward && offset + 2*count > hnm->width * hnm->height) { 210cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n"); 211cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 212cabdff1aSopenharmony_ci } else if (backward && offset + 1 >= hnm->width * hnm->height) { 213cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n"); 214cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 215cabdff1aSopenharmony_ci } else if (writeoffset + 2*count > hnm->width * hnm->height) { 216cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, 217cabdff1aSopenharmony_ci "Attempting to write out of bounds\n"); 218cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 219cabdff1aSopenharmony_ci 220cabdff1aSopenharmony_ci } 221cabdff1aSopenharmony_ci if(backward) { 222cabdff1aSopenharmony_ci if (offset < (!!backline)*(2 * hnm->width - 1) + 2*(left-1)) { 223cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n"); 224cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 225cabdff1aSopenharmony_ci } 226cabdff1aSopenharmony_ci } else { 227cabdff1aSopenharmony_ci if (offset < (!!backline)*(2 * hnm->width - 1)) { 228cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n"); 229cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 230cabdff1aSopenharmony_ci } 231cabdff1aSopenharmony_ci } 232cabdff1aSopenharmony_ci 233cabdff1aSopenharmony_ci if (previous) { 234cabdff1aSopenharmony_ci while (left > 0) { 235cabdff1aSopenharmony_ci if (backline) { 236cabdff1aSopenharmony_ci hnm->current[writeoffset++] = hnm->previous[offset - (2 * hnm->width) + 1]; 237cabdff1aSopenharmony_ci hnm->current[writeoffset++] = hnm->previous[offset++]; 238cabdff1aSopenharmony_ci offset++; 239cabdff1aSopenharmony_ci } else { 240cabdff1aSopenharmony_ci hnm->current[writeoffset++] = hnm->previous[offset++]; 241cabdff1aSopenharmony_ci hnm->current[writeoffset++] = hnm->previous[offset++]; 242cabdff1aSopenharmony_ci } 243cabdff1aSopenharmony_ci if (backward) 244cabdff1aSopenharmony_ci offset -= 4; 245cabdff1aSopenharmony_ci left--; 246cabdff1aSopenharmony_ci } 247cabdff1aSopenharmony_ci } else { 248cabdff1aSopenharmony_ci while (left > 0) { 249cabdff1aSopenharmony_ci if (backline) { 250cabdff1aSopenharmony_ci hnm->current[writeoffset++] = hnm->current[offset - (2 * hnm->width) + 1]; 251cabdff1aSopenharmony_ci hnm->current[writeoffset++] = hnm->current[offset++]; 252cabdff1aSopenharmony_ci offset++; 253cabdff1aSopenharmony_ci } else { 254cabdff1aSopenharmony_ci hnm->current[writeoffset++] = hnm->current[offset++]; 255cabdff1aSopenharmony_ci hnm->current[writeoffset++] = hnm->current[offset++]; 256cabdff1aSopenharmony_ci } 257cabdff1aSopenharmony_ci if (backward) 258cabdff1aSopenharmony_ci offset -= 4; 259cabdff1aSopenharmony_ci left--; 260cabdff1aSopenharmony_ci } 261cabdff1aSopenharmony_ci } 262cabdff1aSopenharmony_ci 263cabdff1aSopenharmony_ci if (swap) { 264cabdff1aSopenharmony_ci left = count; 265cabdff1aSopenharmony_ci writeoffset -= count * 2; 266cabdff1aSopenharmony_ci while (left > 0) { 267cabdff1aSopenharmony_ci swap = hnm->current[writeoffset]; 268cabdff1aSopenharmony_ci hnm->current[writeoffset] = hnm->current[writeoffset + 1]; 269cabdff1aSopenharmony_ci hnm->current[writeoffset + 1] = swap; 270cabdff1aSopenharmony_ci left--; 271cabdff1aSopenharmony_ci writeoffset += 2; 272cabdff1aSopenharmony_ci } 273cabdff1aSopenharmony_ci } 274cabdff1aSopenharmony_ci } 275cabdff1aSopenharmony_ci } 276cabdff1aSopenharmony_ci return 0; 277cabdff1aSopenharmony_ci} 278cabdff1aSopenharmony_ci 279cabdff1aSopenharmony_cistatic void decode_interframe_v4a(AVCodecContext *avctx, const uint8_t *src, 280cabdff1aSopenharmony_ci uint32_t size) 281cabdff1aSopenharmony_ci{ 282cabdff1aSopenharmony_ci Hnm4VideoContext *hnm = avctx->priv_data; 283cabdff1aSopenharmony_ci GetByteContext gb; 284cabdff1aSopenharmony_ci uint32_t writeoffset = 0, offset; 285cabdff1aSopenharmony_ci uint8_t tag, count, previous, delta; 286cabdff1aSopenharmony_ci 287cabdff1aSopenharmony_ci bytestream2_init(&gb, src, size); 288cabdff1aSopenharmony_ci 289cabdff1aSopenharmony_ci while (bytestream2_tell(&gb) < size) { 290cabdff1aSopenharmony_ci count = bytestream2_peek_byte(&gb) & 0x3F; 291cabdff1aSopenharmony_ci if (count == 0) { 292cabdff1aSopenharmony_ci tag = bytestream2_get_byte(&gb) & 0xC0; 293cabdff1aSopenharmony_ci tag = tag >> 6; 294cabdff1aSopenharmony_ci if (tag == 0) { 295cabdff1aSopenharmony_ci writeoffset += bytestream2_get_byte(&gb); 296cabdff1aSopenharmony_ci } else if (tag == 1) { 297cabdff1aSopenharmony_ci if (writeoffset + hnm->width >= hnm->width * hnm->height) { 298cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "writeoffset out of bounds\n"); 299cabdff1aSopenharmony_ci break; 300cabdff1aSopenharmony_ci } 301cabdff1aSopenharmony_ci hnm->current[writeoffset] = bytestream2_get_byte(&gb); 302cabdff1aSopenharmony_ci hnm->current[writeoffset + hnm->width] = bytestream2_get_byte(&gb); 303cabdff1aSopenharmony_ci writeoffset++; 304cabdff1aSopenharmony_ci } else if (tag == 2) { 305cabdff1aSopenharmony_ci writeoffset += hnm->width; 306cabdff1aSopenharmony_ci } else if (tag == 3) { 307cabdff1aSopenharmony_ci break; 308cabdff1aSopenharmony_ci } 309cabdff1aSopenharmony_ci if (writeoffset > hnm->width * hnm->height) { 310cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "writeoffset out of bounds\n"); 311cabdff1aSopenharmony_ci break; 312cabdff1aSopenharmony_ci } 313cabdff1aSopenharmony_ci } else { 314cabdff1aSopenharmony_ci delta = bytestream2_peek_byte(&gb) & 0x80; 315cabdff1aSopenharmony_ci previous = bytestream2_peek_byte(&gb) & 0x40; 316cabdff1aSopenharmony_ci bytestream2_skip(&gb, 1); 317cabdff1aSopenharmony_ci 318cabdff1aSopenharmony_ci offset = writeoffset; 319cabdff1aSopenharmony_ci offset += bytestream2_get_le16(&gb); 320cabdff1aSopenharmony_ci 321cabdff1aSopenharmony_ci if (delta) { 322cabdff1aSopenharmony_ci if (offset < 0x10000) { 323cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n"); 324cabdff1aSopenharmony_ci break; 325cabdff1aSopenharmony_ci } 326cabdff1aSopenharmony_ci offset -= 0x10000; 327cabdff1aSopenharmony_ci } 328cabdff1aSopenharmony_ci 329cabdff1aSopenharmony_ci if (offset + hnm->width + count >= hnm->width * hnm->height) { 330cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n"); 331cabdff1aSopenharmony_ci break; 332cabdff1aSopenharmony_ci } else if (writeoffset + hnm->width + count >= hnm->width * hnm->height) { 333cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Attempting to write out of bounds\n"); 334cabdff1aSopenharmony_ci break; 335cabdff1aSopenharmony_ci } 336cabdff1aSopenharmony_ci 337cabdff1aSopenharmony_ci if (previous) { 338cabdff1aSopenharmony_ci while (count > 0) { 339cabdff1aSopenharmony_ci hnm->current[writeoffset] = hnm->previous[offset]; 340cabdff1aSopenharmony_ci hnm->current[writeoffset + hnm->width] = hnm->previous[offset + hnm->width]; 341cabdff1aSopenharmony_ci writeoffset++; 342cabdff1aSopenharmony_ci offset++; 343cabdff1aSopenharmony_ci count--; 344cabdff1aSopenharmony_ci } 345cabdff1aSopenharmony_ci } else { 346cabdff1aSopenharmony_ci while (count > 0) { 347cabdff1aSopenharmony_ci hnm->current[writeoffset] = hnm->current[offset]; 348cabdff1aSopenharmony_ci hnm->current[writeoffset + hnm->width] = hnm->current[offset + hnm->width]; 349cabdff1aSopenharmony_ci writeoffset++; 350cabdff1aSopenharmony_ci offset++; 351cabdff1aSopenharmony_ci count--; 352cabdff1aSopenharmony_ci } 353cabdff1aSopenharmony_ci } 354cabdff1aSopenharmony_ci } 355cabdff1aSopenharmony_ci } 356cabdff1aSopenharmony_ci} 357cabdff1aSopenharmony_ci 358cabdff1aSopenharmony_cistatic void hnm_update_palette(AVCodecContext *avctx, const uint8_t *src, 359cabdff1aSopenharmony_ci uint32_t size) 360cabdff1aSopenharmony_ci{ 361cabdff1aSopenharmony_ci Hnm4VideoContext *hnm = avctx->priv_data; 362cabdff1aSopenharmony_ci GetByteContext gb; 363cabdff1aSopenharmony_ci uint8_t start, writeoffset; 364cabdff1aSopenharmony_ci uint16_t count; 365cabdff1aSopenharmony_ci int eight_bit_colors; 366cabdff1aSopenharmony_ci 367cabdff1aSopenharmony_ci eight_bit_colors = src[7] & 0x80 && hnm->version == 0x4a; 368cabdff1aSopenharmony_ci 369cabdff1aSopenharmony_ci // skip first 8 bytes 370cabdff1aSopenharmony_ci bytestream2_init(&gb, src + 8, size - 8); 371cabdff1aSopenharmony_ci 372cabdff1aSopenharmony_ci while (bytestream2_tell(&gb) < size - 8) { 373cabdff1aSopenharmony_ci start = bytestream2_get_byte(&gb); 374cabdff1aSopenharmony_ci count = bytestream2_get_byte(&gb); 375cabdff1aSopenharmony_ci if (start == 255 && count == 255) 376cabdff1aSopenharmony_ci break; 377cabdff1aSopenharmony_ci if (count == 0) 378cabdff1aSopenharmony_ci count = 256; 379cabdff1aSopenharmony_ci writeoffset = start; 380cabdff1aSopenharmony_ci while (count > 0) { 381cabdff1aSopenharmony_ci hnm->palette[writeoffset] = bytestream2_get_be24(&gb); 382cabdff1aSopenharmony_ci if (!eight_bit_colors) 383cabdff1aSopenharmony_ci hnm->palette[writeoffset] <<= 2; 384cabdff1aSopenharmony_ci hnm->palette[writeoffset] |= (0xFFU << 24); 385cabdff1aSopenharmony_ci count--; 386cabdff1aSopenharmony_ci writeoffset++; 387cabdff1aSopenharmony_ci } 388cabdff1aSopenharmony_ci } 389cabdff1aSopenharmony_ci} 390cabdff1aSopenharmony_ci 391cabdff1aSopenharmony_cistatic int hnm_decode_frame(AVCodecContext *avctx, AVFrame *frame, 392cabdff1aSopenharmony_ci int *got_frame, AVPacket *avpkt) 393cabdff1aSopenharmony_ci{ 394cabdff1aSopenharmony_ci Hnm4VideoContext *hnm = avctx->priv_data; 395cabdff1aSopenharmony_ci int ret; 396cabdff1aSopenharmony_ci uint16_t chunk_id; 397cabdff1aSopenharmony_ci 398cabdff1aSopenharmony_ci if (avpkt->size < 8) { 399cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "packet too small\n"); 400cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 401cabdff1aSopenharmony_ci } 402cabdff1aSopenharmony_ci 403cabdff1aSopenharmony_ci chunk_id = AV_RL16(avpkt->data + 4); 404cabdff1aSopenharmony_ci 405cabdff1aSopenharmony_ci if (chunk_id == HNM4_CHUNK_ID_PL) { 406cabdff1aSopenharmony_ci hnm_update_palette(avctx, avpkt->data, avpkt->size); 407cabdff1aSopenharmony_ci } else if (chunk_id == HNM4_CHUNK_ID_IZ) { 408cabdff1aSopenharmony_ci if (avpkt->size < 12) { 409cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "packet too small\n"); 410cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 411cabdff1aSopenharmony_ci } 412cabdff1aSopenharmony_ci if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) 413cabdff1aSopenharmony_ci return ret; 414cabdff1aSopenharmony_ci 415cabdff1aSopenharmony_ci unpack_intraframe(avctx, avpkt->data + 12, avpkt->size - 12); 416cabdff1aSopenharmony_ci memcpy(hnm->previous, hnm->current, hnm->width * hnm->height); 417cabdff1aSopenharmony_ci if (hnm->version == 0x4a) 418cabdff1aSopenharmony_ci memcpy(hnm->processed, hnm->current, hnm->width * hnm->height); 419cabdff1aSopenharmony_ci else 420cabdff1aSopenharmony_ci postprocess_current_frame(avctx); 421cabdff1aSopenharmony_ci copy_processed_frame(avctx, frame); 422cabdff1aSopenharmony_ci frame->pict_type = AV_PICTURE_TYPE_I; 423cabdff1aSopenharmony_ci frame->key_frame = 1; 424cabdff1aSopenharmony_ci memcpy(frame->data[1], hnm->palette, 256 * 4); 425cabdff1aSopenharmony_ci *got_frame = 1; 426cabdff1aSopenharmony_ci } else if (chunk_id == HNM4_CHUNK_ID_IU) { 427cabdff1aSopenharmony_ci if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) 428cabdff1aSopenharmony_ci return ret; 429cabdff1aSopenharmony_ci 430cabdff1aSopenharmony_ci if (hnm->version == 0x4a) { 431cabdff1aSopenharmony_ci decode_interframe_v4a(avctx, avpkt->data + 8, avpkt->size - 8); 432cabdff1aSopenharmony_ci memcpy(hnm->processed, hnm->current, hnm->width * hnm->height); 433cabdff1aSopenharmony_ci } else { 434cabdff1aSopenharmony_ci int ret = decode_interframe_v4(avctx, avpkt->data + 8, avpkt->size - 8); 435cabdff1aSopenharmony_ci if (ret < 0) 436cabdff1aSopenharmony_ci return ret; 437cabdff1aSopenharmony_ci postprocess_current_frame(avctx); 438cabdff1aSopenharmony_ci } 439cabdff1aSopenharmony_ci copy_processed_frame(avctx, frame); 440cabdff1aSopenharmony_ci frame->pict_type = AV_PICTURE_TYPE_P; 441cabdff1aSopenharmony_ci frame->key_frame = 0; 442cabdff1aSopenharmony_ci memcpy(frame->data[1], hnm->palette, 256 * 4); 443cabdff1aSopenharmony_ci *got_frame = 1; 444cabdff1aSopenharmony_ci FFSWAP(uint8_t *, hnm->current, hnm->previous); 445cabdff1aSopenharmony_ci } else { 446cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "invalid chunk id: %d\n", chunk_id); 447cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 448cabdff1aSopenharmony_ci } 449cabdff1aSopenharmony_ci 450cabdff1aSopenharmony_ci return avpkt->size; 451cabdff1aSopenharmony_ci} 452cabdff1aSopenharmony_ci 453cabdff1aSopenharmony_cistatic av_cold int hnm_decode_init(AVCodecContext *avctx) 454cabdff1aSopenharmony_ci{ 455cabdff1aSopenharmony_ci Hnm4VideoContext *hnm = avctx->priv_data; 456cabdff1aSopenharmony_ci int ret; 457cabdff1aSopenharmony_ci 458cabdff1aSopenharmony_ci if (avctx->extradata_size < 1) { 459cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, 460cabdff1aSopenharmony_ci "Extradata missing, decoder requires version number\n"); 461cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 462cabdff1aSopenharmony_ci } 463cabdff1aSopenharmony_ci 464cabdff1aSopenharmony_ci ret = av_image_check_size(avctx->width, avctx->height, 0, avctx); 465cabdff1aSopenharmony_ci if (ret < 0) 466cabdff1aSopenharmony_ci return ret; 467cabdff1aSopenharmony_ci if (avctx->height & 1) 468cabdff1aSopenharmony_ci return AVERROR(EINVAL); 469cabdff1aSopenharmony_ci 470cabdff1aSopenharmony_ci hnm->version = avctx->extradata[0]; 471cabdff1aSopenharmony_ci avctx->pix_fmt = AV_PIX_FMT_PAL8; 472cabdff1aSopenharmony_ci hnm->width = avctx->width; 473cabdff1aSopenharmony_ci hnm->height = avctx->height; 474cabdff1aSopenharmony_ci hnm->buffer1 = av_mallocz(avctx->width * avctx->height); 475cabdff1aSopenharmony_ci hnm->buffer2 = av_mallocz(avctx->width * avctx->height); 476cabdff1aSopenharmony_ci hnm->processed = av_mallocz(avctx->width * avctx->height); 477cabdff1aSopenharmony_ci 478cabdff1aSopenharmony_ci if (!hnm->buffer1 || !hnm->buffer2 || !hnm->processed) { 479cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "av_mallocz() failed\n"); 480cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 481cabdff1aSopenharmony_ci } 482cabdff1aSopenharmony_ci 483cabdff1aSopenharmony_ci hnm->current = hnm->buffer1; 484cabdff1aSopenharmony_ci hnm->previous = hnm->buffer2; 485cabdff1aSopenharmony_ci 486cabdff1aSopenharmony_ci return 0; 487cabdff1aSopenharmony_ci} 488cabdff1aSopenharmony_ci 489cabdff1aSopenharmony_cistatic av_cold int hnm_decode_end(AVCodecContext *avctx) 490cabdff1aSopenharmony_ci{ 491cabdff1aSopenharmony_ci Hnm4VideoContext *hnm = avctx->priv_data; 492cabdff1aSopenharmony_ci 493cabdff1aSopenharmony_ci av_freep(&hnm->buffer1); 494cabdff1aSopenharmony_ci av_freep(&hnm->buffer2); 495cabdff1aSopenharmony_ci av_freep(&hnm->processed); 496cabdff1aSopenharmony_ci 497cabdff1aSopenharmony_ci return 0; 498cabdff1aSopenharmony_ci} 499cabdff1aSopenharmony_ci 500cabdff1aSopenharmony_ciconst FFCodec ff_hnm4_video_decoder = { 501cabdff1aSopenharmony_ci .p.name = "hnm4video", 502cabdff1aSopenharmony_ci .p.long_name = NULL_IF_CONFIG_SMALL("HNM 4 video"), 503cabdff1aSopenharmony_ci .p.type = AVMEDIA_TYPE_VIDEO, 504cabdff1aSopenharmony_ci .p.id = AV_CODEC_ID_HNM4_VIDEO, 505cabdff1aSopenharmony_ci .priv_data_size = sizeof(Hnm4VideoContext), 506cabdff1aSopenharmony_ci .init = hnm_decode_init, 507cabdff1aSopenharmony_ci .close = hnm_decode_end, 508cabdff1aSopenharmony_ci FF_CODEC_DECODE_CB(hnm_decode_frame), 509cabdff1aSopenharmony_ci .p.capabilities = AV_CODEC_CAP_DR1, 510cabdff1aSopenharmony_ci .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, 511cabdff1aSopenharmony_ci}; 512