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 libav-devel@libav.org https://lists.libav.org/mailman/listinfo/libav-devel