android - 使用 cv::Mat 和 MediaCodec 在 Android 中编码视频

标签 android opencv java-native-interface android-mediacodec

我正在使用 Android 4.3 设备使用 cv::Mat 对视频进行编码。

我查看了 grafika hacksBigFrake 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 的引用资料。

最佳答案

将 FBO 渲染到编解码器输入表面非常简单。您将需要 GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, framebuffer);
然后将 frameBuffer 的输出纹理 id 绑定(bind)到 mediacodec 上下文,即首先 makeCurrent,

GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);

并使用类似于 mediacodec stufs 中存在的常规复制着色器,但没有 OES 纹理但具有 2D 纹理:例如

private static final String VERTEXT_SHADER =
        "uniform mat4 uOrientationM;\n" +
            "uniform mat4 uTransformM;\n" +
            "attribute vec2 aPosition;\n" +
            "varying vec2 vTextureCoord;\n" +
            "void main() {\n" +
            "gl_Position = vec4(aPosition, 0.0, 1.0);\n" +
            "vTextureCoord = (uTransformM * ((uOrientationM * gl_Position + 1.0) * 0.5)).xy;" +
            "}";

    private static final String FRAGMENT_SHADER =
        "precision mediump float;\n" +
            "uniform sampler2D sTexture;\n" +
            "varying vec2 vTextureCoord;\n" +
            "void main() {\n" +
            "gl_FragColor = texture2D(sTexture, vTextureCoord);\n" +
            "}"; 

该副本的可行示例解决方案以及 FBO 初始化您可以在适用于 Android 的英特尔 INDE 示例中找到 https://software.intel.com/en-us/articles/intel-inde-media-pack-for-android-tutorials

关于android - 使用 cv::Mat 和 MediaCodec 在 Android 中编码视频,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23753932/

相关文章:

c++ - 将 cv::Mat 传递给 labview

java - 使用更少的内存将 Bitmap 传递给 JNI

android - ListView Activity 到 ListFragment 与 SQLite DB

java - Java Android Opencv 2.3 上的凸包

Android 下载 Zip 到 SD 卡?

C++ OpenCV VideoWriter 帧率同步

Android CMake 使用预构建 .a 库

android - 未定义的 lame 解码函数

android - 如何在没有首选项屏幕等的情况下存储共享首选项

android - 从原生访问插件的sqlite数据库