1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Copyright (c) 2019 Paul B Mahol 3cabdff1aSopenharmony_ci * 4cabdff1aSopenharmony_ci * This file is part of FFmpeg. 5cabdff1aSopenharmony_ci * 6cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 7cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 8cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 9cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 10cabdff1aSopenharmony_ci * 11cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 12cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 13cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14cabdff1aSopenharmony_ci * Lesser General Public License for more details. 15cabdff1aSopenharmony_ci * 16cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 17cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 18cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19cabdff1aSopenharmony_ci */ 20cabdff1aSopenharmony_ci 21cabdff1aSopenharmony_ci#include <stdint.h> 22cabdff1aSopenharmony_ci#include <zlib.h> 23cabdff1aSopenharmony_ci 24cabdff1aSopenharmony_ci#include "libavutil/frame.h" 25cabdff1aSopenharmony_ci#include "libavutil/error.h" 26cabdff1aSopenharmony_ci#include "libavutil/log.h" 27cabdff1aSopenharmony_ci 28cabdff1aSopenharmony_ci#include "avcodec.h" 29cabdff1aSopenharmony_ci#include "bytestream.h" 30cabdff1aSopenharmony_ci#include "codec.h" 31cabdff1aSopenharmony_ci#include "codec_internal.h" 32cabdff1aSopenharmony_ci#include "internal.h" 33cabdff1aSopenharmony_ci#include "packet.h" 34cabdff1aSopenharmony_ci#include "png.h" 35cabdff1aSopenharmony_ci#include "pngdsp.h" 36cabdff1aSopenharmony_ci#include "zlib_wrapper.h" 37cabdff1aSopenharmony_ci 38cabdff1aSopenharmony_citypedef struct LSCRContext { 39cabdff1aSopenharmony_ci PNGDSPContext dsp; 40cabdff1aSopenharmony_ci AVCodecContext *avctx; 41cabdff1aSopenharmony_ci 42cabdff1aSopenharmony_ci AVFrame *last_picture; 43cabdff1aSopenharmony_ci uint8_t *buffer; 44cabdff1aSopenharmony_ci int buffer_size; 45cabdff1aSopenharmony_ci uint8_t *crow_buf; 46cabdff1aSopenharmony_ci int crow_size; 47cabdff1aSopenharmony_ci uint8_t *last_row; 48cabdff1aSopenharmony_ci unsigned int last_row_size; 49cabdff1aSopenharmony_ci 50cabdff1aSopenharmony_ci GetByteContext gb; 51cabdff1aSopenharmony_ci uint8_t *image_buf; 52cabdff1aSopenharmony_ci int image_linesize; 53cabdff1aSopenharmony_ci int row_size; 54cabdff1aSopenharmony_ci int cur_h; 55cabdff1aSopenharmony_ci int y; 56cabdff1aSopenharmony_ci 57cabdff1aSopenharmony_ci FFZStream zstream; 58cabdff1aSopenharmony_ci} LSCRContext; 59cabdff1aSopenharmony_ci 60cabdff1aSopenharmony_cistatic void handle_row(LSCRContext *s) 61cabdff1aSopenharmony_ci{ 62cabdff1aSopenharmony_ci uint8_t *ptr, *last_row; 63cabdff1aSopenharmony_ci 64cabdff1aSopenharmony_ci ptr = s->image_buf + s->image_linesize * s->y; 65cabdff1aSopenharmony_ci if (s->y == 0) 66cabdff1aSopenharmony_ci last_row = s->last_row; 67cabdff1aSopenharmony_ci else 68cabdff1aSopenharmony_ci last_row = ptr - s->image_linesize; 69cabdff1aSopenharmony_ci 70cabdff1aSopenharmony_ci ff_png_filter_row(&s->dsp, ptr, s->crow_buf[0], s->crow_buf + 1, 71cabdff1aSopenharmony_ci last_row, s->row_size, 3); 72cabdff1aSopenharmony_ci 73cabdff1aSopenharmony_ci s->y++; 74cabdff1aSopenharmony_ci} 75cabdff1aSopenharmony_ci 76cabdff1aSopenharmony_cistatic int decode_idat(LSCRContext *s, z_stream *zstream, int length) 77cabdff1aSopenharmony_ci{ 78cabdff1aSopenharmony_ci int ret; 79cabdff1aSopenharmony_ci zstream->avail_in = FFMIN(length, bytestream2_get_bytes_left(&s->gb)); 80cabdff1aSopenharmony_ci zstream->next_in = s->gb.buffer; 81cabdff1aSopenharmony_ci 82cabdff1aSopenharmony_ci if (length <= 0) 83cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 84cabdff1aSopenharmony_ci 85cabdff1aSopenharmony_ci bytestream2_skip(&s->gb, length); 86cabdff1aSopenharmony_ci 87cabdff1aSopenharmony_ci /* decode one line if possible */ 88cabdff1aSopenharmony_ci while (zstream->avail_in > 0) { 89cabdff1aSopenharmony_ci ret = inflate(zstream, Z_PARTIAL_FLUSH); 90cabdff1aSopenharmony_ci if (ret != Z_OK && ret != Z_STREAM_END) { 91cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "inflate returned error %d\n", ret); 92cabdff1aSopenharmony_ci return AVERROR_EXTERNAL; 93cabdff1aSopenharmony_ci } 94cabdff1aSopenharmony_ci if (zstream->avail_out == 0) { 95cabdff1aSopenharmony_ci if (s->y < s->cur_h) { 96cabdff1aSopenharmony_ci handle_row(s); 97cabdff1aSopenharmony_ci } 98cabdff1aSopenharmony_ci zstream->avail_out = s->crow_size; 99cabdff1aSopenharmony_ci zstream->next_out = s->crow_buf; 100cabdff1aSopenharmony_ci } 101cabdff1aSopenharmony_ci if (ret == Z_STREAM_END && zstream->avail_in > 0) { 102cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_WARNING, 103cabdff1aSopenharmony_ci "%d undecompressed bytes left in buffer\n", zstream->avail_in); 104cabdff1aSopenharmony_ci return 0; 105cabdff1aSopenharmony_ci } 106cabdff1aSopenharmony_ci } 107cabdff1aSopenharmony_ci return 0; 108cabdff1aSopenharmony_ci} 109cabdff1aSopenharmony_ci 110cabdff1aSopenharmony_cistatic int decode_frame_lscr(AVCodecContext *avctx, AVFrame *rframe, 111cabdff1aSopenharmony_ci int *got_frame, AVPacket *avpkt) 112cabdff1aSopenharmony_ci{ 113cabdff1aSopenharmony_ci LSCRContext *const s = avctx->priv_data; 114cabdff1aSopenharmony_ci GetByteContext *gb = &s->gb; 115cabdff1aSopenharmony_ci AVFrame *frame = s->last_picture; 116cabdff1aSopenharmony_ci int ret, nb_blocks, offset = 0; 117cabdff1aSopenharmony_ci 118cabdff1aSopenharmony_ci if (avpkt->size < 2) 119cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 120cabdff1aSopenharmony_ci if (avpkt->size == 2) 121cabdff1aSopenharmony_ci return 0; 122cabdff1aSopenharmony_ci 123cabdff1aSopenharmony_ci bytestream2_init(gb, avpkt->data, avpkt->size); 124cabdff1aSopenharmony_ci 125cabdff1aSopenharmony_ci nb_blocks = bytestream2_get_le16(gb); 126cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(gb) < 2 + nb_blocks * (12 + 8)) 127cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 128cabdff1aSopenharmony_ci 129cabdff1aSopenharmony_ci ret = ff_reget_buffer(avctx, frame, 130cabdff1aSopenharmony_ci nb_blocks ? 0 : FF_REGET_BUFFER_FLAG_READONLY); 131cabdff1aSopenharmony_ci if (ret < 0) 132cabdff1aSopenharmony_ci return ret; 133cabdff1aSopenharmony_ci 134cabdff1aSopenharmony_ci for (int b = 0; b < nb_blocks; b++) { 135cabdff1aSopenharmony_ci z_stream *const zstream = &s->zstream.zstream; 136cabdff1aSopenharmony_ci int x, y, x2, y2, w, h, left; 137cabdff1aSopenharmony_ci uint32_t csize, size; 138cabdff1aSopenharmony_ci 139cabdff1aSopenharmony_ci if (inflateReset(zstream) != Z_OK) 140cabdff1aSopenharmony_ci return AVERROR_EXTERNAL; 141cabdff1aSopenharmony_ci 142cabdff1aSopenharmony_ci bytestream2_seek(gb, 2 + b * 12, SEEK_SET); 143cabdff1aSopenharmony_ci 144cabdff1aSopenharmony_ci x = bytestream2_get_le16(gb); 145cabdff1aSopenharmony_ci y = bytestream2_get_le16(gb); 146cabdff1aSopenharmony_ci x2 = bytestream2_get_le16(gb); 147cabdff1aSopenharmony_ci y2 = bytestream2_get_le16(gb); 148cabdff1aSopenharmony_ci w = x2-x; 149cabdff1aSopenharmony_ci s->cur_h = h = y2-y; 150cabdff1aSopenharmony_ci 151cabdff1aSopenharmony_ci if (w <= 0 || x < 0 || x >= avctx->width || w + x > avctx->width || 152cabdff1aSopenharmony_ci h <= 0 || y < 0 || y >= avctx->height || h + y > avctx->height) 153cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 154cabdff1aSopenharmony_ci 155cabdff1aSopenharmony_ci size = bytestream2_get_le32(gb); 156cabdff1aSopenharmony_ci 157cabdff1aSopenharmony_ci frame->key_frame = (nb_blocks == 1) && 158cabdff1aSopenharmony_ci (w == avctx->width) && 159cabdff1aSopenharmony_ci (h == avctx->height) && 160cabdff1aSopenharmony_ci (x == 0) && (y == 0); 161cabdff1aSopenharmony_ci 162cabdff1aSopenharmony_ci bytestream2_seek(gb, 2 + nb_blocks * 12 + offset, SEEK_SET); 163cabdff1aSopenharmony_ci csize = bytestream2_get_be32(gb); 164cabdff1aSopenharmony_ci if (bytestream2_get_le32(gb) != MKTAG('I', 'D', 'A', 'T')) 165cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 166cabdff1aSopenharmony_ci 167cabdff1aSopenharmony_ci offset += size; 168cabdff1aSopenharmony_ci left = size; 169cabdff1aSopenharmony_ci 170cabdff1aSopenharmony_ci s->y = 0; 171cabdff1aSopenharmony_ci s->row_size = w * 3; 172cabdff1aSopenharmony_ci 173cabdff1aSopenharmony_ci av_fast_padded_malloc(&s->buffer, &s->buffer_size, s->row_size + 16); 174cabdff1aSopenharmony_ci if (!s->buffer) 175cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 176cabdff1aSopenharmony_ci 177cabdff1aSopenharmony_ci av_fast_padded_malloc(&s->last_row, &s->last_row_size, s->row_size); 178cabdff1aSopenharmony_ci if (!s->last_row) 179cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 180cabdff1aSopenharmony_ci 181cabdff1aSopenharmony_ci s->crow_size = w * 3 + 1; 182cabdff1aSopenharmony_ci s->crow_buf = s->buffer + 15; 183cabdff1aSopenharmony_ci zstream->avail_out = s->crow_size; 184cabdff1aSopenharmony_ci zstream->next_out = s->crow_buf; 185cabdff1aSopenharmony_ci s->image_buf = frame->data[0] + (avctx->height - y - 1) * frame->linesize[0] + x * 3; 186cabdff1aSopenharmony_ci s->image_linesize =-frame->linesize[0]; 187cabdff1aSopenharmony_ci 188cabdff1aSopenharmony_ci while (left > 16) { 189cabdff1aSopenharmony_ci ret = decode_idat(s, zstream, csize); 190cabdff1aSopenharmony_ci if (ret < 0) 191cabdff1aSopenharmony_ci return ret; 192cabdff1aSopenharmony_ci left -= csize + 16; 193cabdff1aSopenharmony_ci if (left > 16) { 194cabdff1aSopenharmony_ci bytestream2_skip(gb, 4); 195cabdff1aSopenharmony_ci csize = bytestream2_get_be32(gb); 196cabdff1aSopenharmony_ci if (bytestream2_get_le32(gb) != MKTAG('I', 'D', 'A', 'T')) 197cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 198cabdff1aSopenharmony_ci } 199cabdff1aSopenharmony_ci } 200cabdff1aSopenharmony_ci } 201cabdff1aSopenharmony_ci 202cabdff1aSopenharmony_ci frame->pict_type = frame->key_frame ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P; 203cabdff1aSopenharmony_ci 204cabdff1aSopenharmony_ci if ((ret = av_frame_ref(rframe, frame)) < 0) 205cabdff1aSopenharmony_ci return ret; 206cabdff1aSopenharmony_ci 207cabdff1aSopenharmony_ci *got_frame = 1; 208cabdff1aSopenharmony_ci 209cabdff1aSopenharmony_ci return avpkt->size; 210cabdff1aSopenharmony_ci} 211cabdff1aSopenharmony_ci 212cabdff1aSopenharmony_cistatic int lscr_decode_close(AVCodecContext *avctx) 213cabdff1aSopenharmony_ci{ 214cabdff1aSopenharmony_ci LSCRContext *s = avctx->priv_data; 215cabdff1aSopenharmony_ci 216cabdff1aSopenharmony_ci av_frame_free(&s->last_picture); 217cabdff1aSopenharmony_ci av_freep(&s->buffer); 218cabdff1aSopenharmony_ci av_freep(&s->last_row); 219cabdff1aSopenharmony_ci ff_inflate_end(&s->zstream); 220cabdff1aSopenharmony_ci 221cabdff1aSopenharmony_ci return 0; 222cabdff1aSopenharmony_ci} 223cabdff1aSopenharmony_ci 224cabdff1aSopenharmony_cistatic int lscr_decode_init(AVCodecContext *avctx) 225cabdff1aSopenharmony_ci{ 226cabdff1aSopenharmony_ci LSCRContext *s = avctx->priv_data; 227cabdff1aSopenharmony_ci 228cabdff1aSopenharmony_ci avctx->color_range = AVCOL_RANGE_JPEG; 229cabdff1aSopenharmony_ci avctx->pix_fmt = AV_PIX_FMT_BGR24; 230cabdff1aSopenharmony_ci 231cabdff1aSopenharmony_ci s->avctx = avctx; 232cabdff1aSopenharmony_ci s->last_picture = av_frame_alloc(); 233cabdff1aSopenharmony_ci if (!s->last_picture) 234cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 235cabdff1aSopenharmony_ci 236cabdff1aSopenharmony_ci ff_pngdsp_init(&s->dsp); 237cabdff1aSopenharmony_ci 238cabdff1aSopenharmony_ci return ff_inflate_init(&s->zstream, avctx); 239cabdff1aSopenharmony_ci} 240cabdff1aSopenharmony_ci 241cabdff1aSopenharmony_cistatic void lscr_decode_flush(AVCodecContext *avctx) 242cabdff1aSopenharmony_ci{ 243cabdff1aSopenharmony_ci LSCRContext *s = avctx->priv_data; 244cabdff1aSopenharmony_ci av_frame_unref(s->last_picture); 245cabdff1aSopenharmony_ci} 246cabdff1aSopenharmony_ci 247cabdff1aSopenharmony_ciconst FFCodec ff_lscr_decoder = { 248cabdff1aSopenharmony_ci .p.name = "lscr", 249cabdff1aSopenharmony_ci .p.long_name = NULL_IF_CONFIG_SMALL("LEAD Screen Capture"), 250cabdff1aSopenharmony_ci .p.type = AVMEDIA_TYPE_VIDEO, 251cabdff1aSopenharmony_ci .p.id = AV_CODEC_ID_LSCR, 252cabdff1aSopenharmony_ci .p.capabilities = AV_CODEC_CAP_DR1, 253cabdff1aSopenharmony_ci .priv_data_size = sizeof(LSCRContext), 254cabdff1aSopenharmony_ci .init = lscr_decode_init, 255cabdff1aSopenharmony_ci .close = lscr_decode_close, 256cabdff1aSopenharmony_ci FF_CODEC_DECODE_CB(decode_frame_lscr), 257cabdff1aSopenharmony_ci .flush = lscr_decode_flush, 258cabdff1aSopenharmony_ci .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, 259cabdff1aSopenharmony_ci}; 260