Question

I'm trying to implement pause/resume feature for my app that records display capture using MediaCodec. I've tried doing mEncoder.stop() and then mEncoder.start() without calling mEncoder.release() but that didn't work. I get IllegalStateException when calling mEncoder.start() again. Right now I implemented a workaround, I'm merging peaces of video after the capture is complete, but it takes a really long time to merge. Can anyone help me with that? Maybe someone has already implemented this thing?

Initialazation:

    MediaCodec mEncoder;
    mEncoder = MediaCodec.createEncoderByType(Preferences.MIME_TYPE);
    mEncoder.configure(mFormat, null, null,
            MediaCodec.CONFIGURE_FLAG_ENCODE);
    mInputSurface = new InputSurface(mEncoder.createInputSurface(),
            mSavedEglContext);
    mEncoder.start();
    try {
        String fileId = String.valueOf(System.currentTimeMillis());
        mMuxer = new MediaMuxer(dir.getPath() + "/Video"
                + fileId + ".mp4",
                MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
        videoParts.add(fileId);
    } catch (IOException ioe) {
        throw new RuntimeException("MediaMuxer creation failed", ioe);
    }
    isRecording = true;

Pause:

    public void pauseRecordPressed() {
    if (isRecording){
        isRecording = false;
        drainEncoder(false);

        if (mEncoder != null) {
            mEncoder.stop();
        }
    }
}

Unpause:

    public void resumeRecordPressed() {
    mEncoder.start();
    isRecording = true;
}

Exception:

01-09 15:34:27.980: E/AndroidRuntime(21467): FATAL EXCEPTION: main
01-09 15:34:27.980: E/AndroidRuntime(21467): Process: com.example.poc, PID: 21467
01-09 15:34:27.980: E/AndroidRuntime(21467): java.lang.IllegalStateException: start failed
01-09 15:34:27.980: E/AndroidRuntime(21467):    at android.media.MediaCodec.start(Native Method)
01-09 15:34:27.980: E/AndroidRuntime(21467):    at com.example.poc.MyRenderer.resumeRecordPressed(MyRenderer.java:501)
01-09 15:34:27.980: E/AndroidRuntime(21467):    at com.example.poc.MyGLSurfaceView.resumeRecordPressed(MyGLSurfaceView.java:243)
01-09 15:34:27.980: E/AndroidRuntime(21467):    at com.example.poc.MainActivity.onClick(MainActivity.java:775)
01-09 15:34:27.980: E/AndroidRuntime(21467):    at android.view.View.performClick(View.java:4438)
01-09 15:34:27.980: E/AndroidRuntime(21467):    at android.view.View$PerformClick.run(View.java:18422)
01-09 15:34:27.980: E/AndroidRuntime(21467):    at android.os.Handler.handleCallback(Handler.java:733)
01-09 15:34:27.980: E/AndroidRuntime(21467):    at android.os.Handler.dispatchMessage(Handler.java:95)
01-09 15:34:27.980: E/AndroidRuntime(21467):    at android.os.Looper.loop(Looper.java:136)
01-09 15:34:27.980: E/AndroidRuntime(21467):    at android.app.ActivityThread.main(ActivityThread.java:5017)
01-09 15:34:27.980: E/AndroidRuntime(21467):    at java.lang.reflect.Method.invokeNative(Native Method)
01-09 15:34:27.980: E/AndroidRuntime(21467):    at java.lang.reflect.Method.invoke(Method.java:515)
01-09 15:34:27.980: E/AndroidRuntime(21467):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
01-09 15:34:27.980: E/AndroidRuntime(21467):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
01-09 15:34:27.980: E/AndroidRuntime(21467):    at dalvik.system.NativeStart.main(Native Method)

MediaFormat:

mFormat = createMediaFormat();

    private static MediaFormat createMediaFormat() {
    MediaFormat format = MediaFormat.createVideoFormat(
            Preferences.MIME_TYPE, mScreenWidth, mScreenHeight);
    format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
            MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
    format.setInteger(MediaFormat.KEY_BIT_RATE, Preferences.BIT_RATE);
    format.setInteger(MediaFormat.KEY_FRAME_RATE, Preferences.FRAME_RATE);
    format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL,
            Preferences.IFRAME_INTERVAL);
    return format;
}
Was it helpful?

Solution

The MediaCodec discards its configuration when stopped, so you will need to call configure() again. I'm not sure why you're trying to do restart it though -- you can just leave it active, without feeding it data.

For example, see the CameraCaptureActivity in Grafika, which leaves the encoder alive across activity restarts. If you don't want to have a pause in the video during the restart, you'll need to keep track of how long encoding was paused, and then adjust the timestamps being fed into the muxer.

OTHER TIPS

private void suspendMediaCodec(boolean suspend)
{
    if(mediaCodec != null)
    {
        Bundle params = new Bundle();
        params.putInt(MediaCodec.PARAMETER_KEY_SUSPEND, suspend ? 1 : 0);
        mediaCodec.setParameters(params);
    }
}

You can suspend/resume mediacodec to drop frames by setting parameter MediaCodec.PARAMETER_KEY_SUSPEND. Above one is example to do it.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top