使用 Android 的 MediaCodec class 编码的绿色视频

Greenish video encoded using Android's MediaCodec class

我正在创建 Bitmaps,我希望它们被(硬件)编码并混合到 .mp4 文件中。

我正在使用 MediaCodec class to encode and MediaMuxer 进行多路复用。

问题是编码器 (MediaCodec) 给我的输入缓冲区太小了。无论我选择什么颜色格式(在传递给编码器的 MediaFormat 对象中),它总是 returns 对我来说等于 resWidth * resHeight * 1.5 的缓冲区,看起来有点像它要我使用 12-位颜色编码。

例如,当我选择我的帧为 960x540 像素时,编码器将向我传递 777600 字节长的缓冲区。当我选择其他分辨率时,它总是会相应地缩放缓冲区。

位图是在程序执行期间创建的,我在其上渲染 Android 个视图(使用 Canvas)。位图 class 规范在颜色格式方面没有给我很多选择,据我所知没有选择 12 位编码的选项。

但是我可以选择 8 位,这就是我尝试用每像素 8 位位图的内容填充输入缓冲区时得到的结果:https://www.youtube.com/watch?v=5c-fjYp9KMQ

如您所见,一切都是绿色的,但不应该如此。这是暴露此问题的最小(2 classes)工作代码示例:https://github.com/eeprojects/MediaCodecExample

您只需 运行 此应用程序并等待几秒钟即可生成上面显示的视频。应用程序在运行时所做的一切都记录在 LogCat.

我尝试手动设置缓冲区大小(这可以通过设置 MediaFormat.KEY_MAX_INPUT_SIZE 字段来实现)并将其设置为 resWidth * resHeight * 2 然后以 16 位编码位图,但同时尝试在此输出缓冲区出队方式,编解码器 returns 致命内部错误和应用程序崩溃:

E/ACodec: [OMX.Exynos.AVC.Encoder] ERROR(0x80001001)
E/ACodec: signalError(omxError 0x80001001, internalError -2147483648)
E/MediaCodec: Codec reported err 0x80001001, actionCode 0, while in state 6

您无需盲目猜测编码器想要的格式 - 您实际上是在应用程序代码中自行选择的。来自你的 MainActivity.java:

    MediaCodecInfo codecInfo = selectCodec(OUTPUT_VIDEO_MIME_TYPE);
    int colorFormat = selectColorFormat(codecInfo, OUTPUT_VIDEO_MIME_TYPE);

    MediaFormat outputVideoFormat =
            MediaFormat.createVideoFormat(OUTPUT_VIDEO_MIME_TYPE, TEX_WIDTH, TEX_HEIGHT);
    outputVideoFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat);

selectColorFormat 方法可能返回了一些 YUV 420 颜色格式。所有常见的 YUV 420 颜色格式(例如 MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar)都是 12 位的。或者更准确地说,你有一个全分辨率的 8 位亮度平面,然后是两个具有 8 位分量的色度平面,但在水平和垂直方向上都进行了 2 倍二次采样。

当你使用 Bitmap.Config.ALPHA_8 绘制它时,你只设置了亮度平面,而色度平面未初始化,可能设置为零,呈现绿色。如果您将输入缓冲区的其余字节设置为 128 而不是 0,您将获得灰度图像。

由于Bitmap不支持YUV像素格式,您要么需要手动转换像素数据,要么使用自Android 4.3起可用的新Surface输入法.然后你可以使用任何可以绘制到 Surface 中的东西来产生输入——你至少可以使用 OpenGL ES,但不确定 Canvas