Reading Pixels as YUV420

160 views
Skip to first unread message

Jason Williams

unread,
Nov 14, 2022, 2:10:14 PM11/14/22
to skia-discuss
Hey All,
I am trying to read pixels from an image in YUV420 format and I am not getting the data I expect. I have the following code:

void readPixelsCallback(SkImage::ReadPixelsContext context, std::unique_ptr<const SkImage::AsyncReadResult> result) {
    auto* pixels = static_cast<std::vector<uint8_t>*>(context);
    if (!result) {
        assert(false);
        return;
    }

    // the data in result is ordered Y, U, then V.
    pixels->resize(result->rowBytes(0) + result->rowBytes(1) + result->rowBytes(2));
    memcpy(pixels->data(), result->data(0), result->rowBytes(0));
    auto* data = pixels->data() + result->rowBytes(0);
    memcpy(data, result->data(1), result->rowBytes(1));
    data += result->rowBytes(1);
    memcpy(data, result->data(2), result->rowBytes(2));
}

std::vector<uint8_t> ContextSkia::readPixelsYUV(sk_sp<SkImage> image, int srcX, int srcY, int width, int height) {
    assert(0 <= srcX && srcX < image->width());
    assert(0 <= srcY && srcY < image->height());
    assert(width <= image->width() - srcX);
    assert(height <= image->height() - srcY);

    int clampedWidth = (width > 0) ? width : image->width();
    int clampedHeight = (height > 0) ? height : image->height();
    int readWidth = srcX + clampedWidth;
    int readHeight = srcY + clampedHeight;
    std::vector<uint8_t> pixels(0);

    image->asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace::kRec709_Limited_SkYUVColorSpace,
                                           SkColorSpace::MakeSRGB(),
                                           SkIRect::MakeXYWH(srcX, srcY, readWidth, readHeight),
                                           SkISize::Make(clampedWidth, clampedHeight),
                                           SkImage::RescaleGamma::kSrc,
                                           SkImage::RescaleMode::kNearest,
                                           readPixelsCallback,
                                           &pixels);
    return pixels;
}

The result's rowBytes for the Y plane is always equal to the image width, but I am expecting it to be the image's width * height. In my tests srcX and srcY are 0 and my width and heights are even values. What am I missing here?
 (BTW: I tried to do this with a  Skia Fiddle and the callback always gets an error not sure what I am doing wrong there either)

Brian Osman

unread,
Nov 15, 2022, 8:08:11 AM11/15/22
to skia-d...@googlegroups.com
Throughout Skia, "rowBytes" refers to the number of bytes for one (horizontal) row of pixels, not the entire image. So if you're trying to size a buffer for an entire block of pixels, you need to multiply rowBytes by the height. rowBytes will often be equal to the width multiplied by the bytes-per-pixel, but may be larger if there is padding at the end of each row.

--
You received this message because you are subscribed to the Google Groups "skia-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to skia-discuss...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/skia-discuss/6203c32c-637c-4365-b81a-02e3751528a2n%40googlegroups.com.

Jason Williams

unread,
Nov 15, 2022, 2:08:59 PM11/15/22
to skia-discuss

Thanks Brian.
Does this mean that result->data(0) has result->rowBytes(0) * height number of bytes in it then? My concern was that if I didn't use rowBytes(0) with that I would read beyond what is in result->data(0).

Jason

Jim Van Verth

unread,
Nov 18, 2022, 6:18:52 AM11/18/22
to skia-d...@googlegroups.com
Yes, result->data(0) should have result->rowBytes(0) * height bytes. Whereas result->data(1) should have result->rowBytes(1) * (height/2), and the equivalent for result->data(2).



--

Jim Van Verth | Software Engineer | jvan...@google.com | 919-210-7664

Reply all
Reply to author
Forward
0 new messages