feat: Add customizable Video Bit Rate (videoBitRate
) (#1882)
* feat: Add `videoBitRate` option to `RecordVideoOptions` * feat: Implement `videoBitRate` on iOS * feat: Implement `videoBitRate` on Android * chore: Format * docs: Separate recording and photo docs * docs: Fix links * docs: Add docs about bitrate and quality * docs: Add blob * fix: Don't use inline style for CI * fix: Correctly log default bitRate * fix: Fix typo * fix: Calculate default bit-rate on Android depending on resolution * Update RecordingSession.kt
This commit is contained in:
@@ -71,7 +71,7 @@ function App() {
|
||||
|
||||
### Capture Errors
|
||||
|
||||
The `CameraCaptureError` represents any kind of error that occured only while capturing a photo or recording a video.
|
||||
The `CameraCaptureError` represents any kind of error that occured only while taking a photo or recording a video.
|
||||
|
||||
```tsx
|
||||
function App() {
|
||||
|
@@ -21,7 +21,7 @@ There are formats specifically designed for high-resolution photo capture (but l
|
||||
|
||||
If you don't want to specify a Camera Format, you don't have to. The Camera automatically chooses the best matching format for the current camera device. This is why the Camera's `format` property is _optional_.
|
||||
|
||||
**🚀 Continue with: [Taking Photos/Recording Videos](./capturing)**
|
||||
**🚀 Continue with: [Taking Photos](./taking-photos)**
|
||||
|
||||
## Choosing custom formats
|
||||
|
||||
@@ -37,7 +37,7 @@ To understand a bit more about camera formats, you first need to understand a fe
|
||||
|
||||
To get all available formats, simply use the `CameraDevice`'s [`formats` property](/docs/api/interfaces/CameraDevice#formats). These are a [CameraFormat's](/docs/api/interfaces/CameraDeviceFormat) props:
|
||||
|
||||
- [`photoHeight`](/docs/api/interfaces/CameraDeviceFormat#photoHeight)/[`photoWidth`](/docs/api/interfaces/CameraDeviceFormat#photoWidth): The resolution that will be used for capturing photos. Choose a format with your desired resolution.
|
||||
- [`photoHeight`](/docs/api/interfaces/CameraDeviceFormat#photoHeight)/[`photoWidth`](/docs/api/interfaces/CameraDeviceFormat#photoWidth): The resolution that will be used for taking photos. Choose a format with your desired resolution.
|
||||
- [`videoHeight`](/docs/api/interfaces/CameraDeviceFormat#videoHeight)/[`videoWidth`](/docs/api/interfaces/CameraDeviceFormat#videoWidth): The resolution that will be used for recording videos. Choose a format with your desired resolution.
|
||||
- [`minFps`](/docs/api/interfaces/CameraDeviceFormat#minFps)/[`maxFps`](/docs/api/interfaces/CameraDeviceFormat#maxFps): A range of possible values for the `fps` property. For example, if your format has `minFps: 1` and `maxFps: 60`, you can either use `fps={30}`, `fps={60}` or any other value in between for recording videos.
|
||||
- [`videoStabilizationModes`](/docs/api/interfaces/CameraDeviceFormat#videoStabilizationModes): All supported Video Stabilization Modes, digital and optical. If this specific format contains your desired [`VideoStabilizationMode`](/docs/api/#videostabilizationmode), you can pass it to your `<Camera>` via the [`videoStabilizationMode` property](/docs/api/interfaces/CameraProps#videoStabilizationMode).
|
||||
@@ -180,4 +180,4 @@ Other props that depend on the `format`:
|
||||
|
||||
<br />
|
||||
|
||||
#### 🚀 Next section: [Taking Photos/Recording Videos](./capturing)
|
||||
#### 🚀 Next section: [Taking Photos](./taking-photos)
|
||||
|
166
docs/docs/guides/RECORDING_VIDEOS.mdx
Normal file
166
docs/docs/guides/RECORDING_VIDEOS.mdx
Normal file
@@ -0,0 +1,166 @@
|
||||
---
|
||||
id: recording-videos
|
||||
title: Recording Videos
|
||||
sidebar_label: Recording Videos
|
||||
---
|
||||
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl'
|
||||
|
||||
<div class="image-container">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="283" height="535">
|
||||
<image href={useBaseUrl("img/demo_capture.gif")} x="18" y="33" width="247" height="469" />
|
||||
<image href={useBaseUrl("img/frame.png")} width="283" height="535" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
## Camera Functions
|
||||
|
||||
The Camera provides certain functions which are available through a [ref object](https://reactjs.org/docs/refs-and-the-dom.html):
|
||||
|
||||
```tsx
|
||||
function App() {
|
||||
const camera = useRef<Camera>(null)
|
||||
// ...
|
||||
|
||||
return (
|
||||
<Camera
|
||||
ref={camera}
|
||||
{...cameraProps}
|
||||
/>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
To use these functions, you need to wait until the [`onInitialized`](/docs/api/interfaces/CameraProps#oninitialized) event has been fired.
|
||||
|
||||
## Recording Videos
|
||||
|
||||
To start a video recording you first have to enable video capture:
|
||||
|
||||
```tsx
|
||||
<Camera
|
||||
{...props}
|
||||
video={true}
|
||||
audio={true} // <-- optional
|
||||
/>
|
||||
```
|
||||
|
||||
Then, simply use the Camera's [`startRecording(...)`](/docs/api/classes/Camera#startrecording) function:
|
||||
|
||||
```ts
|
||||
camera.current.startRecording({
|
||||
onRecordingFinished: (video) => console.log(video),
|
||||
onRecordingError: (error) => console.error(error)
|
||||
})
|
||||
```
|
||||
|
||||
You can customize capture options such as [video codec](/docs/api/interfaces/RecordVideoOptions#videoCodec), [video bit-rate](/docs/api/interfaces/RecordVideoOptions#videoBitRate), [file type](/docs/api/interfaces/RecordVideoOptions#fileType), [enable flash](/docs/api/interfaces/RecordVideoOptions#flash) and more using the [`RecordVideoOptions`](/docs/api/interfaces/RecordVideoOptions) parameter.
|
||||
|
||||
For any error that occured _while recording the video_, the `onRecordingError` callback will be invoked with a [`CaptureError`](/docs/api/classes/CameraCaptureError) and the recording is therefore cancelled.
|
||||
|
||||
To stop the video recording, you can call [`stopRecording(...)`](/docs/api/classes/Camera#stoprecording):
|
||||
|
||||
```ts
|
||||
await camera.current.stopRecording()
|
||||
```
|
||||
|
||||
Once a recording has been stopped, the `onRecordingFinished` callback passed to the [`stopRecording(...)`](/docs/api/classes/Camera#stoprecording) function will be invoked with a [`VideoFile`](/docs/api/interfaces/VideoFile) which you can then use to display in a [`<Video>`](https://github.com/react-native-video/react-native-video) component, uploaded to a backend, or saved to the Camera Roll using [react-native-cameraroll](https://github.com/react-native-cameraroll/react-native-cameraroll).
|
||||
|
||||
### Pause/Resume
|
||||
|
||||
To pause/resume the recordings, you can use [`pauseRecording()`](/docs/api/classes/Camera#pauserecording) and [`resumeRecording()`](/docs/api/classes/Camera#resumerecording):
|
||||
|
||||
```ts
|
||||
await camera.current.pauseRecording()
|
||||
...
|
||||
await camera.current.resumeRecording()
|
||||
```
|
||||
|
||||
### Video Codec
|
||||
|
||||
By default, videos are recorded in the H.264 video codec which is a widely adopted video codec.
|
||||
|
||||
VisionCamera also supports H.265 ([HEVC](https://en.wikipedia.org/wiki/High_Efficiency_Video_Coding)), which is much more efficient in encoding performance as well as an up to 20% smaller file size:
|
||||
|
||||
```ts
|
||||
camera.current.startRecording({
|
||||
...props,
|
||||
videoCodec: 'h265'
|
||||
})
|
||||
```
|
||||
|
||||
### Video Bit Rate
|
||||
|
||||
Videos are recorded with a target bit-rate, which the encoder aims to match as closely as possible. A lower bit-rate means less quality (and less file size), a higher bit-rate means higher quality (and larger file size) since it can assign more bits to moving pixels.
|
||||
|
||||
To simply record videos with higher quality, use a [`videoBitRate`](/docs/api/interfaces/RecordVideoOptions#videoBitRate) of `'high'`, which effectively increases the bit-rate by 20%:
|
||||
|
||||
```ts
|
||||
camera.current.startRecording({
|
||||
...props,
|
||||
videoBitRate: 'high'
|
||||
})
|
||||
```
|
||||
|
||||
To use a lower bit-rate for lower quality and lower file-size, use a [`videoBitRate`](/docs/api/interfaces/RecordVideoOptions#videoBitRate) of `'low'`, which effectively decreases the bit-rate by 20%:
|
||||
|
||||
```ts
|
||||
camera.current.startRecording({
|
||||
...props,
|
||||
videoBitRate: 'low'
|
||||
})
|
||||
```
|
||||
|
||||
#### Custom Bit Rate
|
||||
|
||||
If you want to use a custom bit-rate, you first need to understand how bit-rate is calculated.
|
||||
|
||||
The bit-rate is a product of multiple factors such as resolution, FPS, pixel-format (HDR or non HDR), and video codec.
|
||||
As a good starting point, those are the recommended base bit-rates for their respective resolutions:
|
||||
|
||||
- 480p: 2 Mbps
|
||||
- 720p: 5 Mbps
|
||||
- 1080p: 10 Mbps
|
||||
- 4K: 30 Mbps
|
||||
- 8K: 100 Mbps
|
||||
|
||||
These bit-rates assume a frame rate of 30 FPS, a non-HDR pixel-format, and a H.264 video codec.
|
||||
|
||||
To calculate your target bit-rate, you can use this formula:
|
||||
|
||||
```ts
|
||||
let bitRate = baseBitRate
|
||||
bitRate = bitRate / 30 * fps // FPS
|
||||
if (hdr === true) bitRate *= 1.2 // HDR
|
||||
if (codec === 'h265') bitRate *= 0.8 // H.265
|
||||
bitRate *= yourCustomFactor // e.g. 0.5x for half the bit-rate
|
||||
```
|
||||
|
||||
And then pass it to the [`startRecording(...)`](/docs/api/classes/Camera#startrecording) function (in Mbps):
|
||||
|
||||
```ts
|
||||
camera.current.startRecording({
|
||||
...props,
|
||||
videoBitRate: bitRate // Mbps
|
||||
})
|
||||
```
|
||||
|
||||
## Saving the Video to the Camera Roll
|
||||
|
||||
Since the Video is stored as a temporary file, you need save it to the Camera Roll to permanentely store it. You can use [react-native-cameraroll](https://github.com/react-native-cameraroll/react-native-cameraroll) for this:
|
||||
|
||||
```ts
|
||||
camera.current.startRecording({
|
||||
...props,
|
||||
onRecordingFinished: (video) => {
|
||||
const path = video.path
|
||||
await CameraRoll.save(`file://${path}`, {
|
||||
type: 'video',
|
||||
})
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
<br />
|
||||
|
||||
#### 🚀 Next section: [Frame Processors](frame-processors)
|
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: capturing
|
||||
title: Taking Photos/Recording Videos
|
||||
sidebar_label: Taking Photos/Recording Videos
|
||||
id: taking-photos
|
||||
title: Taking Photos
|
||||
sidebar_label: Taking Photos
|
||||
---
|
||||
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl'
|
||||
@@ -33,7 +33,7 @@ function App() {
|
||||
|
||||
To use these functions, you need to wait until the [`onInitialized`](/docs/api/interfaces/CameraProps#oninitialized) event has been fired.
|
||||
|
||||
### Taking Photos
|
||||
## Taking Photos
|
||||
|
||||
To take a photo you first have to enable photo capture:
|
||||
|
||||
@@ -47,57 +47,46 @@ To take a photo you first have to enable photo capture:
|
||||
Then, simply use the Camera's [`takePhoto(...)`](/docs/api/classes/Camera#takephoto) function:
|
||||
|
||||
```ts
|
||||
const photo = await camera.current.takePhoto({
|
||||
flash: 'on'
|
||||
})
|
||||
const photo = await camera.current.takePhoto()
|
||||
```
|
||||
|
||||
You can customize capture options such as [automatic red-eye reduction](/docs/api/interfaces/TakePhotoOptions#enableautoredeyereduction), [automatic image stabilization](/docs/api/interfaces/TakePhotoOptions#enableautostabilization), [enable flash](/docs/api/interfaces/TakePhotoOptions#flash), [prioritize speed over quality](/docs/api/interfaces/TakePhotoOptions#qualityprioritization), [disable the shutter sound](/docs/api/interfaces/TakePhotoOptions#enableshuttersound) and more using the [`TakePhotoOptions`](/docs/api/interfaces/TakePhotoOptions) parameter.
|
||||
|
||||
This function returns a [`PhotoFile`](/docs/api/interfaces/PhotoFile) which is stored in a temporary directory and can either be displayed using `<Image>` or `<FastImage>`, uploaded to a backend, or saved to the Camera Roll using [react-native-cameraroll](https://github.com/react-native-cameraroll/react-native-cameraroll).
|
||||
|
||||
### Recording Videos
|
||||
### Fast Capture
|
||||
|
||||
To start a video recording you first have to enable video capture:
|
||||
|
||||
```tsx
|
||||
<Camera
|
||||
{...props}
|
||||
video={true}
|
||||
audio={true} // <-- optional
|
||||
/>
|
||||
```
|
||||
|
||||
Then, simply use the Camera's [`startRecording(...)`](/docs/api/classes/Camera#startrecording) function:
|
||||
The [`takePhoto(...)`](/docs/api/classes/Camera#takephoto) function can be configured for faster capture at the cost of lower quality:
|
||||
|
||||
```ts
|
||||
camera.current.startRecording({
|
||||
flash: 'on',
|
||||
onRecordingFinished: (video) => console.log(video),
|
||||
onRecordingError: (error) => console.error(error),
|
||||
const photo = await camera.current.takePhoto({
|
||||
qualityPrioritization: 'speed',
|
||||
flash: 'off',
|
||||
enableShutterSound: false
|
||||
})
|
||||
```
|
||||
|
||||
You can customize capture options such as [video codec](/docs/api/interfaces/RecordVideoOptions#videoCodec), [file type](/docs/api/interfaces/RecordVideoOptions#fileType), [enable flash](/docs/api/interfaces/RecordVideoOptions#flash) and more using the [`RecordVideoOptions`](/docs/api/interfaces/RecordVideoOptions) parameter.
|
||||
## Saving the Photo to the Camera Roll
|
||||
|
||||
For any error that occured _while recording the video_, the `onRecordingError` callback will be invoked with a [`CaptureError`](/docs/api/classes/CameraCaptureError) and the recording is therefore cancelled.
|
||||
|
||||
To stop the video recording, you can call [`stopRecording(...)`](/docs/api/classes/Camera#stoprecording):
|
||||
Since the Photo is stored as a temporary file, you need to save it to the Camera Roll to permanentely store it. You can use [react-native-cameraroll](https://github.com/react-native-cameraroll/react-native-cameraroll) for this:
|
||||
|
||||
```ts
|
||||
await camera.current.stopRecording()
|
||||
const path = await camera.current.takePhoto()
|
||||
await CameraRoll.save(`file://${path}`, {
|
||||
type: 'photo',
|
||||
})
|
||||
```
|
||||
|
||||
Once a recording has been stopped, the `onRecordingFinished` callback passed to the `startRecording(..)` function will be invoked with a [`VideoFile`](/docs/api/interfaces/VideoFile) which you can then use to display in a [`<Video>`](https://github.com/react-native-video/react-native-video) component, uploaded to a backend, or saved to the Camera Roll using [react-native-cameraroll](https://github.com/react-native-cameraroll/react-native-cameraroll).
|
||||
## Getting the Photo's data
|
||||
|
||||
To pause/resume the recordings, you can use `pauseRecording()` and `resumeRecording()`:
|
||||
To get the Photo's pixel data, you can use [`fetch(...)`](https://reactnative.dev/docs/network#using-fetch) to read the local file as a Blob:
|
||||
|
||||
```ts
|
||||
await camera.current.pauseRecording()
|
||||
...
|
||||
await camera.current.resumeRecording()
|
||||
const path = await camera.current.takePhoto()
|
||||
const result = await fetch(`file://${path}`)
|
||||
const data = await result.blob();
|
||||
```
|
||||
|
||||
<br />
|
||||
|
||||
#### 🚀 Next section: [Frame Processors](frame-processors)
|
||||
#### 🚀 Next section: [Recording Videos](recording-videos)
|
Reference in New Issue
Block a user