| @@ -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. |
| | 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 | } |