我正在创建Bitmaps,我希望它们(硬件)编码并复制到.mp4文件中。
我正在使用MediaCodec类进行编码,并使用MediaMuxer进行多路复用。
问题是编码器(MediaCodec)给了我太小的输入缓冲区。无论我选择什么颜色格式(在传递给编码器的MediaFormat对象中),它总是返回给我等于resWidth * resHeight * 1.5
的缓冲区,它看起来好像要我使用12位颜色编码。
例如,当我选择我的帧为960x540像素时,编码器将通过我777600字节长的缓冲区。当我选择其他分辨率时,它将始终相应地缩放缓冲区。
位图在程序执行期间创建,我在其上呈现Android视图(使用Canvas)。 Bitmap类规范在颜色格式方面没有多少选择,据我所知,没有选择12位编码的选项。
我可以选择8位,这是我尝试使用每像素8位位图填充输入缓冲区时得到的结果:https://www.youtube.com/watch?v=5c-fjYp9KMQ
正如你所看到的,一切都是绿色的,它不应该是。以下是揭示此问题的最小(2个类)工作代码示例:https://github.com/eeprojects/MediaCodecExample
您只需运行此应用程序并等待几秒钟即可生成上面显示的视频。 LogCat中记录了应用程序在运行时所做的一切。
我尝试手动设置缓冲区大小(可以通过设置MediaFormat.KEY_MAX_INPUT_SIZE
字段)并将其设置为resWidth * resHeight * 2
然后以16位编码位图,但在尝试以这种方式出列输出缓冲区时,编解码器返回致命的内部错误和应用程序崩溃:
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
答案 0 :(得分:1)
您无需盲目地猜测编码器需要什么格式 - 您实际上是在应用程序代码中自己选择它。来自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位分量的色度平面,但是水平和垂直二次采样。
使用Bitmap.Config.ALPHA_8
绘制时,只设置亮度平面,而色度平面保持未初始化,可能设置为零,呈现浅绿色。如果您将输入缓冲区的其余字节设置为128而不是0,则会得到灰度图像。
由于Bitmap
不支持YUV像素格式,您需要手动转换像素数据,或者使用自Android 4.3以来可用的新Surface
输入法。然后你可以使用任何可以绘制到Surface
的内容来产生输入 - 你至少可以使用OpenGL ES,但不确定Canvas
。