java - 创建一个 YUVFormat 实例

标签 java fmj

我想为使用 YUV420 的动态创建的 CaptureDevice 创建一个 jmf/fmj YUVFormat 实例。我对 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% 确定。

Java文档:http://fmj-sf.net/doc/fmj/javax/media/format/YUVFormat.html

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

四抄送: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);

最佳答案

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

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

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

想想 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 数据写入完整 block ,然后写入所有 V 数据。

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

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

数据从“这里(基数)”开始是这个“宽(步幅)”,下一行从那里开始(偏移量)

对于 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;
}

关于java - 创建一个 YUVFormat 实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24684040/

相关文章:

java - 我的 Android 应用程序应该使用哪种方式保存用户数据?

java - 达到 hibernate.c3p0.timeout 后数据库连接会发生什么?

java - 如何清理四叉树的边缘?

java - JedisPool 连接数问题

java - 是否可以在 Java 中捕获高分辨率网络摄像头图像?

Java视频跨平台是一场噩梦,这有自由吗?

java - 如何使用 FMJ 捕获音频和视频

java - 使用 Swing 设计聊天布局

Java FMJ 不是跨平台的吗?如何修复?

java - Java 中的 FMJ 视频捕获