Android Image U和V缓冲区太大

时间:2015-09-20 14:29:05

标签: android android-camera

我正在使用camera2 api从android图像中读取YUV值。因此,我有3架飞机。

for (int x = 0; x < imageSheaf[0].Width; x++)
{
    for (int y = 0; y < imageSheaf[0].Height; y++)
    {
        imageYuv[x, y] = new yuv();
    }
}


for (int j = 0; bufferY.HasRemaining; j++)
{
    for (int i = 0; i < rowStrideY/2; i += 2)
    {
        if (i > width / 2 - 1 || j > height / 2 - 1)
            Log.Info("Processing", "Out of Bounds");
        imageYuv[i, j].y = bufferY.Get();
        bufferY.Get();//skip a pixel due to 4:2:0 sub sampling
    }

    for (int i = 0; i < rowStrideY/2; i++)//skip a line due to 4:2:0 sub sampling
    {
        bufferY.Get();
        bufferY.Get();
    }

    if (!bufferY.HasRemaining)
        Log.Debug("Processing", "finished");
}

for (int j = 0; bufferU.HasRemaining; j++)
{
    for (int i = 0; i < rowStrideU; i++)
    {
        if (!bufferU.HasRemaining)
            Log.Debug("Processing", "finished");
        imageYuv[i, j].u = bufferU.Get();
    }

    if (!bufferU.HasRemaining)
        Log.Debug("Processing", "finished");
}

for (int j = 0; bufferV.HasRemaining; j++)
{
    for (int i = 0; i < rowStrideV; i++)
    {
        if (!bufferV.HasRemaining)
            Log.Debug("Processing", "finished");
        imageYuv[i, j].v = bufferV.Get();
    }

    if (!bufferV.HasRemaining)
        Log.Debug("Processing", "finished");
}

这是我用来从字节缓冲区中获取Y,U和V值的代码。

ImageFormat是YUV_420_888,据我所知,4:2:0子采样意味着每个U或V像素都有4个Y像素。

我的问题是U和V平面的字节缓冲区大小应该超出它们应该导致数组超出范围的例外:

[Processing] RowstrideY = 720
[Processing] RowstrideU = 368
[Processing] RowstrideV = 368
[Processing] y.remaining = 345600, u.remaining = 88312, v.remaining = 88312

(图像尺寸为720x480)

1 个答案:

答案 0 :(得分:1)

YUV420的Y每像素为8位,U和V的每四像素组为8位。因此,在720x480时,您可以预期U-V平面为360x240。

但是,实际硬件可能有额外的对齐或步幅限制。在这种情况下,看起来硬件要求步幅为16的倍数,因此它将从360增加到368.

你希望变成长度为368 * 240 = 88320,但请记住,每一行的最后八个字节都只是填充。因此缓冲区实际上可以是(368 * 239)+360 = 88312字节,而不会遗漏任何数据。如果你得到数组绑定异常,那是因为你试图从最后一行读取行末字节填充字节,但这是不允许的。 API仅保证您能够读取数据。

这样做的动机是,如果最后一行的填充碰巧跨越页面边界,系统将需要为每个缓冲区分配一个额外的不必要的页面。

您可以修改代码以从每行复制数据字节,然后使用第二个循环来消耗行尾的填充字节(如果有)。