Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android MediaRecorder setCaptureRate() and video playback speed

I've got a MediaRecorder recording video, and I'm very confused by the effect of setCaptureRate().

Specifically, I prepare my MediaRecorder as follows:

mMediaRecorder = new MediaRecorder();
mCamera.stopPreview();
mCamera.unlock();
mMediaRecorder.setCamera(mCamera);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mMediaRecorder.setProfile(CamcorderProfile.QUALITY_TIME_LAPSE_480P);
mMediaRecorder.setCaptureRate(30f);
mMediaRecorder.setOrientationHint(270);
mMediaRecorder.setOutputFile(...);
mMediaRecorder.setPreviewDisplay(...);
mMediaRecorder.prepare();

I record for five seconds (with a CountDownTimer, but that's irrelevant), and this is the file that gets generated:

$ ffmpeg -i ~/CaptureRate30fps.mp4 
...
Seems stream 0 codec frame rate differs from container frame rate: 180000.00 (180000/1) -> 30.00 (30/1)
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/home/mspitz/CaptureRate30fps.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 0
    compatible_brands: isom3gp4
    creation_time   : 2013-06-04 00:52:00
  Duration: 00:00:02.59, start: 0.000000, bitrate: 5238 kb/s
    Stream #0.0(eng): Video: h264 (Baseline), yuv420p, 720x480, 5235 kb/s, PAR 65536:65536 DAR 3:2, 30 fps, 30 tbr, 90k tbn, 180k tbc
    Metadata:
      creation_time   : 2013-06-04 00:52:00

Note that the Duration is just about 3 seconds. The video also plays much faster, as if it were 5 seconds of video crammed into 3.

Now, if I record by preparing my mediaRecorder exactly as above, but subtracting the setCaptureRate(30f) line, I get a file like this:

$ ffmpeg -i ~/NoSetCaptureRate.mp4 
...
Seems stream 0 codec frame rate differs from container frame rate: 180000.00 (180000/1) -> 90000.00 (180000/2)
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/home/mspitz/NoSetCaptureRate.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 0
    compatible_brands: isom3gp4
    creation_time   : 2013-06-04 00:50:41
  Duration: 00:00:04.87, start: 0.000000, bitrate: 2803 kb/s
    Stream #0.0(eng): Video: h264 (Baseline), yuv420p, 720x480, 2801 kb/s, PAR 65536:65536 DAR 3:2, 16.01 fps, 90k tbr, 90k tbn, 180k tbc
    Metadata:
      creation_time   : 2013-06-04 00:50:41

Note that the Duration is as expected, about 5 seconds. The video also plays at a normal speed.

I'm using setCaptureRate(30f) because 30 frames per second is the value of my CamcorderProfile's videoFrameRate. On my Galaxy Nexus S2 (4.2.1), omitting setCaptureRate() is fine, but when I tested on a Galaxy Nexus S3 (4.1.1), omitting setCaptureRate() results in the ever-helpful "start failed -22" error when I called mMediaRecorder.start().

So, what am I missing? I thought that the capture rate and the video frame rate were independent, but it's clear that they're not. Is there a way to determine programmatically what I need to set the capture rate at in order to determine that my video plays back at 1x speed?

like image 596
spitzanator Avatar asked Nov 02 '22 20:11

spitzanator


1 Answers

(This is a summary of the resolution from the comments on the original question)

The problem may be that directly using the QUALITY_TIME_LAPSE_480P profile influences playback rates, since time lapses are implicitly not a 1x playback rate.

Furthermore, if the reason you're using that profile is to prevent audio from being recorded when using QUALITY_480P (since time lapses don't record audio), you may want to instead call CamcorderProfile.get(QUALITY_480P) and set video parameters on the MediaRecorder manually based on the profile, without calling MediaRecorder.setProfile directly. A MediaRecorder that doesn't have any audio parameters set shouldn't in theory record any audio.

like image 149
Roman Nurik Avatar answered Nov 11 '22 11:11

Roman Nurik