diff options
Diffstat (limited to 'media/ffvpx/libavutil/imgutils.c')
-rw-r--r-- | media/ffvpx/libavutil/imgutils.c | 271 |
1 files changed, 253 insertions, 18 deletions
diff --git a/media/ffvpx/libavutil/imgutils.c b/media/ffvpx/libavutil/imgutils.c index 37808e53d..500517880 100644 --- a/media/ffvpx/libavutil/imgutils.c +++ b/media/ffvpx/libavutil/imgutils.c @@ -24,6 +24,7 @@ #include "avassert.h" #include "common.h" #include "imgutils.h" +#include "imgutils_internal.h" #include "internal.h" #include "intreadwrite.h" #include "log.h" @@ -248,19 +249,38 @@ static const AVClass imgutils_class = { .parent_log_context_offset = offsetof(ImgUtils, log_ctx), }; -int av_image_check_size(unsigned int w, unsigned int h, int log_offset, void *log_ctx) +int av_image_check_size2(unsigned int w, unsigned int h, int64_t max_pixels, enum AVPixelFormat pix_fmt, int log_offset, void *log_ctx) { ImgUtils imgutils = { .class = &imgutils_class, .log_offset = log_offset, .log_ctx = log_ctx, }; + int64_t stride = av_image_get_linesize(pix_fmt, w, 0); + if (stride <= 0) + stride = 8LL*w; + stride += 128*8; - if ((int)w>0 && (int)h>0 && (w+128)*(uint64_t)(h+128) < INT_MAX/8) - return 0; + if ((int)w<=0 || (int)h<=0 || stride >= INT_MAX || stride*(uint64_t)(h+128) >= INT_MAX) { + av_log(&imgutils, AV_LOG_ERROR, "Picture size %ux%u is invalid\n", w, h); + return AVERROR(EINVAL); + } - av_log(&imgutils, AV_LOG_ERROR, "Picture size %ux%u is invalid\n", w, h); - return AVERROR(EINVAL); + if (max_pixels < INT64_MAX) { + if (w*(int64_t)h > max_pixels) { + av_log(&imgutils, AV_LOG_ERROR, + "Picture size %ux%u exceeds specified max pixel count %"PRId64", see the documentation if you wish to increase it\n", + w, h, max_pixels); + return AVERROR(EINVAL); + } + } + + return 0; +} + +int av_image_check_size(unsigned int w, unsigned int h, int log_offset, void *log_ctx) +{ + return av_image_check_size2(w, h, INT64_MAX, AV_PIX_FMT_NONE, log_offset, log_ctx); } int av_image_check_sar(unsigned int w, unsigned int h, AVRational sar) @@ -284,9 +304,9 @@ int av_image_check_sar(unsigned int w, unsigned int h, AVRational sar) return AVERROR(EINVAL); } -void av_image_copy_plane(uint8_t *dst, int dst_linesize, - const uint8_t *src, int src_linesize, - int bytewidth, int height) +static void image_copy_plane(uint8_t *dst, ptrdiff_t dst_linesize, + const uint8_t *src, ptrdiff_t src_linesize, + ptrdiff_t bytewidth, int height) { if (!dst || !src) return; @@ -299,9 +319,33 @@ void av_image_copy_plane(uint8_t *dst, int dst_linesize, } } -void av_image_copy(uint8_t *dst_data[4], int dst_linesizes[4], - const uint8_t *src_data[4], const int src_linesizes[4], - enum AVPixelFormat pix_fmt, int width, int height) +static void image_copy_plane_uc_from(uint8_t *dst, ptrdiff_t dst_linesize, + const uint8_t *src, ptrdiff_t src_linesize, + ptrdiff_t bytewidth, int height) +{ + int ret = -1; + +#if ARCH_X86 + ret = ff_image_copy_plane_uc_from_x86(dst, dst_linesize, src, src_linesize, + bytewidth, height); +#endif + + if (ret < 0) + image_copy_plane(dst, dst_linesize, src, src_linesize, bytewidth, height); +} + +void av_image_copy_plane(uint8_t *dst, int dst_linesize, + const uint8_t *src, int src_linesize, + int bytewidth, int height) +{ + image_copy_plane(dst, dst_linesize, src, src_linesize, bytewidth, height); +} + +static void image_copy(uint8_t *dst_data[4], const ptrdiff_t dst_linesizes[4], + const uint8_t *src_data[4], const ptrdiff_t src_linesizes[4], + enum AVPixelFormat pix_fmt, int width, int height, + void (*copy_plane)(uint8_t *, ptrdiff_t, const uint8_t *, + ptrdiff_t, ptrdiff_t, int)) { const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); @@ -310,9 +354,9 @@ void av_image_copy(uint8_t *dst_data[4], int dst_linesizes[4], if (desc->flags & AV_PIX_FMT_FLAG_PAL || desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL) { - av_image_copy_plane(dst_data[0], dst_linesizes[0], - src_data[0], src_linesizes[0], - width, height); + copy_plane(dst_data[0], dst_linesizes[0], + src_data[0], src_linesizes[0], + width, height); /* copy the palette */ memcpy(dst_data[1], src_data[1], 4*256); } else { @@ -323,7 +367,7 @@ void av_image_copy(uint8_t *dst_data[4], int dst_linesizes[4], for (i = 0; i < planes_nb; i++) { int h = height; - int bwidth = av_image_get_linesize(pix_fmt, width, i); + ptrdiff_t bwidth = av_image_get_linesize(pix_fmt, width, i); if (bwidth < 0) { av_log(NULL, AV_LOG_ERROR, "av_image_get_linesize failed\n"); return; @@ -331,13 +375,37 @@ void av_image_copy(uint8_t *dst_data[4], int dst_linesizes[4], if (i == 1 || i == 2) { h = AV_CEIL_RSHIFT(height, desc->log2_chroma_h); } - av_image_copy_plane(dst_data[i], dst_linesizes[i], - src_data[i], src_linesizes[i], - bwidth, h); + copy_plane(dst_data[i], dst_linesizes[i], + src_data[i], src_linesizes[i], + bwidth, h); } } } +void av_image_copy(uint8_t *dst_data[4], int dst_linesizes[4], + const uint8_t *src_data[4], const int src_linesizes[4], + enum AVPixelFormat pix_fmt, int width, int height) +{ + ptrdiff_t dst_linesizes1[4], src_linesizes1[4]; + int i; + + for (i = 0; i < 4; i++) { + dst_linesizes1[i] = dst_linesizes[i]; + src_linesizes1[i] = src_linesizes[i]; + } + + image_copy(dst_data, dst_linesizes1, src_data, src_linesizes1, pix_fmt, + width, height, image_copy_plane); +} + +void av_image_copy_uc_from(uint8_t *dst_data[4], const ptrdiff_t dst_linesizes[4], + const uint8_t *src_data[4], const ptrdiff_t src_linesizes[4], + enum AVPixelFormat pix_fmt, int width, int height) +{ + image_copy(dst_data, dst_linesizes, src_data, src_linesizes, pix_fmt, + width, height, image_copy_plane_uc_from); +} + int av_image_fill_arrays(uint8_t *dst_data[4], int dst_linesize[4], const uint8_t *src, enum AVPixelFormat pix_fmt, int width, int height, int align) @@ -423,3 +491,170 @@ int av_image_copy_to_buffer(uint8_t *dst, int dst_size, return size; } + +// Fill dst[0..dst_size] with the bytes in clear[0..clear_size]. The clear +// bytes are repeated until dst_size is reached. If dst_size is unaligned (i.e. +// dst_size%clear_size!=0), the remaining data will be filled with the beginning +// of the clear data only. +static void memset_bytes(uint8_t *dst, size_t dst_size, uint8_t *clear, + size_t clear_size) +{ + size_t pos = 0; + int same = 1; + int i; + + if (!clear_size) + return; + + // Reduce to memset() if possible. + for (i = 0; i < clear_size; i++) { + if (clear[i] != clear[0]) { + same = 0; + break; + } + } + if (same) + clear_size = 1; + + if (clear_size == 1) { + memset(dst, clear[0], dst_size); + dst_size = 0; + } else if (clear_size == 2) { + uint16_t val = AV_RN16(clear); + for (; dst_size >= 2; dst_size -= 2) { + AV_WN16(dst, val); + dst += 2; + } + } else if (clear_size == 4) { + uint32_t val = AV_RN32(clear); + for (; dst_size >= 4; dst_size -= 4) { + AV_WN32(dst, val); + dst += 4; + } + } else if (clear_size == 8) { + uint32_t val = AV_RN64(clear); + for (; dst_size >= 8; dst_size -= 8) { + AV_WN64(dst, val); + dst += 8; + } + } + + for (; dst_size; dst_size--) + *dst++ = clear[pos++ % clear_size]; +} + +// Maximum size in bytes of a plane element (usually a pixel, or multiple pixels +// if it's a subsampled packed format). +#define MAX_BLOCK_SIZE 32 + +int av_image_fill_black(uint8_t *dst_data[4], const ptrdiff_t dst_linesize[4], + enum AVPixelFormat pix_fmt, enum AVColorRange range, + int width, int height) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + int nb_planes = av_pix_fmt_count_planes(pix_fmt); + // A pixel or a group of pixels on each plane, with a value that represents black. + // Consider e.g. AV_PIX_FMT_UYVY422 for non-trivial cases. + uint8_t clear_block[4][MAX_BLOCK_SIZE] = {{0}}; // clear padding with 0 + int clear_block_size[4] = {0}; + ptrdiff_t plane_line_bytes[4] = {0}; + int rgb, limited; + int plane, c; + + if (!desc || nb_planes < 1 || nb_planes > 4 || desc->flags & AV_PIX_FMT_FLAG_HWACCEL) + return AVERROR(EINVAL); + + rgb = !!(desc->flags & AV_PIX_FMT_FLAG_RGB); + limited = !rgb && range != AVCOL_RANGE_JPEG; + + if (desc->flags & AV_PIX_FMT_FLAG_BITSTREAM) { + ptrdiff_t bytewidth = av_image_get_linesize(pix_fmt, width, 0); + uint8_t *data; + int mono = pix_fmt == AV_PIX_FMT_MONOWHITE || pix_fmt == AV_PIX_FMT_MONOBLACK; + int fill = pix_fmt == AV_PIX_FMT_MONOWHITE ? 0xFF : 0; + if (nb_planes != 1 || !(rgb || mono) || bytewidth < 1) + return AVERROR(EINVAL); + + if (!dst_data) + return 0; + + data = dst_data[0]; + + // (Bitstream + alpha will be handled incorrectly - it'll remain transparent.) + for (;height > 0; height--) { + memset(data, fill, bytewidth); + data += dst_linesize[0]; + } + return 0; + } + + for (c = 0; c < desc->nb_components; c++) { + const AVComponentDescriptor comp = desc->comp[c]; + + // We try to operate on entire non-subsampled pixel groups (for + // AV_PIX_FMT_UYVY422 this would mean two consecutive pixels). + clear_block_size[comp.plane] = FFMAX(clear_block_size[comp.plane], comp.step); + + if (clear_block_size[comp.plane] > MAX_BLOCK_SIZE) + return AVERROR(EINVAL); + } + + // Create a byte array for clearing 1 pixel (sometimes several pixels). + for (c = 0; c < desc->nb_components; c++) { + const AVComponentDescriptor comp = desc->comp[c]; + // (Multiple pixels happen e.g. with AV_PIX_FMT_UYVY422.) + int w = clear_block_size[comp.plane] / comp.step; + uint8_t *c_data[4]; + const int c_linesize[4] = {0}; + uint16_t src_array[MAX_BLOCK_SIZE]; + uint16_t src = 0; + int x; + + if (comp.depth > 16) + return AVERROR(EINVAL); + if (!rgb && comp.depth < 8) + return AVERROR(EINVAL); + if (w < 1) + return AVERROR(EINVAL); + + if (c == 0 && limited) { + src = 16 << (comp.depth - 8); + } else if ((c == 1 || c == 2) && !rgb) { + src = 128 << (comp.depth - 8); + } else if (c == 3) { + // (Assume even limited YUV uses full range alpha.) + src = (1 << comp.depth) - 1; + } + + for (x = 0; x < w; x++) + src_array[x] = src; + + for (x = 0; x < 4; x++) + c_data[x] = &clear_block[x][0]; + + av_write_image_line(src_array, c_data, c_linesize, desc, 0, 0, c, w); + } + + for (plane = 0; plane < nb_planes; plane++) { + plane_line_bytes[plane] = av_image_get_linesize(pix_fmt, width, plane); + if (plane_line_bytes[plane] < 0) + return AVERROR(EINVAL); + } + + if (!dst_data) + return 0; + + for (plane = 0; plane < nb_planes; plane++) { + size_t bytewidth = plane_line_bytes[plane]; + uint8_t *data = dst_data[plane]; + int chroma_div = plane == 1 || plane == 2 ? desc->log2_chroma_h : 0; + int plane_h = ((height + ( 1 << chroma_div) - 1)) >> chroma_div; + + for (; plane_h > 0; plane_h--) { + memset_bytes(data, bytewidth, &clear_block[plane][0], clear_block_size[plane]); + data += dst_linesize[plane]; + } + } + + return 0; +} |