From c5230955640cb65101a5f8add83abee0410583eb Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Mon, 10 Apr 2017 11:08:44 +0200 Subject: [PATCH 1/8] utvideodec: Support UQY2 Signed-off-by: Luca Barbato --- libavcodec/utvideo.c | 6 + libavcodec/utvideo.h | 4 +- libavcodec/utvideodec.c | 282 ++++++++++++++++++++++++++++++++++------ libavformat/riff.c | 1 + 4 files changed, 253 insertions(+), 40 deletions(-) diff --git a/libavcodec/utvideo.c b/libavcodec/utvideo.c index 35e927ca2d..556b4de602 100644 --- a/libavcodec/utvideo.c +++ b/libavcodec/utvideo.c @@ -39,3 +39,9 @@ int ff_ut_huff_cmp_len(const void *a, const void *b) const HuffEntry *aa = a, *bb = b; return (aa->len - bb->len)*256 + aa->sym - bb->sym; } + +int ff_ut10_huff_cmp_len(const void *a, const void *b) +{ + const HuffEntry *aa = a, *bb = b; + return (aa->len - bb->len) * 1024 + aa->sym - bb->sym; +} diff --git a/libavcodec/utvideo.h b/libavcodec/utvideo.h index c7f54145f1..bc83a28d43 100644 --- a/libavcodec/utvideo.h +++ b/libavcodec/utvideo.h @@ -76,6 +76,7 @@ typedef struct UtvideoContext { int compression; int interlaced; int frame_pred; + int pro; ptrdiff_t slice_stride; uint8_t *slice_bits, *slice_buffer[4]; @@ -83,12 +84,13 @@ typedef struct UtvideoContext { } UtvideoContext; typedef struct HuffEntry { - uint8_t sym; + uint16_t sym; uint8_t len; uint32_t code; } HuffEntry; /* Compare huffman tree nodes */ int ff_ut_huff_cmp_len(const void *a, const void *b); +int ff_ut10_huff_cmp_len(const void *a, const void *b); #endif /* AVCODEC_UTVIDEO_H */ diff --git a/libavcodec/utvideodec.c b/libavcodec/utvideodec.c index 2aaf861e62..47f9de86c4 100644 --- a/libavcodec/utvideodec.c +++ b/libavcodec/utvideodec.c @@ -37,6 +37,50 @@ #include "thread.h" #include "utvideo.h" +static int build_huff10(const uint8_t *src, VLC *vlc, int *fsym) +{ + int i; + HuffEntry he[1024]; + int last; + uint32_t codes[1024]; + uint8_t bits[1024]; + uint16_t syms[1024]; + uint32_t code; + + *fsym = -1; + for (i = 0; i < 1024; i++) { + he[i].sym = i; + he[i].len = *src++; + } + qsort(he, 1024, sizeof(*he), ff_ut10_huff_cmp_len); + + if (!he[0].len) { + *fsym = he[0].sym; + return 0; + } + + last = 1023; + while (he[last].len == 255 && last) + last--; + + if (he[last].len > 32) { + return -1; + } + + code = 1; + for (i = last; i >= 0; i--) { + codes[i] = code >> (32 - he[i].len); + bits[i] = he[i].len; + syms[i] = he[i].sym; + code += 0x80000000u >> (he[i].len - 1); + } + + return ff_init_vlc_sparse(vlc, FFMIN(he[last].len, 11), last + 1, + bits, sizeof(*bits), sizeof(*bits), + codes, sizeof(*codes), sizeof(*codes), + syms, sizeof(*syms), sizeof(*syms), 0); +} + static int build_huff(const uint8_t *src, VLC *vlc, int *fsym) { int i; @@ -79,6 +123,111 @@ static int build_huff(const uint8_t *src, VLC *vlc, int *fsym) syms, sizeof(*syms), sizeof(*syms), 0); } +static int decode_plane10(UtvideoContext *c, int plane_no, + uint16_t *dst, int step, int stride, + int width, int height, + const uint8_t *src, const uint8_t *huff, + int use_pred) +{ + BitstreamContext bc; + int i, j, slice, pix, ret; + int sstart, send; + VLC vlc; + int prev, fsym; + + if ((ret = build_huff10(huff, &vlc, &fsym)) < 0) { + av_log(c->avctx, AV_LOG_ERROR, "Cannot build Huffman codes\n"); + return ret; + } + if (fsym >= 0) { // build_huff reported a symbol to fill slices with + send = 0; + for (slice = 0; slice < c->slices; slice++) { + uint16_t *dest; + + sstart = send; + send = (height * (slice + 1) / c->slices); + dest = dst + sstart * stride; + + prev = 0x200; + for (j = sstart; j < send; j++) { + for (i = 0; i < width * step; i += step) { + pix = fsym; + if (use_pred) { + prev += pix; + prev &= 0x3FF; + pix = prev; + } + dest[i] = pix; + } + dest += stride; + } + } + return 0; + } + + send = 0; + for (slice = 0; slice < c->slices; slice++) { + uint16_t *dest; + int slice_data_start, slice_data_end, slice_size; + + sstart = send; + send = (height * (slice + 1) / c->slices); + dest = dst + sstart * stride; + + // slice offset and size validation was done earlier + slice_data_start = slice ? AV_RL32(src + slice * 4 - 4) : 0; + slice_data_end = AV_RL32(src + slice * 4); + slice_size = slice_data_end - slice_data_start; + + if (!slice_size) { + av_log(c->avctx, AV_LOG_ERROR, "Plane has more than one symbol " + "yet a slice has a length of zero.\n"); + goto fail; + } + + memcpy(c->slice_bits, src + slice_data_start + c->slices * 4, + slice_size); + memset(c->slice_bits + slice_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + c->bdsp.bswap_buf((uint32_t *) c->slice_bits, + (uint32_t *) c->slice_bits, + (slice_data_end - slice_data_start + 3) >> 2); + bitstream_init8(&bc, c->slice_bits, slice_size); + + prev = 0x200; + for (j = sstart; j < send; j++) { + for (i = 0; i < width * step; i += step) { + if (bitstream_bits_left(&bc) <= 0) { + av_log(c->avctx, AV_LOG_ERROR, + "Slice decoding ran out of bits\n"); + goto fail; + } + pix = bitstream_read_vlc(&bc, vlc.table, vlc.bits, 3); + if (pix < 0) { + av_log(c->avctx, AV_LOG_ERROR, "Decoding error\n"); + goto fail; + } + if (use_pred) { + prev += pix; + prev &= 0x3FF; + pix = prev; + } + dest[i] = pix; + } + dest += stride; + } + if (bitstream_bits_left(&bc) > 32) + av_log(c->avctx, AV_LOG_WARNING, + "%d bits left after decoding slice\n", bitstream_bits_left(&bc)); + } + + ff_free_vlc(&vlc); + + return 0; +fail: + ff_free_vlc(&vlc); + return AVERROR_INVALIDDATA; +} + static int decode_plane(UtvideoContext *c, int plane_no, uint8_t *dst, int step, ptrdiff_t stride, int width, int height, @@ -350,35 +499,68 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, /* parse plane structure to get frame flags and validate slice offsets */ bytestream2_init(&gb, buf, buf_size); - for (i = 0; i < c->planes; i++) { - plane_start[i] = gb.buffer; - if (bytestream2_get_bytes_left(&gb) < 256 + 4 * c->slices) { - av_log(avctx, AV_LOG_ERROR, "Insufficient data for a plane\n"); + if (c->pro) { + if (bytestream2_get_bytes_left(&gb) < c->frame_info_size) { + av_log(avctx, AV_LOG_ERROR, "Not enough data for frame information\n"); return AVERROR_INVALIDDATA; } - bytestream2_skipu(&gb, 256); - slice_start = 0; - slice_end = 0; - for (j = 0; j < c->slices; j++) { - slice_end = bytestream2_get_le32u(&gb); - if (slice_end < 0 || slice_end < slice_start || - bytestream2_get_bytes_left(&gb) < slice_end) { - av_log(avctx, AV_LOG_ERROR, "Incorrect slice size\n"); + c->frame_info = bytestream2_get_le32u(&gb); + c->slices = ((c->frame_info >> 16) & 0xff) + 1; + for (i = 0; i < c->planes; i++) { + plane_start[i] = gb.buffer; + if (bytestream2_get_bytes_left(&gb) < 1024 + 4 * c->slices) { + av_log(avctx, AV_LOG_ERROR, "Insufficient data for a plane\n"); return AVERROR_INVALIDDATA; } - slice_size = slice_end - slice_start; - slice_start = slice_end; - max_slice_size = FFMAX(max_slice_size, slice_size); + slice_start = 0; + slice_end = 0; + for (j = 0; j < c->slices; j++) { + slice_end = bytestream2_get_le32u(&gb); + if (slice_end < 0 || slice_end < slice_start || + bytestream2_get_bytes_left(&gb) < slice_end) { + av_log(avctx, AV_LOG_ERROR, "Incorrect slice size\n"); + return AVERROR_INVALIDDATA; + } + slice_size = slice_end - slice_start; + slice_start = slice_end; + max_slice_size = FFMAX(max_slice_size, slice_size); + } + plane_size = slice_end; + bytestream2_skipu(&gb, plane_size); + bytestream2_skipu(&gb, 1024); } - plane_size = slice_end; - bytestream2_skipu(&gb, plane_size); + plane_start[c->planes] = gb.buffer; + } else { + for (i = 0; i < c->planes; i++) { + plane_start[i] = gb.buffer; + if (bytestream2_get_bytes_left(&gb) < 256 + 4 * c->slices) { + av_log(avctx, AV_LOG_ERROR, "Insufficient data for a plane\n"); + return AVERROR_INVALIDDATA; + } + bytestream2_skipu(&gb, 256); + slice_start = 0; + slice_end = 0; + for (j = 0; j < c->slices; j++) { + slice_end = bytestream2_get_le32u(&gb); + if (slice_end < 0 || slice_end < slice_start || + bytestream2_get_bytes_left(&gb) < slice_end) { + av_log(avctx, AV_LOG_ERROR, "Incorrect slice size\n"); + return AVERROR_INVALIDDATA; + } + slice_size = slice_end - slice_start; + slice_start = slice_end; + max_slice_size = FFMAX(max_slice_size, slice_size); + } + plane_size = slice_end; + bytestream2_skipu(&gb, plane_size); + } + plane_start[c->planes] = gb.buffer; + if (bytestream2_get_bytes_left(&gb) < c->frame_info_size) { + av_log(avctx, AV_LOG_ERROR, "Not enough data for frame information\n"); + return AVERROR_INVALIDDATA; + } + c->frame_info = bytestream2_get_le32u(&gb); } - plane_start[c->planes] = gb.buffer; - if (bytestream2_get_bytes_left(&gb) < c->frame_info_size) { - av_log(avctx, AV_LOG_ERROR, "Not enough data for frame information\n"); - return AVERROR_INVALIDDATA; - } - c->frame_info = bytestream2_get_le32u(&gb); av_log(avctx, AV_LOG_DEBUG, "frame information flags %"PRIX32"\n", c->frame_info); @@ -464,6 +646,15 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, } } break; + case AV_PIX_FMT_YUV422P10: + for (i = 0; i < 3; i++) { + ret = decode_plane10(c, i, (uint16_t *)frame.f->data[i], 1, frame.f->linesize[i] / 2, + avctx->width >> !!i, avctx->height, + plane_start[i], plane_start[i + 1] - 1024, c->frame_pred == PRED_LEFT); + if (ret) + return ret; + } + break; } frame.f->key_frame = 1; @@ -484,28 +675,37 @@ static av_cold int decode_init(AVCodecContext *avctx) ff_bswapdsp_init(&c->bdsp); - if (avctx->extradata_size < 16) { + if (avctx->extradata_size >= 16) { + av_log(avctx, AV_LOG_DEBUG, "Encoder version %d.%d.%d.%d\n", + avctx->extradata[3], avctx->extradata[2], + avctx->extradata[1], avctx->extradata[0]); + av_log(avctx, AV_LOG_DEBUG, "Original format %"PRIX32"\n", + AV_RB32(avctx->extradata + 4)); + c->frame_info_size = AV_RL32(avctx->extradata + 8); + c->flags = AV_RL32(avctx->extradata + 12); + + if (c->frame_info_size != 4) + avpriv_request_sample(avctx, "Frame info not 4 bytes"); + av_log(avctx, AV_LOG_DEBUG, "Encoding parameters %08"PRIX32"\n", c->flags); + c->slices = (c->flags >> 24) + 1; + c->compression = c->flags & 1; + c->interlaced = c->flags & 0x800; + } else if (avctx->extradata_size == 8) { + av_log(avctx, AV_LOG_DEBUG, "Encoder version %d.%d.%d.%d\n", + avctx->extradata[3], avctx->extradata[2], + avctx->extradata[1], avctx->extradata[0]); + av_log(avctx, AV_LOG_DEBUG, "Original format %"PRIX32"\n", + AV_RB32(avctx->extradata + 4)); + c->interlaced = 0; + c->pro = 1; + c->frame_info_size = 4; + } else { av_log(avctx, AV_LOG_ERROR, "Insufficient extradata size %d, should be at least 16\n", avctx->extradata_size); return AVERROR_INVALIDDATA; } - av_log(avctx, AV_LOG_DEBUG, "Encoder version %d.%d.%d.%d\n", - avctx->extradata[3], avctx->extradata[2], - avctx->extradata[1], avctx->extradata[0]); - av_log(avctx, AV_LOG_DEBUG, "Original format %"PRIX32"\n", - AV_RB32(avctx->extradata + 4)); - c->frame_info_size = AV_RL32(avctx->extradata + 8); - c->flags = AV_RL32(avctx->extradata + 12); - - if (c->frame_info_size != 4) - avpriv_request_sample(avctx, "Frame info not 4 bytes"); - av_log(avctx, AV_LOG_DEBUG, "Encoding parameters %08"PRIX32"\n", c->flags); - c->slices = (c->flags >> 24) + 1; - c->compression = c->flags & 1; - c->interlaced = c->flags & 0x800; - c->slice_bits_size = 0; switch (avctx->codec_tag) { @@ -527,6 +727,10 @@ static av_cold int decode_init(AVCodecContext *avctx) avctx->pix_fmt = AV_PIX_FMT_YUV422P; avctx->colorspace = AVCOL_SPC_BT470BG; break; + case MKTAG('U', 'Q', 'Y', '2'): + c->planes = 3; + avctx->pix_fmt = AV_PIX_FMT_YUV422P10; + break; case MKTAG('U', 'L', 'H', '0'): c->planes = 3; avctx->pix_fmt = AV_PIX_FMT_YUV420P; diff --git a/libavformat/riff.c b/libavformat/riff.c index 49b8c762d6..69dabc0d52 100644 --- a/libavformat/riff.c +++ b/libavformat/riff.c @@ -342,6 +342,7 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'L', 'Y', '2') }, { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'L', 'H', '0') }, { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'L', 'H', '2') }, + { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'Q', 'Y', '2') }, { AV_CODEC_ID_VBLE, MKTAG('V', 'B', 'L', 'E') }, { AV_CODEC_ID_ESCAPE130, MKTAG('E', '1', '3', '0') }, { AV_CODEC_ID_DXTORY, MKTAG('x', 't', 'o', 'r') }, From 030c8be7a2c0f3ce0440ef37fe5207c0288b8c9e Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Fri, 10 Jun 2016 12:48:09 +0200 Subject: [PATCH 2/8] pixfmt: Add gbrap10 pixel format Signed-off-by: Paul B Mahol Signed-off-by: Luca Barbato --- libavutil/pixdesc.c | 28 ++++++++++++++++++++++++++++ libavutil/pixfmt.h | 4 ++++ 2 files changed, 32 insertions(+) diff --git a/libavutil/pixdesc.c b/libavutil/pixdesc.c index 815e084155..fb2e1a12f3 100644 --- a/libavutil/pixdesc.c +++ b/libavutil/pixdesc.c @@ -1683,6 +1683,34 @@ static const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = { }, .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_BE, }, + [AV_PIX_FMT_GBRAP10LE] = { + .name = "gbrap10le", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 10, 1, 9, 1 }, /* R */ + { 0, 2, 0, 0, 10, 1, 9, 1 }, /* G */ + { 1, 2, 0, 0, 10, 1, 9, 1 }, /* B */ + { 3, 2, 0, 0, 10, 1, 9, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB | + AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_GBRAP10BE] = { + .name = "gbrap10be", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 10, 1, 9, 1 }, /* R */ + { 0, 2, 0, 0, 10, 1, 9, 1 }, /* G */ + { 1, 2, 0, 0, 10, 1, 9, 1 }, /* B */ + { 3, 2, 0, 0, 10, 1, 9, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | + AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA, + }, [AV_PIX_FMT_GBRAP12LE] = { .name = "gbrap12le", .nb_components = 4, diff --git a/libavutil/pixfmt.h b/libavutil/pixfmt.h index 3c670fc9d4..fc1969ef12 100644 --- a/libavutil/pixfmt.h +++ b/libavutil/pixfmt.h @@ -234,6 +234,9 @@ enum AVPixelFormat { AV_PIX_FMT_GRAY12BE, ///< Y , 12bpp, big-endian AV_PIX_FMT_GRAY12LE, ///< Y , 12bpp, little-endian + AV_PIX_FMT_GBRAP10BE, ///< planar GBR 4:4:4:4 40bpp, big-endian + AV_PIX_FMT_GBRAP10LE, ///< planar GBR 4:4:4:4 40bpp, little-endian + AV_PIX_FMT_NB, ///< number of pixel formats, DO NOT USE THIS if you want to link with shared libav* because the number of formats might differ between versions }; @@ -280,6 +283,7 @@ enum AVPixelFormat { #define AV_PIX_FMT_GBRP12 AV_PIX_FMT_NE(GBRP12BE, GBRP12LE) #define AV_PIX_FMT_GBRP16 AV_PIX_FMT_NE(GBRP16BE, GBRP16LE) +#define AV_PIX_FMT_GBRAP10 AV_PIX_FMT_NE(GBRAP10BE, GBRAP10LE) #define AV_PIX_FMT_GBRAP12 AV_PIX_FMT_NE(GBRAP12BE, GBRAP12LE) #define AV_PIX_FMT_GBRAP16 AV_PIX_FMT_NE(GBRAP16BE, GBRAP16LE) From f6a9c20a52d67df2cd1cdbe3d2c58f336666b7d4 Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Fri, 10 Jun 2016 13:01:26 +0200 Subject: [PATCH 3/8] swscale: Add input support for gbrap10 pixel format Signed-off-by: Paul B Mahol --- libswscale/input.c | 16 ++++++++++++++++ libswscale/utils.c | 3 +++ 2 files changed, 19 insertions(+) diff --git a/libswscale/input.c b/libswscale/input.c index d8560a1f2b..761776c1ce 100644 --- a/libswscale/input.c +++ b/libswscale/input.c @@ -699,11 +699,21 @@ static void planar_rgb10le_to_y(uint8_t *dst, const uint8_t *src[4], int w) planar_rgb16_to_y(dst, src, w, 10, 0); } +static void planar_rgb10le_to_a(uint8_t *dst, const uint8_t *src[4], int w) +{ + planar_rgb16_to_a(dst, src, w, 10, 0); +} + static void planar_rgb10be_to_y(uint8_t *dst, const uint8_t *src[4], int w) { planar_rgb16_to_y(dst, src, w, 10, 1); } +static void planar_rgb10be_to_a(uint8_t *dst, const uint8_t *src[4], int w) +{ + planar_rgb16_to_a(dst, src, w, 10, 1); +} + static void planar_rgb12le_to_y(uint8_t *dst, const uint8_t *src[4], int w) { planar_rgb16_to_y(dst, src, w, 12, 0); @@ -842,6 +852,7 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c) case AV_PIX_FMT_GBRP9LE: c->readChrPlanar = planar_rgb9le_to_uv; break; + case AV_PIX_FMT_GBRAP10LE: case AV_PIX_FMT_GBRP10LE: c->readChrPlanar = planar_rgb10le_to_uv; break; @@ -856,6 +867,7 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c) case AV_PIX_FMT_GBRP9BE: c->readChrPlanar = planar_rgb9be_to_uv; break; + case AV_PIX_FMT_GBRAP10BE: case AV_PIX_FMT_GBRP10BE: c->readChrPlanar = planar_rgb10be_to_uv; break; @@ -1073,6 +1085,8 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c) case AV_PIX_FMT_GBRP9LE: c->readLumPlanar = planar_rgb9le_to_y; break; + case AV_PIX_FMT_GBRAP10LE: + c->readAlpPlanar = planar_rgb10le_to_a; case AV_PIX_FMT_GBRP10LE: c->readLumPlanar = planar_rgb10le_to_y; break; @@ -1089,6 +1103,8 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c) case AV_PIX_FMT_GBRP9BE: c->readLumPlanar = planar_rgb9be_to_y; break; + case AV_PIX_FMT_GBRAP10BE: + c->readAlpPlanar = planar_rgb10be_to_a; case AV_PIX_FMT_GBRP10BE: c->readLumPlanar = planar_rgb10be_to_y; break; diff --git a/libswscale/utils.c b/libswscale/utils.c index 6034b70465..3a5c779ea3 100644 --- a/libswscale/utils.c +++ b/libswscale/utils.c @@ -191,6 +191,8 @@ static const FormatEntry format_entries[AV_PIX_FMT_NB] = { [AV_PIX_FMT_GBRP16LE] = { 1, 0 }, [AV_PIX_FMT_GBRP16BE] = { 1, 0 }, [AV_PIX_FMT_GBRAP] = { 1, 1 }, + [AV_PIX_FMT_GBRAP10LE] = { 1, 0 }, + [AV_PIX_FMT_GBRAP10BE] = { 1, 0 }, [AV_PIX_FMT_GBRAP12LE] = { 1, 1 }, [AV_PIX_FMT_GBRAP12BE] = { 1, 1 }, [AV_PIX_FMT_GBRAP16LE] = { 1, 0 }, @@ -1021,6 +1023,7 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter, srcFormat != AV_PIX_FMT_RGB4_BYTE && srcFormat != AV_PIX_FMT_BGR4_BYTE && srcFormat != AV_PIX_FMT_GBRP9BE && srcFormat != AV_PIX_FMT_GBRP9LE && srcFormat != AV_PIX_FMT_GBRP10BE && srcFormat != AV_PIX_FMT_GBRP10LE && + srcFormat != AV_PIX_FMT_GBRAP10BE && srcFormat != AV_PIX_FMT_GBRAP10LE && srcFormat != AV_PIX_FMT_GBRP12BE && srcFormat != AV_PIX_FMT_GBRP12LE && srcFormat != AV_PIX_FMT_GBRP16BE && srcFormat != AV_PIX_FMT_GBRP16LE && ((dstW >> c->chrDstHSubSample) <= (srcW >> 1) || From ac29b82ec596c19c649b43f9988cbcc56f83b9e8 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer Date: Thu, 10 Nov 2016 00:02:50 +0100 Subject: [PATCH 4/8] swscale: Add gbrap10 output Signed-off-by: Michael Niedermayer Signed-off-by: Luca Barbato --- libswscale/output.c | 2 ++ libswscale/utils.c | 4 ++-- tests/ref/fate/filter-pixdesc-gbrap10be | 1 + tests/ref/fate/filter-pixdesc-gbrap10le | 1 + tests/ref/fate/filter-pixfmts-copy | 2 ++ tests/ref/fate/filter-pixfmts-null | 2 ++ tests/ref/fate/filter-pixfmts-scale | 2 ++ tests/ref/fate/filter-pixfmts-vflip | 2 ++ 8 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 tests/ref/fate/filter-pixdesc-gbrap10be create mode 100644 tests/ref/fate/filter-pixdesc-gbrap10le diff --git a/libswscale/output.c b/libswscale/output.c index d0c303c3a8..cfb204300a 100644 --- a/libswscale/output.c +++ b/libswscale/output.c @@ -1457,6 +1457,8 @@ av_cold void ff_sws_init_output_funcs(SwsContext *c, case AV_PIX_FMT_GBRP10LE: case AV_PIX_FMT_GBRP12BE: case AV_PIX_FMT_GBRP12LE: + case AV_PIX_FMT_GBRAP10BE: + case AV_PIX_FMT_GBRAP10LE: case AV_PIX_FMT_GBRAP12BE: case AV_PIX_FMT_GBRAP12LE: case AV_PIX_FMT_GBRP16BE: diff --git a/libswscale/utils.c b/libswscale/utils.c index 3a5c779ea3..248a8081ff 100644 --- a/libswscale/utils.c +++ b/libswscale/utils.c @@ -191,8 +191,8 @@ static const FormatEntry format_entries[AV_PIX_FMT_NB] = { [AV_PIX_FMT_GBRP16LE] = { 1, 0 }, [AV_PIX_FMT_GBRP16BE] = { 1, 0 }, [AV_PIX_FMT_GBRAP] = { 1, 1 }, - [AV_PIX_FMT_GBRAP10LE] = { 1, 0 }, - [AV_PIX_FMT_GBRAP10BE] = { 1, 0 }, + [AV_PIX_FMT_GBRAP10LE] = { 1, 1 }, + [AV_PIX_FMT_GBRAP10BE] = { 1, 1 }, [AV_PIX_FMT_GBRAP12LE] = { 1, 1 }, [AV_PIX_FMT_GBRAP12BE] = { 1, 1 }, [AV_PIX_FMT_GBRAP16LE] = { 1, 0 }, diff --git a/tests/ref/fate/filter-pixdesc-gbrap10be b/tests/ref/fate/filter-pixdesc-gbrap10be new file mode 100644 index 0000000000..de31be676d --- /dev/null +++ b/tests/ref/fate/filter-pixdesc-gbrap10be @@ -0,0 +1 @@ +pixdesc-gbrap10be 555c0acf80a24fbe2cac7e1babf90e05 diff --git a/tests/ref/fate/filter-pixdesc-gbrap10le b/tests/ref/fate/filter-pixdesc-gbrap10le new file mode 100644 index 0000000000..7e355e2cf0 --- /dev/null +++ b/tests/ref/fate/filter-pixdesc-gbrap10le @@ -0,0 +1 @@ +pixdesc-gbrap10le 7745a3c869fd7dbc1d8fd9db28bd2f89 diff --git a/tests/ref/fate/filter-pixfmts-copy b/tests/ref/fate/filter-pixfmts-copy index bd16f11075..c23187c595 100644 --- a/tests/ref/fate/filter-pixfmts-copy +++ b/tests/ref/fate/filter-pixfmts-copy @@ -13,6 +13,8 @@ bgr565le 6a0d182c7165103b2613d1805c822f9f bgr8 36b9ef72c87da36ac547202d85a5805f bgra 56e6e1bfde40aaa27473e01b46345c82 gbrap 57cb1a02d6f015a4329fe367f3bdfe49 +gbrap10be 56d152356064bce059f85be97f548d68 +gbrap10le 30e9fdb568a60eb3f8dcd55497425fa2 gbrap12be df4b550099df0702f602a8b305702a8c gbrap12le f947c43e494ab87410dfb2547e7e22f2 gbrp d5f73b5d3ba7f6cadbc9b4ecbc161005 diff --git a/tests/ref/fate/filter-pixfmts-null b/tests/ref/fate/filter-pixfmts-null index bd16f11075..c23187c595 100644 --- a/tests/ref/fate/filter-pixfmts-null +++ b/tests/ref/fate/filter-pixfmts-null @@ -13,6 +13,8 @@ bgr565le 6a0d182c7165103b2613d1805c822f9f bgr8 36b9ef72c87da36ac547202d85a5805f bgra 56e6e1bfde40aaa27473e01b46345c82 gbrap 57cb1a02d6f015a4329fe367f3bdfe49 +gbrap10be 56d152356064bce059f85be97f548d68 +gbrap10le 30e9fdb568a60eb3f8dcd55497425fa2 gbrap12be df4b550099df0702f602a8b305702a8c gbrap12le f947c43e494ab87410dfb2547e7e22f2 gbrp d5f73b5d3ba7f6cadbc9b4ecbc161005 diff --git a/tests/ref/fate/filter-pixfmts-scale b/tests/ref/fate/filter-pixfmts-scale index e1737f0b20..0c73ec827a 100644 --- a/tests/ref/fate/filter-pixfmts-scale +++ b/tests/ref/fate/filter-pixfmts-scale @@ -13,6 +13,8 @@ bgr565le 34438643c183ff1748cf7d71453f981c bgr8 e731ba3dbec294e1daa7313e08e88034 bgra 6e1f417ae41636f631de1cfe39ce1778 gbrap eefdbfd1426765ce5e9790022533db0d +gbrap10be 27453716362dda9ebf43c0f6992eff48 +gbrap10le 253139dcb985b9d7c2e583595596dfa0 gbrap12be af4acb3ad0a6630f6ec4534e4d2e869a gbrap12le 90ca5271960dc1ebd6ebe14189223e36 gbrp 5d14768d2ab6cbf3879966b5d5c6befb diff --git a/tests/ref/fate/filter-pixfmts-vflip b/tests/ref/fate/filter-pixfmts-vflip index 11a48c7c71..184793000a 100644 --- a/tests/ref/fate/filter-pixfmts-vflip +++ b/tests/ref/fate/filter-pixfmts-vflip @@ -13,6 +13,8 @@ bgr565le 6f98ccb05e608863ef0912b9a6fd960b bgr8 1f916a75563e6be42c056e7d973a7356 bgra dd8eaea69683884ea45bf2fb635ce415 gbrap 38e04cbd4dc5566586d58ffed0c6b20d +gbrap10be 1c2ddca8b0404ff80e6761c816536b0e +gbrap10le 16382a4276c0c30b90d52d206ad9da32 gbrap12be c53126e45593f2e49451c9c9f58cffac gbrap12le 6d5b3a8f8aae74f3542a63bcd1179a6c gbrp 37954476d089b5b74b06891e64ad6b9e From a93faf30d688b872e0ecc453b2dfc36470683ed6 Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Mon, 10 Apr 2017 11:35:00 +0200 Subject: [PATCH 5/8] utvideodec: Support UQRA and UQRG --- libavcodec/utvideodec.c | 43 +++++++++++++++++++++++++++++++++++++++++ libavformat/riff.c | 2 ++ 2 files changed, 45 insertions(+) diff --git a/libavcodec/utvideodec.c b/libavcodec/utvideodec.c index 47f9de86c4..cc18e3dc95 100644 --- a/libavcodec/utvideodec.c +++ b/libavcodec/utvideodec.c @@ -351,6 +351,28 @@ static void restore_rgb_planes(uint8_t *src, int step, ptrdiff_t stride, } } +static void restore_rgb_planes10(AVFrame *frame, int width, int height) +{ + uint16_t *src_r = (uint16_t *)frame->data[2]; + uint16_t *src_g = (uint16_t *)frame->data[0]; + uint16_t *src_b = (uint16_t *)frame->data[1]; + int r, g, b; + int i, j; + + for (j = 0; j < height; j++) { + for (i = 0; i < width; i++) { + r = src_r[i]; + g = src_g[i]; + b = src_b[i]; + src_r[i] = (r + g - 0x200) & 0x3FF; + src_b[i] = (b + g - 0x200) & 0x3FF; + } + src_r += frame->linesize[2] / 2; + src_g += frame->linesize[0] / 2; + src_b += frame->linesize[1] / 2; + } +} + static void restore_median(uint8_t *src, int step, ptrdiff_t stride, int width, int height, int slices, int rmode) { @@ -605,6 +627,19 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, restore_rgb_planes(frame.f->data[0], c->planes, frame.f->linesize[0], avctx->width, avctx->height); break; + case AV_PIX_FMT_GBRAP10: + case AV_PIX_FMT_GBRP10: + for (i = 0; i < c->planes; i++) { + ret = decode_plane10(c, i, (uint16_t *)frame.f->data[i], 1, + frame.f->linesize[i] / 2, avctx->width, + avctx->height, plane_start[i], + plane_start[i + 1] - 1024, + c->frame_pred == PRED_LEFT); + if (ret) + return ret; + } + restore_rgb_planes10(frame.f, avctx->width, avctx->height); + break; case AV_PIX_FMT_YUV420P: for (i = 0; i < 3; i++) { ret = decode_plane(c, i, frame.f->data[i], 1, frame.f->linesize[i], @@ -731,6 +766,14 @@ static av_cold int decode_init(AVCodecContext *avctx) c->planes = 3; avctx->pix_fmt = AV_PIX_FMT_YUV422P10; break; + case MKTAG('U', 'Q', 'R', 'G'): + c->planes = 3; + avctx->pix_fmt = AV_PIX_FMT_GBRP10; + break; + case MKTAG('U', 'Q', 'R', 'A'): + c->planes = 4; + avctx->pix_fmt = AV_PIX_FMT_GBRAP10; + break; case MKTAG('U', 'L', 'H', '0'): c->planes = 3; avctx->pix_fmt = AV_PIX_FMT_YUV420P; diff --git a/libavformat/riff.c b/libavformat/riff.c index 69dabc0d52..9cd330b344 100644 --- a/libavformat/riff.c +++ b/libavformat/riff.c @@ -343,6 +343,8 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'L', 'H', '0') }, { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'L', 'H', '2') }, { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'Q', 'Y', '2') }, + { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'Q', 'R', 'A') }, + { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'Q', 'R', 'G') }, { AV_CODEC_ID_VBLE, MKTAG('V', 'B', 'L', 'E') }, { AV_CODEC_ID_ESCAPE130, MKTAG('E', '1', '3', '0') }, { AV_CODEC_ID_DXTORY, MKTAG('x', 't', 'o', 'r') }, From 4f33d9d41a03981adff0a9a95ef034fd14625e95 Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Sun, 4 Sep 2016 01:56:02 +0200 Subject: [PATCH 6/8] utvideodec: Support ULY4 and ULH4 Signed-off-by: Paul B Mahol Signed-off-by: Luca Barbato --- libavcodec/utvideodec.c | 30 ++++++++++++++++++++++++++++++ libavformat/riff.c | 2 ++ 2 files changed, 32 insertions(+) diff --git a/libavcodec/utvideodec.c b/libavcodec/utvideodec.c index cc18e3dc95..f5fae8ba44 100644 --- a/libavcodec/utvideodec.c +++ b/libavcodec/utvideodec.c @@ -681,6 +681,26 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, } } break; + case AV_PIX_FMT_YUV444P: + for (i = 0; i < 3; i++) { + ret = decode_plane(c, i, frame.f->data[i], 1, frame.f->linesize[i], + avctx->width, avctx->height, + plane_start[i], c->frame_pred == PRED_LEFT); + if (ret) + return ret; + if (c->frame_pred == PRED_MEDIAN) { + if (!c->interlaced) { + restore_median(frame.f->data[i], 1, frame.f->linesize[i], + avctx->width, avctx->height, + c->slices, 0); + } else { + restore_median_il(frame.f->data[i], 1, frame.f->linesize[i], + avctx->width, avctx->height, + c->slices, 0); + } + } + } + break; case AV_PIX_FMT_YUV422P10: for (i = 0; i < 3; i++) { ret = decode_plane10(c, i, (uint16_t *)frame.f->data[i], 1, frame.f->linesize[i] / 2, @@ -762,6 +782,11 @@ static av_cold int decode_init(AVCodecContext *avctx) avctx->pix_fmt = AV_PIX_FMT_YUV422P; avctx->colorspace = AVCOL_SPC_BT470BG; break; + case MKTAG('U', 'L', 'Y', '4'): + c->planes = 3; + avctx->pix_fmt = AV_PIX_FMT_YUV444P; + avctx->colorspace = AVCOL_SPC_BT470BG; + break; case MKTAG('U', 'Q', 'Y', '2'): c->planes = 3; avctx->pix_fmt = AV_PIX_FMT_YUV422P10; @@ -784,6 +809,11 @@ static av_cold int decode_init(AVCodecContext *avctx) avctx->pix_fmt = AV_PIX_FMT_YUV422P; avctx->colorspace = AVCOL_SPC_BT709; break; + case MKTAG('U', 'L', 'H', '4'): + c->planes = 3; + avctx->pix_fmt = AV_PIX_FMT_YUV444P; + avctx->colorspace = AVCOL_SPC_BT709; + break; default: av_log(avctx, AV_LOG_ERROR, "Unknown Ut Video FOURCC provided (%08X)\n", avctx->codec_tag); diff --git a/libavformat/riff.c b/libavformat/riff.c index 9cd330b344..a6734f2789 100644 --- a/libavformat/riff.c +++ b/libavformat/riff.c @@ -340,8 +340,10 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'L', 'R', 'G') }, { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'L', 'Y', '0') }, { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'L', 'Y', '2') }, + { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'L', 'Y', '4') }, { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'L', 'H', '0') }, { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'L', 'H', '2') }, + { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'L', 'H', '4') }, { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'Q', 'Y', '2') }, { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'Q', 'R', 'A') }, { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'Q', 'R', 'G') }, From 9227bd8ac2f22cfad2ee5bc3122d407196a0ba15 Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Fri, 23 Dec 2016 15:41:51 +0100 Subject: [PATCH 7/8] utvideodec: Reuse the huffyuv add_left ~10% faster when simd is available. Signed-off-by: Paul B Mahol Signed-off-by: Luca Barbato --- configure | 2 +- libavcodec/utvideo.h | 2 + libavcodec/utvideodec.c | 164 ++++++++++++++++++++++++++++++++-------- 3 files changed, 137 insertions(+), 31 deletions(-) diff --git a/configure b/configure index ecc77842ff..e83a4cf697 100755 --- a/configure +++ b/configure @@ -2129,7 +2129,7 @@ truespeech_decoder_select="bswapdsp" tscc_decoder_deps="zlib" txd_decoder_select="texturedsp" twinvq_decoder_select="mdct lsp sinewin" -utvideo_decoder_select="bswapdsp" +utvideo_decoder_select="bswapdsp huffyuvdsp" utvideo_encoder_select="bswapdsp huffman huffyuvencdsp" vble_decoder_select="huffyuvdsp" vc1_decoder_select="blockdsp error_resilience h263_decoder h264qpel intrax8 mpeg_er mpegvideo vc1dsp" diff --git a/libavcodec/utvideo.h b/libavcodec/utvideo.h index bc83a28d43..2fa2b7cb93 100644 --- a/libavcodec/utvideo.h +++ b/libavcodec/utvideo.h @@ -30,6 +30,7 @@ #include "libavutil/common.h" #include "avcodec.h" #include "bswapdsp.h" +#include "huffyuvdsp.h" #include "huffyuvencdsp.h" enum { @@ -68,6 +69,7 @@ typedef struct UtvideoContext { const AVClass *class; AVCodecContext *avctx; BswapDSPContext bdsp; + HuffYUVDSPContext hdspdec; HuffYUVEncDSPContext hdsp; uint32_t frame_info_size, flags, frame_info; diff --git a/libavcodec/utvideodec.c b/libavcodec/utvideodec.c index f5fae8ba44..67ffe6f253 100644 --- a/libavcodec/utvideodec.c +++ b/libavcodec/utvideodec.c @@ -373,8 +373,110 @@ static void restore_rgb_planes10(AVFrame *frame, int width, int height) } } -static void restore_median(uint8_t *src, int step, ptrdiff_t stride, - int width, int height, int slices, int rmode) +static void restore_median_planar(UtvideoContext *c, uint8_t *src, + ptrdiff_t stride, int width, int height, + int slices, int rmode) +{ + int i, j, slice; + int A, B, C; + uint8_t *bsrc; + int slice_start, slice_height; + const int cmask = ~rmode; + + for (slice = 0; slice < slices; slice++) { + slice_start = ((slice * height) / slices) & cmask; + slice_height = ((((slice + 1) * height) / slices) & cmask) - + slice_start; + + if (!slice_height) + continue; + bsrc = src + slice_start * stride; + + // first line - left neighbour prediction + bsrc[0] += 0x80; + c->hdspdec.add_hfyu_left_pred(bsrc, bsrc, width, 0); + bsrc += stride; + if (slice_height <= 1) + continue; + // second line - first element has top prediction, the rest uses median + C = bsrc[-stride]; + bsrc[0] += C; + A = bsrc[0]; + for (i = 1; i < width; i++) { + B = bsrc[i - stride]; + bsrc[i] += mid_pred(A, B, (uint8_t)(A + B - C)); + C = B; + A = bsrc[i]; + } + bsrc += stride; + // the rest of lines use continuous median prediction + for (j = 2; j < slice_height; j++) { + c->hdspdec.add_hfyu_median_pred(bsrc, bsrc - stride, + bsrc, width, &A, &B); + bsrc += stride; + } + } +} + +/* UtVideo interlaced mode treats every two lines as a single one, + * so restoring function should take care of possible padding between + * two parts of the same "line". + */ +static void restore_median_planar_il(UtvideoContext *c, uint8_t *src, + ptrdiff_t stride, int width, int height, + int slices, int rmode) +{ + int i, j, slice; + int A, B, C; + uint8_t *bsrc; + int slice_start, slice_height; + const int cmask = ~(rmode ? 3 : 1); + const int stride2 = stride << 1; + + for (slice = 0; slice < slices; slice++) { + slice_start = ((slice * height) / slices) & cmask; + slice_height = ((((slice + 1) * height) / slices) & cmask) - + slice_start; + slice_height >>= 1; + if (!slice_height) + continue; + + bsrc = src + slice_start * stride; + + // first line - left neighbour prediction + bsrc[0] += 0x80; + A = c->hdspdec.add_hfyu_left_pred(bsrc, bsrc, width, 0); + c->hdspdec.add_hfyu_left_pred(bsrc + stride, bsrc + stride, width, A); + bsrc += stride2; + if (slice_height <= 1) + continue; + // second line - first element has top prediction, the rest uses median + C = bsrc[-stride2]; + bsrc[0] += C; + A = bsrc[0]; + for (i = 1; i < width; i++) { + B = bsrc[i - stride2]; + bsrc[i] += mid_pred(A, B, (uint8_t)(A + B - C)); + C = B; + A = bsrc[i]; + } + c->hdspdec.add_hfyu_median_pred(bsrc + stride, bsrc - stride, + bsrc + stride, width, &A, &B); + bsrc += stride2; + // the rest of lines use continuous median prediction + for (j = 2; j < slice_height; j++) { + c->hdspdec.add_hfyu_median_pred(bsrc, bsrc - stride2, + bsrc, width, &A, &B); + c->hdspdec.add_hfyu_median_pred(bsrc + stride, bsrc - stride, + bsrc + stride, width, &A, &B); + bsrc += stride2; + } + } +} + +static void restore_median_packed(uint8_t *src, int step, ptrdiff_t stride, + int width, int height, + int slices, int rmode) { int i, j, slice; int A, B, C; @@ -429,8 +531,9 @@ static void restore_median(uint8_t *src, int step, ptrdiff_t stride, * so restoring function should take care of possible padding between * two parts of the same "line". */ -static void restore_median_il(uint8_t *src, int step, ptrdiff_t stride, - int width, int height, int slices, int rmode) +static void restore_median_packed_il(uint8_t *src, int step, ptrdiff_t stride, + int width, int height, + int slices, int rmode) { int i, j, slice; int A, B, C; @@ -613,14 +716,14 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, return ret; if (c->frame_pred == PRED_MEDIAN) { if (!c->interlaced) { - restore_median(frame.f->data[0] + ff_ut_rgb_order[i], - c->planes, frame.f->linesize[0], avctx->width, - avctx->height, c->slices, 0); + restore_median_packed(frame.f->data[0] + ff_ut_rgb_order[i], + c->planes, frame.f->linesize[0], avctx->width, + avctx->height, c->slices, 0); } else { - restore_median_il(frame.f->data[0] + ff_ut_rgb_order[i], - c->planes, frame.f->linesize[0], - avctx->width, avctx->height, c->slices, - 0); + restore_median_packed_il(frame.f->data[0] + ff_ut_rgb_order[i], + c->planes, frame.f->linesize[0], + avctx->width, avctx->height, c->slices, + 0); } } } @@ -649,14 +752,14 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, return ret; if (c->frame_pred == PRED_MEDIAN) { if (!c->interlaced) { - restore_median(frame.f->data[i], 1, frame.f->linesize[i], - avctx->width >> !!i, avctx->height >> !!i, - c->slices, !i); + restore_median_planar(c, frame.f->data[i], frame.f->linesize[i], + avctx->width >> !!i, avctx->height >> !!i, + c->slices, !i); } else { - restore_median_il(frame.f->data[i], 1, frame.f->linesize[i], - avctx->width >> !!i, - avctx->height >> !!i, - c->slices, !i); + restore_median_planar_il(c, frame.f->data[i], frame.f->linesize[i], + avctx->width >> !!i, + avctx->height >> !!i, + c->slices, !i); } } } @@ -670,13 +773,13 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, return ret; if (c->frame_pred == PRED_MEDIAN) { if (!c->interlaced) { - restore_median(frame.f->data[i], 1, frame.f->linesize[i], - avctx->width >> !!i, avctx->height, - c->slices, 0); + restore_median_planar(c, frame.f->data[i], frame.f->linesize[i], + avctx->width >> !!i, avctx->height, + c->slices, 0); } else { - restore_median_il(frame.f->data[i], 1, frame.f->linesize[i], - avctx->width >> !!i, avctx->height, - c->slices, 0); + restore_median_planar_il(c, frame.f->data[i], frame.f->linesize[i], + avctx->width >> !!i, avctx->height, + c->slices, 0); } } } @@ -690,13 +793,13 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, return ret; if (c->frame_pred == PRED_MEDIAN) { if (!c->interlaced) { - restore_median(frame.f->data[i], 1, frame.f->linesize[i], - avctx->width, avctx->height, - c->slices, 0); + restore_median_planar(c, frame.f->data[i], frame.f->linesize[i], + avctx->width, avctx->height, + c->slices, 0); } else { - restore_median_il(frame.f->data[i], 1, frame.f->linesize[i], - avctx->width, avctx->height, - c->slices, 0); + restore_median_planar_il(c, frame.f->data[i], frame.f->linesize[i], + avctx->width, avctx->height, + c->slices, 0); } } } @@ -729,6 +832,7 @@ static av_cold int decode_init(AVCodecContext *avctx) c->avctx = avctx; ff_bswapdsp_init(&c->bdsp); + ff_huffyuvdsp_init(&c->hdspdec); if (avctx->extradata_size >= 16) { av_log(avctx, AV_LOG_DEBUG, "Encoder version %d.%d.%d.%d\n", From 378460fef1e563704bc5a307ba748a2b819cc09d Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Fri, 7 Apr 2017 20:09:22 +0200 Subject: [PATCH 8/8] utvideodec: Support for gradient prediction Introduced with utvideo 18. Signed-off-by: Paul B Mahol Signed-off-by: Luca Barbato --- libavcodec/utvideodec.c | 232 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 227 insertions(+), 5 deletions(-) diff --git a/libavcodec/utvideodec.c b/libavcodec/utvideodec.c index 67ffe6f253..910d64b57e 100644 --- a/libavcodec/utvideodec.c +++ b/libavcodec/utvideodec.c @@ -602,6 +602,189 @@ static void restore_median_packed_il(uint8_t *src, int step, ptrdiff_t stride, } } +static void restore_gradient_planar(UtvideoContext *c, uint8_t *src, ptrdiff_t stride, + int width, int height, int slices, int rmode) +{ + int i, j, slice; + int A, B, C; + uint8_t *bsrc; + int slice_start, slice_height; + const int cmask = ~rmode; + + for (slice = 0; slice < slices; slice++) { + slice_start = ((slice * height) / slices) & cmask; + slice_height = ((((slice + 1) * height) / slices) & cmask) - + slice_start; + + if (!slice_height) + continue; + bsrc = src + slice_start * stride; + + // first line - left neighbour prediction + bsrc[0] += 0x80; + c->hdspdec.add_hfyu_left_pred(bsrc, bsrc, width, 0); + bsrc += stride; + if (slice_height <= 1) + continue; + for (j = 1; j < slice_height; j++) { + // second line - first element has top prediction, the rest uses gradient + bsrc[0] = (bsrc[0] + bsrc[-stride]) & 0xFF; + for (i = 1; i < width; i++) { + A = bsrc[i - stride]; + B = bsrc[i - (stride + 1)]; + C = bsrc[i - 1]; + bsrc[i] = (A - B + C + bsrc[i]) & 0xFF; + } + bsrc += stride; + } + } +} + +static void restore_gradient_planar_il(UtvideoContext *c, uint8_t *src, ptrdiff_t stride, + int width, int height, int slices, int rmode) +{ + int i, j, slice; + int A, B, C; + uint8_t *bsrc; + int slice_start, slice_height; + const int cmask = ~(rmode ? 3 : 1); + const ptrdiff_t stride2 = stride << 1; + + for (slice = 0; slice < slices; slice++) { + slice_start = ((slice * height) / slices) & cmask; + slice_height = ((((slice + 1) * height) / slices) & cmask) - + slice_start; + slice_height >>= 1; + if (!slice_height) + continue; + + bsrc = src + slice_start * stride; + + // first line - left neighbour prediction + bsrc[0] += 0x80; + A = c->hdspdec.add_hfyu_left_pred(bsrc, bsrc, width, 0); + c->hdspdec.add_hfyu_left_pred(bsrc + stride, bsrc + stride, width, A); + bsrc += stride2; + if (slice_height <= 1) + continue; + for (j = 1; j < slice_height; j++) { + // second line - first element has top prediction, the rest uses gradient + bsrc[0] = (bsrc[0] + bsrc[-stride2]) & 0xFF; + for (i = 1; i < width; i++) { + A = bsrc[i - stride2]; + B = bsrc[i - (stride2 + 1)]; + C = bsrc[i - 1]; + bsrc[i] = (A - B + C + bsrc[i]) & 0xFF; + } + for (i = 0; i < width; i++) { + A = bsrc[i - stride]; + B = bsrc[i - (1 + stride)]; + C = bsrc[i - 1 + stride]; + bsrc[i + stride] = (A - B + C + bsrc[i + stride]) & 0xFF; + } + bsrc += stride2; + } + } +} + +static void restore_gradient_packed(uint8_t *src, int step, ptrdiff_t stride, + int width, int height, int slices, int rmode) +{ + int i, j, slice; + int A, B, C; + uint8_t *bsrc; + int slice_start, slice_height; + const int cmask = ~rmode; + + for (slice = 0; slice < slices; slice++) { + slice_start = ((slice * height) / slices) & cmask; + slice_height = ((((slice + 1) * height) / slices) & cmask) - + slice_start; + + if (!slice_height) + continue; + bsrc = src + slice_start * stride; + + // first line - left neighbour prediction + bsrc[0] += 0x80; + A = bsrc[0]; + for (i = step; i < width * step; i += step) { + bsrc[i] += A; + A = bsrc[i]; + } + bsrc += stride; + if (slice_height <= 1) + continue; + for (j = 1; j < slice_height; j++) { + // second line - first element has top prediction, the rest uses gradient + C = bsrc[-stride]; + bsrc[0] += C; + for (i = step; i < width * step; i += step) { + A = bsrc[i - stride]; + B = bsrc[i - (stride + step)]; + C = bsrc[i - step]; + bsrc[i] = (A - B + C + bsrc[i]) & 0xFF; + } + bsrc += stride; + } + } +} + +static void restore_gradient_packed_il(uint8_t *src, int step, ptrdiff_t stride, + int width, int height, int slices, int rmode) +{ + int i, j, slice; + int A, B, C; + uint8_t *bsrc; + int slice_start, slice_height; + const int cmask = ~(rmode ? 3 : 1); + const ptrdiff_t stride2 = stride << 1; + + for (slice = 0; slice < slices; slice++) { + slice_start = ((slice * height) / slices) & cmask; + slice_height = ((((slice + 1) * height) / slices) & cmask) - + slice_start; + slice_height >>= 1; + if (!slice_height) + continue; + + bsrc = src + slice_start * stride; + + // first line - left neighbour prediction + bsrc[0] += 0x80; + A = bsrc[0]; + for (i = step; i < width * step; i += step) { + bsrc[i] += A; + A = bsrc[i]; + } + for (i = 0; i < width * step; i += step) { + bsrc[stride + i] += A; + A = bsrc[stride + i]; + } + bsrc += stride2; + if (slice_height <= 1) + continue; + for (j = 1; j < slice_height; j++) { + // second line - first element has top prediction, the rest uses gradient + C = bsrc[-stride2]; + bsrc[0] += C; + for (i = step; i < width * step; i += step) { + A = bsrc[i - stride2]; + B = bsrc[i - (stride2 + step)]; + C = bsrc[i - step]; + bsrc[i] = (A - B + C + bsrc[i]) & 0xFF; + } + for (i = 0; i < width * step; i += step) { + A = bsrc[i - stride]; + B = bsrc[i - (step + stride)]; + C = bsrc[i - step + stride]; + bsrc[i + stride] = (A - B + C + bsrc[i + stride]) & 0xFF; + } + bsrc += stride2; + } + } +} + static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt) { @@ -691,11 +874,6 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, c->frame_pred = (c->frame_info >> 8) & 3; - if (c->frame_pred == PRED_GRADIENT) { - avpriv_request_sample(avctx, "Frame with gradient prediction"); - return AVERROR_PATCHWELCOME; - } - av_fast_malloc(&c->slice_bits, &c->slice_bits_size, max_slice_size + AV_INPUT_BUFFER_PADDING_SIZE); @@ -725,6 +903,18 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, avctx->width, avctx->height, c->slices, 0); } + } else if (c->frame_pred == PRED_GRADIENT) { + if (!c->interlaced) { + restore_gradient_packed(frame.f->data[0] + ff_ut_rgb_order[i], + c->planes, frame.f->linesize[0], + avctx->width, avctx->height, + c->slices, 0); + } else { + restore_gradient_packed_il(frame.f->data[0] + ff_ut_rgb_order[i], + c->planes, frame.f->linesize[0], + avctx->width, avctx->height, + c->slices, 0); + } } } restore_rgb_planes(frame.f->data[0], c->planes, frame.f->linesize[0], @@ -761,6 +951,18 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, avctx->height >> !!i, c->slices, !i); } + } else if (c->frame_pred == PRED_GRADIENT) { + if (!c->interlaced) { + restore_gradient_planar(c, frame.f->data[i], frame.f->linesize[i], + avctx->width >> !!i, + avctx->height >> !!i, + c->slices, !i); + } else { + restore_gradient_planar_il(c, frame.f->data[i], frame.f->linesize[i], + avctx->width >> !!i, + avctx->height >> !!i, + c->slices, !i); + } } } break; @@ -781,6 +983,16 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, avctx->width >> !!i, avctx->height, c->slices, 0); } + } else if (c->frame_pred == PRED_GRADIENT) { + if (!c->interlaced) { + restore_gradient_planar(c, frame.f->data[i], frame.f->linesize[i], + avctx->width >> !!i, avctx->height, + c->slices, 0); + } else { + restore_gradient_planar_il(c, frame.f->data[i], frame.f->linesize[i], + avctx->width >> !!i, avctx->height, + c->slices, 0); + } } } break; @@ -801,6 +1013,16 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, avctx->width, avctx->height, c->slices, 0); } + } else if (c->frame_pred == PRED_GRADIENT) { + if (!c->interlaced) { + restore_gradient_planar(c, frame.f->data[i], frame.f->linesize[i], + avctx->width, avctx->height, + c->slices, 0); + } else { + restore_gradient_planar_il(c, frame.f->data[i], frame.f->linesize[i], + avctx->width, avctx->height, + c->slices, 0); + } } } break;