简体   繁体   English

如何将YUV高效转换为RGB

[英]How to convert YUV to RGB efficient

``I want to use RGB in the camera's preview.I used JNI to do the YUV to RGB conversion.I changed the data in RGB,then I show RGB on preview by using drawBitmap.But it shows the very slow,how could I improve it ``我想在相机的预览中使用RGB。我使用JNI进行YUV到RGB的转换。我更改了RGB中的数据,然后使用drawBitmap在预览中显示了RGB。但是它显示的很慢,我怎么能改进它

    public void onPreviewFrame(final byte[] data, Camera camera) {

    Thread showPic = new Thread(new Runnable() {

        @Override
        public void run() {
            // TODO Auto-generated method stub
            Canvas c = mHolder.lockCanvas(null);
            try {

                synchronized (mHolder) {

                    // TODO Auto-generated method stub
                    int imageWidth = mCamera.getParameters()
                            .getPreviewSize().width;
                    int imageHeight = mCamera.getParameters()
                            .getPreviewSize().height;
                    int RGBData[] = new int[imageWidth * imageHeight];
                    int RGBDataa[] = new int[imageWidth * imageHeight];
                    int RGBDatab[] = new int[imageWidth * imageHeight];
                    int center = imageWidth * imageHeight / 2;

                    Jni.decodeYUV420SP(RGBData, data, imageWidth,
                            imageHeight); // decode
                    for (int i = 0; i < center; i++)
                        RGBDataa[i] = RGBData[i];
                    for (int i = center; i < imageWidth * imageHeight; i++)
                        RGBDatab[i - center] = RGBData[i];
                    for (int i = 0; i < center; i++)
                        RGBData[i] = RGBDatab[i];
                    for (int i = center; i < imageWidth * imageHeight; i++)
                        RGBData[i] = RGBDataa[i - center];

                    c.drawBitmap(RGBData, 0, imageWidth, 0, 0, imageWidth,
                            imageHeight, false, new Paint());

                    // Bitmap bm = Bitmap.createBitmap(RGBData, imageWidth,
                    // imageHeight, Config.ARGB_8888);

                }

            } finally {
                if (data != null)
                    mHolder.unlockCanvasAndPost(c);
            }
        }
    });
    showPic.run();

}

The following code is Jni 以下代码是Jni

    public class Jni {
public native static void decodeYUV420SP(int[] rgb, byte[] yuv420sp, int width,
        int height);

} The method decodeYUV420SP is completed by C. }方法decodeYUV420SP由C完成。

I came across this thread searching for YUV420sp to RGB565 conversion. 我碰到了这个线程,正在寻找YUV420sp到RGB565的转换。 Using decodeYUV420SP as suggested above works fine, but I want to add some runtime considerations. 如上面建议的那样使用解码YUV420SP可以正常工作,但是我想添加一些运行时注意事项。

My first test using decodeYUV420SP in Java took 74 seconds decoding and converting a 10 second .mp4 FullHD video (using an Nexus 6 Android device). 我的第一次使用Java中的 encodeYUV420SP进行的测试耗时74秒,解码并转换了10秒的.mp4 FullHD视频(使用Nexus 6 Android设备)。 The profiler reported 96% of the overall process has been spent in decodeYUV420SP. 探查器报告说,整个过程的96%都花在了解码YUV420SP上。

Moving decodeYUV420SP to JNI / C made made overall time spent go down to 32 seconds. 将解码器YUV420SP转移到JNI / C使得总时间减少到32秒。 Turning on GCC code optimization, it fell to 12 seconds. 开启GCC代码优化后,它降到了12秒。

Although the OP suggested this already, I wanted to emphasizes it will not be an improvement to move the routine to Java. 尽管OP已经提出了这一建议,但我想强调的是将例程移至Java不会有所改善。 While it is correct a context change between Java and C comes at a cost, this is a good example an expensive operation performed in the native function will easily compensate this overhead. 虽然正确地在Java和C之间进行上下文更改是有代价的,但这是一个很好的例子,在本机函数中执行的昂贵操作将很容易地补偿此开销。 The statement on overhead costs is valid for very simple JNI functions and in case method and field lookups back and forth are required. 有关间接费用的声明仅对非常简单的JNI函数有效,并且在需要来回查找方法和字段的情况下有效。 Nothing of this applies here. 这里没有任何内容适用。

To improve the performance of the OP's code: get rid of the memory allocation done for each frame and store it globally, get rid of the arithmetic on RGBData* and move that stuff to JNI too. 要提高OP代码的性能,请执行以下操作:取消为每个帧完成的内存分配,并将其全局存储,摆脱RGBData *上的算法,并将这些内容也移至JNI。 Arrays can be accessed on JNI level at no cost using the Critical functions. 使用Critical函数可以在JNI级别上免费访问阵列。

It's not recommended to use jni because of slow speed for compiler to change java code to C++. 不建议使用jni,因为编译器将Java代码更改为C ++的速度较慢。 I think you should use direct method like this 我认为你应该使用这样的直接方法

public void decodeYUV420SP(int[] rgb, byte[] yuv420sp, int width, int height) {
    final int frameSize = width * height;

    for (int j = 0, yp = 0; j < height; j++) {
        int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;
        for (int i = 0; i < width; i++, yp++) {
            int y = (0xff & ((int) yuv420sp[yp])) - 16;
            if (y < 0) y = 0;
            if ((i & 1) == 0) {
                v = (0xff & yuv420sp[uvp++]) - 128;
                u = (0xff & yuv420sp[uvp++]) - 128;
            }

            int y1192 = 1192 * y;
            int r = (y1192 + 1634 * v);
            int g = (y1192 - 833 * v - 400 * u);
            int b = (y1192 + 2066 * u);

            if (r < 0) r = 0; else if (r > 262143) r = 262143;
            if (g < 0) g = 0; else if (g > 262143) g = 262143;
            if (b < 0) b = 0; else if (b > 262143) b = 262143;

            rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);
        }
    }
}

OR simply use this 或者简单地使用这个

Camera.Parameters.setPreviewFormat(ImageFormat.RGB_565);

to change the format output to rgb directly 将格式输出直接更改为rgb

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM