1

我想为使用 YUV420YUVFormat动态创建的一个 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 = 宽度,strideUV = 宽度/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);
4

2 回答 2

2

上次我使用这些类时,我在内部遇到了内存问题。

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

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

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

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

因此,如果图片大小为 320 x 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 平面的起始地址。

数据开始'here(base)'是这个'wide(stride)',下一行从那里开始(偏移量)

使用 java 可能会给出基地址。

可能没有回答问题哈哈

{
    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;
}
于 2014-07-10T20:44:37.887 回答
1

步幅和偏移量取决于帧内存布局和视频帧尺寸和可能的填充。

于 2014-07-10T21:02:48.597 回答