【问题标题】:how to use software codec in android using mediacodec如何使用 mediacodec 在 android 中使用软件编解码器
【发布时间】:2017-01-02 19:12:45
【问题描述】:

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

我使用谷歌软件编码器OMX.google.h264.encoder

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

什么是我无法识别的问题。

来源:

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$2.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$1.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)

【问题讨论】:

    标签: android android-mediacodec


    【解决方案1】:

    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 主版本中(也就是说,可能在下一个主要版本中,除非该版本已经完成并且尚未包含此更改),编码器已替换为功能更强大的编码器,但对于现有发布后,除了在您的应用中捆绑更好的 SW 编码器之外,您无能为力。

    编辑:今天发布的 Android M 预览版确实包含新的 SW 编码器,它应该适用于这个用例。

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

    【讨论】:

    • 我不确定这是否已知,但编码器的输出没有起始码不是问题。 IMO,这是设计使然,因为编码器的输出可能会被流式传输。当您使用RTP 流式传输数据时,需要从NAL 有效负载中去除起始码。一些播放器会处理启动代码(如果存在),但有些播放器不会处理相同的。例如,我对 Apple 的 QuickTime Player 有很多问题,它不支持带有起始码的流媒体内容。为了保持编码器的通用性,实现可能被设计为不发出它们。
    • 事实上,每个其他编码器都会输出起始码,并且接口使用的 OMX 标准也要求使用它们,这一点是不同的。是的,如果您要剥离它们然后读取其他内容,那么您只需要确保之前确实有一个起始码 - 那么这可能不是问题。但是,如果您将其写入 mpegts(或其他需要 startcode 的地方),您现在需要检查是否有 startcode,如果没有,请添加它。唯一需要它的单一编码器是极其有限的OMX.google.h264.encoder
    • OMX IL 1.1.2 规范没有说明,但是 OMX IL 1.2.0 说的很清楚(见OMX_NALSTREAMFORMATTYPE),默认是OMX_NaluFormatStartCodes,因为这个参数是'在 MediaCodec 中不可读取/可设置,只有默认值有效。此外,即使您不同意,Google 自己也得出结论认为这是一个错误(并且已修复)。即使存在其他行为不同的 OMX 编码器,Google 也强制要求 MediaCodec 采用这种行为。此外,我不反对它是可以处理的——显然是——但这是这个 SW 编码器的另一个问题。
    • Stagefright 中使用的当前OMX IL 版本是1.1.2,因此是我之前的评论。我不反对1.2.0,但规范是临时的。我并不是说编码器的实现是真正正确的。我只是说特定的定制是合理的。 SW Encoder 有很多问题,这在社区中广为人知。我不反对谷歌会修复这个错误,但如果由于OMX_NALSTREAMFORMATTYPE 而做了同样的事情,我会感到惊讶。
    • Google 想要修复编码器中的错误的另一个原因:以前他们自己的编码器未能通过他们自己的 EncodeDecodeTest CTS 测试 - 修复了起始码,它通过了(对于较低的分辨率)。
    猜你喜欢
    • 2015-04-30
    • 2012-10-08
    • 1970-01-01
    • 2014-01-04
    • 2014-05-16
    • 2013-06-18
    • 2013-02-22
    • 2018-10-17
    • 2015-12-03
    相关资源
    最近更新 更多