I don't know what changed but as of Monday (1/1/18) I lost the ability to record videos at anything other than 30 FPS. I can't even force recording to 24 FPS. I still get 30. Lower resolutions and lower bitrates don't help. Nor does switching on or off the Camera2 APIs. A few days before I was recording 1080p60 just fine. I still have those videos. The stock camera also will only record at 30 FPS now so I'm not pointing the finger at OpenCamera by any means. I'm just not sure what else to check.
Any ideas? I'm trying to remember if I got a system update at that time but I'm not remembering.
Pixel XL (1st gen) 128mb
Running 8.1.0 with the December 5 Update.
Here's what I get from ffprobe on a recorded video...
I just grabbed the git repo and tried a few versions back with no luck so I'm thinking I got an android update that broke it. I'm going to try reverting the update and see what happens. If I can even revert it.
Since I have the source code now and can build it, if there are things I can try, let me know.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Well, I'm going to retract the statement that I made about it working before. After examininng the videos, the 60fps ones were recorded with the stock camera app. I reflashed the phone back to 8.0.0 and tried earlier versions of OpenCamera to no avail.
Without the Camera2 API, I get a message from Stagefright complaining that the framerate of 60 is too large and it's being clamped down to 30. With the Camera2 API, I get nothing from Stagefright but I do get...
I've even tried forcing SENSOR_FRAME_DURATION (with auto-ae off) and but still get 30fps although at one point I managed to get the frame rate reduced to 7.5fps although I'm not sure how.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thanks for the update. Yes, it's a bit odd that Camera2 adds support for high frame rates which therefore allows that, but slower frame rates are left undefined.
I'd started working on high speed frame rates and slow motion, but it wasn't working right on my OnePlus 3T - thanks for the report that it does seem to work for the Pixel XL!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
So now I DO have 60fps without using high speed and still have 120 and audio with high speed. Now the question is how to integrate that into the codebase as it required changes to Preview, CameraController2 and VideoProfile.
The changes to CameraController2 and VideoProfile are generic and should work on any device. For CameraController2, I just implemeneted the setPreviewFpsRange and getSupportedPreviewFpsRange methods. For VideoProfile, I added audioChannels, audioBitRate, audioSampleRate, videoEncodingProfile and videoEncodingLevel so I don't have to use CamcorderProfile.
Preview is a different story. The whole process around VideoProfile, CamcorderProfile and VideoQualityHandler is pretty complicated and my changes make it worse. But, if I just strip the guts out of getVideoProfile and unconditionally create and return a VideoProfile directly without any CamcorderProfile or using the VideoQualityHandler, everything still works fine, high speed or not. Of course, I don't know if everything will still work fine for other devices but I think it would. The only "special" logic I have is if the desired frame rate > 60, set video_high_speed. I could just wrap that with an "if pixelxl". But it's also a little complicated because much of the slow/fast motion stuff around high speed is commented out. To get 120fps, I need to use high speed but without the capture rate adjustments.
Got any advice or direction for how to integrate it? I could just send you a patch to look at if you'd like.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I'd noted on my OnePlus 3T that although it seems to support high frame rates, it doesn't support any CamcorderProfiles for high speed frame rates. It's still a bit unclear to me the connection between Android's CamcorderProfile class, and what's passed into MediaRecorder. I think the CamcorderProfiles are meant to provide a set of useful "default" values for things like bitrate at various resolutions.
Originally in Open Camera, all video resolutions used one of the CamcorderProfiles, which was optionally modified for things like resolution - this is done in Preview.getCamcorderProfile().
But for high speed frame rates, I added VideoProfile which supports the camcorderprofile being null, and all the info being stored separately in the class. So adding the audio values makes sense (I hadn't done those yet as I was focusing on slow motion which doesn't need audio, but yes audio is needed for regular 120fps).
In Preview.getVideoProfile(), it already constructs a videoprofile with a null camcorderprofile if video_high_speed==true - as you say, it returns a VideoProfile directly without any CamcorderProfile or using the VideoQualityHandler - so I think this is the codepath you want. Although it may be you've chosen different values for the VideoProfile.
"The only "special" logic I have is if the desired frame rate > 60, set video_high_speed."
I think the question is how to integrate this at the user interface. Since I currently have a video frame rate setting, it would seem sensible to enable the video_high_speed if fps is greater than 60 as you say. But high speed frame rates also make other restrictions, such as what video resolutions are available. On top of that, slow motion would have to be enabled separately anyway (and people would expect it to switch to 120fps automaticall). So it may be better under a separate mode for high speed frame rates (and I'll just remove the frame rates greater than 60 from the existing video frame rate).
Either way though, I think the way it should be controlled in the Preview class is via the video_high_speed flag.
So in summary, I'm working on how to integrate this, but I'd be curious to see your changes to CameraController2 and VideoProfile please as they seem useful changes to help this.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Here's the patch. I probably went a bit overboard on the refactoring, sorry. :)
Most of the work was in refactoring getVideoProfile and that started a ripple effect (as refactoring often does). In any case, things still to do would be to filter the preferences dialogs so if you specify a specific resolution, you only get frame rates the resolution supports. Also the addition of the capture to encoder frame rates for slow/fast motion.
The thing to pay attention to is that "high speed" is now determined in getVideoProfile by matching requested size and fps against those available.
Thanks! I'll take a look at adding this. For legal issues, would it be possible please for me to have copyright over the changes? Or licence the patch under Creative Commons CC0 if you prefer? (It makes things easier for licensing, also please be aware I do sometimes sell non-GPL commercial licences; plus in future I want to retain options to relicence under other licenses such as BSD.)
Of course I will credit you, please let me know if you want me to add an email and/or URL for you?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
OK, here's the latest patch BUT somehow I lost 60fps recording again. 120 works as does not-quite 240. Just not 60. I DID have it working, I swear. :) Anyway, I 'll keep working on it. I was able to get Google's Camera2Video example to work at 60fps so I know it can be done.
To make things like this easier, you may want to think about refactoring Preview and the CameraControllers into separate classes for still vs video and Camera vs Camera2. It's really hard to figure out what gets called in what situation right now. It takes time though, I know.
There are some overlap between photo and video but yes it would make sense for the CameraController classes to be split up more. I also want to move the video handling (MediaRecorder usage etc) from Preview into a separate class at some point.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hey George, did you manage to get 60fps back working? If so, would you mind uploading APK somewhere, so I could check if it works on my Galaxy S7? Would be awesome!
P.S. I can't find ANY Android app in Google Play store that allows 60fps recording except for the one preinstalled in the system, but there's no bitrate control, so such videos are of low quality.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Note that the latest version of Open Camera (1.43 onwards) now has the changes described here for high FPS and slow motion. But I don't have a Pixel to test with, so I don't know whether 60fps was able to work or not. So I guess try it and see. Though note there's another issue with video recording on Samsung devices with Camera2 API on Android 8, see https://sourceforge.net/p/opencamera/discussion/general/thread/9e36899f .
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I figured it out. Since the device supports photo_video_recording, a third surface (3840x2160) is automatically added to the capture session in addition to the preview and record 1920x1080 surfaces. Since the max frame rate for 3840x2160 is 30fps, that's the limit.
My feeling is that if a user selects a specific frame rate, that should be honored if possible so a few things can be done...
Add a "Disable photo capture if selected frame rate can't be met" option to video settings and disable the "take picture" button on the live video screen when the frame rate can't be met and the option is set.
Take the picture size from ptoto settings/resolution instead of using the largest resolution that matches the video aspect ratio.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Related to this is that the code in Preview under the video_high_speed flag already disables the "take photo while recording video" feature - for now I've merged this with your changes so that video_high_speed is set when using a high speed frame rate. (I haven't uploaded the changes yet as I'm still working on reviewing changes.) I think that for other reasons, video snapshot doesn't work for high speed fps (e.g., https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createConstrainedHighSpeedCaptureSession(java.util.List<android.view.Surface>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) says only 2 output surfaces are supported, so we need those for preview and video).
But yes, your case shows that even for non-high speed frame rates this can be a problem. We could do a combination of the two ideas: take the picture size as being the largest resolution matching the video aspect ratio, that also satisfies the requested frame rate. So that way people using default fps don't have their functionality changed. And it means even if a non-default fps is selected, the feature is still available but potentially with a lower photo resolution. (See Preview.getOptimalVideoPictureSize()). I've made a note to take a look at this.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Code reviews are a good thing and feedback would be most welcomed! My Java is a little rusty and I only saw that code for the first time the week before last. Don't feel you have to fix issue in my contribution yourself.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Well it's more so I can understand the changes too :) I've integrated the changes and synced to my Git repository. There are a number of differences or additions I made:
In Preview, I linked up the high speed behaviour to the video_high_speed flag. This does some extra things, such as ensuring we set a preview size that matches the video resolution (this is needed on my OnePlus 3T at least). It also disables the "photo while video recording" option.
Integrating all the setup of the video into Preview.getVideoProfile() seems a good change, but I moved the showing of the toast for no audio permission back out to when recording video (otherwise it shows every time we call getVideoProfile()).
I made a few changes to VideoProfile.copyToMediaRecorder() - I don't think there's anything wrong with your way, but I wanted to minimise changes to how the MediaRecorder is set up in non-high-fps cases, to minimise any possible risk of change of behaviour (e.g., so I only call MediaRecorder.setCaptureRate() if videoCaptureRate is not equal to videoFrameRate).
VideoProfile no longer keeps a record of camcorderProfile (with your changes, we no longer need to keep it!)
VideoProfile stores the record_audio flag to explicitly tell us if audio is enabled.
I don't override the videoCodec or audioCodec obtained from the CamcorderProfile (just in case this changes behaviour on some devices).
Checking whether we need high speed or not is now done when setting up the camera (setupCameraParameters()) instead of getVideoProfile(). Perhaps we should check in getVideoProfile(), but for now I wanted to keep things consistent with the setup/checks for other video related features (e.g., seeing if the video resolution is valid). Currently changing a video setting will always involve going through setupCameraParameters() again. I also store the high speed sizes in VideoQualityHandler so we don't need to get the camera_features again.
For now I haven't included the code to take action if the requested size and frame rate aren't compatible. I'm still thinking about how to do the user interface level - ideally it should be clear to the user. Though I'll still be putting the check back in Preview just to be safe (e.g., in rare cases a phone OS upgrade might change available camera settings, so the user interface could still be set in a state that requests a setting that is no longer valid).
I don't bother putting the fps ranges in CameraController.CameraFeatures.
In CameraController2, I set CONTROL_AE_TARGET_FPS_RANGE entirely via CameraSettings.setAEMode(), rather than setAETargetFpsRange(); similarly for setSensorFrameDuration()
Interestingly, implementing CameraController2.setPreviewFpsRange() caused the preview on my OnePlus 3T to become too dark in video mode. It's something I saw before on the Nexus 6 (with old camera API), and is fixed in Preview.setPreviewFps() via the preview_too_dark flag, which means (if using "default" video fps) we try to set the broadest range for fps values rather than trying to match the video frame rate. So I've enabled the preview_too_dark flag for all devices on Camera2 API. (To be honest, I'm not entirely sure how preview frame rate ranges matches up to video capture rate or resultant frame rate - e.g., should it just include the requested fps in the range, or should it also be as narrow a range as possible.)
Also some questions I have:
For now I haven't included the MediaRecorder.setVideoEncodingProfileLevel for Android 8 - I wasn't sure what this does, I couldn't find useful documentation on these settings? Is it needed for high fps?
In CameraController2, I wasn't sure why in initVideoRecorderPostPrepare is sensor_frame_duration set to a fixed value of 60fps, ignoring the value set from setPreviewFpsRange? Does the sensor_frame_duration setting matter either way for accurate fps?
In CameraController2, setManualExposureTime() now uses a default SENSOR_FRAME_DURATION (if we didn't get one from the captureresult) of 60fps instead of 30fps - does this matter either way?
And most important of all - does my version of the code still work with high speed frame rates on your Pixel? Unfortunately although my OnePlus 3T claims to support high speed frame rates (so I could test the code that sets things up), it fails to then record video (which could just be a OnePlus 3T bug - Footej's slow motion doesn't work on it either - but means I'm unable to fully test things).
Thanks!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Just to give an update: I now have a Nokia 8 where 120fps does seem to be working, so I can now test things properly.
I'm now working on adding support for the user interface side of things. Have already fixed Preview to make us fall back to a supported high speed video resolution if an incompatible resolution and fps are requested by the application. I've also set the fps preference now be per-camera.
So hopefully this should all be in the next version (and then after that I can look at slow motion). Thanks a lot for your help and code!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
My first post in the forums. I don't have an account but my name's Vlad. Mark, thanks for a wonderful app.
I wanted to boost this/ add my own experience with the current version 1.42.2. I recently downloaded Open Camera for my Pixel XL (gen1), with Android 8.1.0.
Regardless, I ran some tests an hour ago, so I can have a look at how the footage looks but also because things weren't adding up: it didn't look like the slow framrates were working when viewing footage through Google Photos and also when setting it to record at high fps (60, 100 or 120) the shutter speeds were sometimes as low as 1/40 or 1/60 which is a dead giveaway that something was up.
Here are the different settings I used and the framerates it recorded at. As you can see, almost everything is still the default 29.97 except for numbers 6 and 11.
1) 2k/24fps/100mbps - recorded at 29.97 fps
2) 2k/60fps/100mbps - recorded at 29.97 fps
3) 2k/120fps/100mbps - recorded at 29.97 fps
4) 2k/24fps/50mbps - recorded at 29.97 fps
5) 2k/25fps/100mbps - recorded at 29.97 fps
6) 2.7k/24fps/100mbps - recorded at 29.80 fps
7) 2.7k/60fps/100mbps - recorded at 29.97 fps
8) 2.7k/120fps/100mbps - recorded at 29.97 fps
9) 2.7k/100fps/100mbps - recorded at 29.97 fps
10) 4k/24fps/100mbps - recorded at 29.97 fps
11) 4k/60fps/100mbps - recorded at 29.81 fps
As I said, I'm using a 120gb Gen1 Google Pixel XL. It's currently fully updated to Android 8.1.0. I used Open Camera v1.42.2 and I have the Camera2 API on (although I don't know what an API is, only an incling).
Sorry, I only understand about a quarter of what you guys are talking about and have no idea about app development but I can appreciate it's a lot of hard work. Did the changes suggested by George in his patch already make their way into the current version of the app? and if so (or not) is there anything I can do at this point in time to allow different framerates to work?
Did I say, thanks for a great app, Mark?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thanks for the info! Just to confirm that the changes mentioned above aren't in the currently released version 1.42.2. I don't think there's anything you can do in the meantime I'm afraid.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
Anonymous
-
2018-04-22
Same here on Samsung Galaxy S7 with 1.42.2. I deeply regret the lack of changing framerate. Kindly PLEASE support it in the next version.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
Anonymous
-
2018-04-22
...but I can easily record 60 fps videos using system camera app with no problem (if that helps). I'm on Android 7.0 (highest available for S7).
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
Anonymous
-
2020-05-31
Sorry for reviving this thread, but I had the exact same issue with 26FPS fixed (no other option produces other FPS values). Should I have opened a new thread about this?
Thanks in advance for fixing the issue...
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
Anonymous
-
2020-05-31
P.S.
Using the app on OnePlus 8 Pro with Android 10 patched with April 1 security update, kernel 4.19.81-perf+, Oxygen OS 10.5.8.IN11BA
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
First... Love the app. Thanks!
I don't know what changed but as of Monday (1/1/18) I lost the ability to record videos at anything other than 30 FPS. I can't even force recording to 24 FPS. I still get 30. Lower resolutions and lower bitrates don't help. Nor does switching on or off the Camera2 APIs. A few days before I was recording 1080p60 just fine. I still have those videos. The stock camera also will only record at 30 FPS now so I'm not pointing the finger at OpenCamera by any means. I'm just not sure what else to check.
Any ideas? I'm trying to remember if I got a system update at that time but I'm not remembering.
Pixel XL (1st gen) 128mb
Running 8.1.0 with the December 5 Update.
Here's what I get from ffprobe on a recorded video...
Here's a dump of the debug info...
I just grabbed the git repo and tried a few versions back with no luck so I'm thinking I got an android update that broke it. I'm going to try reverting the update and see what happens. If I can even revert it.
Since I have the source code now and can build it, if there are things I can try, let me know.
Well, I'm going to retract the statement that I made about it working before. After examininng the videos, the 60fps ones were recorded with the stock camera app. I reflashed the phone back to 8.0.0 and tried earlier versions of OpenCamera to no avail.
Without the Camera2 API, I get a message from Stagefright complaining that the framerate of 60 is too large and it's being clamped down to 30. With the Camera2 API, I get nothing from Stagefright but I do get...
mm-camera: <CPP>< INFO> 1732: cpp_module_handle_stream_cfg_event: frame_offset=3, input_fps=30.00, identity=0x2000f
regardless of the chosen frame rate but with the stock camera app I get...
mm-camera: <CPP>< INFO> 1732: cpp_module_handle_stream_cfg_event: frame_offset=3, input_fps=60.00, identity=0x2000f
I've even tried forcing SENSOR_FRAME_DURATION (with auto-ae off) and but still get 30fps although at one point I managed to get the frame rate reduced to 7.5fps although I'm not sure how.
Ha!. I've now got it recording at 120fps by forcing video_high_speed = true and has_capture_rate_factor = false. Still can't get 60 though. :)
Thanks for the update. Yes, it's a bit odd that Camera2 adds support for high frame rates which therefore allows that, but slower frame rates are left undefined.
I'd started working on high speed frame rates and slow motion, but it wasn't working right on my OnePlus 3T - thanks for the report that it does seem to work for the Pixel XL!
So now I DO have 60fps without using high speed and still have 120 and audio with high speed. Now the question is how to integrate that into the codebase as it required changes to Preview, CameraController2 and VideoProfile.
The changes to CameraController2 and VideoProfile are generic and should work on any device. For CameraController2, I just implemeneted the setPreviewFpsRange and getSupportedPreviewFpsRange methods. For VideoProfile, I added audioChannels, audioBitRate, audioSampleRate, videoEncodingProfile and videoEncodingLevel so I don't have to use CamcorderProfile.
Preview is a different story. The whole process around VideoProfile, CamcorderProfile and VideoQualityHandler is pretty complicated and my changes make it worse. But, if I just strip the guts out of getVideoProfile and unconditionally create and return a VideoProfile directly without any CamcorderProfile or using the VideoQualityHandler, everything still works fine, high speed or not. Of course, I don't know if everything will still work fine for other devices but I think it would. The only "special" logic I have is if the desired frame rate > 60, set video_high_speed. I could just wrap that with an "if pixelxl". But it's also a little complicated because much of the slow/fast motion stuff around high speed is commented out. To get 120fps, I need to use high speed but without the capture rate adjustments.
Got any advice or direction for how to integrate it? I could just send you a patch to look at if you'd like.
I'd noted on my OnePlus 3T that although it seems to support high frame rates, it doesn't support any CamcorderProfiles for high speed frame rates. It's still a bit unclear to me the connection between Android's CamcorderProfile class, and what's passed into MediaRecorder. I think the CamcorderProfiles are meant to provide a set of useful "default" values for things like bitrate at various resolutions.
Originally in Open Camera, all video resolutions used one of the CamcorderProfiles, which was optionally modified for things like resolution - this is done in Preview.getCamcorderProfile().
But for high speed frame rates, I added VideoProfile which supports the camcorderprofile being null, and all the info being stored separately in the class. So adding the audio values makes sense (I hadn't done those yet as I was focusing on slow motion which doesn't need audio, but yes audio is needed for regular 120fps).
In Preview.getVideoProfile(), it already constructs a videoprofile with a null camcorderprofile if video_high_speed==true - as you say, it returns a VideoProfile directly without any CamcorderProfile or using the VideoQualityHandler - so I think this is the codepath you want. Although it may be you've chosen different values for the VideoProfile.
"The only "special" logic I have is if the desired frame rate > 60, set video_high_speed."
I think the question is how to integrate this at the user interface. Since I currently have a video frame rate setting, it would seem sensible to enable the video_high_speed if fps is greater than 60 as you say. But high speed frame rates also make other restrictions, such as what video resolutions are available. On top of that, slow motion would have to be enabled separately anyway (and people would expect it to switch to 120fps automaticall). So it may be better under a separate mode for high speed frame rates (and I'll just remove the frame rates greater than 60 from the existing video frame rate).
Either way though, I think the way it should be controlled in the Preview class is via the video_high_speed flag.
So in summary, I'm working on how to integrate this, but I'd be curious to see your changes to CameraController2 and VideoProfile please as they seem useful changes to help this.
Here's the patch. I probably went a bit overboard on the refactoring, sorry. :)
Most of the work was in refactoring getVideoProfile and that started a ripple effect (as refactoring often does). In any case, things still to do would be to filter the preferences dialogs so if you specify a specific resolution, you only get frame rates the resolution supports. Also the addition of the capture to encoder frame rates for slow/fast motion.
The thing to pay attention to is that "high speed" is now determined in getVideoProfile by matching requested size and fps against those available.
Oh yeah, 1920x1080 240fps is pretty sweet :)
Last edit: George Joseph 2018-01-16
Thanks! I'll take a look at adding this. For legal issues, would it be possible please for me to have copyright over the changes? Or licence the patch under Creative Commons CC0 if you prefer? (It makes things easier for licensing, also please be aware I do sometimes sell non-GPL commercial licences; plus in future I want to retain options to relicence under other licenses such as BSD.)
Of course I will credit you, please let me know if you want me to add an email and/or URL for you?
You can have the copyright. also there were some bugs in that patch which I need to correct so stay tuned. :)
Last edit: George Joseph 2018-01-17
OK, here's the latest patch BUT somehow I lost 60fps recording again. 120 works as does not-quite 240. Just not 60. I DID have it working, I swear. :) Anyway, I 'll keep working on it. I was able to get Google's Camera2Video example to work at 60fps so I know it can be done.
To make things like this easier, you may want to think about refactoring Preview and the CameraControllers into separate classes for still vs video and Camera vs Camera2. It's really hard to figure out what gets called in what situation right now. It takes time though, I know.
Thanks! I'll take a look at this.
There are some overlap between photo and video but yes it would make sense for the CameraController classes to be split up more. I also want to move the video handling (MediaRecorder usage etc) from Preview into a separate class at some point.
Hey George, did you manage to get 60fps back working? If so, would you mind uploading APK somewhere, so I could check if it works on my Galaxy S7? Would be awesome!
P.S. I can't find ANY Android app in Google Play store that allows 60fps recording except for the one preinstalled in the system, but there's no bitrate control, so such videos are of low quality.
Note that the latest version of Open Camera (1.43 onwards) now has the changes described here for high FPS and slow motion. But I don't have a Pixel to test with, so I don't know whether 60fps was able to work or not. So I guess try it and see. Though note there's another issue with video recording on Samsung devices with Camera2 API on Android 8, see https://sourceforge.net/p/opencamera/discussion/general/thread/9e36899f .
I figured it out. Since the device supports photo_video_recording, a third surface (3840x2160) is automatically added to the capture session in addition to the preview and record 1920x1080 surfaces. Since the max frame rate for 3840x2160 is 30fps, that's the limit.
My feeling is that if a user selects a specific frame rate, that should be honored if possible so a few things can be done...
Add a "Disable photo capture if selected frame rate can't be met" option to video settings and disable the "take picture" button on the live video screen when the frame rate can't be met and the option is set.
Take the picture size from ptoto settings/resolution instead of using the largest resolution that matches the video aspect ratio.
Related to this is that the code in Preview under the video_high_speed flag already disables the "take photo while recording video" feature - for now I've merged this with your changes so that video_high_speed is set when using a high speed frame rate. (I haven't uploaded the changes yet as I'm still working on reviewing changes.) I think that for other reasons, video snapshot doesn't work for high speed fps (e.g., https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createConstrainedHighSpeedCaptureSession(java.util.List<android.view.Surface>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) says only 2 output surfaces are supported, so we need those for preview and video).
But yes, your case shows that even for non-high speed frame rates this can be a problem. We could do a combination of the two ideas: take the picture size as being the largest resolution matching the video aspect ratio, that also satisfies the requested frame rate. So that way people using default fps don't have their functionality changed. And it means even if a non-default fps is selected, the feature is still available but potentially with a lower photo resolution. (See Preview.getOptimalVideoPictureSize()). I've made a note to take a look at this.
Cool!
Code reviews are a good thing and feedback would be most welcomed! My Java is a little rusty and I only saw that code for the first time the week before last. Don't feel you have to fix issue in my contribution yourself.
Hi,
Well it's more so I can understand the changes too :) I've integrated the changes and synced to my Git repository. There are a number of differences or additions I made:
In Preview, I linked up the high speed behaviour to the video_high_speed flag. This does some extra things, such as ensuring we set a preview size that matches the video resolution (this is needed on my OnePlus 3T at least). It also disables the "photo while video recording" option.
Integrating all the setup of the video into Preview.getVideoProfile() seems a good change, but I moved the showing of the toast for no audio permission back out to when recording video (otherwise it shows every time we call getVideoProfile()).
I made a few changes to VideoProfile.copyToMediaRecorder() - I don't think there's anything wrong with your way, but I wanted to minimise changes to how the MediaRecorder is set up in non-high-fps cases, to minimise any possible risk of change of behaviour (e.g., so I only call MediaRecorder.setCaptureRate() if videoCaptureRate is not equal to videoFrameRate).
VideoProfile no longer keeps a record of camcorderProfile (with your changes, we no longer need to keep it!)
VideoProfile stores the record_audio flag to explicitly tell us if audio is enabled.
I don't override the videoCodec or audioCodec obtained from the CamcorderProfile (just in case this changes behaviour on some devices).
Checking whether we need high speed or not is now done when setting up the camera (setupCameraParameters()) instead of getVideoProfile(). Perhaps we should check in getVideoProfile(), but for now I wanted to keep things consistent with the setup/checks for other video related features (e.g., seeing if the video resolution is valid). Currently changing a video setting will always involve going through setupCameraParameters() again. I also store the high speed sizes in VideoQualityHandler so we don't need to get the camera_features again.
For now I haven't included the code to take action if the requested size and frame rate aren't compatible. I'm still thinking about how to do the user interface level - ideally it should be clear to the user. Though I'll still be putting the check back in Preview just to be safe (e.g., in rare cases a phone OS upgrade might change available camera settings, so the user interface could still be set in a state that requests a setting that is no longer valid).
I don't bother putting the fps ranges in CameraController.CameraFeatures.
In CameraController2, I set CONTROL_AE_TARGET_FPS_RANGE entirely via CameraSettings.setAEMode(), rather than setAETargetFpsRange(); similarly for setSensorFrameDuration()
Interestingly, implementing CameraController2.setPreviewFpsRange() caused the preview on my OnePlus 3T to become too dark in video mode. It's something I saw before on the Nexus 6 (with old camera API), and is fixed in Preview.setPreviewFps() via the preview_too_dark flag, which means (if using "default" video fps) we try to set the broadest range for fps values rather than trying to match the video frame rate. So I've enabled the preview_too_dark flag for all devices on Camera2 API. (To be honest, I'm not entirely sure how preview frame rate ranges matches up to video capture rate or resultant frame rate - e.g., should it just include the requested fps in the range, or should it also be as narrow a range as possible.)
Also some questions I have:
For now I haven't included the MediaRecorder.setVideoEncodingProfileLevel for Android 8 - I wasn't sure what this does, I couldn't find useful documentation on these settings? Is it needed for high fps?
In CameraController2, I wasn't sure why in initVideoRecorderPostPrepare is sensor_frame_duration set to a fixed value of 60fps, ignoring the value set from setPreviewFpsRange? Does the sensor_frame_duration setting matter either way for accurate fps?
In CameraController2, setManualExposureTime() now uses a default SENSOR_FRAME_DURATION (if we didn't get one from the captureresult) of 60fps instead of 30fps - does this matter either way?
And most important of all - does my version of the code still work with high speed frame rates on your Pixel? Unfortunately although my OnePlus 3T claims to support high speed frame rates (so I could test the code that sets things up), it fails to then record video (which could just be a OnePlus 3T bug - Footej's slow motion doesn't work on it either - but means I'm unable to fully test things).
Thanks!
Just to give an update: I now have a Nokia 8 where 120fps does seem to be working, so I can now test things properly.
I'm now working on adding support for the user interface side of things. Have already fixed Preview to make us fall back to a supported high speed video resolution if an incompatible resolution and fps are requested by the application. I've also set the fps preference now be per-camera.
So hopefully this should all be in the next version (and then after that I can look at slow motion). Thanks a lot for your help and code!
View and moderate all "General Discussion" comments posted by this user
Mark all as spam, and block user from posting to "Discussion"
Hi guys,
My first post in the forums. I don't have an account but my name's Vlad. Mark, thanks for a wonderful app.
I wanted to boost this/ add my own experience with the current version 1.42.2. I recently downloaded Open Camera for my Pixel XL (gen1), with Android 8.1.0.
Regardless, I ran some tests an hour ago, so I can have a look at how the footage looks but also because things weren't adding up: it didn't look like the slow framrates were working when viewing footage through Google Photos and also when setting it to record at high fps (60, 100 or 120) the shutter speeds were sometimes as low as 1/40 or 1/60 which is a dead giveaway that something was up.
Here are the different settings I used and the framerates it recorded at. As you can see, almost everything is still the default 29.97 except for numbers 6 and 11.
1) 2k/24fps/100mbps - recorded at 29.97 fps
2) 2k/60fps/100mbps - recorded at 29.97 fps
3) 2k/120fps/100mbps - recorded at 29.97 fps
4) 2k/24fps/50mbps - recorded at 29.97 fps
5) 2k/25fps/100mbps - recorded at 29.97 fps
6) 2.7k/24fps/100mbps - recorded at 29.80 fps
7) 2.7k/60fps/100mbps - recorded at 29.97 fps
8) 2.7k/120fps/100mbps - recorded at 29.97 fps
9) 2.7k/100fps/100mbps - recorded at 29.97 fps
10) 4k/24fps/100mbps - recorded at 29.97 fps
11) 4k/60fps/100mbps - recorded at 29.81 fps
As I said, I'm using a 120gb Gen1 Google Pixel XL. It's currently fully updated to Android 8.1.0. I used Open Camera v1.42.2 and I have the Camera2 API on (although I don't know what an API is, only an incling).
Sorry, I only understand about a quarter of what you guys are talking about and have no idea about app development but I can appreciate it's a lot of hard work. Did the changes suggested by George in his patch already make their way into the current version of the app? and if so (or not) is there anything I can do at this point in time to allow different framerates to work?
Did I say, thanks for a great app, Mark?
Thanks for the info! Just to confirm that the changes mentioned above aren't in the currently released version 1.42.2. I don't think there's anything you can do in the meantime I'm afraid.
Same here on Samsung Galaxy S7 with 1.42.2. I deeply regret the lack of changing framerate. Kindly PLEASE support it in the next version.
...but I can easily record 60 fps videos using system camera app with no problem (if that helps). I'm on Android 7.0 (highest available for S7).
Sorry for reviving this thread, but I had the exact same issue with 26FPS fixed (no other option produces other FPS values). Should I have opened a new thread about this?
Thanks in advance for fixing the issue...
P.S.
Using the app on OnePlus 8 Pro with Android 10 patched with April 1 security update, kernel 4.19.81-perf+, Oxygen OS 10.5.8.IN11BA