Quoting wm4 (2017-07-16 12:41:59)
> Black isn't always just memset(ptr, 0, size). Limited YUV in particular
> requires relatively non-obvious values, and filling a frame with
> repeating 0 bytes is disallowed in some contexts. With component sizes
> larger than 8 or packed YUV, this can become relatively complicated. So
> having a generic function for this seems helpful.
>
> In order to handle the complex cases in a generic way without destroying
> performance, this code attempts to compute a black pixel, and then uses
> that value to clear the image data quickly by using a function like
> memset.
>
> Common cases like yuv410p10 or rgba can't be handled with a simple
> memset, so there is some code to fill memory with 2 and 4 byte patterns.
> For the remaining cases, a generic slow fallback is used. This code
> should probably have a 8 byte case too, to deal with rgba64.
>
> ---
> Fixed:
> - simply reduction to memset code
> - fix monow/monob handling
> - change alpha range
> - add 8 bytes path (untested)
> - allow dst_data==NULL with special semantics
> TODO: APIchanges, version bumps, FATE test
> ---
> libavutil/imgutils.c | 167
> +++++++++++++++++++++++++++++++++++++++++++++++++++
> libavutil/imgutils.h | 27 +++++++++
> 2 files changed, 194 insertions(+)
>
> diff --git a/libavutil/imgutils.c b/libavutil/imgutils.c
> index 84abb11656..c43185ccff 100644
> --- a/libavutil/imgutils.c
> +++ b/libavutil/imgutils.c
> @@ -435,3 +435,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_PIXEL_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 on each plane, with a value that represents black.
> + // Consider e.g. AV_PIX_FMT_UYVY422 for non-trivial cases.
> + uint8_t pixel[4][MAX_PIXEL_SIZE] = {0}; // clear padding with 0
> + int pixel_size[4] = {0};
The naming is a bit confusing, since those are not individual pixels,
but blocks of "maximum step size". How about block_val / block_size for
those two.
Otherwise looks ok-ish. Not exactly pretty, but that's probably
unavoidable for such code.
--
Anton Khirnov
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel