【发布时间】:2014-05-20 07:51:09
【问题描述】:
我正在使用 Android 4.3 设备使用 cv::Mat 对视频进行编码。
我查看了grafika hacks 和BigFrake samples,我已经对它们进行了测试并且它们正在工作。
我在 c++ 中有我的 cv::Mat,使用 JNI 我可以将缓冲区或缓冲区指针发送到我准备好的 Java 和编码器:
///////////////////////// Configure encoder
// QVGA at 2Mbps
mWidth = 320;
mHeight = 240;
mBitRate = 2000000;
//////////////////////////////////////
MediaCodecInfo codecInfo = selectCodec(MIME_TYPE);
if (codecInfo == null)
{
// Don't fail CTS if they don't have an AVC codec (not here, anyway).
Log.e(LOG_TAG, "Unable to find an appropriate codec for " + MIME_TYPE);
}
if (VERBOSE) Log.d(LOG_TAG, "found codec: " + codecInfo.getName());
mBufferInfo = new MediaCodec.BufferInfo();
MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, mWidth, mHeight);
// Set some properties. Failing to specify some of these can cause the MediaCodec
// configure() call to throw an unhelpful exception.
format.setInteger(MediaFormat.KEY_BIT_RATE, mBitRate);
format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE);
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL);
// format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
// format.setInteger(MediaFormat.KEY_SAMPLE_RATE, 200);
format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface); // PROBLEM: Color_formatSurface is the only want who works!!!!!
if (VERBOSE) Log.d(LOG_TAG, "format: " + format);
// Create a MediaCodec encoder, and configure it with our format.
//
mEncoder = MediaCodec.createEncoderByType(MIME_TYPE);
mEncoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
//mInputSurface = new CodecInputSurface(mEncoder.createInputSurface()); // I don't want to use a surface
mEncoder.start();
inputBuffers = mEncoder.getInputBuffers();
outputBuffers = mEncoder.getOutputBuffers();
问题是,MediaFormat.KEY_COLOR_FORMAT 只承认 COLOR_FormatSurface 或 COLOR_FormatYUV420SemiPlanar,但我的数据是 RGB,没有表面元数据或 YUV。我尝试过使用我可以使用的 3 个编解码器:
//private static final String MIME_TYPE = "video/avc"; // H.264 Advanced Video Coding
//private static final String MIME_TYPE = "video/mp4v-es"; // Mp4
private static final String MIME_TYPE = "video/3gpp"; // 3gpp
1) 在这种情况下,颜色格式有问题吗?我的意思是,是否可以直接使用,我必须使用 PixelBuffer 来伪造 COLOR_FormatSurface,或者将我的数据转换为 YUV?
2) 将数据从 cv::Mat.data 指针复制到 MediaCodec 缓冲区最有效的方法是什么?
更新 1:
- 在提取 CV:Mat 之前,我有一个 FBO OpenGL。我认为另一种解决方案是在 InputSurface 中渲染 FBO 以直接使用 MediaCodec 对视频进行编码,而无需共享上下文。但是我没有找到将 FBO 从 OpenGL 上下文复制到 CodecInputSurface 的参考。
【问题讨论】:
-
Grafika“Record GL 应用程序”演示了通过从 FBO 进行位传输(以及其他方法)来记录到 Surface。除非您需要支持 API 16/17,否则应避免将 ByteBuffer 输入到 MediaCodec,因为它需要 YUV 数据并且速度较慢。您可以使用
glTexImage2D将 RGB 数据上传到纹理; Grafika (512x512 RGBA) 中有一个基准,表明它在当前设备上相当快。
标签: android opencv java-native-interface android-mediacodec