Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pause/Resume MediaCodec

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;
}
like image 745
Alexey Avatar asked Jan 09 '14 11:01

Alexey


2 Answers

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.

like image 199
fadden Avatar answered Nov 01 '22 18:11

fadden


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.

like image 25
Ganesan Avatar answered Nov 01 '22 18:11

Ganesan