diff options
author | Paul B Mahol <onemda@gmail.com> | 2019-04-12 17:25:26 +0200 |
---|---|---|
committer | Paul B Mahol <onemda@gmail.com> | 2019-04-13 18:10:11 +0200 |
commit | 16f7c1f2911c5cd01ed0e38d4d34ba519950e893 (patch) | |
tree | e56c2354f70a052b19cc419907caccc0b2bbd3f1 /libavcodec/pngdec.c | |
parent | 3e10223385b83358f013cbf6ba069f15fedc731a (diff) | |
download | ffmpeg-16f7c1f2911c5cd01ed0e38d4d34ba519950e893.tar.gz |
avcodec: add LSCR decoder
Fixes #4711.
Diffstat (limited to 'libavcodec/pngdec.c')
-rw-r--r-- | libavcodec/pngdec.c | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/libavcodec/pngdec.c b/libavcodec/pngdec.c index 189bb9a4c1..6a681be29d 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 |