1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * TDSC decoder 3cabdff1aSopenharmony_ci * Copyright (C) 2015 Vittorio Giovara <vittorio.giovara@gmail.com> 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 * TDSC decoder 25cabdff1aSopenharmony_ci * 26cabdff1aSopenharmony_ci * Fourcc: TSDC 27cabdff1aSopenharmony_ci * 28cabdff1aSopenharmony_ci * TDSC is very simple. It codes picture by tiles, storing them in raw BGR24 29cabdff1aSopenharmony_ci * format or compressing them in JPEG. Frames can be full pictures or just 30cabdff1aSopenharmony_ci * updates to the previous frame. Cursor is found in its own frame or at the 31cabdff1aSopenharmony_ci * bottom of the picture. Every frame is then packed with zlib. 32cabdff1aSopenharmony_ci * 33cabdff1aSopenharmony_ci * Supports: BGR24 34cabdff1aSopenharmony_ci */ 35cabdff1aSopenharmony_ci 36cabdff1aSopenharmony_ci#include <stdint.h> 37cabdff1aSopenharmony_ci#include <zlib.h> 38cabdff1aSopenharmony_ci 39cabdff1aSopenharmony_ci#include "libavutil/imgutils.h" 40cabdff1aSopenharmony_ci 41cabdff1aSopenharmony_ci#include "avcodec.h" 42cabdff1aSopenharmony_ci#include "bytestream.h" 43cabdff1aSopenharmony_ci#include "codec_internal.h" 44cabdff1aSopenharmony_ci#include "internal.h" 45cabdff1aSopenharmony_ci 46cabdff1aSopenharmony_ci#define BITMAPINFOHEADER_SIZE 0x28 47cabdff1aSopenharmony_ci#define TDSF_HEADER_SIZE 0x56 48cabdff1aSopenharmony_ci#define TDSB_HEADER_SIZE 0x08 49cabdff1aSopenharmony_ci 50cabdff1aSopenharmony_citypedef struct TDSCContext { 51cabdff1aSopenharmony_ci AVCodecContext *jpeg_avctx; // wrapper context for MJPEG 52cabdff1aSopenharmony_ci 53cabdff1aSopenharmony_ci int width, height; 54cabdff1aSopenharmony_ci GetByteContext gbc; 55cabdff1aSopenharmony_ci 56cabdff1aSopenharmony_ci AVFrame *refframe; // full decoded frame (without cursor) 57cabdff1aSopenharmony_ci AVPacket *jpkt; // encoded JPEG tile 58cabdff1aSopenharmony_ci AVFrame *jpgframe; // decoded JPEG tile 59cabdff1aSopenharmony_ci uint8_t *tilebuffer; // buffer containing tile data 60cabdff1aSopenharmony_ci 61cabdff1aSopenharmony_ci /* zlib interaction */ 62cabdff1aSopenharmony_ci uint8_t *deflatebuffer; 63cabdff1aSopenharmony_ci uLongf deflatelen; 64cabdff1aSopenharmony_ci 65cabdff1aSopenharmony_ci /* All that is cursor */ 66cabdff1aSopenharmony_ci uint8_t *cursor; 67cabdff1aSopenharmony_ci int cursor_stride; 68cabdff1aSopenharmony_ci int cursor_w, cursor_h, cursor_x, cursor_y; 69cabdff1aSopenharmony_ci int cursor_hot_x, cursor_hot_y; 70cabdff1aSopenharmony_ci} TDSCContext; 71cabdff1aSopenharmony_ci 72cabdff1aSopenharmony_ci/* 1 byte bits, 1 byte planes, 2 bytes format (probably) */ 73cabdff1aSopenharmony_cienum TDSCCursorFormat { 74cabdff1aSopenharmony_ci CUR_FMT_MONO = 0x01010004, 75cabdff1aSopenharmony_ci CUR_FMT_BGRA = 0x20010004, 76cabdff1aSopenharmony_ci CUR_FMT_RGBA = 0x20010008, 77cabdff1aSopenharmony_ci}; 78cabdff1aSopenharmony_ci 79cabdff1aSopenharmony_cistatic av_cold int tdsc_close(AVCodecContext *avctx) 80cabdff1aSopenharmony_ci{ 81cabdff1aSopenharmony_ci TDSCContext *ctx = avctx->priv_data; 82cabdff1aSopenharmony_ci 83cabdff1aSopenharmony_ci av_frame_free(&ctx->refframe); 84cabdff1aSopenharmony_ci av_frame_free(&ctx->jpgframe); 85cabdff1aSopenharmony_ci av_packet_free(&ctx->jpkt); 86cabdff1aSopenharmony_ci av_freep(&ctx->deflatebuffer); 87cabdff1aSopenharmony_ci av_freep(&ctx->tilebuffer); 88cabdff1aSopenharmony_ci av_freep(&ctx->cursor); 89cabdff1aSopenharmony_ci avcodec_free_context(&ctx->jpeg_avctx); 90cabdff1aSopenharmony_ci 91cabdff1aSopenharmony_ci return 0; 92cabdff1aSopenharmony_ci} 93cabdff1aSopenharmony_ci 94cabdff1aSopenharmony_cistatic av_cold int tdsc_init(AVCodecContext *avctx) 95cabdff1aSopenharmony_ci{ 96cabdff1aSopenharmony_ci TDSCContext *ctx = avctx->priv_data; 97cabdff1aSopenharmony_ci const AVCodec *codec; 98cabdff1aSopenharmony_ci int ret; 99cabdff1aSopenharmony_ci 100cabdff1aSopenharmony_ci avctx->pix_fmt = AV_PIX_FMT_BGR24; 101cabdff1aSopenharmony_ci 102cabdff1aSopenharmony_ci /* These needs to be set to estimate buffer and frame size */ 103cabdff1aSopenharmony_ci if (!(avctx->width && avctx->height)) { 104cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Video size not set.\n"); 105cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 106cabdff1aSopenharmony_ci } 107cabdff1aSopenharmony_ci 108cabdff1aSopenharmony_ci /* This value should be large enough for a RAW-only frame plus headers */ 109cabdff1aSopenharmony_ci ctx->deflatelen = avctx->width * avctx->height * (3 + 1); 110cabdff1aSopenharmony_ci ret = av_reallocp(&ctx->deflatebuffer, ctx->deflatelen); 111cabdff1aSopenharmony_ci if (ret < 0) 112cabdff1aSopenharmony_ci return ret; 113cabdff1aSopenharmony_ci 114cabdff1aSopenharmony_ci /* Allocate reference and JPEG frame */ 115cabdff1aSopenharmony_ci ctx->refframe = av_frame_alloc(); 116cabdff1aSopenharmony_ci ctx->jpgframe = av_frame_alloc(); 117cabdff1aSopenharmony_ci ctx->jpkt = av_packet_alloc(); 118cabdff1aSopenharmony_ci if (!ctx->refframe || !ctx->jpgframe || !ctx->jpkt) 119cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 120cabdff1aSopenharmony_ci 121cabdff1aSopenharmony_ci /* Prepare everything needed for JPEG decoding */ 122cabdff1aSopenharmony_ci codec = avcodec_find_decoder(AV_CODEC_ID_MJPEG); 123cabdff1aSopenharmony_ci if (!codec) 124cabdff1aSopenharmony_ci return AVERROR_BUG; 125cabdff1aSopenharmony_ci ctx->jpeg_avctx = avcodec_alloc_context3(codec); 126cabdff1aSopenharmony_ci if (!ctx->jpeg_avctx) 127cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 128cabdff1aSopenharmony_ci ctx->jpeg_avctx->flags = avctx->flags; 129cabdff1aSopenharmony_ci ctx->jpeg_avctx->flags2 = avctx->flags2; 130cabdff1aSopenharmony_ci ctx->jpeg_avctx->dct_algo = avctx->dct_algo; 131cabdff1aSopenharmony_ci ctx->jpeg_avctx->idct_algo = avctx->idct_algo; 132cabdff1aSopenharmony_ci ret = avcodec_open2(ctx->jpeg_avctx, codec, NULL); 133cabdff1aSopenharmony_ci if (ret < 0) 134cabdff1aSopenharmony_ci return ret; 135cabdff1aSopenharmony_ci 136cabdff1aSopenharmony_ci /* Set the output pixel format on the reference frame */ 137cabdff1aSopenharmony_ci ctx->refframe->format = avctx->pix_fmt; 138cabdff1aSopenharmony_ci 139cabdff1aSopenharmony_ci return 0; 140cabdff1aSopenharmony_ci} 141cabdff1aSopenharmony_ci 142cabdff1aSopenharmony_ci#define APPLY_ALPHA(src, new, alpha) \ 143cabdff1aSopenharmony_ci src = (src * (256 - alpha) + new * alpha) >> 8 144cabdff1aSopenharmony_ci 145cabdff1aSopenharmony_ci/* Paint a region over a buffer, without drawing out of its bounds. */ 146cabdff1aSopenharmony_cistatic void tdsc_paint_cursor(AVCodecContext *avctx, uint8_t *dst, int stride) 147cabdff1aSopenharmony_ci{ 148cabdff1aSopenharmony_ci TDSCContext *ctx = avctx->priv_data; 149cabdff1aSopenharmony_ci const uint8_t *cursor = ctx->cursor; 150cabdff1aSopenharmony_ci int x = ctx->cursor_x - ctx->cursor_hot_x; 151cabdff1aSopenharmony_ci int y = ctx->cursor_y - ctx->cursor_hot_y; 152cabdff1aSopenharmony_ci int w = ctx->cursor_w; 153cabdff1aSopenharmony_ci int h = ctx->cursor_h; 154cabdff1aSopenharmony_ci int i, j; 155cabdff1aSopenharmony_ci 156cabdff1aSopenharmony_ci if (!ctx->cursor) 157cabdff1aSopenharmony_ci return; 158cabdff1aSopenharmony_ci 159cabdff1aSopenharmony_ci if (x + w > ctx->width) 160cabdff1aSopenharmony_ci w = ctx->width - x; 161cabdff1aSopenharmony_ci if (y + h > ctx->height) 162cabdff1aSopenharmony_ci h = ctx->height - y; 163cabdff1aSopenharmony_ci if (x < 0) { 164cabdff1aSopenharmony_ci w += x; 165cabdff1aSopenharmony_ci cursor += -x * 4; 166cabdff1aSopenharmony_ci } else { 167cabdff1aSopenharmony_ci dst += x * 3; 168cabdff1aSopenharmony_ci } 169cabdff1aSopenharmony_ci if (y < 0) { 170cabdff1aSopenharmony_ci h += y; 171cabdff1aSopenharmony_ci cursor += -y * ctx->cursor_stride; 172cabdff1aSopenharmony_ci } else { 173cabdff1aSopenharmony_ci dst += y * stride; 174cabdff1aSopenharmony_ci } 175cabdff1aSopenharmony_ci if (w < 0 || h < 0) 176cabdff1aSopenharmony_ci return; 177cabdff1aSopenharmony_ci 178cabdff1aSopenharmony_ci for (j = 0; j < h; j++) { 179cabdff1aSopenharmony_ci for (i = 0; i < w; i++) { 180cabdff1aSopenharmony_ci uint8_t alpha = cursor[i * 4]; 181cabdff1aSopenharmony_ci APPLY_ALPHA(dst[i * 3 + 0], cursor[i * 4 + 1], alpha); 182cabdff1aSopenharmony_ci APPLY_ALPHA(dst[i * 3 + 1], cursor[i * 4 + 2], alpha); 183cabdff1aSopenharmony_ci APPLY_ALPHA(dst[i * 3 + 2], cursor[i * 4 + 3], alpha); 184cabdff1aSopenharmony_ci } 185cabdff1aSopenharmony_ci dst += stride; 186cabdff1aSopenharmony_ci cursor += ctx->cursor_stride; 187cabdff1aSopenharmony_ci } 188cabdff1aSopenharmony_ci} 189cabdff1aSopenharmony_ci 190cabdff1aSopenharmony_ci/* Load cursor data and store it in ABGR mode. */ 191cabdff1aSopenharmony_cistatic int tdsc_load_cursor(AVCodecContext *avctx) 192cabdff1aSopenharmony_ci{ 193cabdff1aSopenharmony_ci TDSCContext *ctx = avctx->priv_data; 194cabdff1aSopenharmony_ci int i, j, k, ret, cursor_fmt; 195cabdff1aSopenharmony_ci uint8_t *dst; 196cabdff1aSopenharmony_ci 197cabdff1aSopenharmony_ci ctx->cursor_hot_x = bytestream2_get_le16(&ctx->gbc); 198cabdff1aSopenharmony_ci ctx->cursor_hot_y = bytestream2_get_le16(&ctx->gbc); 199cabdff1aSopenharmony_ci ctx->cursor_w = bytestream2_get_le16(&ctx->gbc); 200cabdff1aSopenharmony_ci ctx->cursor_h = bytestream2_get_le16(&ctx->gbc); 201cabdff1aSopenharmony_ci 202cabdff1aSopenharmony_ci ctx->cursor_stride = FFALIGN(ctx->cursor_w, 32) * 4; 203cabdff1aSopenharmony_ci cursor_fmt = bytestream2_get_le32(&ctx->gbc); 204cabdff1aSopenharmony_ci 205cabdff1aSopenharmony_ci if (ctx->cursor_x >= avctx->width || ctx->cursor_y >= avctx->height) { 206cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, 207cabdff1aSopenharmony_ci "Invalid cursor position (%d.%d outside %dx%d).\n", 208cabdff1aSopenharmony_ci ctx->cursor_x, ctx->cursor_y, avctx->width, avctx->height); 209cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 210cabdff1aSopenharmony_ci } 211cabdff1aSopenharmony_ci if (ctx->cursor_w < 1 || ctx->cursor_w > 256 || 212cabdff1aSopenharmony_ci ctx->cursor_h < 1 || ctx->cursor_h > 256) { 213cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, 214cabdff1aSopenharmony_ci "Invalid cursor dimensions %dx%d.\n", 215cabdff1aSopenharmony_ci ctx->cursor_w, ctx->cursor_h); 216cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 217cabdff1aSopenharmony_ci } 218cabdff1aSopenharmony_ci if (ctx->cursor_hot_x > ctx->cursor_w || 219cabdff1aSopenharmony_ci ctx->cursor_hot_y > ctx->cursor_h) { 220cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_WARNING, "Invalid hotspot position %d.%d.\n", 221cabdff1aSopenharmony_ci ctx->cursor_hot_x, ctx->cursor_hot_y); 222cabdff1aSopenharmony_ci ctx->cursor_hot_x = FFMIN(ctx->cursor_hot_x, ctx->cursor_w - 1); 223cabdff1aSopenharmony_ci ctx->cursor_hot_y = FFMIN(ctx->cursor_hot_y, ctx->cursor_h - 1); 224cabdff1aSopenharmony_ci } 225cabdff1aSopenharmony_ci 226cabdff1aSopenharmony_ci ret = av_reallocp(&ctx->cursor, ctx->cursor_stride * ctx->cursor_h); 227cabdff1aSopenharmony_ci if (ret < 0) { 228cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Cannot allocate cursor buffer.\n"); 229cabdff1aSopenharmony_ci return ret; 230cabdff1aSopenharmony_ci } 231cabdff1aSopenharmony_ci 232cabdff1aSopenharmony_ci dst = ctx->cursor; 233cabdff1aSopenharmony_ci /* here data is packed in BE */ 234cabdff1aSopenharmony_ci switch (cursor_fmt) { 235cabdff1aSopenharmony_ci case CUR_FMT_MONO: 236cabdff1aSopenharmony_ci for (j = 0; j < ctx->cursor_h; j++) { 237cabdff1aSopenharmony_ci for (i = 0; i < ctx->cursor_w; i += 32) { 238cabdff1aSopenharmony_ci uint32_t bits = bytestream2_get_be32(&ctx->gbc); 239cabdff1aSopenharmony_ci for (k = 0; k < 32; k++) { 240cabdff1aSopenharmony_ci dst[0] = !!(bits & 0x80000000); 241cabdff1aSopenharmony_ci dst += 4; 242cabdff1aSopenharmony_ci bits <<= 1; 243cabdff1aSopenharmony_ci } 244cabdff1aSopenharmony_ci } 245cabdff1aSopenharmony_ci dst += ctx->cursor_stride - ctx->cursor_w * 4; 246cabdff1aSopenharmony_ci } 247cabdff1aSopenharmony_ci 248cabdff1aSopenharmony_ci dst = ctx->cursor; 249cabdff1aSopenharmony_ci for (j = 0; j < ctx->cursor_h; j++) { 250cabdff1aSopenharmony_ci for (i = 0; i < ctx->cursor_w; i += 32) { 251cabdff1aSopenharmony_ci uint32_t bits = bytestream2_get_be32(&ctx->gbc); 252cabdff1aSopenharmony_ci for (k = 0; k < 32; k++) { 253cabdff1aSopenharmony_ci int mask_bit = !!(bits & 0x80000000); 254cabdff1aSopenharmony_ci switch (dst[0] * 2 + mask_bit) { 255cabdff1aSopenharmony_ci case 0: 256cabdff1aSopenharmony_ci dst[0] = 0xFF; 257cabdff1aSopenharmony_ci dst[1] = 0x00; 258cabdff1aSopenharmony_ci dst[2] = 0x00; 259cabdff1aSopenharmony_ci dst[3] = 0x00; 260cabdff1aSopenharmony_ci break; 261cabdff1aSopenharmony_ci case 1: 262cabdff1aSopenharmony_ci dst[0] = 0xFF; 263cabdff1aSopenharmony_ci dst[1] = 0xFF; 264cabdff1aSopenharmony_ci dst[2] = 0xFF; 265cabdff1aSopenharmony_ci dst[3] = 0xFF; 266cabdff1aSopenharmony_ci break; 267cabdff1aSopenharmony_ci default: 268cabdff1aSopenharmony_ci dst[0] = 0x00; 269cabdff1aSopenharmony_ci dst[1] = 0x00; 270cabdff1aSopenharmony_ci dst[2] = 0x00; 271cabdff1aSopenharmony_ci dst[3] = 0x00; 272cabdff1aSopenharmony_ci } 273cabdff1aSopenharmony_ci dst += 4; 274cabdff1aSopenharmony_ci bits <<= 1; 275cabdff1aSopenharmony_ci } 276cabdff1aSopenharmony_ci } 277cabdff1aSopenharmony_ci dst += ctx->cursor_stride - ctx->cursor_w * 4; 278cabdff1aSopenharmony_ci } 279cabdff1aSopenharmony_ci break; 280cabdff1aSopenharmony_ci case CUR_FMT_BGRA: 281cabdff1aSopenharmony_ci case CUR_FMT_RGBA: 282cabdff1aSopenharmony_ci /* Skip monochrome version of the cursor */ 283cabdff1aSopenharmony_ci bytestream2_skip(&ctx->gbc, 284cabdff1aSopenharmony_ci ctx->cursor_h * (FFALIGN(ctx->cursor_w, 32) >> 3)); 285cabdff1aSopenharmony_ci if (cursor_fmt & 8) { // RGBA -> ABGR 286cabdff1aSopenharmony_ci for (j = 0; j < ctx->cursor_h; j++) { 287cabdff1aSopenharmony_ci for (i = 0; i < ctx->cursor_w; i++) { 288cabdff1aSopenharmony_ci int val = bytestream2_get_be32(&ctx->gbc); 289cabdff1aSopenharmony_ci *dst++ = val >> 24; 290cabdff1aSopenharmony_ci *dst++ = val >> 16; 291cabdff1aSopenharmony_ci *dst++ = val >> 8; 292cabdff1aSopenharmony_ci *dst++ = val >> 0; 293cabdff1aSopenharmony_ci } 294cabdff1aSopenharmony_ci dst += ctx->cursor_stride - ctx->cursor_w * 4; 295cabdff1aSopenharmony_ci } 296cabdff1aSopenharmony_ci } else { // BGRA -> ABGR 297cabdff1aSopenharmony_ci for (j = 0; j < ctx->cursor_h; j++) { 298cabdff1aSopenharmony_ci for (i = 0; i < ctx->cursor_w; i++) { 299cabdff1aSopenharmony_ci int val = bytestream2_get_be32(&ctx->gbc); 300cabdff1aSopenharmony_ci *dst++ = val >> 0; 301cabdff1aSopenharmony_ci *dst++ = val >> 24; 302cabdff1aSopenharmony_ci *dst++ = val >> 16; 303cabdff1aSopenharmony_ci *dst++ = val >> 8; 304cabdff1aSopenharmony_ci } 305cabdff1aSopenharmony_ci dst += ctx->cursor_stride - ctx->cursor_w * 4; 306cabdff1aSopenharmony_ci } 307cabdff1aSopenharmony_ci } 308cabdff1aSopenharmony_ci break; 309cabdff1aSopenharmony_ci default: 310cabdff1aSopenharmony_ci avpriv_request_sample(avctx, "Cursor format %08x", cursor_fmt); 311cabdff1aSopenharmony_ci return AVERROR_PATCHWELCOME; 312cabdff1aSopenharmony_ci } 313cabdff1aSopenharmony_ci 314cabdff1aSopenharmony_ci return 0; 315cabdff1aSopenharmony_ci} 316cabdff1aSopenharmony_ci 317cabdff1aSopenharmony_ci/* Convert a single YUV pixel to RGB. */ 318cabdff1aSopenharmony_cistatic inline void tdsc_yuv2rgb(uint8_t *out, int Y, int U, int V) 319cabdff1aSopenharmony_ci{ 320cabdff1aSopenharmony_ci out[0] = av_clip_uint8(Y + ( 91881 * V + 32768 >> 16)); 321cabdff1aSopenharmony_ci out[1] = av_clip_uint8(Y + (-22554 * U - 46802 * V + 32768 >> 16)); 322cabdff1aSopenharmony_ci out[2] = av_clip_uint8(Y + (116130 * U + 32768 >> 16)); 323cabdff1aSopenharmony_ci} 324cabdff1aSopenharmony_ci 325cabdff1aSopenharmony_ci/* Convert a YUV420 buffer to a RGB buffer. */ 326cabdff1aSopenharmony_cistatic av_always_inline void tdsc_blit(uint8_t *dst, int dst_stride, 327cabdff1aSopenharmony_ci const uint8_t *srcy, int srcy_stride, 328cabdff1aSopenharmony_ci const uint8_t *srcu, const uint8_t *srcv, 329cabdff1aSopenharmony_ci int srcuv_stride, int width, int height) 330cabdff1aSopenharmony_ci{ 331cabdff1aSopenharmony_ci int col, line; 332cabdff1aSopenharmony_ci for (line = 0; line < height; line++) { 333cabdff1aSopenharmony_ci for (col = 0; col < width; col++) 334cabdff1aSopenharmony_ci tdsc_yuv2rgb(dst + col * 3, srcy[col], 335cabdff1aSopenharmony_ci srcu[col >> 1] - 128, srcv[col >> 1] - 128); 336cabdff1aSopenharmony_ci 337cabdff1aSopenharmony_ci dst += dst_stride; 338cabdff1aSopenharmony_ci srcy += srcy_stride; 339cabdff1aSopenharmony_ci srcu += srcuv_stride * (line & 1); 340cabdff1aSopenharmony_ci srcv += srcuv_stride * (line & 1); 341cabdff1aSopenharmony_ci } 342cabdff1aSopenharmony_ci} 343cabdff1aSopenharmony_ci 344cabdff1aSopenharmony_ci/* Invoke the MJPEG decoder to decode the tile. */ 345cabdff1aSopenharmony_cistatic int tdsc_decode_jpeg_tile(AVCodecContext *avctx, int tile_size, 346cabdff1aSopenharmony_ci int x, int y, int w, int h) 347cabdff1aSopenharmony_ci{ 348cabdff1aSopenharmony_ci TDSCContext *ctx = avctx->priv_data; 349cabdff1aSopenharmony_ci int ret; 350cabdff1aSopenharmony_ci 351cabdff1aSopenharmony_ci /* Prepare a packet and send to the MJPEG decoder */ 352cabdff1aSopenharmony_ci av_packet_unref(ctx->jpkt); 353cabdff1aSopenharmony_ci ctx->jpkt->data = ctx->tilebuffer; 354cabdff1aSopenharmony_ci ctx->jpkt->size = tile_size; 355cabdff1aSopenharmony_ci 356cabdff1aSopenharmony_ci ret = avcodec_send_packet(ctx->jpeg_avctx, ctx->jpkt); 357cabdff1aSopenharmony_ci if (ret < 0) { 358cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Error submitting a packet for decoding\n"); 359cabdff1aSopenharmony_ci return ret; 360cabdff1aSopenharmony_ci } 361cabdff1aSopenharmony_ci 362cabdff1aSopenharmony_ci ret = avcodec_receive_frame(ctx->jpeg_avctx, ctx->jpgframe); 363cabdff1aSopenharmony_ci if (ret < 0 || ctx->jpgframe->format != AV_PIX_FMT_YUVJ420P) { 364cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, 365cabdff1aSopenharmony_ci "JPEG decoding error (%d).\n", ret); 366cabdff1aSopenharmony_ci 367cabdff1aSopenharmony_ci /* Normally skip, error if explode */ 368cabdff1aSopenharmony_ci if (avctx->err_recognition & AV_EF_EXPLODE) 369cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 370cabdff1aSopenharmony_ci else 371cabdff1aSopenharmony_ci return 0; 372cabdff1aSopenharmony_ci } 373cabdff1aSopenharmony_ci 374cabdff1aSopenharmony_ci /* Let's paint onto the buffer */ 375cabdff1aSopenharmony_ci tdsc_blit(ctx->refframe->data[0] + x * 3 + ctx->refframe->linesize[0] * y, 376cabdff1aSopenharmony_ci ctx->refframe->linesize[0], 377cabdff1aSopenharmony_ci ctx->jpgframe->data[0], ctx->jpgframe->linesize[0], 378cabdff1aSopenharmony_ci ctx->jpgframe->data[1], ctx->jpgframe->data[2], 379cabdff1aSopenharmony_ci ctx->jpgframe->linesize[1], w, h); 380cabdff1aSopenharmony_ci 381cabdff1aSopenharmony_ci av_frame_unref(ctx->jpgframe); 382cabdff1aSopenharmony_ci 383cabdff1aSopenharmony_ci return 0; 384cabdff1aSopenharmony_ci} 385cabdff1aSopenharmony_ci 386cabdff1aSopenharmony_ci/* Parse frame and either copy data or decode JPEG. */ 387cabdff1aSopenharmony_cistatic int tdsc_decode_tiles(AVCodecContext *avctx, int number_tiles) 388cabdff1aSopenharmony_ci{ 389cabdff1aSopenharmony_ci TDSCContext *ctx = avctx->priv_data; 390cabdff1aSopenharmony_ci int i; 391cabdff1aSopenharmony_ci 392cabdff1aSopenharmony_ci /* Iterate over the number of tiles */ 393cabdff1aSopenharmony_ci for (i = 0; i < number_tiles; i++) { 394cabdff1aSopenharmony_ci int tile_size; 395cabdff1aSopenharmony_ci int tile_mode; 396cabdff1aSopenharmony_ci int x, y, x2, y2, w, h; 397cabdff1aSopenharmony_ci int ret; 398cabdff1aSopenharmony_ci 399cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&ctx->gbc) < 4 || 400cabdff1aSopenharmony_ci bytestream2_get_le32(&ctx->gbc) != MKTAG('T','D','S','B') || 401cabdff1aSopenharmony_ci bytestream2_get_bytes_left(&ctx->gbc) < TDSB_HEADER_SIZE - 4) { 402cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "TDSB tag is too small.\n"); 403cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 404cabdff1aSopenharmony_ci } 405cabdff1aSopenharmony_ci 406cabdff1aSopenharmony_ci tile_size = bytestream2_get_le32(&ctx->gbc); 407cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&ctx->gbc) < tile_size) 408cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 409cabdff1aSopenharmony_ci 410cabdff1aSopenharmony_ci tile_mode = bytestream2_get_le32(&ctx->gbc); 411cabdff1aSopenharmony_ci bytestream2_skip(&ctx->gbc, 4); // unknown 412cabdff1aSopenharmony_ci x = bytestream2_get_le32(&ctx->gbc); 413cabdff1aSopenharmony_ci y = bytestream2_get_le32(&ctx->gbc); 414cabdff1aSopenharmony_ci x2 = bytestream2_get_le32(&ctx->gbc); 415cabdff1aSopenharmony_ci y2 = bytestream2_get_le32(&ctx->gbc); 416cabdff1aSopenharmony_ci 417cabdff1aSopenharmony_ci if (x < 0 || y < 0 || x2 <= x || y2 <= y || 418cabdff1aSopenharmony_ci x2 > ctx->width || y2 > ctx->height 419cabdff1aSopenharmony_ci ) { 420cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, 421cabdff1aSopenharmony_ci "Invalid tile position (%d.%d %d.%d outside %dx%d).\n", 422cabdff1aSopenharmony_ci x, y, x2, y2, ctx->width, ctx->height); 423cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 424cabdff1aSopenharmony_ci } 425cabdff1aSopenharmony_ci w = x2 - x; 426cabdff1aSopenharmony_ci h = y2 - y; 427cabdff1aSopenharmony_ci 428cabdff1aSopenharmony_ci ret = av_reallocp(&ctx->tilebuffer, tile_size); 429cabdff1aSopenharmony_ci if (!ctx->tilebuffer) 430cabdff1aSopenharmony_ci return ret; 431cabdff1aSopenharmony_ci 432cabdff1aSopenharmony_ci bytestream2_get_buffer(&ctx->gbc, ctx->tilebuffer, tile_size); 433cabdff1aSopenharmony_ci 434cabdff1aSopenharmony_ci if (tile_mode == MKTAG('G','E','P','J')) { 435cabdff1aSopenharmony_ci /* Decode JPEG tile and copy it in the reference frame */ 436cabdff1aSopenharmony_ci ret = tdsc_decode_jpeg_tile(avctx, tile_size, x, y, w, h); 437cabdff1aSopenharmony_ci if (ret < 0) 438cabdff1aSopenharmony_ci return ret; 439cabdff1aSopenharmony_ci } else if (tile_mode == MKTAG(' ','W','A','R')) { 440cabdff1aSopenharmony_ci /* Just copy the buffer to output */ 441cabdff1aSopenharmony_ci av_image_copy_plane(ctx->refframe->data[0] + x * 3 + 442cabdff1aSopenharmony_ci ctx->refframe->linesize[0] * y, 443cabdff1aSopenharmony_ci ctx->refframe->linesize[0], ctx->tilebuffer, 444cabdff1aSopenharmony_ci w * 3, w * 3, h); 445cabdff1aSopenharmony_ci } else { 446cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Unknown tile type %08x.\n", tile_mode); 447cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 448cabdff1aSopenharmony_ci } 449cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_DEBUG, "Tile %d, %dx%d (%d.%d)\n", i, w, h, x, y); 450cabdff1aSopenharmony_ci } 451cabdff1aSopenharmony_ci 452cabdff1aSopenharmony_ci return 0; 453cabdff1aSopenharmony_ci} 454cabdff1aSopenharmony_ci 455cabdff1aSopenharmony_cistatic int tdsc_parse_tdsf(AVCodecContext *avctx, int number_tiles) 456cabdff1aSopenharmony_ci{ 457cabdff1aSopenharmony_ci TDSCContext *ctx = avctx->priv_data; 458cabdff1aSopenharmony_ci int ret, w, h, init_refframe = !ctx->refframe->data[0]; 459cabdff1aSopenharmony_ci 460cabdff1aSopenharmony_ci /* BITMAPINFOHEADER 461cabdff1aSopenharmony_ci * http://msdn.microsoft.com/en-us/library/windows/desktop/dd183376.aspx */ 462cabdff1aSopenharmony_ci if (bytestream2_get_le32(&ctx->gbc) != BITMAPINFOHEADER_SIZE) 463cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 464cabdff1aSopenharmony_ci 465cabdff1aSopenharmony_ci /* Store size, but wait for context reinit before updating avctx */ 466cabdff1aSopenharmony_ci w = bytestream2_get_le32(&ctx->gbc); 467cabdff1aSopenharmony_ci h = -bytestream2_get_le32(&ctx->gbc); 468cabdff1aSopenharmony_ci 469cabdff1aSopenharmony_ci if (bytestream2_get_le16(&ctx->gbc) != 1 || // 1 plane 470cabdff1aSopenharmony_ci bytestream2_get_le16(&ctx->gbc) != 24) // BGR24 471cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 472cabdff1aSopenharmony_ci 473cabdff1aSopenharmony_ci bytestream2_skip(&ctx->gbc, 24); // unused fields 474cabdff1aSopenharmony_ci 475cabdff1aSopenharmony_ci /* Update sizes */ 476cabdff1aSopenharmony_ci if (avctx->width != w || avctx->height != h) { 477cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_DEBUG, "Size update %dx%d -> %d%d.\n", 478cabdff1aSopenharmony_ci avctx->width, avctx->height, ctx->width, ctx->height); 479cabdff1aSopenharmony_ci ret = ff_set_dimensions(avctx, w, h); 480cabdff1aSopenharmony_ci if (ret < 0) 481cabdff1aSopenharmony_ci return ret; 482cabdff1aSopenharmony_ci init_refframe = 1; 483cabdff1aSopenharmony_ci } 484cabdff1aSopenharmony_ci ctx->refframe->width = ctx->width = w; 485cabdff1aSopenharmony_ci ctx->refframe->height = ctx->height = h; 486cabdff1aSopenharmony_ci 487cabdff1aSopenharmony_ci /* Allocate the reference frame if not already done or on size change */ 488cabdff1aSopenharmony_ci if (init_refframe) { 489cabdff1aSopenharmony_ci ret = av_frame_get_buffer(ctx->refframe, 0); 490cabdff1aSopenharmony_ci if (ret < 0) 491cabdff1aSopenharmony_ci return ret; 492cabdff1aSopenharmony_ci } 493cabdff1aSopenharmony_ci 494cabdff1aSopenharmony_ci /* Decode all tiles in a frame */ 495cabdff1aSopenharmony_ci return tdsc_decode_tiles(avctx, number_tiles); 496cabdff1aSopenharmony_ci} 497cabdff1aSopenharmony_ci 498cabdff1aSopenharmony_cistatic int tdsc_parse_dtsm(AVCodecContext *avctx) 499cabdff1aSopenharmony_ci{ 500cabdff1aSopenharmony_ci TDSCContext *ctx = avctx->priv_data; 501cabdff1aSopenharmony_ci int ret; 502cabdff1aSopenharmony_ci int action = bytestream2_get_le32(&ctx->gbc); 503cabdff1aSopenharmony_ci 504cabdff1aSopenharmony_ci bytestream2_skip(&ctx->gbc, 4); // some kind of ID or version maybe? 505cabdff1aSopenharmony_ci 506cabdff1aSopenharmony_ci if (action == 2 || action == 3) { 507cabdff1aSopenharmony_ci /* Load cursor coordinates */ 508cabdff1aSopenharmony_ci ctx->cursor_x = bytestream2_get_le32(&ctx->gbc); 509cabdff1aSopenharmony_ci ctx->cursor_y = bytestream2_get_le32(&ctx->gbc); 510cabdff1aSopenharmony_ci 511cabdff1aSopenharmony_ci /* Load a full cursor sprite */ 512cabdff1aSopenharmony_ci if (action == 3) { 513cabdff1aSopenharmony_ci ret = tdsc_load_cursor(avctx); 514cabdff1aSopenharmony_ci /* Do not consider cursor errors fatal unless in explode mode */ 515cabdff1aSopenharmony_ci if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE)) 516cabdff1aSopenharmony_ci return ret; 517cabdff1aSopenharmony_ci } 518cabdff1aSopenharmony_ci } else { 519cabdff1aSopenharmony_ci avpriv_request_sample(avctx, "Cursor action %d", action); 520cabdff1aSopenharmony_ci } 521cabdff1aSopenharmony_ci 522cabdff1aSopenharmony_ci return 0; 523cabdff1aSopenharmony_ci} 524cabdff1aSopenharmony_ci 525cabdff1aSopenharmony_cistatic int tdsc_decode_frame(AVCodecContext *avctx, AVFrame *frame, 526cabdff1aSopenharmony_ci int *got_frame, AVPacket *avpkt) 527cabdff1aSopenharmony_ci{ 528cabdff1aSopenharmony_ci TDSCContext *ctx = avctx->priv_data; 529cabdff1aSopenharmony_ci int ret, tag_header, keyframe = 0; 530cabdff1aSopenharmony_ci uLongf dlen; 531cabdff1aSopenharmony_ci 532cabdff1aSopenharmony_ci /* Resize deflate buffer on resolution change */ 533cabdff1aSopenharmony_ci if (ctx->width != avctx->width || ctx->height != avctx->height) { 534cabdff1aSopenharmony_ci int deflatelen = avctx->width * avctx->height * (3 + 1); 535cabdff1aSopenharmony_ci if (deflatelen != ctx->deflatelen) { 536cabdff1aSopenharmony_ci ctx->deflatelen =deflatelen; 537cabdff1aSopenharmony_ci ret = av_reallocp(&ctx->deflatebuffer, ctx->deflatelen); 538cabdff1aSopenharmony_ci if (ret < 0) { 539cabdff1aSopenharmony_ci ctx->deflatelen = 0; 540cabdff1aSopenharmony_ci return ret; 541cabdff1aSopenharmony_ci } 542cabdff1aSopenharmony_ci } 543cabdff1aSopenharmony_ci } 544cabdff1aSopenharmony_ci dlen = ctx->deflatelen; 545cabdff1aSopenharmony_ci 546cabdff1aSopenharmony_ci /* Frames are deflated, need to inflate them first */ 547cabdff1aSopenharmony_ci ret = uncompress(ctx->deflatebuffer, &dlen, avpkt->data, avpkt->size); 548cabdff1aSopenharmony_ci if (ret) { 549cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Deflate error %d.\n", ret); 550cabdff1aSopenharmony_ci return AVERROR_UNKNOWN; 551cabdff1aSopenharmony_ci } 552cabdff1aSopenharmony_ci 553cabdff1aSopenharmony_ci bytestream2_init(&ctx->gbc, ctx->deflatebuffer, dlen); 554cabdff1aSopenharmony_ci 555cabdff1aSopenharmony_ci /* Check for tag and for size info */ 556cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&ctx->gbc) < 4 + 4) { 557cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Frame is too small.\n"); 558cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 559cabdff1aSopenharmony_ci } 560cabdff1aSopenharmony_ci 561cabdff1aSopenharmony_ci /* Read tag */ 562cabdff1aSopenharmony_ci tag_header = bytestream2_get_le32(&ctx->gbc); 563cabdff1aSopenharmony_ci 564cabdff1aSopenharmony_ci if (tag_header == MKTAG('T','D','S','F')) { 565cabdff1aSopenharmony_ci int number_tiles; 566cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&ctx->gbc) < TDSF_HEADER_SIZE) { 567cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "TDSF tag is too small.\n"); 568cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 569cabdff1aSopenharmony_ci } 570cabdff1aSopenharmony_ci /* First 4 bytes here are the number of GEPJ/WAR tiles in this frame */ 571cabdff1aSopenharmony_ci number_tiles = bytestream2_get_le32(&ctx->gbc); 572cabdff1aSopenharmony_ci 573cabdff1aSopenharmony_ci bytestream2_skip(&ctx->gbc, 4); // internal timestamp maybe? 574cabdff1aSopenharmony_ci keyframe = bytestream2_get_le32(&ctx->gbc) == 0x30; 575cabdff1aSopenharmony_ci 576cabdff1aSopenharmony_ci ret = tdsc_parse_tdsf(avctx, number_tiles); 577cabdff1aSopenharmony_ci if (ret < 0) 578cabdff1aSopenharmony_ci return ret; 579cabdff1aSopenharmony_ci 580cabdff1aSopenharmony_ci /* Check if there is anything else we are able to parse */ 581cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&ctx->gbc) >= 4 + 4) 582cabdff1aSopenharmony_ci tag_header = bytestream2_get_le32(&ctx->gbc); 583cabdff1aSopenharmony_ci } 584cabdff1aSopenharmony_ci 585cabdff1aSopenharmony_ci /* This tag can be after a TDSF block or on its own frame */ 586cabdff1aSopenharmony_ci if (tag_header == MKTAG('D','T','S','M')) { 587cabdff1aSopenharmony_ci /* First 4 bytes here are the total size in bytes for this frame */ 588cabdff1aSopenharmony_ci int tag_size = bytestream2_get_le32(&ctx->gbc); 589cabdff1aSopenharmony_ci 590cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&ctx->gbc) < tag_size) { 591cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "DTSM tag is too small.\n"); 592cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 593cabdff1aSopenharmony_ci } 594cabdff1aSopenharmony_ci 595cabdff1aSopenharmony_ci ret = tdsc_parse_dtsm(avctx); 596cabdff1aSopenharmony_ci if (ret < 0) 597cabdff1aSopenharmony_ci return ret; 598cabdff1aSopenharmony_ci } 599cabdff1aSopenharmony_ci 600cabdff1aSopenharmony_ci /* Get the output frame and copy the reference frame */ 601cabdff1aSopenharmony_ci ret = ff_get_buffer(avctx, frame, 0); 602cabdff1aSopenharmony_ci if (ret < 0) 603cabdff1aSopenharmony_ci return ret; 604cabdff1aSopenharmony_ci 605cabdff1aSopenharmony_ci ret = av_frame_copy(frame, ctx->refframe); 606cabdff1aSopenharmony_ci if (ret < 0) 607cabdff1aSopenharmony_ci return ret; 608cabdff1aSopenharmony_ci 609cabdff1aSopenharmony_ci /* Paint the cursor on the output frame */ 610cabdff1aSopenharmony_ci tdsc_paint_cursor(avctx, frame->data[0], frame->linesize[0]); 611cabdff1aSopenharmony_ci 612cabdff1aSopenharmony_ci /* Frame is ready to be output */ 613cabdff1aSopenharmony_ci if (keyframe) { 614cabdff1aSopenharmony_ci frame->pict_type = AV_PICTURE_TYPE_I; 615cabdff1aSopenharmony_ci frame->key_frame = 1; 616cabdff1aSopenharmony_ci } else { 617cabdff1aSopenharmony_ci frame->pict_type = AV_PICTURE_TYPE_P; 618cabdff1aSopenharmony_ci } 619cabdff1aSopenharmony_ci *got_frame = 1; 620cabdff1aSopenharmony_ci 621cabdff1aSopenharmony_ci return avpkt->size; 622cabdff1aSopenharmony_ci} 623cabdff1aSopenharmony_ci 624cabdff1aSopenharmony_ciconst FFCodec ff_tdsc_decoder = { 625cabdff1aSopenharmony_ci .p.name = "tdsc", 626cabdff1aSopenharmony_ci .p.long_name = NULL_IF_CONFIG_SMALL("TDSC"), 627cabdff1aSopenharmony_ci .p.type = AVMEDIA_TYPE_VIDEO, 628cabdff1aSopenharmony_ci .p.id = AV_CODEC_ID_TDSC, 629cabdff1aSopenharmony_ci .init = tdsc_init, 630cabdff1aSopenharmony_ci FF_CODEC_DECODE_CB(tdsc_decode_frame), 631cabdff1aSopenharmony_ci .close = tdsc_close, 632cabdff1aSopenharmony_ci .priv_data_size = sizeof(TDSCContext), 633cabdff1aSopenharmony_ci .p.capabilities = AV_CODEC_CAP_DR1, 634cabdff1aSopenharmony_ci .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | 635cabdff1aSopenharmony_ci FF_CODEC_CAP_INIT_CLEANUP, 636cabdff1aSopenharmony_ci}; 637