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.
Related
I want to have an FPS counter that displays the frame rate of the video as it is being played to see the FPS count change from when the video was playing in regular speed until it goes to slow motion.
Is there an API in Android SDK that allows us to track every time the frames are rendered when the video plays?
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);
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());
Edit as i wasn't clear at first time:
I'm trying to use android MediaCodec to get each frame from existing video file(videoBefore.MP4) ,process the frame(like blur) and then encode each frame to a new video file(videoAfter.MP4).
The new video have to be in the same duration as the first.
Just 1 condition:
Every frame should be process with unlimited time,it mean that 10 sec video could take 1 minute for processing.
So far i saw only examples with quick processing (like blue shift) that could be done in real time.
Is there any way to grab the frame from the video,and then "take my time" to process it,and still preserved the new video with the same frame rate or frame timing?
*it could be better if i can preserve the audio too-but the frame is what important.
Thanks!
You can take as long as you like. The timing of the frames is determined by the presentation time stamp embedded in the .mp4 file, not the rate at which the code is accessed.
You get the time value for each frame from MediaExtractor#getSampleTime(), pass it into the decoder's queueInputBuffer(), and receive it in the BufferInfo struct associated with the decoder's output buffer. Do your processing and submit the frame to the encoder, again specifying the time stamp in queueInputBuffer(). It will be passed through BufferInfo to the output side of the encoder, and you just pass the whole BufferInfo to MediaMuxer#writeSampleData().
You can see the extraction side in ExtractMpegFramesTest and the muxing side in EncodeAndMuxTest. The DecodeEditEncodeTest does the encode/decode preserving the time stamp, but doesn't show the MediaExtractor or MediaMuxer usage.
Bear in mind that the codecs don't really care about time stamps. It's just the extractor/muxer code that handles the .mp4 file that cares. The value gets passed through the codec partly as a convenience, and partly because it's possible for encoded frames to appear out of order. (The decoded frames, i.e. what comes out of the decoder, will always be in order.)
If you fail to preserve the presentation times, you will get video that either lasts zero seconds (and isn't very interesting), or possibly video that lasts a very, very long time. The screenrecord command introduced in Android 4.4 uses the time stamps to avoid recording frames when the screen isn't being updated.
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.