2012-07-18 92 views
1

``我想在相机的预览中使用RGB。我使用JNI来进行YUV到RGB的转换。我改变了RGB中的数据,然后使用drawBitmap在预览中显示RGB。但它显示了非常缓慢的,我怎么能改善它如何将YUV转换为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(); 

} 

下面的代码是JNI

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

} 方法decodeYUV420SP由C.

+0

嘿我是堆pn同样的问题,但我把这可以在onpicture采取我想问哪里把这种方法,以及如何叫 – Tony 2015-08-29 05:27:12

回答

-2

完成这也由于编译器将Java代码更改为C++,速度较慢,所以建议使用jni。我认为你应该使用直接的方法是这样

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); 
     } 
    } 
} 

或者干脆用这个

Camera.Parameters.setPreviewFormat(ImageFormat.RGB_565); 

更改格式输出为rgb直接

+0

请注意,有些设备可能不支持ImageFormat.RGB_565 – 2015-02-12 08:42:17

0

我碰到这个线程搜索YUV420sp到RGB565转换来。如上所示使用decodeYUV420SP可以正常工作,但我想添加一些运行时注意事项。

我的第一个测试使用decodeYUV420SP在Java花费了74秒解码和转换10秒.4全高清视频(使用Nexus 6 Android设备)。 Profiler报告说,整个过程中有96%用于解码YUV420SP。

将解码器YUV420SP移动到JNI/C使得整体耗费的时间降低到32秒。打开GCC代码优化,它下降到12秒。

尽管OP已经提出了这个问题,但我想强调,将例程移到Java并不是一个改进。尽管Java和C之间的上下文变化是正确的,但这是一个很好的例子,在本地函数中执行的昂贵的操作很容易弥补这种开销。管理费用声明对于非常简单的JNI函数是有效的,并且需要来回方法和字段查找。这里没有什么适用的。

为了提高OP代码的性能:摆脱为每一帧完成的内存分配并将其存储在全局中,摆脱RGBData *上的算术并将其移至JNI。使用关键函数可以免费访问数组的JNI级别。

+0

还有更多的东西在发布的代码中清理:除去'mCamera.getParameters()'并使用预先计算的宽度和高度;使用本地访问位图数据('AndroidBitmap_lockPixels()'等)来更新位图而不是复制像素;重用线程并摆脱同步锁......可以使用renderscript卸载到GPU的转换,或切换到OpenGL并让片段着色器完成艰苦的工作。有一件事是肯定的:今天在Android上,在C和Java中编写YUV到RGB转换是合理的。 – 2016-02-07 13:48:04