如何使用 mediacodec 在 android 中使用软件编解码器

how to use software codec in android using mediacodec

我想使用 mediacodec 软件编解码器将 yuv 数据编码为 h264。

我用Google软件编码器OMX.google.h264.encoder

当我使用硬件编码器[OMX.qcom.video.encoder.avc]时它可以工作,但是当我使用软件编码器[OMX.google.h264.encoder]时它不编码file.it会给出错误 [在日志中查看]。

我无法确定是什么问题。

来源:

mediaCodec = MediaCodec.createByCodecName("OMX.google.h264.encoder");
    //mediaCodec = MediaCodec.createByCodecName(codecInfo.getName());
    Log.i(TAG,"codec name : "+ mediaCodec.getName());
    int mBitrate  = (int) ((MainActivity.mHeight * MainActivity.mWidth * MainActivity.frameRate)*2*0.07);
    MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc",MainActivity.mWidth,MainActivity.mHeight);
    mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE,mBitrate);
    mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, MainActivity.frameRate);
    //   mediaFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 320*240);
    mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,colorFormat);
    //mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,MediaCodecInfo.CodecProfileLevel.AVCLevel12);
    mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL,1);
    try{
        mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
        mediaCodec.start();
        Log.i(TAG,"H264 Encoder init success");


    }catch(IllegalArgumentException e)
    {
        e.printStackTrace();
    }catch (IllegalStateException e) {
        e.printStackTrace();
    }catch (Exception e) { 
        e.printStackTrace();// TODO: handle exception
    }

但是我收到这个错误。

日志:

I/H264Encoder(7772): outputStream initialized
I/OMXClient(7772): Using client-side OMX mux.
I/H264Encoder(7772): found colorFormat: 21
I/OMXClient(7772): Using client-side OMX mux.
E/OMXMaster(7772): A component of name 'OMX.qcom.audio.decoder.aac' already exists, ignoring this one.
I/SoftAVCEncoder(7772): Construct SoftAVCEncoder
I/H264Encoder(7772): codec name : OMX.google.h264.encoder
E/SoftAVCEncoder(7772): internalSetParameter: StoreMetadataInBuffersParams.nPortIndex not zero!
E/OMXNodeInstance(7772): OMX_SetParameter() failed for StoreMetaDataInBuffers: 0x80001001
E/ACodec(7772): [OMX.google.h264.encoder] storeMetaDataInBuffers (output) failed w/ err -2147483648
I/ACodec(7772): setupVideoEncoder succeeded
I/H264Encoder(7772): H264 Encoder init success
E/SoftAVCEncoder(7772): Video frame size 1920x1080 must be a multiple of 16
E/SoftAVCEncoder(7772): Failed to initialized encoder params
E/ACodec(7772): [OMX.google.h264.encoder] ERROR(0x80001001)
E/MediaCodec(7772): Codec reported an error. (omx error 0x80001001, internalError -2147483648)
   W/System.err(7772): java.lang.IllegalStateException
   W/System.err(7772):  at android.media.MediaCodec.getBuffers(Native Method)
    W/System.err(7772):     at android.media.MediaCodec.getInputBuffers(MediaCodec.java:542)
  W/System.err(7772):   at com.ei.encodertest.H264Encoder.offerEncoder(H264Encoder.java:170)
  W/System.err(7772):   at com.ei.encodertest.MainActivity$ReadRawFileTask.doInBackground(MainActivity.java:113)
 W/System.err(7772):    at com.ei.encodertest.MainActivity$ReadRawFileTask.doInBackground(MainActivity.java:1)
 W/System.err(7772):    at android.os.AsyncTask.call(AsyncTask.java:288)
 W/System.err(7772):    at java.util.concurrent.FutureTask.run(FutureTask.java:237)
 W/System.err(7772):    at android.os.AsyncTask$SerialExecutor.run(AsyncTask.java:231)
 W/System.err(7772):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
   W/System.err(7772):  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
  W/System.err(7772):   at java.lang.Thread.run(Thread.java:841)

SW 编码器 OMX.google.h264.encoder 目前非常有限(编辑:在 Android 5.0 上),几乎无法使用。

此编码器不允许使用不是 16 的倍数的分辨率。在您的情况下,1920x1080,高度 1080 不能被 16 整除,因此对于此编码器来说是不可接受的。 (请参阅 https://android-review.googlesource.com/38904 尝试解决此问题。)

如果您将其更改为 1088,则 16 的倍数不是问题,但编码器也不允许您将其用于任何高于 352x288 的分辨率(参见 https://android-review.googlesource.com/82133).

最后,在较早的 Android 版本(5.0 之前)上,它的输出格式也略有不同(缺少启动代码,请参阅 https://android-review.googlesource.com/42321),这意味着您必须手动在每个输出数据包的开头添加启动代码,以便能够在某些地方使用它们(MediaMuxer 可能会按原样处理它,不过,主要是偶然)。

在当前的 AOSP master 中(也就是说,可能在下一个主要版本中,除非已经完成并且此更改未包含在其中),编码器已被替换为功能更强大的编码器,但是对于现有版本,除了在您的应用程序中捆绑更好的 SW 编码器之外,您无能为力。

编辑:今天发布的 Android M 预览版确实包含新的 SW 编码器,对于这个用例应该可以正常工作。

Edit2:新编码器包含在 Android 6.0 版本 (M) 中,因此从那时起,它应该可以使用。