2012-07-18 282 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