Regression: After upgrading to SDK42, Camera recordAsync with maxDuration doesn't work with quality 720p specified on iOS
See original GitHub issueSummary
After upgrading to SDK 42, Camera’s recordAsync({maxDuration: 5, quality: Camera.Constants.VideoQuality['720p']})
no longer works on iOS: recordAsync
returns immediately and although it returns with a .mov
file name, FileSystem.getInfoAsync
returns that the file doesn’t exist. Commenting out the quality
option resolves the issue.
Managed or bare workflow? If you have ios/
or android/
directories in your project, the answer is bare!
managed
What platform(s) does this occur on?
iOS
SDK Version (managed workflow only)
42
Environment
% expo diagnostics
Expo CLI 4.7.3 environment info:
System:
OS: macOS 11.4
Shell: 5.8 - /bin/zsh
Binaries:
Node: 14.17.3 - /usr/local/bin/node
Yarn: 1.22.10 - /usr/local/bin/yarn
npm: 6.14.13 - /usr/local/bin/npm
Watchman: 2021.06.07.00 - /usr/local/bin/watchman
Managers:
CocoaPods: 1.10.1 - /usr/local/bin/pod
SDKs:
iOS SDK:
Platforms: iOS 14.5, DriverKit 20.4, macOS 11.3, tvOS 14.5, watchOS 7.4
IDEs:
Xcode: 12.5.1/12E507 - /usr/bin/xcodebuild
npmPackages:
expo: ~42.0.1 => 42.0.1
react: 16.13.1 => 16.13.1
react-dom: 16.13.1 => 16.13.1
react-native: https://github.com/expo/react-native/archive/sdk-42.0.0.tar.gz => 0.63.2
react-native-web: ~0.13.12 => 0.13.18
npmGlobalPackages:
expo-cli: 4.7.3
Expo Workflow: managed
Reproducible demo or steps to reproduce from a blank project
Minimal reproducible demo: https://github.com/kevgrig/exposdk42vidissue App.js reproduced below. Steps:
- Launch App
- Click Record. Console shows that
this.cameraRef.recordAsync
returns immediately with amov
file that doesn’t exist:TakeVideoScreen.startRecording maxDuration: 5 TakeVideoScreen.startRecording returned: [...]]CA6F553ECB0E.mov File doesn't exist
- Change
const USE_QUALITY = true;
toconst USE_QUALITY = false;
- Click Record and it works as expected with
this.cameraRef.recordAsync
returning after 5 seconds and themov
file exists:TakeVideoScreen.startRecording maxDuration: 5 onRecordingInterval 5 onRecordingInterval 4 onRecordingInterval 3 onRecordingInterval 2 onRecordingInterval 1 TakeVideoScreen.startRecording returned: [...]]3A417EB33340.mov TakeVideoScreen.startRecording bytes: 5147387, uri: [...]]3A417EB33340.mov
App.js:
import React from 'react';
import { Button, Dimensions, Text, View } from 'react-native';
import { Audio } from 'expo-av';
import { Camera } from 'expo-camera';
import * as FileSystem from 'expo-file-system';
const MAX_DURATION = 5;
const USE_QUALITY = false;
class TakeVideoScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
hasCameraPermission: false,
timeLeft: MAX_DURATION,
};
}
async componentDidMount() {
try {
const { status: cameraStatus } = await Camera.requestPermissionsAsync();
const { status: audioStatus } = await Audio.requestPermissionsAsync();
this.setState({ hasCameraPermission: cameraStatus === "granted" && audioStatus === "granted" });
} catch (e) {
console.log(e);
}
}
onRecordingInterval = () => {
console.log("onRecordingInterval " + this.state.timeLeft);
this.setState((state, props) => {
let timeLeft = state.timeLeft - 1;
if (timeLeft < 0) {
timeLeft = 0;
}
return { timeLeft: timeLeft };
});
}
startRecording = async () => {
if (!this.isRecording) {
try {
this.isRecording = true;
if (this.intervalId) {
clearInterval(this.intervalId);
}
console.log("TakeVideoScreen.startRecording maxDuration: " + this.state.timeLeft);
this.intervalId = setInterval(this.onRecordingInterval, 1000);
const options = {
maxDuration: MAX_DURATION,
};
if (USE_QUALITY) {
options.quality = Camera.Constants.VideoQuality['720p']
}
const data = await this.cameraRef.recordAsync(options);
console.log("TakeVideoScreen.startRecording returned: " + data.uri);
clearInterval(this.intervalId);
const fileInfo = await FileSystem.getInfoAsync(data.uri);
if (fileInfo.exists) {
const numBytes = fileInfo.size;
console.log("TakeVideoScreen.startRecording bytes: " + numBytes + ", uri: " + data.uri);
} else {
console.log("File doesn't exist")
}
this.setState({ timeLeft: MAX_DURATION });
} catch (e) {
console.log("Error: " + e);
} finally {
this.isRecording = false;
}
}
}
render() {
if (this.state.hasCameraPermission === null) {
// Asking for permissions
return <View />;
} else if (this.state.hasCameraPermission === false) {
return (
<Text>No Camera</Text>
);
} else {
const { width, height } = Dimensions.get("window");
return (
<View style={{ flex: 1, paddingTop: 40, paddingBottom: 40 }}>
<Button title="Record" onPress={this.startRecording} />
<Text style={{ alignSelf: "center", padding: 20 }}>Time left: {this.state.timeLeft} seconds</Text>
<Camera
style={{ flex: 1, width: width - 40 }}
type={Camera.Constants.Type.front}
ref={camera => this.cameraRef = camera}
/>
</View>
);
}
}
}
export default function App() {
return (
<View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
<TakeVideoScreen />
</View>
);
}
Issue Analytics
- State:
- Created 2 years ago
- Reactions:1
- Comments:5 (2 by maintainers)
Top Results From Across the Web
Camera
Camera. expo-camera provides a React component that renders a preview for the device's front or back camera. The camera's parameters like zoom, auto...
Read more >Unable to save video anymore with Expo on iOS
Issue is create by camera.recordAsync() that stops almost as soon as it starts. Only happens when the quality prop is used.
Read more >[RESOLVED] Using .recordAsync and .stopRecording ...
I've tried testing on my phone and it's not working but I don't have a great ... { quality: '720p', maxDuration: 60 };...
Read more >Changelog
[Android] Core: Fix a bug where the camera preview would not be centered on screen when setting setPreviewAspectFill to true on the ScanFragment...
Read more >Expo SDK 41
Today we're announcing the release of Expo SDK 41. SDK 41 includes React Native 0.63, the same vers... Tagged with mobile, reactnative, ios, ......
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
@kevgrig thank you for putting together this repro! really helps a lot! a fix for this is coming soon 👍
hey there - we should be releasing sdk 43 within the next few weeks. otherwise you’d have to eject your app to get the updates. for future reference, you can check the changeling of a package to see if its available: https://github.com/expo/expo/blob/master/packages/expo-camera/CHANGELOG.md
in this case, there are native code changes which means a new native build is required. we usually have a beta period before releasing a new sdk which would let you try out these changes sooner than the official release date, so I would also keep an eye out for that!