MediaCodec的解码流程这里就不做分析了。
主要分析outputbuffer拿到数据以后的问题。

outputbuffer有两种(只可取其一)可用的资源,一种是数据流,也就是byte[]存储的,yuv格式的数据,而bitmap需要的是rgb格式的数据。
所以取另一种,image存储的数据,

image = mediaCodec.getOutputImage(outIndex);

多平面Android YUV 420格式
这种格式是一种通用的YCbCr格式,能够描述任何4:2:0色度子采样平面或半平面缓冲器(但不是完全交错的),每个颜色样本有8位。
这种格式的图像总是由三个独立的数据缓冲区表示,每个颜色平面一个缓冲区。附加信息总是伴随着缓冲区,描述每个平面的行步幅和像素步幅。
保证Image#getPlanes()返回的数组中平面的顺序,使平面#0始终为Y,平面#1始终为U(Cb),平面#2始终为V(Cr)。
Y平面保证不会与U/V平面交错(特别是,像素步幅在yPlane.getPixelStride()中始终为1)。
U/V平面保证具有相同的行步幅和像素步幅。例如,Image对象可以通过ImageReader对象从CameraDevice提供此格式的数据。

关于YuvImage

YuvImage包含YUV数据,并提供了一种将YUV数据的区域压缩为Jpeg的方法。YUV数据应作为单字节数组提供,而不考虑其中图像平面的数量。目前仅支持ImageFormat.NV21和ImageFormat.YUY2。要压缩YUV数据中的矩形区域,用户必须按左、上、宽和高指定区域。

NV21

YCrCb格式用于图像,该格式使用NV21编码格式。
这是android.hardware.Camera预览图像的默认格式,如果未使用android.hhardware.Camer.Parameters.setPreviewFormat(int)进行设置。

YUV2

用于图像的YCbCr格式,其使用YUYV(YUY2)编码格式。
对于android.hardware.camera2 API,建议使用YUV_420_888格式作为YUV输出。
这是android.hardware.Camera预览图像的另一种格式。摄像头硬件是否支持这种格式可以由android.hardware.CCamera.Parameters.getSupportedPreviewFormats()决定。

对于android.hardware.camera2 API,建议使用YUV_420_888格式作为YUV输出。
拿到image之后,

YuvImage yuvImage = new YuvImage(YUV_420_888toNV21(image), ImageFormat.NV21, width,height, null);

Image.getPlanes()
获取此图像的像素平面阵列。平面的数量由图像的格式决定。如果图像格式为PRIVATE,则应用程序将获得一个空数组,因为无法直接访问图像像素数据。应用程序可以通过调用getFormat()来检查图像格式。

private static byte[] YUV_420_888toNV21(Image image) {
        byte[] nv21;
        ByteBuffer yBuffer = image.getPlanes()[0].getBuffer();
       ByteBuffer uBuffer = image.getPlanes()[1].getBuffer();
       ByteBuffer vBuffer = image.getPlanes()[2].getBuffer();
       int ySize = yBuffer.remaining();
       int uSize = uBuffer.remaining();
       int vSize = vBuffer.remaining();
       nv21 = new byte[ySize + uSize + vSize];
       //U and V are swapped
       yBuffer.get(nv21, 0, ySize);
       vBuffer.get(nv21, ySize, vSize);
       uBuffer.get(nv21, ySize + vSize, uSize);
       return nv21;
    }

yuvImage.compressToJpeg
将YuvImage中的矩形区域压缩为jpeg。目前仅支持ImageFormat.NV21和ImageFormat.YUY2。
参数:
矩形–要压缩的矩形区域。该方法检查矩形是否在图像内部。此外,如果矩形中的色度像素与其中的亮度像素不匹配,则该方法会修改矩形。
质量–压缩机提示,0-100。0表示小尺寸压缩,100表示最大质量压缩。
stream–OutputStream,用于写入压缩数据。

ByteArrayOutputStream stream = new ByteArrayOutputStream();
yuvImage.compressToJpeg(new Rect(0, 0, width, height), 80, stream);
bitmap = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());
try {
    stream.close();
  } catch (IOException e) {
      e.printStackTrace();
  }

这样就完成了yuv->bitmap.
PS:可以直接使用,想知其然又想知其所以然,可以私信我。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐