Java H.261 编码器帧输出中的奇怪模式

问题描述 投票:0回答:1

我正在用 Java 创建一个 H.261 编码器: https://github.com/ericynt/h26x-playground

为了制作编码器,我使用了 H.261 标准文档: https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-H.261-198811-S!!PDF-E&type=items

应用程序的结构是: FrameGenerator --[RGB 帧]--> H261Encoder --[H261 数据包]--> UdpStreamer --[UDP 数据报]--> 127.0.0.1:55555

RGB 帧输入是什么样子

编码器输出是什么样子

预期的编码器输出应与输入相同,但压缩算法的质量损失较小。

根据标准文档在宏块内进行块排序

看起来宏块位于帧中的正确位置,但不知何故它们没有正确显示。我找不到问题所在。据我所知,我遵循标准,但我一定错过了一些东西..

如果我必须猜测哪里出了问题,我会在 Y 组件部分的 toBlocks 方法中说(但我可能是错的):

    private int[][][] toBlocks (
            final Pair<Integer, Integer> pixelRowAndColumn,
            final int[][][] yCbCr
    ) {

        // YCbCr 4:4:4 to 4:2:0
        // and transform 16x16x3 to 6x8x8 (4 Y, 1 Cb, 1 Cr)

        int[][][] blocks = new int[TOTAL_BLOCKS][BLOCK_SIZE][BLOCK_SIZE];
        int[][] cbAccumulators = new int[BLOCK_SIZE][BLOCK_SIZE];
        int[][] crAccumulators = new int[BLOCK_SIZE][BLOCK_SIZE];
        int[][] countAccumulators = new int[BLOCK_SIZE][BLOCK_SIZE];

        for (int i = pixelRowAndColumn.getKey(); i < pixelRowAndColumn.getKey() + MACROBLOCK_SIZE; i++) {

            for (int j = pixelRowAndColumn.getValue(); j < pixelRowAndColumn.getValue() + MACROBLOCK_SIZE; j++) {

                int x = i % 16;
                int y = j % 16;

                // Y component
                if (x < 8 && y < 8) {

                    // Bottom left
                    blocks[2][x][y] = yCbCr[i][j][0];
                } else if (x < 8) {

                    // Top left
                    blocks[0][x][y - 8] = yCbCr[i][j][0];
                } else if (y < 8) {

                    // Bottom right
                    blocks[3][x - 8][y] = yCbCr[i][j][0];
                } else {

                    // Top right
                    blocks[1][x - 8][y - 8] = yCbCr[i][j][0];
                }

                // Cb and Cr components
                int cbCrX = x / 2;
                int cbCrY = y / 2;

                cbAccumulators[cbCrX][cbCrY] += yCbCr[i][j][1];
                crAccumulators[cbCrX][cbCrY] += yCbCr[i][j][2];
                countAccumulators[cbCrX][cbCrY]++;
            }
        }

        // Calculate and assign the averages for Cb and Cr
        for (int i = 0; i < 8; i++) {

            for (int j = 0; j < 8; j++) {

                blocks[4][i][j] = cbAccumulators[i][j] / countAccumulators[i][j];
                blocks[5][i][j] = crAccumulators[i][j] / countAccumulators[i][j];
            }
        }

        return blocks;
    }

我的问题是:输出中出现奇怪模式的原因是什么以及如何解决它?

java
1个回答
0
投票

在寻找问题原因几个小时后,我终于找到了问题所在。

在查看 C 语言中 H.261 编码器的实现时,我发现了一种转置方法。据我所知,标准文档中没有提及这一点。 https://github.com/maikmerten/p64/blob/cfba372679f6683a45c95817d9ed51c09566ce31/transform.c#L38

添加转置矩阵并垂直翻转 Y 分量块的方法后,问题就解决了!

现在,帧看起来与输入相同,除了压缩算法产生的一些轻微伪像之外,如预期的那样

正确的编码器输出

© www.soinside.com 2019 - 2024. All rights reserved.