Android capturing slow motion video using CamcorderProfile - android

I am trying to capture slow motion video on my Nexus 5x. This is how I am configuring the media recorder:
CamcorderProfile profile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH_SPEED_HIGH);
mMediaRecorder = new MediaRecorder();
// Step 1: Unlock and set camera to MediaRecorder
mCamera.unlock();
mMediaRecorder.setCamera(mCamera);
// Step 2: Set sources
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
// Step 3: Set the high speed CamcorderProfile
mMediaRecorder.setProfile(profile);
// Step 4: Set output file
// Step 5: Prepare media recorder
// Step 6: Capture video
The problem is, the captured videos are not the 120 fps slow motion videos that my device supports. They are the regular 29 fps videos.
I went through this answer, which talks about the following in the official documentation:
For all the high speed profiles defined below ((from
QUALITY_HIGH_SPEED_LOW to QUALITY_HIGH_SPEED_2160P), they are similar
as normal recording profiles, with just higher output frame rate and
bit rate. Therefore, setting these profiles with
setProfile(CamcorderProfile) without specifying any other encoding
parameters will produce high speed videos rather than slow motion
videos that have different capture and output (playback) frame rates.
To record slow motion videos, the application must set video output
(playback) frame rate and bit rate appropriately via
setVideoFrameRate(int) and setVideoEncodingBitRate(int) based on the
slow motion factor. If the application intends to do the video
recording with MediaCodec encoder, it must set each individual field
of MediaFormat similarly according to this CamcorderProfile.
The thing that I don't get is, setProfile already calls the two methods setVideoFrameRate and setVideoEncodingBitRate with parameters derived from the chosen CamcorderProfile. Why do I need to call them again? What am I missing here?
Any help would be greatly appreciated. For the life of me, I cannot get this to work!
EDIT: I have tried calling the methods like so but it still captures normal speed video:
mMediaRecorder.setVideoFrameRate(profile.videoFrameRate/4);
mMediaRecorder.setVideoEncodingBitRate(profile.videoBitRate/4);
1/4 since the advertised frame rate by the CamcorderProfile.QUALITY_HIGH_SPEED_HIGH is 120 and I want to capture a 30 fps video as stated in the document here
public int videoFrameRate
Added in API level 8 The target video frame rate in frames per second.
This is the target recorded video output frame rate per second if the
application configures the video recording via
setProfile(CamcorderProfile) without specifying any other
MediaRecorder encoding parameters. For example, for high speed quality
profiles (from QUALITY_HIGH_SPEED_LOW to QUALITY_HIGH_SPEED_2160P),
this is the frame rate where the video is recorded and played back
with. If the application intends to create slow motion use case with
the high speed quality profiles, it must set a different video frame
rate that is corresponding to the desired output (playback) frame rate
via setVideoFrameRate(int). For example, if QUALITY_HIGH_SPEED_720P
advertises 240fps videoFrameRate in the CamcorderProfile, and the
application intends to create 1/8 factor slow motion recording videos,
the application must set 30fps via setVideoFrameRate(int). Failing to
do so will result in high speed videos with normal speed playback
frame rate (240fps for above example). If the application intends to
do the video recording with MediaCodec encoder, it must set each
individual field of MediaFormat similarly according to this
CamcorderProfile.

mMediaRecorder.setVideoFrameRate(QUALITY_HIGH_SPEED_LOW);
or
mMediaRecorder.setVideoFrameRate(QUALITY_HIGH_SPEED_HIGH);

Related

How to implement SlowMotion and TimeLapse video recording using Camera API

Is there any way to implement Slow Motion and Time Lapse recording using Camera API?
I tried using MediaRecorder setting VideoFrameRate, VideoBitRate VideoCaptureRate but nothing work for me.
I have successfully implemented using JNI but i found it is taking too much time and not optimized as well.
If you find any other solution available please help me.
I solved it myself and i am sharing my working code piece , just using Camera API slow motion and timelapse are implemented
Before start you must know definition of setCaptureRate(double fps)
Set video frame capture rate.
This can be used to set a different video frame capture rate than the
recorded video's playback rate. This method also sets the recording
mode to time lapse. In time lapse video recording, only video is
recorded. Audio related parameters are ignored when a time lapse
recording session starts, if an application sets them.
TimeLapse
For time lapse you need to use following camera profile , According to you video frame width and height. Choose any one from below profile or you may choose other according to your need.
profile = CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_1080P);
profile = CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_720P);
profile = CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_480P);
And now you need configure your video setCaptureRate and setVideoEncodingBitRate
video_recorder.setCaptureRate(profile.videoFrameRate/6.0f);
video_recorder.setVideoEncodingBitRate(profile.videoBitRate);
and at last you need to set your configured Profile to your MediaRecorder.
video_recorder.setProfile(profile);
Slow Motion
For slow motion you also need to configure CamcorderProfile i am using following config for profile.
profile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH_SPEED_HIGH);
video_recorder.setCaptureRate(profile.videoFrameRate / 0.25f);
video_recorder.setVideoEncodingBitRate(profile.videoBitRate);
video_recorder.setProfile(profile);
For slowmotion you have to use CameraAPI2 otherwise it will not work.

Android capturing slow motion video

How can i capture slow motion video in my app?
I tried using
mMediaRecorder.setVideoFrameRate(100);
but app crashes if i set the value 20 or more with IllegalStateException.
I have researched a lot.Normal video is between 24 and 30 fps.To see slow motion video we need to capture 100-120 fps but device does not allow that.But I see the default camera in my device has an option of Slow motion.Also few apps in play store allow to create slow motion videos.I also tried setting higher setCaptureRate(),but with that also normal mode video is captured.At few places it is mentioned that slow motion movie can be accomplished through OpenCV/JavaCV libraries but i failed to understand how to use these libraries to capture slow motion video in android?
From the source you provided (CamcorderProfile), all you have to do is INCREASE taken images per second:
mMediaRecorder.setVideoFrameRate(QUALITY_HIGH_SPEED_LOW);
or
mMediaRecorder.setVideoFrameRate(QUALITY_HIGH_SPEED_HIGH);
So, if you take a 100 images per seconds, and show 25 Frames per second, that recorded second takes 4 seconds to shownPlease, read the documentation on the class you are using:
public static final int QUALITY_HIGH_SPEED_LOW
High speed ( >= 100fps) quality level corresponding to the lowest available resolution.
For all the high speed profiles defined below ((from QUALITY_HIGH_SPEED_LOW to QUALITY_HIGH_SPEED_2160P), they are similar as normal recording profiles, with just higher output frame rate and bit rate. Therefore, setting these profiles with setProfile(CamcorderProfile) without specifying any other encoding parameters will produce high speed videos rather than slow motion videos that have different capture and output (playback) frame rates. To record slow motion videos, the application must set video output (playback) frame rate and bit rate appropriately via setVideoFrameRate(int) and setVideoEncodingBitRate(int) based on the slow motion factor. If the application intends to do the video recording with MediaCodec encoder, it must set each individual field of MediaFormat similarly according to this CamcorderProfile.
Although I am not able to capture smooth slow motion video without jerks but i am able to convert captured video into slow motion using ffmpeg which comes out to be very smooth and even.For integrating FFmpeg in android we can use precompiled libraries like ffmpeg-android.
As per the case in question,we can capture video from camera and then convert it into slow motion using ffmpeg.
To create a slow motion video we can use the below command-
String[] complexCommand = {"-y", "-i", inputFileAbsolutePath, "-filter_complex", "[0:v]setpts=2.0*PTS[v];[0:a]atempo=0.5[a]", "-map", "[v]", "-map", "[a]", "-b:v", "2097k", "-r", "60", "-vcodec", "mpeg4", outputFileAbsolutePath};
Here,
-y
Overwrite output files without asking
-i
ffmpeg reads from an arbitrary number of input “files” specified by the -i option
-map
Output link labels are referred to with -map.
-b:v
Set the video bitrate
-r
Set frame rate
-vcodec
Set the video codec
-filter_complex filtergraph
Define a complex filtergraph, i.e. one with arbitrary number of inputs and/or outputs.
The filter works by changing the presentation timestamp (PTS) of each video frame.To slow down your video, you have to use a multiplier greater than 1. For example, if there are two succesive frames shown at timestamps 1 and 2, and you want to slow down the video, those timestamps need to become 2 and 4, respectively.Thus, we have to multiply them by 2.0.
You can speed up or slow down audio with the atemto audio filter.The atempo filter is limited to using values between 0.5 and 2.0 (so it can slow it down to no less than half the original speed, and speed up to no more than double the input).To slow down the audio to half of its speed we have to use atempo value 0.5 .
Check out this fffmpeg video editor tutorial which I have written on my blog which includes creating slow motion video and the complete code for the tutorial here.
What worked for me was to put higher the capture rate of mMediaRecorder like:
mMediaRecorder.setVideoFrameRate(profile.videoFrameRate / 2);
mMediaRecorder.setVideoEncodingBitRate(profile.videoBitRate / 2);
mMediaRecorder.setCaptureRate(profile.videoFrameRate);
Where profile is the CamcorderProfileset with QUALITY_HIGH (I can't have more since I'm using a LG G2, API 19).
Here in my case,profile.videoFrameRate is equal to 30.
More info about setCaptureRate in the official documentation:
Set video frame capture rate. This can be used to set a different video frame capture rate than the recorded video's playback rate. This method also sets the recording mode to time lapse. In time lapse video recording, only video is recorded. Audio related parameters are ignored when a time lapse recording session starts, if an application sets them.
The video recorded result is twice as long as the initial capture. However setting the capture rate disables the audio. In my case, my max fps rate seems to be 30fps, and then it got played back at 15fps.
Hope it helps.
Try this code.It will help...
myCamera = getCameraInstance();
mediaRecorder = new MediaRecorder();
myCamera.unlock();
mediaRecorder.setCamera(myCamera);
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
mediaRecorder.setPreviewDisplay(mSurfaceView.getHolder().getSurface());

Diffrence between Capture rate and Frame rate?

setCaptureRate:
http://developer.android.com/reference/android/media/MediaRecorder.html#setCaptureRate%28double%29
setVideoFrameRate:
http://developer.android.com/reference/android/media/MediaRecorder.html#setVideoFrameRate%28int%29
What is the diffrence between setCaptureRate() and setVideoFrameRate() API's in MediaRecorder Class of Android?
From documentation for setCaptureRate():
Set video frame capture rate. This can be used to set a different
video frame capture rate than the recorded video's playback rate. This
method also sets the recording mode to time lapse. In time lapse video
recording, only video is recorded. Audio related parameters are
ignored when a time lapse recording session starts, if an application
sets them.
let's use 0.1fps as parameter so
setCaptureRate(0.1) means 1 frame per 10 seconds. 0.001 would be 1 frame per 100 seconds.
I've found example: here
and setVideoFrameRate() is what you know:
Sets the frame rate of the video to be captured
25fps, 30fps, 60fps -
You can see difference also in paramater. setCaptureRate() can accept decimals but setVideoFrameRate() works only with integers.

Android MediaCodec API video plays too fast

I'm currently working with Android Jelly Bean MediaCodec API to develop a simple video player.
I extract tracks, play audio and video in separate threads. The problem is that video track always is played too fast.
Where can be the problem hidden?
Both audio and video are treated almost the same way, except audio is played via AudioTrack and video is rendered to the surface.
If you render frames at maximum speed you'll hit 60fps on most devices. You need to pace it according to the presentation time stamps provided by the encoder.
For example, if the input is a format supported by Android (e.g. a typical .mp4 file), you can use the MediaExtractor class to extract each frame. The time stamp can be retrieved with getSampleTime(). You want to delay rendering by the difference between timestamps on consecutive frames -- don't assume that the first frame will have a timestamp of zero.
Also, don't assume that video frames appear at a constant rate (e.g. 30fps). For some sources the frames will arrive unevenly.
See the "Play video (TextureView)" example in Grafika, particularly the SpeedControlCallback class. The gen-eight-rects.mp4 video uses variable frame durations to exercise it. If you check the "Play at 60fps" box, the presentation time stamps are ignored.

Android recording video using Camcorder on HTC one X

I implemented a video recorder in my code and it runs perfectly on almost all the devices
except to HTC One X. There the video record getting stuck(the first image doesn't change) and when I'm trying to open the file I'm receiving a pop-up "Cannot play video, sorry this video cannot be played"
Here are my settings
mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
// Use the same frame rate for both, since internally
// if the frame rate is too large, it can cause camera to become
// unstable. We need to fix the MediaRecorder to disable the support
// of setting frame rate for now.
mMediaRecorder.setVideoFrameRate(mProfile.videoFrameRate);
//mMediaRecorder.setVideoSize(mVideoWidth, mVideoHeight);
mMediaRecorder.setVideoSize(640,480); // Works On Note(not on HTC One X)
mMediaRecorder.setVideoEncodingBitRate(MAXIMAL_PERMITTED_VIDEO_ENCODING_BITRATE);
// mMediaRecorder.setVideoEncoder(mProfile.videoCodec);
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
// mMediaRecorder.setAudioEncoder(mProfile.audioCodec);
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
Thanks
I adapted some code from this question How can I capture a video recording on Android? for recording video, set it to 640x480, and it ran fine on my AT&T One X:
https://raw.github.com/lnanek/Misc/master/HtcOneXVideoRecord/src/com/htc/sample/videorecord/RecordVideo.java
So it isn't the 640x480 that isn't working in and of itself. What's the value for the bitrate you are setting? Have you considered using profiles instead, which are build in supported combinations? For example, you would set:
mRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH)
And that would set the resolution, bit rate, etc. to values that work. There are various constants for high quality recording, low, etc..

Categories

Resources