1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Pictor/PC Paint decoder 3cabdff1aSopenharmony_ci * Copyright (c) 2010 Peter Ross <pross@xvid.org> 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 * Pictor/PC Paint decoder 25cabdff1aSopenharmony_ci */ 26cabdff1aSopenharmony_ci 27cabdff1aSopenharmony_ci#include "libavutil/imgutils.h" 28cabdff1aSopenharmony_ci#include "avcodec.h" 29cabdff1aSopenharmony_ci#include "bytestream.h" 30cabdff1aSopenharmony_ci#include "cga_data.h" 31cabdff1aSopenharmony_ci#include "codec_internal.h" 32cabdff1aSopenharmony_ci#include "internal.h" 33cabdff1aSopenharmony_ci 34cabdff1aSopenharmony_citypedef struct PicContext { 35cabdff1aSopenharmony_ci int width, height; 36cabdff1aSopenharmony_ci int nb_planes; 37cabdff1aSopenharmony_ci GetByteContext g; 38cabdff1aSopenharmony_ci} PicContext; 39cabdff1aSopenharmony_ci 40cabdff1aSopenharmony_cistatic void picmemset_8bpp(PicContext *s, AVFrame *frame, int value, int run, 41cabdff1aSopenharmony_ci int *x, int *y) 42cabdff1aSopenharmony_ci{ 43cabdff1aSopenharmony_ci while (run > 0) { 44cabdff1aSopenharmony_ci uint8_t *d = frame->data[0] + *y * frame->linesize[0]; 45cabdff1aSopenharmony_ci if (*x + run >= s->width) { 46cabdff1aSopenharmony_ci int n = s->width - *x; 47cabdff1aSopenharmony_ci memset(d + *x, value, n); 48cabdff1aSopenharmony_ci run -= n; 49cabdff1aSopenharmony_ci *x = 0; 50cabdff1aSopenharmony_ci *y -= 1; 51cabdff1aSopenharmony_ci if (*y < 0) 52cabdff1aSopenharmony_ci break; 53cabdff1aSopenharmony_ci } else { 54cabdff1aSopenharmony_ci memset(d + *x, value, run); 55cabdff1aSopenharmony_ci *x += run; 56cabdff1aSopenharmony_ci break; 57cabdff1aSopenharmony_ci } 58cabdff1aSopenharmony_ci } 59cabdff1aSopenharmony_ci} 60cabdff1aSopenharmony_ci 61cabdff1aSopenharmony_cistatic void picmemset(PicContext *s, AVFrame *frame, unsigned value, int run, 62cabdff1aSopenharmony_ci int *x, int *y, int *plane, int bits_per_plane) 63cabdff1aSopenharmony_ci{ 64cabdff1aSopenharmony_ci uint8_t *d; 65cabdff1aSopenharmony_ci int shift = *plane * bits_per_plane; 66cabdff1aSopenharmony_ci unsigned mask = ((1U << bits_per_plane) - 1) << shift; 67cabdff1aSopenharmony_ci int xl = *x; 68cabdff1aSopenharmony_ci int yl = *y; 69cabdff1aSopenharmony_ci int planel = *plane; 70cabdff1aSopenharmony_ci int pixels_per_value = 8/bits_per_plane; 71cabdff1aSopenharmony_ci value <<= shift; 72cabdff1aSopenharmony_ci 73cabdff1aSopenharmony_ci d = frame->data[0] + yl * frame->linesize[0]; 74cabdff1aSopenharmony_ci while (run > 0) { 75cabdff1aSopenharmony_ci int j; 76cabdff1aSopenharmony_ci for (j = 8-bits_per_plane; j >= 0; j -= bits_per_plane) { 77cabdff1aSopenharmony_ci d[xl] |= (value >> j) & mask; 78cabdff1aSopenharmony_ci xl += 1; 79cabdff1aSopenharmony_ci while (xl == s->width) { 80cabdff1aSopenharmony_ci yl -= 1; 81cabdff1aSopenharmony_ci xl = 0; 82cabdff1aSopenharmony_ci if (yl < 0) { 83cabdff1aSopenharmony_ci yl = s->height - 1; 84cabdff1aSopenharmony_ci planel += 1; 85cabdff1aSopenharmony_ci if (planel >= s->nb_planes) 86cabdff1aSopenharmony_ci goto end; 87cabdff1aSopenharmony_ci value <<= bits_per_plane; 88cabdff1aSopenharmony_ci mask <<= bits_per_plane; 89cabdff1aSopenharmony_ci } 90cabdff1aSopenharmony_ci d = frame->data[0] + yl * frame->linesize[0]; 91cabdff1aSopenharmony_ci if (s->nb_planes == 1 && 92cabdff1aSopenharmony_ci run*pixels_per_value >= s->width && 93cabdff1aSopenharmony_ci pixels_per_value < (s->width / pixels_per_value * pixels_per_value) 94cabdff1aSopenharmony_ci ) { 95cabdff1aSopenharmony_ci for (; xl < pixels_per_value; xl ++) { 96cabdff1aSopenharmony_ci j = (j < bits_per_plane ? 8 : j) - bits_per_plane; 97cabdff1aSopenharmony_ci d[xl] |= (value >> j) & mask; 98cabdff1aSopenharmony_ci } 99cabdff1aSopenharmony_ci av_memcpy_backptr(d+xl, pixels_per_value, s->width - xl); 100cabdff1aSopenharmony_ci run -= s->width / pixels_per_value; 101cabdff1aSopenharmony_ci xl = s->width / pixels_per_value * pixels_per_value; 102cabdff1aSopenharmony_ci } 103cabdff1aSopenharmony_ci } 104cabdff1aSopenharmony_ci } 105cabdff1aSopenharmony_ci run--; 106cabdff1aSopenharmony_ci } 107cabdff1aSopenharmony_ciend: 108cabdff1aSopenharmony_ci *x = xl; 109cabdff1aSopenharmony_ci *y = yl; 110cabdff1aSopenharmony_ci *plane = planel; 111cabdff1aSopenharmony_ci} 112cabdff1aSopenharmony_ci 113cabdff1aSopenharmony_cistatic const uint8_t cga_mode45_index[6][4] = { 114cabdff1aSopenharmony_ci [0] = { 0, 3, 5, 7 }, // mode4, palette#1, low intensity 115cabdff1aSopenharmony_ci [1] = { 0, 2, 4, 6 }, // mode4, palette#2, low intensity 116cabdff1aSopenharmony_ci [2] = { 0, 3, 4, 7 }, // mode5, low intensity 117cabdff1aSopenharmony_ci [3] = { 0, 11, 13, 15 }, // mode4, palette#1, high intensity 118cabdff1aSopenharmony_ci [4] = { 0, 10, 12, 14 }, // mode4, palette#2, high intensity 119cabdff1aSopenharmony_ci [5] = { 0, 11, 12, 15 }, // mode5, high intensity 120cabdff1aSopenharmony_ci}; 121cabdff1aSopenharmony_ci 122cabdff1aSopenharmony_cistatic int decode_frame(AVCodecContext *avctx, AVFrame *frame, 123cabdff1aSopenharmony_ci int *got_frame, AVPacket *avpkt) 124cabdff1aSopenharmony_ci{ 125cabdff1aSopenharmony_ci PicContext *s = avctx->priv_data; 126cabdff1aSopenharmony_ci uint32_t *palette; 127cabdff1aSopenharmony_ci int bits_per_plane, bpp, etype, esize, npal, pos_after_pal; 128cabdff1aSopenharmony_ci int i, x, y, plane, tmp, ret, val; 129cabdff1aSopenharmony_ci 130cabdff1aSopenharmony_ci bytestream2_init(&s->g, avpkt->data, avpkt->size); 131cabdff1aSopenharmony_ci 132cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&s->g) < 11) 133cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 134cabdff1aSopenharmony_ci 135cabdff1aSopenharmony_ci if (bytestream2_get_le16u(&s->g) != 0x1234) 136cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 137cabdff1aSopenharmony_ci 138cabdff1aSopenharmony_ci s->width = bytestream2_get_le16u(&s->g); 139cabdff1aSopenharmony_ci s->height = bytestream2_get_le16u(&s->g); 140cabdff1aSopenharmony_ci bytestream2_skip(&s->g, 4); 141cabdff1aSopenharmony_ci tmp = bytestream2_get_byteu(&s->g); 142cabdff1aSopenharmony_ci bits_per_plane = tmp & 0xF; 143cabdff1aSopenharmony_ci s->nb_planes = (tmp >> 4) + 1; 144cabdff1aSopenharmony_ci bpp = bits_per_plane * s->nb_planes; 145cabdff1aSopenharmony_ci if (bits_per_plane > 8 || bpp < 1 || bpp > 32) { 146cabdff1aSopenharmony_ci avpriv_request_sample(avctx, "Unsupported bit depth"); 147cabdff1aSopenharmony_ci return AVERROR_PATCHWELCOME; 148cabdff1aSopenharmony_ci } 149cabdff1aSopenharmony_ci 150cabdff1aSopenharmony_ci if (bytestream2_peek_byte(&s->g) == 0xFF || bpp == 1 || bpp == 4 || bpp == 8) { 151cabdff1aSopenharmony_ci bytestream2_skip(&s->g, 2); 152cabdff1aSopenharmony_ci etype = bytestream2_get_le16(&s->g); 153cabdff1aSopenharmony_ci esize = bytestream2_get_le16(&s->g); 154cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(&s->g) < esize) 155cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 156cabdff1aSopenharmony_ci } else { 157cabdff1aSopenharmony_ci etype = -1; 158cabdff1aSopenharmony_ci esize = 0; 159cabdff1aSopenharmony_ci } 160cabdff1aSopenharmony_ci 161cabdff1aSopenharmony_ci avctx->pix_fmt = AV_PIX_FMT_PAL8; 162cabdff1aSopenharmony_ci 163cabdff1aSopenharmony_ci if (av_image_check_size(s->width, s->height, 0, avctx) < 0) 164cabdff1aSopenharmony_ci return -1; 165cabdff1aSopenharmony_ci if (s->width != avctx->width || s->height != avctx->height) { 166cabdff1aSopenharmony_ci ret = ff_set_dimensions(avctx, s->width, s->height); 167cabdff1aSopenharmony_ci if (ret < 0) 168cabdff1aSopenharmony_ci return ret; 169cabdff1aSopenharmony_ci } 170cabdff1aSopenharmony_ci 171cabdff1aSopenharmony_ci if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) 172cabdff1aSopenharmony_ci return ret; 173cabdff1aSopenharmony_ci memset(frame->data[0], 0, s->height * frame->linesize[0]); 174cabdff1aSopenharmony_ci frame->pict_type = AV_PICTURE_TYPE_I; 175cabdff1aSopenharmony_ci frame->palette_has_changed = 1; 176cabdff1aSopenharmony_ci 177cabdff1aSopenharmony_ci pos_after_pal = bytestream2_tell(&s->g) + esize; 178cabdff1aSopenharmony_ci palette = (uint32_t*)frame->data[1]; 179cabdff1aSopenharmony_ci if (etype == 1 && esize > 1 && bytestream2_peek_byte(&s->g) < 6) { 180cabdff1aSopenharmony_ci int idx = bytestream2_get_byte(&s->g); 181cabdff1aSopenharmony_ci npal = 4; 182cabdff1aSopenharmony_ci for (i = 0; i < npal; i++) 183cabdff1aSopenharmony_ci palette[i] = ff_cga_palette[ cga_mode45_index[idx][i] ]; 184cabdff1aSopenharmony_ci } else if (etype == 2) { 185cabdff1aSopenharmony_ci npal = FFMIN(esize, 16); 186cabdff1aSopenharmony_ci for (i = 0; i < npal; i++) { 187cabdff1aSopenharmony_ci int pal_idx = bytestream2_get_byte(&s->g); 188cabdff1aSopenharmony_ci palette[i] = ff_cga_palette[FFMIN(pal_idx, 15)]; 189cabdff1aSopenharmony_ci } 190cabdff1aSopenharmony_ci } else if (etype == 3) { 191cabdff1aSopenharmony_ci npal = FFMIN(esize, 16); 192cabdff1aSopenharmony_ci for (i = 0; i < npal; i++) { 193cabdff1aSopenharmony_ci int pal_idx = bytestream2_get_byte(&s->g); 194cabdff1aSopenharmony_ci palette[i] = ff_ega_palette[FFMIN(pal_idx, 63)]; 195cabdff1aSopenharmony_ci } 196cabdff1aSopenharmony_ci } else if (etype == 4 || etype == 5) { 197cabdff1aSopenharmony_ci npal = FFMIN(esize / 3, 256); 198cabdff1aSopenharmony_ci for (i = 0; i < npal; i++) { 199cabdff1aSopenharmony_ci palette[i] = bytestream2_get_be24(&s->g) << 2; 200cabdff1aSopenharmony_ci palette[i] |= 0xFFU << 24 | palette[i] >> 6 & 0x30303; 201cabdff1aSopenharmony_ci } 202cabdff1aSopenharmony_ci } else { 203cabdff1aSopenharmony_ci if (bpp == 1) { 204cabdff1aSopenharmony_ci npal = 2; 205cabdff1aSopenharmony_ci palette[0] = 0xFF000000; 206cabdff1aSopenharmony_ci palette[1] = 0xFFFFFFFF; 207cabdff1aSopenharmony_ci } else if (bpp == 2) { 208cabdff1aSopenharmony_ci npal = 4; 209cabdff1aSopenharmony_ci for (i = 0; i < npal; i++) 210cabdff1aSopenharmony_ci palette[i] = ff_cga_palette[ cga_mode45_index[0][i] ]; 211cabdff1aSopenharmony_ci } else { 212cabdff1aSopenharmony_ci npal = 16; 213cabdff1aSopenharmony_ci memcpy(palette, ff_cga_palette, npal * 4); 214cabdff1aSopenharmony_ci } 215cabdff1aSopenharmony_ci } 216cabdff1aSopenharmony_ci // fill remaining palette entries 217cabdff1aSopenharmony_ci memset(palette + npal, 0, AVPALETTE_SIZE - npal * 4); 218cabdff1aSopenharmony_ci // skip remaining palette bytes 219cabdff1aSopenharmony_ci bytestream2_seek(&s->g, pos_after_pal, SEEK_SET); 220cabdff1aSopenharmony_ci 221cabdff1aSopenharmony_ci val = 0; 222cabdff1aSopenharmony_ci y = s->height - 1; 223cabdff1aSopenharmony_ci if (bytestream2_get_le16(&s->g)) { 224cabdff1aSopenharmony_ci x = 0; 225cabdff1aSopenharmony_ci plane = 0; 226cabdff1aSopenharmony_ci while (bytestream2_get_bytes_left(&s->g) >= 6) { 227cabdff1aSopenharmony_ci int stop_size, marker, t1, t2; 228cabdff1aSopenharmony_ci 229cabdff1aSopenharmony_ci t1 = bytestream2_get_bytes_left(&s->g); 230cabdff1aSopenharmony_ci t2 = bytestream2_get_le16(&s->g); 231cabdff1aSopenharmony_ci stop_size = t1 - FFMIN(t1, t2); 232cabdff1aSopenharmony_ci // ignore uncompressed block size 233cabdff1aSopenharmony_ci bytestream2_skip(&s->g, 2); 234cabdff1aSopenharmony_ci marker = bytestream2_get_byte(&s->g); 235cabdff1aSopenharmony_ci 236cabdff1aSopenharmony_ci while (plane < s->nb_planes && 237cabdff1aSopenharmony_ci bytestream2_get_bytes_left(&s->g) > stop_size) { 238cabdff1aSopenharmony_ci int run = 1; 239cabdff1aSopenharmony_ci val = bytestream2_get_byte(&s->g); 240cabdff1aSopenharmony_ci if (val == marker) { 241cabdff1aSopenharmony_ci run = bytestream2_get_byte(&s->g); 242cabdff1aSopenharmony_ci if (run == 0) 243cabdff1aSopenharmony_ci run = bytestream2_get_le16(&s->g); 244cabdff1aSopenharmony_ci val = bytestream2_get_byte(&s->g); 245cabdff1aSopenharmony_ci } 246cabdff1aSopenharmony_ci 247cabdff1aSopenharmony_ci if (bits_per_plane == 8) { 248cabdff1aSopenharmony_ci picmemset_8bpp(s, frame, val, run, &x, &y); 249cabdff1aSopenharmony_ci if (y < 0) 250cabdff1aSopenharmony_ci goto finish; 251cabdff1aSopenharmony_ci } else { 252cabdff1aSopenharmony_ci picmemset(s, frame, val, run, &x, &y, &plane, bits_per_plane); 253cabdff1aSopenharmony_ci } 254cabdff1aSopenharmony_ci } 255cabdff1aSopenharmony_ci } 256cabdff1aSopenharmony_ci 257cabdff1aSopenharmony_ci if (s->nb_planes - plane > 1) 258cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 259cabdff1aSopenharmony_ci 260cabdff1aSopenharmony_ci if (plane < s->nb_planes && x < avctx->width) { 261cabdff1aSopenharmony_ci int run = (y + 1) * avctx->width - x; 262cabdff1aSopenharmony_ci if (bits_per_plane == 8) 263cabdff1aSopenharmony_ci picmemset_8bpp(s, frame, val, run, &x, &y); 264cabdff1aSopenharmony_ci else 265cabdff1aSopenharmony_ci picmemset(s, frame, val, run / (8 / bits_per_plane), &x, &y, &plane, bits_per_plane); 266cabdff1aSopenharmony_ci } 267cabdff1aSopenharmony_ci } else { 268cabdff1aSopenharmony_ci while (y >= 0 && bytestream2_get_bytes_left(&s->g) > 0) { 269cabdff1aSopenharmony_ci memcpy(frame->data[0] + y * frame->linesize[0], s->g.buffer, FFMIN(avctx->width, bytestream2_get_bytes_left(&s->g))); 270cabdff1aSopenharmony_ci bytestream2_skip(&s->g, avctx->width); 271cabdff1aSopenharmony_ci y--; 272cabdff1aSopenharmony_ci } 273cabdff1aSopenharmony_ci } 274cabdff1aSopenharmony_cifinish: 275cabdff1aSopenharmony_ci 276cabdff1aSopenharmony_ci *got_frame = 1; 277cabdff1aSopenharmony_ci return avpkt->size; 278cabdff1aSopenharmony_ci} 279cabdff1aSopenharmony_ci 280cabdff1aSopenharmony_ciconst FFCodec ff_pictor_decoder = { 281cabdff1aSopenharmony_ci .p.name = "pictor", 282cabdff1aSopenharmony_ci .p.long_name = NULL_IF_CONFIG_SMALL("Pictor/PC Paint"), 283cabdff1aSopenharmony_ci .p.type = AVMEDIA_TYPE_VIDEO, 284cabdff1aSopenharmony_ci .p.id = AV_CODEC_ID_PICTOR, 285cabdff1aSopenharmony_ci .p.capabilities = AV_CODEC_CAP_DR1, 286cabdff1aSopenharmony_ci .priv_data_size = sizeof(PicContext), 287cabdff1aSopenharmony_ci FF_CODEC_DECODE_CB(decode_frame), 288cabdff1aSopenharmony_ci}; 289