Skip to content
This repository has been archived by the owner on Sep 10, 2020. It is now read-only.

Added Video Framerate to Fix 'prepare' crash #15

Merged
merged 1 commit into from
Jan 18, 2015
Merged

Added Video Framerate to Fix 'prepare' crash #15

merged 1 commit into from
Jan 18, 2015

Conversation

jaredsburrows
Copy link
Contributor

Added Video Framerate to Fix 'prepare' crash - on HTC DNA running Android 5.0.2

Crash:

java.lang.RuntimeException: Unable to prepare MediaRecorder.
at com.jakewharton.telecine.RecordingSession.startRecording(RecordingSession.java:179)
at com.jakewharton.telecine.RecordingSession.access$100(RecordingSession.java:47)
at com.jakewharton.telecine.RecordingSession$1.onStart(RecordingSession.java:111)
at com.jakewharton.telecine.OverlayView.startRecording(OverlayView.java:147)
at com.jakewharton.telecine.OverlayView.access$300(OverlayView.java:31)
at com.jakewharton.telecine.OverlayView$5$1$1.run(OverlayView.java:163)
at android.view.ViewPropertyAnimator$AnimatorEventListener.onAnimationEnd(ViewPropertyAnimator.java:1121)
at android.animation.ValueAnimator.endAnimation(ValueAnimator.java:1089)
at android.animation.ValueAnimator$AnimationHandler.doAnimationFrame(ValueAnimator.java:666)
at android.animation.ValueAnimator$AnimationHandler.run(ValueAnimator.java:682)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:795)
at android.view.Choreographer.doCallbacks(Choreographer.java:599)
at android.view.Choreographer.doFrame(Choreographer.java:559)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:781)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5466)
at java.lang.reflect.Method.invoke(Method.java:-2)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:938)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:733)
Caused by: java.io.IOException: prepare failed.
at android.media.MediaRecorder._prepare(MediaRecorder.java:-2)
at android.media.MediaRecorder.prepare(MediaRecorder.java:742)
at com.jakewharton.telecine.RecordingSession.startRecording(RecordingSession.java:177)
at com.jakewharton.telecine.RecordingSession.access$100(RecordingSession.java:47)
at com.jakewharton.telecine.RecordingSession$1.onStart(RecordingSession.java:111)
at com.jakewharton.telecine.OverlayView.startRecording(OverlayView.java:147)
at com.jakewharton.telecine.OverlayView.access$300(OverlayView.java:31)
at com.jakewharton.telecine.OverlayView$5$1$1.run(OverlayView.java:163)
at android.view.ViewPropertyAnimator$AnimatorEventListener.onAnimationEnd(ViewPropertyAnimator.java:1121)
at android.animation.ValueAnimator.endAnimation(ValueAnimator.java:1089)
at android.animation.ValueAnimator$AnimationHandler.doAnimationFrame(ValueAnimator.java:666)
at android.animation.ValueAnimator$AnimationHandler.run(ValueAnimator.java:682)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:795)
at android.view.Choreographer.doCallbacks(Choreographer.java:599)
at android.view.Choreographer.doFrame(Choreographer.java:559)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:781)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5466)
at java.lang.reflect.Method.invoke(Method.java:-2)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:938)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:733)

@monxalo
Copy link
Contributor

monxalo commented Jan 15, 2015

I tried this on a Nexus 7 (2013) with 5.0.1 but i still get the exception.

Maybe something related to the 5.0.1?

@jaredsburrows
Copy link
Contributor Author

@monxalo Good! Someone else tried this out.

Since every device is different, trying different parameters before calling prepare could help:
http://developer.android.com/reference/android/media/MediaRecorder.html

Instead of:

recorder.setVideoSource(SURFACE);
recorder.setOutputFormat(MPEG_4);
recorder.setVideoFrameRate(30);
recorder.setVideoEncoder(H264);

Try:

recorder.setVideoSource(SURFACE);
recorder.setOutputFormat(DEFAULT);  // select your devices default, guaranteed support
recorder.setVideoFrameRate(20);     // maybe your device does not support this frame rate?
recorder.setVideoEncoder(DEFAULT);  // select your devices default, guaranteed support

Basically, we should probably check to see the devices capabilities for support these codes before setting up the MediaRecorder with the specified parameters.

@JakeWharton
Copy link
Owner

Ugh 😦

@monxalo
Copy link
Contributor

monxalo commented Jan 15, 2015

Okay, after testing a few times the setVideoFrameRate(30) works, but only with video size set to: 75% and 50%.

@jaredsburrows
Copy link
Contributor Author

@monxalo So we probably need something similar to what @gabin8 was talking about here: #6.

We should allow the user to choose specific framerates.

@monxalo
Copy link
Contributor

monxalo commented Jan 15, 2015

After debugging some more, i noticed that recorder.setVideoSize when setting video size to 100% is using:
displayWidth = 1200
displayHeight = 1822.

I think although the Nexus 7 (2013) has a display of 1200 x 1920 the MediaRecorder must only record up to 1080x1920.

@JakeWharton
Copy link
Owner

So there's two problems:

  • Max size must be 1080p
  • Framerate must be set for some devices

Both seem reasonable changes then.

@monxalo
Copy link
Contributor

monxalo commented Jan 15, 2015

Agreed, maybe the default framerate would be 30 and like @jaredsburrows said, allow to change framerate from list of common framerates. (24, 25, 30, 50, 60)

@JakeWharton
Copy link
Owner

Why would changing the framerate be useful?

@monxalo
Copy link
Contributor

monxalo commented Jan 15, 2015

I was thinking about file size but i just reminded that only the bitrate affects file size.

@monxalo
Copy link
Contributor

monxalo commented Jan 15, 2015

Also I was only able to record at a max framerate of 30 on this device.

A note from the documentation:

NOTE: On some devices that have auto-frame rate, this sets the maximum frame rate, not a constant frame rate.

@jaredsburrows
Copy link
Contributor Author

@monxalo Yes, the framerate should at least be set. Without that, it will not run on my device. When you say you were only able to record a max framerate, were you just trying different values to verify?

@monxalo
Copy link
Contributor

monxalo commented Jan 15, 2015

@jaredsburrows yes, i tried various values above 30 and always resulted in a crash.

BTW, what message do you get when it crashes on your device?

I always get prepare failed: -2147483648.

@JakeWharton
Copy link
Owner

That is the same as others have reported.

@jaredsburrows
Copy link
Contributor Author

@monxalo What I usually see is the same error as I posted in the post:

java.lang.RuntimeException: Unable to prepare MediaRecorder.
at com.jakewharton.telecine.RecordingSession.startRecording(RecordingSession.java:179)
at com.jakewharton.telecine.RecordingSession.access$100(RecordingSession.java:47)
at com.jakewharton.telecine.RecordingSession$1.onStart(RecordingSession.java:111)
....
Caused by: java.io.IOException: prepare failed.
at android.media.MediaRecorder._prepare(MediaRecorder.java:-2)
at android.media.MediaRecorder.prepare(MediaRecorder.java:742)
at com.jakewharton.telecine.RecordingSession.startRecording(RecordingSession.java:177)

Is there anyway we could automatically check to see what the user's device is capable of and then let them decide on specifics?

Or figure out what works for all devices and have a try/catch, put the specifics in the try and the defaults in the catch.

@JakeWharton
Copy link
Owner

I'd rather crash. Otherwise there's no way of knowing which devices are operating in the crappy settings.

@jaredsburrows
Copy link
Contributor Author

You throw the RuntimeException for the BugSnag. What is wrong with defaults? You can't fix the user's device.

@monxalo
Copy link
Contributor

monxalo commented Jan 15, 2015

A quick update, after some more tests I was able to record at a framerate higher that 30. Here are the results:

  • 540 x 960 (50%) -> 60
  • 810 x 1440 (75%) -> 50
  • 1080 x 1920 (100%) -> 30

So there seems to be a relation between the video size and the framerate you can record.

@jaredsburrows
Copy link
Contributor Author

@monxalo This makes sense, lower the resolution -> higher the framerate. It would be nice if MediaRecorder could return an optimal configuration or we can check for one.

@monxalo
Copy link
Contributor

monxalo commented Jan 15, 2015

The MediaRecorder was the API intially to record the Camera so i'm assuming that it uses the Camera resolution rather than the screen resolution. We can get a CamcorderProfile and get each value for the MediaRecorder, displayWidth, displayHeight, videoBitRate and videoFrameRate.

After some testing recording with various profiles, the best one for a smooth video playback with no stuttering was CamcorderProfile.QUALITY_720P for this device.

@JakeWharton JakeWharton merged commit 032efa3 into JakeWharton:master Jan 18, 2015
@JakeWharton
Copy link
Owner

Continue any discussion in #17 around media recorder failing.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants