History

imgutils: add function to clear an image to black

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/4/8 byte patterns. For the remaining cases, a generic slow fallback is used.

wm4 committed 9 years ago

Commit 45df7ad1 parent 47399cc4 files · +198 −1Browse files

Unified · Split

4 files
  1. doc/APIchanges +3 −0
  2. libavutil/imgutils.c +167 −0
  3. libavutil/imgutils.h +27 −0
  4. libavutil/version.h +1 −1
doc/APIchanges+3−0
@@ -13,6 +13,9 @@ libavutil: 2017-03-23 · 12 unmodified lines
13 13
14API changes, most recent first:14API changes, most recent first:
15 15
162017-xx-xx - xxxxxxx - lavu 56.4.0 - imgutils.h
17 Add av_image_fill_black().
18
162017-xx-xx - xxxxxxx - lavu 56.3.0 - frame.h192017-xx-xx - xxxxxxx - lavu 56.3.0 - frame.h
17 Add av_frame_apply_cropping().20 Add av_frame_apply_cropping().
18 21
libavutil/imgutils.c+167−0
@@ -435,3 +435,170 @@ int av_image_copy_to_buffer(uint8_t *dst, int dst_size, · 434 unmodified lines
435 435
436 return size;436 return size;
437}437}
438
439// Fill dst[0..dst_size] with the bytes in clear[0..clear_size]. The clear
440// bytes are repeated until dst_size is reached. If dst_size is unaligned (i.e.
441// dst_size%clear_size!=0), the remaining data will be filled with the beginning
442// of the clear data only.
443static void memset_bytes(uint8_t *dst, size_t dst_size, uint8_t *clear,
444 size_t clear_size)
445{
446 size_t pos = 0;
447 int same = 1;
448 int i;
449
450 if (!clear_size)
451 return;
452
453 // Reduce to memset() if possible.
454 for (i = 0; i < clear_size; i++) {
455 if (clear[i] != clear[0]) {
456 same = 0;
457 break;
458 }
459 }
460 if (same)
461 clear_size = 1;
462
463 if (clear_size == 1) {
464 memset(dst, clear[0], dst_size);
465 dst_size = 0;
466 } else if (clear_size == 2) {
467 uint16_t val = AV_RN16(clear);
468 for (; dst_size >= 2; dst_size -= 2) {
469 AV_WN16(dst, val);
470 dst += 2;
471 }
472 } else if (clear_size == 4) {
473 uint32_t val = AV_RN32(clear);
474 for (; dst_size >= 4; dst_size -= 4) {
475 AV_WN32(dst, val);
476 dst += 4;
477 }
478 } else if (clear_size == 8) {
479 uint32_t val = AV_RN64(clear);
480 for (; dst_size >= 8; dst_size -= 8) {
481 AV_WN64(dst, val);
482 dst += 8;
483 }
484 }
485
486 for (; dst_size; dst_size--)
487 *dst++ = clear[pos++ % clear_size];
488}
489
490// Maximum size in bytes of a plane element (usually a pixel, or multiple pixels
491// if it's a subsampled packed format).
492#define MAX_BLOCK_SIZE 32
493
494int av_image_fill_black(uint8_t *dst_data[4], const ptrdiff_t dst_linesize[4],
495 enum AVPixelFormat pix_fmt, enum AVColorRange range,
496 int width, int height)
497{
498 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
499 int nb_planes = av_pix_fmt_count_planes(pix_fmt);
500 // A pixel or a group of pixels on each plane, with a value that represents black.
501 // Consider e.g. AV_PIX_FMT_UYVY422 for non-trivial cases.
502 uint8_t clear_block[4][MAX_BLOCK_SIZE] = {0}; // clear padding with 0
503 int clear_block_size[4] = {0};
504 ptrdiff_t plane_line_bytes[4] = {0};
505 int rgb, limited;
506 int plane, c;
507
508 if (!desc || nb_planes < 1 || nb_planes > 4 || desc->flags & AV_PIX_FMT_FLAG_HWACCEL)
509 return AVERROR(EINVAL);
510
511 rgb = !!(desc->flags & AV_PIX_FMT_FLAG_RGB);
512 limited = !rgb && range != AVCOL_RANGE_JPEG;
513
514 if (desc->flags & AV_PIX_FMT_FLAG_BITSTREAM) {
515 ptrdiff_t bytewidth = av_image_get_linesize(pix_fmt, width, 0);
516 uint8_t *data;
517 int mono = pix_fmt == AV_PIX_FMT_MONOWHITE || pix_fmt == AV_PIX_FMT_MONOBLACK;
518 int fill = pix_fmt == AV_PIX_FMT_MONOWHITE ? 0xFF : 0;
519 if (nb_planes != 1 || !(rgb || mono) || bytewidth < 1)
520 return AVERROR(EINVAL);
521
522 if (!dst_data)
523 return 0;
524
525 data = dst_data[0];
526
527 // (Bitstream + alpha will be handled incorrectly - it'll remain transparent.)
528 for (;height > 0; height--) {
529 memset(data, fill, bytewidth);
530 data += dst_linesize[0];
531 }
532 return 0;
533 }
534
535 for (c = 0; c < desc->nb_components; c++) {
536 const AVComponentDescriptor comp = desc->comp[c];
537
538 // We try to operate on entire non-subsampled pixel groups (for
539 // AV_PIX_FMT_UYVY422 this would mean two consecutive pixels).
540 clear_block_size[comp.plane] = FFMAX(clear_block_size[comp.plane], comp.step);
541
542 if (clear_block_size[comp.plane] > MAX_BLOCK_SIZE)
543 return AVERROR(EINVAL);
544 }
545
546 // Create a byte array for clearing 1 pixel (sometimes several pixels).
547 for (c = 0; c < desc->nb_components; c++) {
548 const AVComponentDescriptor comp = desc->comp[c];
549 // (Multiple pixels happen e.g. with AV_PIX_FMT_UYVY422.)
550 int w = clear_block_size[comp.plane] / comp.step;
551 uint8_t *c_data[4];
552 const int c_linesize[4] = {0};
553 uint16_t src_array[MAX_BLOCK_SIZE];
554 uint16_t src = 0;
555 int x;
556
557 if (comp.depth > 16)
558 return AVERROR(EINVAL);
559 if (!rgb && comp.depth < 8)
560 return AVERROR(EINVAL);
561 if (w < 1)
562 return AVERROR(EINVAL);
563
564 if (c == 0 && limited) {
565 src = 16 << (comp.depth - 8);
566 } else if ((c == 1 || c == 2) && !rgb) {
567 src = 128 << (comp.depth - 8);
568 } else if (c == 3) {
569 // (Assume even limited YUV uses full range alpha.)
570 src = (1 << comp.depth) - 1;
571 }
572
573 for (x = 0; x < w; x++)
574 src_array[x] = src;
575
576 for (x = 0; x < 4; x++)
577 c_data[x] = &clear_block[x][0];
578
579 av_write_image_line(src_array, c_data, c_linesize, desc, 0, 0, c, w);
580 }
581
582 for (plane = 0; plane < nb_planes; plane++) {
583 plane_line_bytes[plane] = av_image_get_linesize(pix_fmt, width, plane);
584 if (plane_line_bytes[plane] < 0)
585 return AVERROR(EINVAL);
586 }
587
588 if (!dst_data)
589 return 0;
590
591 for (plane = 0; plane < nb_planes; plane++) {
592 size_t bytewidth = plane_line_bytes[plane];
593 uint8_t *data = dst_data[plane];
594 int chroma_div = plane == 1 || plane == 2 ? desc->log2_chroma_h : 0;
595 int plane_h = ((height + ( 1 << chroma_div) - 1)) >> chroma_div;
596
597 for (; plane_h > 0; plane_h--) {
598 memset_bytes(data, bytewidth, &clear_block[plane][0], clear_block_size[plane]);
599 data += dst_linesize[plane];
600 }
601 }
602
603 return 0;
604}
libavutil/imgutils.h+27−0
@@ -224,6 +224,33 @@ int av_image_check_size(unsigned int w, unsigned int h, int log_offset, void *lo · 223 unmodified lines
224 */224 */
225int av_image_check_sar(unsigned int w, unsigned int h, AVRational sar);225int av_image_check_sar(unsigned int w, unsigned int h, AVRational sar);
226 226
227/**
228 * Overwrite the image data with black. This is suitable for filling a
229 * sub-rectangle of an image, meaning the padding between the right most pixel
230 * and the left most pixel on the next line will not be overwritten. For some
231 * formats, the image size might be rounded up due to inherent alignment.
232 *
233 * If the pixel format has alpha, the alpha is cleared to opaque.
234 *
235 * This can return an error if the pixel format is not supported. Normally, all
236 * non-hwaccel pixel formats should be supported.
237 *
238 * Passing NULL for dst_data is allowed. Then the function returns whether the
239 * operation would have succeeded. (It can return an error if the pix_fmt is
240 * not supported.)
241 *
242 * @param dst_data data pointers to destination image
243 * @param dst_linesize linesizes for the destination image
244 * @param pix_fmt the pixel format of the image
245 * @param range the color range of the image (important for colorspaces such as YUV)
246 * @param width the width of the image in pixels
247 * @param height the height of the image in pixels
248 * @return 0 if the image data was cleared, a negative AVERROR code otherwise
249 */
250int av_image_fill_black(uint8_t *dst_data[4], const ptrdiff_t dst_linesize[4],
251 enum AVPixelFormat pix_fmt, enum AVColorRange range,
252 int width, int height);
253
227/**254/**
228 * @}255 * @}
229 */256 */
libavutil/version.h+1−1
@@ -54,7 +54,7 @@ · 53 unmodified lines
54 */54 */
55 55
56#define LIBAVUTIL_VERSION_MAJOR 5656#define LIBAVUTIL_VERSION_MAJOR 56
57#define LIBAVUTIL_VERSION_MINOR 357#define LIBAVUTIL_VERSION_MINOR 4
58#define LIBAVUTIL_VERSION_MICRO 058#define LIBAVUTIL_VERSION_MICRO 0
59 59
60#define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \60#define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t