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());
Related
I have android tv application playing 2 different videos udp streaming using Exoplayer, the below images(image1 and image2) show the specifications of every video .. First one with low resolution play well without any problem in buffering, the second one have bad buffering and streaming.
image 1 : the first video with lower resolution (1280x720) which is playing well without any freezing or problem
image 2 : the second video with high resolution (1920x1080) play with freezing, or incontinious buffering
Below is my exoplayer initialisation
ExoPlayer.Builder playerbuilder = new ExoPlayer.Builder(WelcomeActivity.this);
LoadControl loadControl = new DefaultLoadControl.Builder()
.setBufferDurationsMs(15000, 50000, 2000, 5000)
.setTargetBufferBytes(DefaultLoadControl.DEFAULT_TARGET_BUFFER_BYTES)
.setAllocator(new DefaultAllocator(true, C.DEFAULT_BUFFER_SEGMENT_SIZE))
.setPrioritizeTimeOverSizeThresholds(DefaultLoadControl.DEFAULT_PRIORITIZE_TIME_OVER_SIZE_THRESHOLDS)
.build();
player = playerbuilder .setLoadControl(loadControl).setRenderersFactory(buildRenderersFactory(WelcomeActivity.this)).build();
player.setTrackSelectionParameters(
player.getTrackSelectionParameters()
.buildUpon()
.setMaxVideoSize(1280, 720)
.setPreferredTextLanguage("ar")
.build());
As you notice i am setting the maximum video size to low resolution .setMaxVideoSize(1280, 720) but this not changing any thing regards the bad buffering of the second video with high resolution
The size and bit rate of an encoded video is determined by how it is encoded - e.g. what codec is used and what parameters and configuration the encoding uses.
Nearly all encoders try to reduce the size of the encoded video, to make it easier to store and to transmit, and there is a balance between the size reduction and the visual quality of the video when it is subsequently decoded and played.
Generally, smaller size/bit rate means less quality, but it does depend on the content itself - for example some cartoons are very tolerant of lower bit rates. More advanced commercial encoders can do 'context aware' encoding and adjust the quality and bit rate depending on the scenes.
The most common codec at this time is the h.264 codec and ffmpeg is probably the most common open source tool for encoding.
ffmpeg provides a guide for encoding videos, or re-encoding / transcoding videos with h.264 and this includes notes and examples on quality vs bit rate trade off:
https://trac.ffmpeg.org/wiki/Encode/H.264
The two key sections in the above are for Constant Rate Factor encoding and two pass encoding.
CRF
allows the encoder to attempt to achieve a certain output quality for the whole file when output file size is of less importance. This provides maximum compression efficiency with a single pass
Two Pass
Use this rate control mode if you are targeting a specific output file size, and if output quality from frame to frame is of less importance
There is also a note on Constrained encoding (VBV / maximum bit rate) which it would be good to look at too.
I think you might be best to start with CRF encoding and experiment with the CRF value to see if you can find a quality/bit rate combination you are happy with.
Finally, it would be worth you checking out ABR streaming also, especially if you plan to host many videos and want your users to have consistent experience. For ABR you create multiple copies of the video, each encoded with different resolution/bit rate.
The client device or player downloads the video in chunks, e.g 10 second chunks, and selects the next chunk from the bit rate most appropriate to the current network conditions. See some more info in this answer also: https://stackoverflow.com/a/42365034/334402
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);
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.
Disclaimer: I know very little about Video codecs & encoding.
I'm developing an iOS and Android app that allows users to record videos. I want to be able to upload the videos to YouTube & have them play at 720p quality.
The videos I'm recording will always be less than 180 seconds, always be ~30fps and will always have audio.
As far as I can tell, this means I need to record at a resolution of 1280x720, then I should be good. Is this correct?
I'm trying to determine how large, on average, an H.264 video file will be per second of video. From my understanding, I need to know the bitrate of the videos. What will the bitrate of recorded H.264 video be on Android 2.2+, and iOS 5+? This Android developer page mentions a bitrate of "2Mbps" for "HD" video - is that 2 Megabytes per second or 2 Megabits per second? Will that rate be the same for any recorded H.264 video?
Part of the reason I'm so confused about this is because I did a test with 4 different Android-encoded videos of different lengths, and produced the following output;
Wtf!?
Bonus points if you can link me to some iOS developer docs detailing this information - I've searched and can't find anything.
EDITS:
Possibly Related: H.264 file size for 1 hr of HD video
This wikipedia article mentions that the max bitrate for level 3.1 H.264 video (1280x720 # 30fps) is from 14000 - 17500kbps.
Yeah, 720p stands for 1280x720. I think it is correct.
To define how large your video file will be, you should record at a constant bitrate(CBR), but I doubt the camera will be using CBR while VBR(variable bitrate) is more efficient.
Mbps stands for Megabits per second.
I doubt that the rate will be the same as I stated earlier VBR could be used.
Edit:
Judging from the graph, it is definitely a VBR.
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..