2017-03-07 167 views
0

我試圖挽救YUV在android系統camera2獲得JPEG 420個預覽畫面爲JPEG。我發現這樣做的唯一方法是將yuv420轉換爲nv21,構建一個yuvimage,然後使用compresstojpeg方法獲取jpeg。爲了從YUV420轉換到jpeg我使用下面轉換YUV420在android系統camera2

  Image.Plane Y = img.getPlanes()[0]; 
      Image.Plane U = img.getPlanes()[2]; 
      Image.Plane V = img.getPlanes()[1]; 

      int Yb = Y.getBuffer().remaining(); 
      int Ub = U.getBuffer().remaining(); 
      int Vb = V.getBuffer().remaining(); 

      byte[] data = new byte[Yb + Ub + Vb]; 

      Y.getBuffer().get(data, 0, Yb); 
      U.getBuffer().get(data, Yb, Ub); 
      V.getBuffer().get(data, Yb + Ub, Vb); 

      YuvImage yuvImage = new YuvImage(data, ImageFormat.NV21, 
       mPreviewSize.getWidth(), mPreviewSize.getHeight(), null); 
      ByteArrayOutputStream out = new ByteArrayOutputStream(); 
      yuvImage.compressToJpeg(new Rect(0, 0, 
        mPreviewSize.getWidth(), mPreviewSize.getHeight()), 
       100, out); 

然而這會導致在獲得綠色圖像的某些分辨率144 X 176,176×144,352×288,480x360,720x540和1280×960的邏輯。轉換爲nv21的邏輯是否正確?我可以使用其他方式從yuv420轉換爲jpeg。 有沒有Java/Android API?

回答

1

不,這是不正確的 - 你不重視飛機的排步幅或像素間距。

你必須解析這些,並確保你的輸出緩衝區實際上符合YuvImage的NV21輸入(假設行跨度=寬度)和交錯V/U平面的輸入期望值。

你只會工作,如果輸入圖像U/V平面實際上是交錯的代碼(在這種情況下,你要添加兩次您需要的UV數據,但第一個副本恰好是正確的佈局...) ,如果width == row stride。寬度==行寬是否取決於分辨率;由於硬件限制,通常步幅必須是16像素的倍數或類似的東西。因此,對於不是16的倍數的解決方案,例如,您的代碼將無法工作。

請解決這兩個問題 - 關注行和像素間距;否則你可能會意外地使它在你的設備上工作,並且仍然會在具有不同參數的設備上被破壞。

編輯:

一些示例C++代碼,它這種轉換可以在Android AOSP照相機服務代碼中找到:CallbackProcessor::convertFromFlexibleYuv

映射以供參考:

previewFormat的
  • HAL_PIXEL_FORMAT_YCrCb_420_SP是NV21。
  • src.data是平面0
  • src.dataCb是是平面1
  • src.dataCr是平面2
  • src.stride是平面0 rowStride
  • src.chromaStride是平面1和2 rowStride
  • src.chromaStep是平面1 AND2 pixelStride
  • 平面0像素間距爲1
+0

感謝您的輸入。你有沒有任何參考資料可以查找這個特定轉換的算法。 – user3294816

+0

我沒有方便的Java參考,但添加了C​​ ++代碼參考 –

+0

謝謝!這工作完美無瑕。我只需要切換Cr和Cb的定義即可正確顯示顏色。 – user3294816