androidandroid-canvasmediarecordersurfaceandroid-mediarecorder

MediaRecorder and VideoSource.SURFACE, stop failed: -1007 (a serious Android bug)


I'm trying to record MediaRecorder without using Camera instance but using Surface video source (yes it's possible, but it turned out that it's not that perfect) - mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);

I just write what the issue:

Next code works only on some devices and works temporary on some devices after a recent device rebooting or doesn't work at all

If it doesn't work ok MediaRecorder.stop() method fails with the next error

E/MediaRecorder: stop failed: -1007 W/System.err:

java.lang.RuntimeException: stop failed. at

android.media.MediaRecorder.stop(Native Method)

recorder mp4 file is too small size (kilobytes) and it can't be played

Tested devices:

works on Lenovo P2, Xiaomi Mi A1

doesn't work on Xiaomi Redmi 5, Sony Xperia, Xiaomi Redmi 4 Prime

Also you can read comments in my code to understand the issue better

new Thread(() -> {

    MediaRecorder mediaRecorder = new MediaRecorder();

    File file = new File(Environment.getExternalStorageDirectory()
            + File.separator + "test_media_recorder_surface_source.mp4");
    if (file.exists()) {
        file.delete();
    }

    mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
    mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
    mediaRecorder.setOutputFile(file.getAbsolutePath());
    mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
    mediaRecorder.setVideoSize(1280, 720);
    mediaRecorder.setCaptureRate(24);

    try {
        mediaRecorder.prepare();

        int sleepTime = 1000 / 24;

        Surface surface = mediaRecorder.getSurface();

        mediaRecorder.start();

        // record something (we can also record frames here from onPreviewFrame byte arrays)
        // e.g. convert raw frame byte[] to Bitmap using mb OpenCV and then draw bitmap on canvas
        // using canvas.drawBitmap(...)
        // here we record just blue background...
        for (int i = 0; i < 120; i++) { // 5 seconds, 24 fps
            Canvas canvas = surface.lockCanvas(null);
            canvas.drawColor(Color.BLUE);
            surface.unlockCanvasAndPost(canvas);
            try {
                Thread.sleep(sleepTime);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // on many devices stop fails with RuntimeException -1007 error code
        // I guess it works ok 100% only for modern powerful devices...
        mediaRecorder.stop();
        // E/MediaRecorder: stop failed: -1007
        // W/System.err: java.lang.RuntimeException: stop failed.
        // at android.media.MediaRecorder.stop(Native Method)

        // recorder.reset();
        mediaRecorder.release();
        // I get file with very small size (kilobytes) and it can't be played

        // ######## RESULTS ######

        // WORKS OK ON:
        // - Lenovo P2 (Android 7)
        // - Xiaomi Mi A1 (Android 8)

        // DOESN'T WORK ON (stop fails with -1007, small video file and can't be played):
        // - Xiaomi Redmi 5 (Android 7)
        // - Sony Xperia (I don't remember the exact model and Android OS)
        // - Xiaomi Redmi 4 Prime (Android 6) *

        // * p.s. on Xiaomi Redmi 4 Prime it works some time after rebooting the device
        // if I leave this smartphone for a while and try again it will fail again
        // until I reboot the device...

    } catch (Exception e) {
        e.printStackTrace();
    }
}).start();

UPDATE #1 seems some progress what could be the issue - codes issue (mp4/h264)

it works better with WEBM/VP8, videos can be played now, but something wrong with fps, it shows 1000 in proporties

mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.WEBM);
mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.VP8);

also MediaRecord doesn't record audio when using

mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.VORBIS);

check Android MediaRecorder crashes on stop when using MP4/H264 and a resolution bigger than 720p so it also happens when you use MediaRecorder and MediaProjection to record/capture device Screen (because it also uses Surface...)

UPDATE 2 yes seems vp8 codec works fine, but one problem for webm container - NO AUDIO!

buggy Android just doesn't support VORBIS/OGG audio encoding... https://developer.android.com/guide/topics/media/media-formats#audio-formats


Solution

  • I guess there is no solution

    so the answer: MediaRecorder/Android is buggy or Mobile companies didn't care of all Android features while developing their devices

    Update

    MediaCodec is also buggy with canvas

    mSurface = mMediaCodec.createInputSurface();
    mSurface.lockHardwareCanvas()
    

    It works on most devices with MediaCodec but still some devices may fail to record video correctly using this method

    So final answer: don't ever use lockCanvas or lockHardwareCanvas when working with MediaCodec or MediaRecorder, it's buggy.. At least on old phones, newer Android versions I guess should work fine

    The only way - OpenGl ES

    other links about issue:

    https://github.com/googlesamples/android-Camera2Video/issues/86 https://issuetracker.google.com/issues/111433520