X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fpngdec.c;h=6a681be29d795a01157a3cc1bf6a9afa68393468;hb=81acc9adbfef9a4867862033b769b5d198cea679;hp=189bb9a4c1733d25a7baae6c43c254dbfac52b89;hpb=29929fc8e2449d2db8bd144b2badc8d1e6347412;p=ffmpeg diff --git a/libavcodec/pngdec.c b/libavcodec/pngdec.c index 189bb9a4c17..6a681be29d7 100644 --- a/libavcodec/pngdec.c +++ b/libavcodec/pngdec.c @@ -1525,6 +1525,141 @@ end: } #endif +#if CONFIG_LSCR_DECODER +static int decode_frame_lscr(AVCodecContext *avctx, + void *data, int *got_frame, + AVPacket *avpkt) +{ + PNGDecContext *const s = avctx->priv_data; + GetByteContext *gb = &s->gb; + AVFrame *frame = data; + int ret, nb_blocks, offset = 0; + + bytestream2_init(gb, avpkt->data, avpkt->size); + + if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0) + return ret; + + nb_blocks = bytestream2_get_le16(gb); + + if (s->last_picture.f->data[0]) { + ret = av_frame_copy(frame, s->last_picture.f); + if (ret < 0) + return ret; + } + + for (int b = 0; b < nb_blocks; b++) { + int x, y, x2, y2, w, h, left; + uint32_t csize, size; + + s->zstream.zalloc = ff_png_zalloc; + s->zstream.zfree = ff_png_zfree; + s->zstream.opaque = NULL; + + if ((ret = inflateInit(&s->zstream)) != Z_OK) { + av_log(avctx, AV_LOG_ERROR, "inflateInit returned error %d\n", ret); + ret = AVERROR_EXTERNAL; + goto end; + } + + bytestream2_seek(gb, 2 + b * 12, SEEK_SET); + + x = bytestream2_get_le16(gb); + y = bytestream2_get_le16(gb); + x2 = bytestream2_get_le16(gb); + y2 = bytestream2_get_le16(gb); + s->width = s->cur_w = w = x2-x; + s->height = s->cur_h = h = y2-y; + + if (w <= 0 || x < 0 || x >= avctx->width || w + x > avctx->width || + h <= 0 || y < 0 || y >= avctx->height || h + y > avctx->height) { + ret = AVERROR_INVALIDDATA; + goto end; + } + + size = bytestream2_get_le32(gb); + + frame->key_frame = (nb_blocks == 1) && + (w == avctx->width) && + (h == avctx->height) && + (x == 0) && (y == 0); + + bytestream2_seek(gb, 2 + nb_blocks * 12 + offset, SEEK_SET); + csize = bytestream2_get_be32(gb); + if (bytestream2_get_le32(gb) != MKTAG('I', 'D', 'A', 'T')) { + ret = AVERROR_INVALIDDATA; + goto end; + } + + offset += size; + left = size; + + s->y = 0; + s->row_size = w * 3; + + av_fast_padded_malloc(&s->buffer, &s->buffer_size, s->row_size + 16); + if (!s->buffer) { + ret = AVERROR(ENOMEM); + goto end; + } + + av_fast_padded_malloc(&s->last_row, &s->last_row_size, s->row_size); + if (!s->last_row) { + ret = AVERROR(ENOMEM); + goto end; + } + + s->crow_size = w * 3 + 1; + s->crow_buf = s->buffer + 15; + s->zstream.avail_out = s->crow_size; + s->zstream.next_out = s->crow_buf; + s->image_buf = frame->data[0] + (avctx->height - y - 1) * frame->linesize[0] + x * 3; + s->image_linesize =-frame->linesize[0]; + s->bpp = 3; + s->pic_state = 0; + + while (left > 16) { + ret = png_decode_idat(s, csize); + if (ret < 0) + goto end; + left -= csize + 16; + if (left > 16) { + bytestream2_skip(gb, 4); + csize = bytestream2_get_be32(gb); + if (bytestream2_get_le32(gb) != MKTAG('I', 'D', 'A', 'T')) { + ret = AVERROR_INVALIDDATA; + goto end; + } + } + } + + inflateEnd(&s->zstream); + } + + frame->pict_type = frame->key_frame ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P; + + av_frame_unref(s->last_picture.f); + if ((ret = av_frame_ref(s->last_picture.f, frame)) < 0) + return ret; + + *got_frame = 1; +end: + inflateEnd(&s->zstream); + + if (ret < 0) + return ret; + return avpkt->size; +} + +static void decode_flush(AVCodecContext *avctx) +{ + PNGDecContext *s = avctx->priv_data; + + av_frame_unref(s->last_picture.f); +} + +#endif + #if HAVE_THREADS static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src) { @@ -1581,6 +1716,9 @@ static av_cold int png_dec_init(AVCodecContext *avctx) avctx->color_range = AVCOL_RANGE_JPEG; + if (avctx->codec_id == AV_CODEC_ID_LSCR) + avctx->pix_fmt = AV_PIX_FMT_BGR24; + s->avctx = avctx; s->previous_picture.f = av_frame_alloc(); s->last_picture.f = av_frame_alloc(); @@ -1653,3 +1791,19 @@ AVCodec ff_png_decoder = { .caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM | FF_CODEC_CAP_INIT_THREADSAFE, }; #endif + +#if CONFIG_LSCR_DECODER +AVCodec ff_lscr_decoder = { + .name = "lscr", + .long_name = NULL_IF_CONFIG_SMALL("LEAD Screen Capture"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_LSCR, + .priv_data_size = sizeof(PNGDecContext), + .init = png_dec_init, + .close = png_dec_end, + .decode = decode_frame_lscr, + .flush = decode_flush, + .capabilities = AV_CODEC_CAP_DR1 /*| AV_CODEC_CAP_DRAW_HORIZ_BAND*/, + .caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM | FF_CODEC_CAP_INIT_THREADSAFE, +}; +#endif