7

In my i want encode yuv data into h264 using mediacodec software codec.

I use Google software encoder OMX.google.h264.encoder

when i use hardware encoder[OMX.qcom.video.encoder.avc] that time it work but when i use software encoder[OMX.google.h264.encoder] it not encode file.it will give error [see in log].

what is problem i couldn’t identify.

Source :

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
    }

But i getting this error.

Log :

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)
Bhagirathsinh Gohil
  • 673
  • 1
  • 9
  • 25

1 Answers1

15

The SW encoder OMX.google.h264.encoder is very limited at the moment (edit: On Android 5.0), close to being unusable.

This encoder doesn't allow using resolutions that aren't a multiple of 16. In your case, 1920x1080, the height 1080 isn't evenly dividable by 16, and thus isn't acceptable for this encoder. (See https://android-review.googlesource.com/38904 for an attempt at fixing this.)

If you'd change it into 1088, the multiple-of-16 wouldn't be an issue, but the encoder also won't allow you to use it with any resolution above 352x288 (see e.g. https://android-review.googlesource.com/82133).

Finally, on older Android versions (prior to 5.0), it also did output in a slightly different format (missing startcodes, see https://android-review.googlesource.com/42321), which meant that you would have to manually add startcodes at the start of each output packet to be able to use them in certain places (the MediaMuxer might have handled it as it was, though, mostly by chance).

In the current AOSP master (that is, maybe in the next major release, unless that already is being finalized and this change hasn't been included there), the encoder has been replaced with a more capable one, but for existing releases, there's not much you can do other than bundling a better SW encoder within your app.

Edit: The Android M preview that was released today does include the new SW encoder, which should work fine for this usecase.

Edit2: The new encoder was included in the Android 6.0 release (M), so since then, it should be usable.

mstorsjo
  • 12,983
  • 2
  • 39
  • 62
  • I am not sure if this is known, but the encoder's output not having startcodes is not an issue. IMO, this is by design as the encoder's output may potentially could be streamed. When you stream data using `RTP`, it is required to strip the start codes from the `NAL` payload. Some players handle the startcodes if present, but there are some players which will not handle the same. For example, I had a lot of issue with Apple's `QuickTime Player` which doesn't support a streaming content with startcodes. To keep the encoder generic, the implementation may have been designed not to emit them. – Ganesh May 30 '15 at 03:47
  • The fact that every single other encoder does output startcodes, and that the OMX standard that the interface uses also mandates the use of them, begs to differ. Yes, if you are going to strip them and then readd something else, then you only need to make sure that there actually is a startcode before - then perhaps it's not an issue. But if you are writing it into mpegts (or something else where the startcodes are needed), you now need to check if there is a startcode, and if not, add it. And the only single encoder out there that needs it, is the horribly limited `OMX.google.h264.encoder`. – mstorsjo May 30 '15 at 17:59
  • This is also the exact reason why this encoder happened to work with the `MPEG4Writer` class within stagefright - this class stripped the startcodes (if they were present). It didn't work with `MPEGTSWriter`, and when I pointed this out, the fix obviously wasn't to make `MPEGTSWriter` handle the case that startcodes were missing, but to add them in the encoder - see https://android-review.googlesource.com/42045 for details: "No, we don't want this patch, if our software encoder misbehaves, please file a bug and we'll fix _that_. We're not going to work around it." – mstorsjo May 30 '15 at 18:05
  • Finally - an encoder returning packets without startcodes obviously does not work if the encoder wants to return multiple NAL units for one frame (e.g. multiple slices). So returning packets without start codes simply is wrong and can only be handled with special case code, and only for special cases (single slice). – mstorsjo May 30 '15 at 18:07
  • AFAIK, `OMX` specification only mandates the correct coding type to be set and doesn't specifically deal with the `startcodes'` presence/absence. Now, from an encoder's perspective, I can vouch that there are a lot of different implementations out in the world, that its a difficult proposition to say all are common. The implementation is based on use-case specific. If you are authoring a file, you require different semantics, whereas if you are streaming, you need to adhere to `RTP` constraints which in this case mandates that `startcode` shouldn't be present. – Ganesh May 31 '15 at 01:21
  • Coming to multiple `NAL`, as I said that if you are authoring a file, then it makes sense. However, more often than not, it is a common practice that all file authoring encoders are single slice encoders. Multiple slices is more beneficial and commonly employed in `streaming` scenarios where you would like to consider latency, error resilience etc. However, real-time multi-slice encoders are rare especially at high resolutions. – Ganesh May 31 '15 at 01:24
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/79233/discussion-between-ganesh-and-mstorsjo). – Ganesh May 31 '15 at 01:26
  • 2
    The OMX IL 1.1.2 spec doesn't say anything about it, but OMX IL 1.2.0 says clearly (see `OMX_NALSTREAMFORMATTYPE`), the default is `OMX_NaluFormatStartCodes`, and since this parameter isn't readable/settable in MediaCodec, only the default is valid. Also even if you'd disagree, Google themselves concluded that it was a bug (and was fixed). Even if there are other OMX encoders out there that behave differently, Google mandates this behaviour for MediaCodec. Also I don't disagree that it is possible to handle - it obviously is - but it was yet another issue with this SW encoder. – mstorsjo May 31 '15 at 07:05
  • 1
    The current `OMX IL` version employed in `Stagefright` is `1.1.2` and hence, my earlier comment. I don't disagree with `1.2.0`, but the specification was provisional. I am not saying that the encoder implementation is truly correct. All I am saying that specific customizations are plausible. `SW Encoder` was known to have a lot of issues and this is widely known in the community. I don't disagree that Google would have fixed the bug, but will be surprised if the same was done due to the `OMX_NALSTREAMFORMATTYPE`. – Ganesh May 31 '15 at 11:34
  • 1
    Another reason why Google wanted to fix the bug in the encoder: Previously their own encoder failed their own EncodeDecodeTest CTS test - with the startcodes fixed, it passes (for the lower resolutions). – mstorsjo May 31 '15 at 17:11
  • @mstorsjo Why did you say OMX.google.h264.encoder is a software encoder? Is there a way to judge an encoder soft or hard with programming? – dragonfly Jun 30 '16 at 03:03