Android Mediacodec解码h264视频流单帧与大绿色填充

y53ybaqx  于 2023-06-20  发布在  Android
关注(0)|答案(1)|浏览(282)

我想解码一个H.264视频流的单帧,这是由服务器发送,但当我这样做,结果图片有很大的填充。

编码和结果:

代码:

  1. val singleFrameMediaCodec= MediaCodec.createDecoderByType("video/hevc")
  2. mediaFormat.setInteger(
  3. MediaFormat.KEY_COLOR_FORMAT,
  4. MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible
  5. )
  6. singleFrameMediaCodec.configure(mediaFormat, null, null, 0)
  7. singleFrameMediaCodec.setCallback(object : MediaCodec.Callback() {
  8. override fun onInputBufferAvailable(
  9. _codec: MediaCodec,
  10. index: Int
  11. ) {
  12. val buffer = _codec.getInputBuffer(index)
  13. singleFrameMediaCodec.queueInputBuffer(
  14. index,
  15. 0,
  16. data.size,
  17. 0,
  18. /*BUFFER_FLAG_END_OF_STREAM*/0
  19. )
  20. }
  21. override fun onOutputBufferAvailable(
  22. _codec: MediaCodec,
  23. index: Int,
  24. info: MediaCodec.BufferInfo
  25. ) {
  26. try {
  27. val info = MediaCodec.BufferInfo()
  28. val outputIndex = index
  29. val image: Image? = _codec.getOutputImage(outputIndex)
  30. val rect = image.cropRect
  31. val yuvImage = YuvImage(
  32. YUV_420_888toNV21(image),
  33. NV21,
  34. rect.width(),
  35. rect.height(),
  36. null
  37. )
  38. val stream = ByteArrayOutputStream()
  39. yuvImage.compressToJpeg(
  40. Rect(0, 0, rect.width(), rect.height()),
  41. 80,
  42. stream
  43. )
  44. val frameBitmap: Bitmap =
  45. BitmapFactory.decodeByteArray(
  46. stream.toByteArray(),
  47. 0,
  48. stream.size()
  49. )
  50. imageView.setImageBitmap(frameBitmap)
  51. _codec.stop()
  52. stream.close()
  53. image.close()
  54. if (outputIndex >= 0) {
  55. _codec.releaseOutputBuffer(outputIndex, false)
  56. }
  57. } catch (e: Exception) {
  58. Log.d(SLIDER_PRECISION, "errors here: " + e.toString())
  59. }
  60. }
  61. override fun onError(
  62. _codec: MediaCodec,
  63. e: MediaCodec.CodecException
  64. ) {
  65. }
  66. override fun onOutputFormatChanged(
  67. _codec: MediaCodec,
  68. format: MediaFormat
  69. ) {
  70. }
  71. })
  72. singleFrameMediaCodec.start();

现在的结果是这样的大加法:

我做错了什么?重新缩放YUV图像没有帮助,并导致图片具有0维。(我把200和600)
我的YUV转换代码:

  1. public static byte[] YUV_420_888toNV21(Image image) {
  2. byte[] nv21;
  3. ByteBuffer yBuffer = image.getPlanes()[0].getBuffer();
  4. ByteBuffer uBuffer = image.getPlanes()[1].getBuffer();
  5. ByteBuffer vBuffer = image.getPlanes()[2].getBuffer();
  6. int ySize = yBuffer.remaining();
  7. int uSize = uBuffer.remaining();
  8. int vSize = vBuffer.remaining();
  9. nv21 = new byte[ySize + uSize + vSize];
  10. //U and V are swapped
  11. yBuffer.get(nv21, 0, ySize);
  12. vBuffer.get(nv21, ySize, vSize);
  13. uBuffer.get(nv21, ySize + vSize, uSize);
  14. return nv21;
  15. }

我也抛出了这个异常:
android mediacodec分配组件'OMX.qcom.video.decoder.hevc'失败,请尝试下一个。

apeeds0o

apeeds0o1#

我想解释一下问题出在哪里,这样任何有同样问题的人都可以学习。我已经按照上面的代码设置了正确的填充。那么是什么导致了这个错误的输出呢?问题是我在活动中生成了两个MediaCodec示例,因此操作系统遇到了低资源并给出了此错误结果。只需一个MediaCodec示例就解决了这个问题。(请注意,此问题会发生,但更有可能在使用较旧Android版本的手机中(a.k.a =<8)。

编辑:另一点:

重新缩放YUV图像没有帮助,并导致图片具有0维。(我把200和600)
这是因为如果你为mediaCodec设置了一个表面,它将是MediaCodec的唯一输出,所以在onOutputBufferReady回调中获取Bitmap,将不会返回任何东西。

相关问题