Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 716
user25 Avatar asked Jul 13 '18 20:07

user25


1 Answers

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 much more 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..

The only way - OpenGl ES

other links about issue:

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

like image 168
user25 Avatar answered Nov 14 '22 23:11

user25