创建YUVFormat实例

时间:2014-07-10 18:44:41

标签: java fmj

我想使用YUV420为动态创建的YUVFormat创建一个jmf / fmj CaptureDevice实例。我对strideY,strideUV,offsetY,offsetU和offsetV的值应该是多么困惑。 YUVFormat类中只有以下构造函数可用:

1. YUVFormat()
2. YUVFormat(int yuvType)
3. YUVFormat(java.awt.Dimension size, int maxDataLength, java.lang.Class dataType, float frameRate, int yuvType, int strideY, int strideUV, int offsetY, int offsetU, int offsetV)

使用#1或#2不允许我在事后设置大小,帧速率或数据类型;所以我不能用它们。使用#3需要我知道另外五个参数。我已经阅读了谷歌搜索中的以下所有帖子,但我仍然对这些值应该是什么感到困惑。我认为我可以安全地假设strideY和strideUV将是帧的宽度,但我不是100%肯定。

Javadoc:http://fmj-sf.net/doc/fmj/javax/media/format/YUVFormat.html

MediaWiki:http://wiki.multimedia.cx/index.php?title=PIX_FMT_YUV420P

FourCC:http://www.fourcc.org/yuv.php#IYUV

到目前为止,这是我的代码:

int strideY = width, strideUV = width / 2;
int offsetY = 0, offsetU = 0, offsetV = 0;
YUVFormat yuv = new YUVFormat(new Dimension(width, height), Format.NOT_SPECIFIED, Format.byteArray, frameRate, YUVFormat.YUV_420, strideY, strideUV, offsetY, offsetU, offsetV);

2 个答案:

答案 0 :(得分:2)

上次我使用这些课程时,我内心都有内存问题。

格式不应该真正需要数据速率或帧速率。它仅指定像素在内存中的排列方式。

如果可能,我建议处理数组中的字节。

想想RGBA数据。内存中的每个字都是4个像素。 [RGBA] [RGBA] ...通常它首先写出左下角,然后在右上角结束。数据的大小很容易知道,特定像素易于操作。

YUV是平面或半平面格式,平均每像素12位而不是32位。这是通过具有8位Y和8位U和V以及U和V双倍大小来实现的。 U和V的8位覆盖Y平面的4个像素。

因此,如果图像尺寸为320×240,则前320 * 240字节将是Y平面数据。

内存中的下一个字节是隔行扫描的U / V线为半平面或全部是平面的,首先是全U,然后是所有V数据。

Y的步幅是宽度。 U / V的步幅是宽度的一半。 Y的偏移量是像素行/步幅之间的字节数。 U的偏移量是像素行/步幅之间的字节数。 V的偏移量是像素行/步幅之间的字节数。

他们还拥有基地址'这不是在java中公开的。第一个Y像素数据的存储器地址。

在只能分配32位字的存储器的系统上,使用12位色深或奇数像素大小的图像可以使主机系统以不同的方式表现像素数据驻留在寻址存储器中的位置。

例如,

写入所有打包的Y数据,它将具有零偏移量。 接下来写一个U数据的水平线。 接下来写一个水平线的V数据。 接下来写一个U数据的水平线。 接下来写一个V数据的水平线。

U和V的步幅是Y的一半。

在java中,您应该能够通过写入像素数据来使用零偏移,而不会在U和V数据之间产生间隙。

yuv的另一种格式将所有U和所有V数据写成完整的块。

偏移量对应于单个Y / U / V行之间的字节数。

基地址对应于U / V平面的起始地址。

数据开始在这里(基地)'这是广泛的(跨步)'从那里开始的下一行(偏移)

使用java可能会给出基址。

可能没有回答问题lol

{
    unsigned int planeSize;
    unsigned int halfWidth;

    unsigned char * yplane;
    unsigned char * uplane;
    unsigned char * vplane;
    const unsigned char * rgbIndex;

    int x, y;
    unsigned char * yline;
    unsigned char * uline;
    unsigned char * vline;

    planeSize = srcFrameWidth * srcFrameHeight;
    halfWidth = srcFrameWidth >> 1;

    // get pointers to the data
    yplane = yuv;
    uplane = yuv + planeSize;
    vplane = yuv + planeSize + (planeSize >> 2);
    rgbIndex = rgb;

        for (y = 0; y < srcFrameHeight; y++)
        {
        yline = yplane + (y * srcFrameWidth);
        uline = uplane + ((y >> 1) * halfWidth);
        vline = vplane + ((y >> 1) * halfWidth);

        if (flip)
        rgbIndex = rgb + (srcFrameWidth*(srcFrameHeight-1-y)*rgbIncrement);

            for (x = 0; x < (int) srcFrameWidth; x+=2)
            {
                rgbtoyuv(rgbIndex[0], rgbIndex[1], rgbIndex[2], *yline, *uline, *vline);
                rgbIndex += rgbIncrement;
                yline++;
                rgbtoyuv(rgbIndex[0], rgbIndex[1], rgbIndex[2], *yline, *uline, *vline);
                rgbIndex += rgbIncrement;
                yline++;
                uline++;
                vline++;
}
}
}

在java ..

public static byte[] YV12toYUV420Planar(byte[] input, byte[] output, int width, int height) {
    final int frameSize = width * height;
    final int qFrameSize = frameSize/4;

    System.arraycopy(input, 0, output, 0, frameSize); // Y
    System.arraycopy(input, frameSize, output, frameSize + qFrameSize, qFrameSize); // Cr (V)
    System.arraycopy(input, frameSize + qFrameSize, output, frameSize, qFrameSize); // Cb (U)

    return output;
}

答案 1 :(得分:1)

步幅和偏移取决于帧存储器布局和视频帧尺寸以及可能的填充。

  • 通常,步幅(explained here)是字节数 你需要添加一个指针,从一个平面线到另一个平面线。
  • 偏移量是从帧的起点移动到特定平面(Y,U或V)时需要添加的字节数
  • 请参阅this Microsoft article解释各种YUV帧存储器布局。
  • 另请参阅此Android源代码,其中strides and offsets are calculated取决于FOURCC(仅适用于Android支持的格式)。