| @@ -435,3 +435,170 @@ int av_image_copy_to_buffer(uint8_t *dst, int dst_size, · 434 unmodified lines |
| 435 | 435 | |
| 436 | 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. |
| 443 | +static 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 | + |
| 494 | +int 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 | +} |