MediaCodec在genymotion和huddle 2上有不同的颜色

时间:2015-05-10 07:50:27

标签: android colors mediacodec renderscript yuv

我的目标:
使用渲染脚本在SD卡的MP4视频上使用滤镜(裁剪,黑白,边缘检测)。

尝试解决方案
- 使用MediaCodec直接输出到曲面。
渲染的颜色是正确的但我找不到一种方法来一次处理每个帧以使用renderscript应用过滤器。

- 从渲染脚本复制解码缓冲区并使用ScriptIntrinsicYuvToRGB转换为RGB
我无法使用ScriptIntrinsicYuvToRGB,因为它假定传入的YUV数据的格式与传入数据的格式不同。 (How do I correctly convert YUV colours to RGB in Android?

- 从渲染脚本复制解码缓冲区并使用自定义代码转换为RGB
我目前的解决方案使用与https://stackoverflow.com/a/12702836/601147非常相似的代码将YUV转换为RGB(感谢@Derzu)

            /**
         * Converts YUV420 NV21 to RGB8888
         *
         * @param data byte array on YUV420 NV21 format.
         * @param width pixels width
         * @param height pixels height
         * @return a RGB8888 pixels int array. Where each int is a pixels ARGB.
         */
        public int[] convertYUV420_NV21toRGB8888(byte [] data, int width, int height) {
            int size = width*height;
            int offset = size;
            int[] pixels = new int[size];
            int u, v, y1, y2, y3, y4;

            // i percorre os Y and the final pixels
            // k percorre os pixles U e V
            for(int i=0, k=0; i < size; i+=2, k+=2) {
                y1 = data[i]&0xff;
                y2 = data[i+1]&0xff;
                y3 = data[width+i  ]&0xff;
                y4 = data[width+i+1]&0xff;

                u = data[offset+k  ]&0xff;
                v = data[offset+k+1]&0xff;
                u = u-128;
                v = v-128;

//                pixels[i] = convertYUVtoRGB(y1, v,u);
//                pixels[i+1] = convertYUVtoRGB(y2, v,u);
//                pixels[width+i  ] = convertYUVtoRGB(y3, v,u);
//                pixels[width+i+1] = convertYUVtoRGB(y4, v,u);

                pixels[i] = convertYUVtoRGB(y1, u, v);
                pixels[i+1] = convertYUVtoRGB(y2,  u, v);
                pixels[width+i  ] = convertYUVtoRGB(y3,  u, v);
                pixels[width+i+1] = convertYUVtoRGB(y4, u, v);

                if (i!=0 && (i+2)%width==0)
                    i+=width;
            }

            return pixels;
        }

        private int convertYUVtoRGB(int y, int u, int v) {
            int r,g,b;

            r = y + (int)1.402f*v;
            g = y - (int)(0.344f*u +0.714f*v);
            b = y + (int)1.772f*u;
            r = r>255? 255 : r<0 ? 0 : r;
            g = g>255? 255 : g<0 ? 0 : g;
            b = b>255? 255 : b<0 ? 0 : b;
            return 0xff000000 | (b<<16) | (g<<8) | r;
        }

我唯一的区别就是从

翻转UV值
pixels[i] = convertYUVtoRGB(y1, v,u);

pixels[i] = convertYUVtoRGB(y1, u, v);

因为后者效果更好。

我的问题
我的Huddle 2上的颜色看起来很好,但是它们在Genymotion JellyBean模拟器上完全错误。

Huddle2 colour being rendered on my Huddle 2 ok-ish

Genymotion Genymotion rendering the colours totally wrong

请您能给我提供帮助和建议吗? 非常感谢你

1 个答案:

答案 0 :(得分:3)

您需要检查它实际使用的颜色格式 - 这假设输出是NV12,但看起来您的输出是I420或类似的东西(平面,而不是半平面)。请查看http://bigflake.com/mediacodec/,特别是https://android.googlesource.com/platform/cts/+/jb-mr2-release/tests/tests/media/src/android/media/cts/EncodeDecodeTest.javacheckFrame方法)。

关键因素是:

int colorFormat = format.getInteger(MediaFormat.KEY_COLOR_FORMAT);

checkFrame方法还会告诉您如何处理它,如果它是平面而不是半平面,这应该适用于您的情况。

请记住,设备也允许以专有格式输出,你无法解释为这么简单 - 你需要准备以某种方式处理这种情况(例如告诉用户你的应用可以处理它,回退到其他基于SW的实现,等等。)