是否有可能从 MediaCodec 获取 BGR?

If is it possible to get BGR from MediaCodec?

据我所知,MediaCodec return YUV420 中的图像输出缓冲区,然后您可以随意处理它......但就我而言,我需要在 BGR 中转换 YUV420,这是相当昂贵的转换。

所以,问题是是否可以立即(无需转换)从 MediaCodec 得到 BGR

我现在的代码

uint8_t *buf = AMediaCodec_getOutputBuffer(m_data.codec, static_cast<size_t>(status), /*bufsize*/nullptr);
cv::Mat YUVframe(cv::Size(m_frameSize.width, static_cast<int>(m_frameSize.height * 1.5)), CV_8UC1, buf);

cv::Mat colImg(m_frameSize, CV_8UC3);
cv::cvtColor(YUVframe, colImg, CV_YUV420sp2BGR, 3);
auto dataSize = colImg.rows * colImg.cols * colImg.channels();
imageData.assign(colImg.data, colImg.data + dataSize);

因此,正如您在此处看到的那样

cv::Mat YUVframe(cv::Size(m_frameSize.width, static_cast<int>(m_frameSize.height * 1.5)), CV_8UC1, buf);

我正在从编解码器缓冲区获取 YUVframe,然后在此处获取

cv::cvtColor(YUVframe, colImg, CV_YUV420sp2BGR, 3);

我进行转换

转换需要很长时间。对我来说性能很重要。

帧以编解码器喜欢的任何格式从 MediaCodec 输出。大多数数码相机和视频编解码器使用 YUV 格式帧。在捕捉静止图像时,相机需要使用两种特定格式中的一种,但 MediaCodec 更像是一种免费的格式。如果您希望数据采用特定格式,则必须进行转换。

在 Android 上,您可以通过涉及 GPU 来让硬件为您完成这项工作,GPU 需要接受 MediaCodec 决定在该设备上生成的任何格式。您将每个帧作为 "external" 纹理锁定,方法是将其馈送到 SurfaceTexture 中,然后告诉 GLES 在 pbuffer 上以 RGB 格式渲染它,然后您可以通过不同的方式访问它。有关使用 glReadPixels() 的示例,请参阅 ExtractMpegFramesTest

glReadPixels() 的替代方法,它们依赖于私有本地方法来访问 pbuffer(例如 this and this),但是使用非 public API 是不明智的,除非您有完全的控制权设备的。

可能有一些我没有使用过的访问 pbuffer 的新方法,例如使用 native hardware buffers seems potentially useful ().