From patchwork Wed Apr 10 11:45:52 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul B Mahol X-Patchwork-Id: 12687 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id 69BED4496EA for ; Wed, 10 Apr 2019 14:46:09 +0300 (EEST) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 4880468AF00; Wed, 10 Apr 2019 14:46:09 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wr1-f67.google.com (mail-wr1-f67.google.com [209.85.221.67]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 98FA368AE2E for ; Wed, 10 Apr 2019 14:46:03 +0300 (EEST) Received: by mail-wr1-f67.google.com with SMTP id p10so2597616wrq.1 for ; Wed, 10 Apr 2019 04:46:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references; bh=dzcYiLrq5nrGGLlNab6RIqGJRoVSSaFNdcRzlicnChk=; b=VJpvOYQY4ikr0TYUN9o0jj/TCpX9h20NpK3BrYS1l4lmUa7aG4l77i45oxZcrVhGUb P9eAQKmxBccx6QsJb2cZYPd7MRmK9AmC8ky+EHfxpmpTfWifq540HKrK4tZO2yH5NWZk eXsuDMxUVrr6YS92131wpk3/777S/Ol1I8nHNJaxlUN2+il/ulWWi30Wkeuvx0K5uSRJ lilty9WU39vzGpo9hLBesYT5Qd79H0ww2BQ7OmPesmqwON6f/ogy0LWWj4n4zGhjbtPJ FRAsyzrfI8k0mBFjEUgsNUmexE+6B06u1UmICgc2JaTBRryyGKQm7ruadPCQ5UhGlFND w+Fw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=dzcYiLrq5nrGGLlNab6RIqGJRoVSSaFNdcRzlicnChk=; b=B84R3bAAskYHcGdADDmCc7eti8nMKT4tkYZmBSBQong7USM6EAKevO+10kMcSrPrHU FnU0o7a0wDBi3kJuuAL7dKu4VQ9FptXsGpP5vMOes3NVTAUZsQFKCvZ6KYnDwCG55xgs QuLPsm4BGjGPJmTbPYmRDtyMIlNNYhmu3dQByznZ/qyGBzucBSerzy09VIAwNZWSz2lV oUlipPKnUMMXlxqY/kUYtrEAHNinEUfJIWURARcYJkEJ0D8x/RcMBKzw23n7Rulbavax l/hAP5iN0zb2vxN1ISR/troyWib8dka+MdhP93d3IUWklZ/N2EDN1DeVzl9IQXhb0y7D jlmg== X-Gm-Message-State: APjAAAVYDMKaahzeIa0OwDuiud8V1kgIo91rpyAxhZes8z7ac5EmOSdu LBAYutRtUnPpDxSO9bfmjbbp4eG8 X-Google-Smtp-Source: APXvYqxB3osQQla3YN99LF8UZgkfrdkwOcrJgnxWkRNycaXWafjYx5xOk5hjdUI1WFOquCItz1erWw== X-Received: by 2002:a5d:4f89:: with SMTP id d9mr7822104wru.195.1554896762735; Wed, 10 Apr 2019 04:46:02 -0700 (PDT) Received: from localhost.localdomain ([37.244.238.255]) by smtp.gmail.com with ESMTPSA id s2sm2293636wmc.7.2019.04.10.04.46.01 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 10 Apr 2019 04:46:02 -0700 (PDT) From: Paul B Mahol To: ffmpeg-devel@ffmpeg.org Date: Wed, 10 Apr 2019 13:45:52 +0200 Message-Id: <20190410114553.16723-2-onemda@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190410114553.16723-1-onemda@gmail.com> References: <20190410114553.16723-1-onemda@gmail.com> Subject: [FFmpeg-devel] [PATCH 2/3] avcodec/agm: add support for non-dct coding X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Signed-off-by: Paul B Mahol --- libavcodec/agm.c | 332 +++++++++++++++++++++++++++++++++++++++------ libavformat/riff.c | 2 + 2 files changed, 291 insertions(+), 43 deletions(-) diff --git a/libavcodec/agm.c b/libavcodec/agm.c index 1d6a277827..e465b22d41 100644 --- a/libavcodec/agm.c +++ b/libavcodec/agm.c @@ -68,10 +68,13 @@ typedef struct AGMContext { int blocks_h; int size[3]; int plus; + int dct; + int rgb; unsigned flags; unsigned fflags; uint8_t *output; + unsigned padded_output_size; unsigned output_size; MotionVector *mvectors; @@ -562,6 +565,227 @@ static void compute_quant_matrix(AGMContext *s, double qscale) } } +static int decode_raw_intra_rgb(AVCodecContext *avctx, GetByteContext *gbyte, AVFrame *frame) +{ + uint8_t *dst = frame->data[0] + (avctx->height - 1) * frame->linesize[0]; + uint8_t r = 0, g = 0, b = 0; + + for (int y = 0; y < avctx->height; y++) { + for (int x = 0; x < avctx->width; x++) { + dst[x*3+0] = bytestream2_get_byte(gbyte) + r; + r = dst[x*3+0]; + dst[x*3+1] = bytestream2_get_byte(gbyte) + g; + g = dst[x*3+1]; + dst[x*3+2] = bytestream2_get_byte(gbyte) + b; + b = dst[x*3+2]; + } + dst -= frame->linesize[0]; + } + + return 0; +} + +static int fill_pixels(uint8_t **y0, uint8_t **y1, + uint8_t **u, uint8_t **v, + int ylinesize, int ulinesize, int vlinesize, + uint8_t *fill, + int *nx, int *ny, int *np, int w, int h) +{ + uint8_t *y0dst = *y0; + uint8_t *y1dst = *y1; + uint8_t *udst = *u; + uint8_t *vdst = *v; + int x = *nx, y = *ny, pos = *np; + + if (pos == 0) { + y0dst[2*x+0] += fill[0]; + y0dst[2*x+1] += fill[1]; + y1dst[2*x+0] += fill[2]; + y1dst[2*x+1] += fill[3]; + pos++; + } else if (pos == 1) { + udst[x] += fill[0]; + vdst[x] += fill[1]; + x++; + if (x >= w) { + x = 0; + y++; + if (y >= h) + return 1; + y0dst -= 2*ylinesize; + y1dst -= 2*ylinesize; + udst -= ulinesize; + vdst -= vlinesize; + } + y0dst[2*x+0] += fill[2]; + y0dst[2*x+1] += fill[3]; + pos++; + } else if (pos == 2) { + y1dst[2*x+0] += fill[0]; + y1dst[2*x+1] += fill[1]; + udst[x] += fill[2]; + vdst[x] += fill[3]; + x++; + if (x >= w) { + x = 0; + y++; + if (y >= h) + return 1; + y0dst -= 2*ylinesize; + y1dst -= 2*ylinesize; + udst -= ulinesize; + vdst -= vlinesize; + } + pos = 0; + } + + *y0 = y0dst; + *y1 = y1dst; + *u = udst; + *v = vdst; + *np = pos; + *nx = x; + *ny = y; + + return 0; +} + +static int decode_runlen_rgb(AVCodecContext *avctx, GetByteContext *gbyte, AVFrame *frame) +{ + uint8_t *dst = frame->data[0] + (avctx->height - 1) * frame->linesize[0]; + int runlen, y = 0, x = 0; + uint8_t fill[4]; + unsigned code; + + while (bytestream2_get_bytes_left(gbyte) > 0) { + code = bytestream2_peek_le32(gbyte); + runlen = code & 0xFFFFFF; + + if (code >> 24 == 0x77) { + bytestream2_skip(gbyte, 4); + + for (int i = 0; i < 4; i++) + fill[i] = bytestream2_get_byte(gbyte); + + while (runlen > 0) { + runlen--; + + for (int i = 0; i < 4; i++) { + dst[x] = fill[i]; + x++; + if (x >= frame->width * 3) { + x = 0; + y++; + dst -= frame->linesize[0]; + if (y >= frame->height) + return 0; + } + } + } + } else { + for (int i = 0; i < 4; i++) + fill[i] = bytestream2_get_byte(gbyte); + + for (int i = 0; i < 4; i++) { + dst[x] = fill[i]; + x++; + if (x >= frame->width * 3) { + x = 0; + y++; + dst -= frame->linesize[0]; + if (y >= frame->height) + return 0; + } + } + } + } + + return 0; +} + +static int decode_runlen(AVCodecContext *avctx, GetByteContext *gbyte, AVFrame *frame) +{ + uint8_t *y0dst = frame->data[0] + (avctx->height - 1) * frame->linesize[0]; + uint8_t *y1dst = y0dst - frame->linesize[0]; + uint8_t *udst = frame->data[1] + ((avctx->height >> 1) - 1) * frame->linesize[1]; + uint8_t *vdst = frame->data[2] + ((avctx->height >> 1) - 1) * frame->linesize[2]; + int runlen, y = 0, x = 0, pos = 0; + uint8_t fill[4]; + unsigned code; + + while (bytestream2_get_bytes_left(gbyte) > 0) { + code = bytestream2_peek_le32(gbyte); + runlen = code & 0xFFFFFF; + + if (code >> 24 == 0x77) { + bytestream2_skip(gbyte, 4); + + for (int i = 0; i < 4; i++) + fill[i] = bytestream2_get_byte(gbyte); + + while (runlen > 0) { + runlen--; + + if (fill_pixels(&y0dst, &y1dst, &udst, &vdst, + frame->linesize[0], + frame->linesize[1], + frame->linesize[2], + fill, &x, &y, &pos, + avctx->width / 2, + avctx->height / 2)) + return 0; + } + } else { + for (int i = 0; i < 4; i++) + fill[i] = bytestream2_get_byte(gbyte); + + if (fill_pixels(&y0dst, &y1dst, &udst, &vdst, + frame->linesize[0], + frame->linesize[1], + frame->linesize[2], + fill, &x, &y, &pos, + avctx->width / 2, + avctx->height / 2)) + return 0; + } + } + + return 0; +} + +static int decode_raw_intra(AVCodecContext *avctx, GetByteContext *gbyte, AVFrame *frame) +{ + uint8_t *y0dst = frame->data[0] + (avctx->height - 1) * frame->linesize[0]; + uint8_t *y1dst = y0dst - frame->linesize[0]; + uint8_t *udst = frame->data[1] + ((avctx->height >> 1) - 1) * frame->linesize[1]; + uint8_t *vdst = frame->data[2] + ((avctx->height >> 1) - 1) * frame->linesize[2]; + uint8_t ly0 = 0, ly1 = 0, ly2 = 0, ly3 = 0, lu = 0, lv = 0; + + for (int y = 0; y < avctx->height / 2; y++) { + for (int x = 0; x < avctx->width / 2; x++) { + y0dst[x*2+0] = bytestream2_get_byte(gbyte) + ly0; + ly0 = y0dst[x*2+0]; + y0dst[x*2+1] = bytestream2_get_byte(gbyte) + ly1; + ly1 = y0dst[x*2+1]; + y1dst[x*2+0] = bytestream2_get_byte(gbyte) + ly2; + ly2 = y1dst[x*2+0]; + y1dst[x*2+1] = bytestream2_get_byte(gbyte) + ly3; + ly3 = y1dst[x*2+1]; + udst[x] = bytestream2_get_byte(gbyte) + lu; + lu = udst[x]; + vdst[x] = bytestream2_get_byte(gbyte) + lv; + lv = vdst[x]; + } + + y0dst -= 2*frame->linesize[0]; + y1dst -= 2*frame->linesize[0]; + udst -= frame->linesize[1]; + vdst -= frame->linesize[2]; + } + + return 0; +} + static int decode_intra(AVCodecContext *avctx, GetBitContext *gb, AVFrame *frame) { AGMContext *s = avctx->priv_data; @@ -808,16 +1032,15 @@ static int decode_huffman2(AVCodecContext *avctx, int header, int size) AGMContext *s = avctx->priv_data; GetBitContext *gb = &s->gb; uint8_t lens[256]; - unsigned output_size; int ret, x, len; if ((ret = init_get_bits8(gb, s->gbyte.buffer, bytestream2_get_bytes_left(&s->gbyte))) < 0) return ret; - output_size = get_bits_long(gb, 32); + s->output_size = get_bits_long(gb, 32); - av_fast_padded_malloc(&s->output, &s->output_size, output_size); + av_fast_padded_malloc(&s->output, &s->padded_output_size, s->output_size); if (!s->output) return AVERROR(ENOMEM); @@ -843,7 +1066,7 @@ static int decode_huffman2(AVCodecContext *avctx, int header, int size) return ret; x = 0; - while (get_bits_left(gb) > 0 && x < output_size) { + while (get_bits_left(gb) > 0 && x < s->output_size) { int val = get_vlc2(gb, s->vlc.table, s->vlc.bits, 3); if (val < 0) return AVERROR_INVALIDDATA; @@ -862,6 +1085,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, AVFrame *frame = data; int w, h, width, height, header; unsigned compressed_size; + long skip; int ret; if (!avpkt->size) @@ -877,7 +1101,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, if (avpkt->size < s->bitstream_size + 8) return AVERROR_INVALIDDATA; - s->key_frame = avpkt->flags & AV_PKT_FLAG_KEY; + s->key_frame = (avpkt->flags & AV_PKT_FLAG_KEY); frame->key_frame = s->key_frame; frame->pict_type = s->key_frame ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P; @@ -890,53 +1114,65 @@ static int decode_frame(AVCodecContext *avctx, void *data, if (ret < 0) return ret; bytestream2_init(gbyte, s->output, s->output_size); + } else if (!s->dct) { + bytestream2_skip(gbyte, 4); } - s->flags = 0; - w = bytestream2_get_le32(gbyte); - h = bytestream2_get_le32(gbyte); - if (w == INT32_MIN || h == INT32_MIN) - return AVERROR_INVALIDDATA; - if (w < 0) { - w = -w; - s->flags |= 2; - } - if (h < 0) { - h = -h; - s->flags |= 1; - } + if (s->dct) { + s->flags = 0; + w = bytestream2_get_le32(gbyte); + h = bytestream2_get_le32(gbyte); + if (w == INT32_MIN || h == INT32_MIN) + return AVERROR_INVALIDDATA; + if (w < 0) { + w = -w; + s->flags |= 2; + } + if (h < 0) { + h = -h; + s->flags |= 1; + } - width = avctx->width; - height = avctx->height; - if (w < width || h < height || w & 7 || h & 7) - return AVERROR_INVALIDDATA; + width = avctx->width; + height = avctx->height; + if (w < width || h < height || w & 7 || h & 7) + return AVERROR_INVALIDDATA; - ret = ff_set_dimensions(avctx, w, h); - if (ret < 0) - return ret; - avctx->width = width; - avctx->height = height; + ret = ff_set_dimensions(avctx, w, h); + if (ret < 0) + return ret; + avctx->width = width; + avctx->height = height; - s->compression = bytestream2_get_le32(gbyte); - if (s->compression < 0 || s->compression > 100) - return AVERROR_INVALIDDATA; + s->compression = bytestream2_get_le32(gbyte); + if (s->compression < 0 || s->compression > 100) + return AVERROR_INVALIDDATA; - for (int i = 0; i < 3; i++) - s->size[i] = bytestream2_get_le32(gbyte); - if (header) - compressed_size = s->output_size; - else - compressed_size = avpkt->size; - if (s->size[0] < 0 || s->size[1] < 0 || s->size[2] < 0 || - 32LL + s->size[0] + s->size[1] + s->size[2] > compressed_size) { - return AVERROR_INVALIDDATA; + for (int i = 0; i < 3; i++) + s->size[i] = bytestream2_get_le32(gbyte); + if (header) { + compressed_size = s->output_size; + skip = 8LL; + } else { + compressed_size = avpkt->size; + skip = 32LL; + } + if (s->size[0] < 0 || s->size[1] < 0 || s->size[2] < 0 || + skip + s->size[0] + s->size[1] + s->size[2] > compressed_size) { + return AVERROR_INVALIDDATA; + } } if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0) return ret; if (frame->key_frame) { - ret = decode_intra(avctx, gb, frame); + if (!s->dct && !s->rgb) + ret = decode_raw_intra(avctx, gbyte, frame); + else if (!s->dct && s->rgb) + ret = decode_raw_intra_rgb(avctx, gbyte, frame); + else + ret = decode_intra(avctx, gb, frame); } else { if (!s->prev_frame->data[0]) { av_log(avctx, AV_LOG_ERROR, "Missing reference frame.\n"); @@ -949,7 +1185,13 @@ static int decode_frame(AVCodecContext *avctx, void *data, return ret; } - ret = decode_inter(avctx, gb, frame, s->prev_frame); + if (s->dct) { + ret = decode_inter(avctx, gb, frame, s->prev_frame); + } else if (!s->dct && !s->rgb) { + ret = decode_runlen(avctx, gbyte, frame); + } else { + ret = decode_runlen_rgb(avctx, gbyte, frame); + } } if (ret < 0) return ret; @@ -970,11 +1212,15 @@ static av_cold int decode_init(AVCodecContext *avctx) { AGMContext *s = avctx->priv_data; - avctx->pix_fmt = AV_PIX_FMT_YUV420P; + s->rgb = avctx->codec_tag == MKTAG('A', 'G', 'M', '4'); + avctx->pix_fmt = s->rgb ? AV_PIX_FMT_BGR24 : AV_PIX_FMT_YUV420P; s->avctx = avctx; s->plus = avctx->codec_tag == MKTAG('A', 'G', 'M', '3') || avctx->codec_tag == MKTAG('A', 'G', 'M', '7'); + s->dct = avctx->codec_tag != MKTAG('A', 'G', 'M', '4') && + avctx->codec_tag != MKTAG('A', 'G', 'M', '5'); + avctx->idct_algo = FF_IDCT_SIMPLE; ff_idctdsp_init(&s->idsp, avctx); ff_init_scantable(s->idsp.idct_permutation, &s->scantable, ff_zigzag_direct); @@ -1004,7 +1250,7 @@ static av_cold int decode_close(AVCodecContext *avctx) av_freep(&s->wblocks); s->wblocks_size = 0; av_freep(&s->output); - s->output_size = 0; + s->padded_output_size = 0; av_freep(&s->map); s->map_size = 0; diff --git a/libavformat/riff.c b/libavformat/riff.c index 3d77efa7d7..394481becd 100644 --- a/libavformat/riff.c +++ b/libavformat/riff.c @@ -481,6 +481,8 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_AGM, MKTAG('A', 'G', 'M', '1') }, { AV_CODEC_ID_AGM, MKTAG('A', 'G', 'M', '2') }, { AV_CODEC_ID_AGM, MKTAG('A', 'G', 'M', '3') }, + { AV_CODEC_ID_AGM, MKTAG('A', 'G', 'M', '4') }, + { AV_CODEC_ID_AGM, MKTAG('A', 'G', 'M', '5') }, { AV_CODEC_ID_AGM, MKTAG('A', 'G', 'M', '6') }, { AV_CODEC_ID_AGM, MKTAG('A', 'G', 'M', '7') }, { AV_CODEC_ID_NONE, 0 }