Skip to content
This repository has been archived by the owner on Jun 16, 2023. It is now read-only.

Ability to set video resolutions (videoFrameWidth & videoFrameHeight) #3121

Open
wants to merge 14 commits into
base: master
Choose a base branch
from

Conversation

makzee
Copy link

@makzee makzee commented Feb 23, 2021

It adds the ability to set videoFrameWidth and videoFrameHeight.

Test Plan
Recorded two videos, 1 with the desired resolutions and other without setting them at all. 2nd test is it make sure that it still works as it used to previously.

Test 1

const video = await cameraRef.recordAsync({ mute: true, quality: '4:3', videoFrameWidth: 1280, videoFrameHeight: 960 });

image

Test 2

const video = await cameraRef.recordAsync({ mute: true, quality: '4:3' });

image

Copy link
Collaborator

@MarcoScabbiolo MarcoScabbiolo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No more post-recording cropping in Android to have 4:3 🎉 🎉
I think setting the preview dimensions in iOS and quality 4:3 produces the same result, right?

Haven't tested it myself.

@MateusAndrade
Copy link
Collaborator

Nice! Do you think we can proceed to merge this @MarcoScabbiolo?

@makzee
Copy link
Author

makzee commented Feb 23, 2021

I'm sorry I forgot to mention that it is Android only. I don't have iPhone, I can fix it later for iOS too.

Another thing I would like to mention is that the resolution should be supported by the device otherwise it would fail to record. For that we need to expose getSupportedVideoSizes(). I have looked into OpenCamera source code to see how it generates the list of supported video sizes, I'm currently working on that (Will create another PR for that).

@MarcoScabbiolo
Copy link
Collaborator

I think it will be best if you add the method to get the supported sizes to this PR, so the feature is complete once released. Mainly because of the many differences across Android devices.

@makzee
Copy link
Author

makzee commented Feb 23, 2021

Sure I can do that.

@cristianoccazinsp
Copy link
Contributor

Does this replace setting quality='480p' or 720? How does these new props interact with the quality setting? As far as I know, the quality value already sets the video resolution/frame, doesn't it?

@makzee
Copy link
Author

makzee commented Feb 23, 2021

With this change we can deprecate 4:3. Each quality setting maps to one of the CamcorderProfile. 4:3 (i.e. VIDEO_4x3) is a special quality that maps to QUALITY_480P (which is 480x720) and sets the videoFrameWidth to 640.

As far as I know, the quality value already sets the video resolution/frame, doesn't it?

Correct but all those profiles are 16:9. With this PR the width/height can be overridden to get the desired aspect ratio. For example: Currently it is not possible to record in high quality with aspect ratio of 4:3.

@cristianoccazinsp
Copy link
Contributor

I see, I'm slightly confused, but when I set 4:3 I always get consistent videos in either 720p or 480p (with different aspect rations for each quality, basically 4:3 is ignored right now?). Is ratio='4:3' even used when recording videos?

What would happen to iOS?

@makzee
Copy link
Author

makzee commented Feb 24, 2021

I have added getAvailableVideoSizes(). It can be called like:

const videoSizes = await cameraRef.getAvailableVideoSizes();
console.log(videoSizes);

(Note: The result is for the ratio set in <RNCamera ratio={ratio} ... />)

The sample output is:
["320x240", "640x480", "960x720", "1280x960", "1440x1080"]

I originally wanted to return json (width & height in their own fields) instead of string but decided to keep it consistent with getAvailablePictureSizes() output. I would prefer to return json, I can make the change if that is ok? After change output will be like:

[{"height": 240, "width": 320}, {"height": 480, "width": 640}, {"height": 720, "width": 960}, {"height": 960, "width": 1280}, {"height": 1080, "width": 1440}]

@cristianoccazinsp
Copy link
Contributor

Isn't ratio an actual aspect ratio ("4:3", "16:9") ?

Does this mean that we need to we will need to "parse" the results in order to set videoFrameWidth and videoFrameHeight? It's probably a better idea to return a JSON as you mentioned.

@makzee
Copy link
Author

makzee commented Feb 24, 2021

Isn't ratio an actual aspect ratio ("4:3", "16:9") ?

Yes, it is actual aspect ratio.

Does this mean that we need to we will need to "parse" the results in order to set videoFrameWidth and videoFrameHeight? It's probably a better idea to return a JSON as you mentioned.

Right, I did it to be consistent with getAvailablePictureSizes(). Let me change it to json.

@cristianoccazinsp
Copy link
Contributor

@makzee what will be the behaviour if invalid values are set? Have you also tried with all available cameras (front, back)?

…upported. It returns empty array instead of exception
@makzee
Copy link
Author

makzee commented Mar 2, 2021

@makzee what will be the behaviour if invalid values are set? Have you also tried with all available cameras (front, back)?

When invalid values are set, it returns an error. Yes I have tested with both the cameras, it works fine.

I have added getAvailableVideoSizes(). Call it like:

const sizes = await cameraRef.getAvailableVideoSizes();

Reponse:
[{"height": 240, "width": 320}, {"height": 480, "width": 640}, {"height": 720, "width": 960}, {"height": 960, "width": 1280}, {"height": 1080, "width": 1440}]

It is ready to be reviewed and merged.

@MateusAndrade
Copy link
Collaborator

MateusAndrade commented Mar 2, 2021

@cristianoccazinsp, @MarcoScabbiolo do you think we can go on merging this?

@cristianoccazinsp
Copy link
Contributor

It looks pretty good to me! Although I'm still not sure what's the benefit of setting the frame width/height, if you already "control" that with the quality parameter. For example, what would happen if the following options are used:

// change quality but use a fixed width/height ?
{quality: '480p', videoFrameWidth: 1280, videoFrameHeight: 960}
{quality: '720p', videoFrameWidth: 1280, videoFrameHeight: 960}
{quality: '1080p', videoFrameWidth: 1280, videoFrameHeight: 960}

// The other way around
{quality: '720p', videoFrameWidth: 1280, videoFrameHeight: 480}
{quality: '720p', videoFrameWidth: 1280, videoFrameHeight: 720}
{quality: '720p', videoFrameWidth: 1920, videoFrameHeight: 1080}

Looks like it may end up causing some confusion because the pixel dimension is usually strictly tied to the quality name.

@makzee
Copy link
Author

makzee commented Mar 2, 2021

Each quality maps to one of the CamcorderProfile (https://developer.android.com/reference/android/media/CamcorderProfile). A profile has a fixed set of settings like fps, bitrate, resolution, codec etc but you are still allowed to change them as per your requirement. The reason for these changes was that we needed to record video in 4:3 at a higher resolution (not just 480p). Most of all these profiles correspond to 16:9, for example: QUALITY_1080P gives you 1920x1080. If I want to record 1080p in 4:3 (i.e. 1440x1080), this PR allows to you do that.

{quality: '1080p', videoFrameWidth: 1440}

It means "Use 1080p profile but override the width to 1440.".

Quality represents a baseline profile and we need to allow flexibility to change specific attributes of that profile.

@cristianoccazinsp
Copy link
Contributor

@makzee that greatly explains it, and makes complete sense. Good work!

Do we need this for iOS as well?

@makzee
Copy link
Author

makzee commented Mar 2, 2021

Thanks @cristianoccazinsp.

Yes we need this for iOS as well but I don't have a bandwidth for it right now. I'm planning to implement this in a month or so.

Copy link
Collaborator

@MarcoScabbiolo MarcoScabbiolo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Havent tested it myself

@MarcoScabbiolo
Copy link
Collaborator

I see, I'm slightly confused, but when I set 4:3 I always get consistent videos in either 720p or 480p (with different aspect rations for each quality, basically 4:3 is ignored right now?). Is ratio='4:3' even used when recording videos?
What would happen to iOS?

4:3 is actually 640:480 in iOS. Implementing this on iOS should be doable, AVCaptureMovieFileOutput settings include width and height keys, havent used/tested it myself though, they might be read-only. We should have in mind setting these outputsettings (including codecType) leads to the video being re-encoded as its recorded and might mean a performance hit as more settings are set.

(Note for v4): The options that make a difference between raw recording and re-encoding should be made clear even if they change across devices, mostly on Android. Remove 4:3

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants