react-native-vision-camera icon indicating copy to clipboard operation
react-native-vision-camera copied to clipboard

🐛 Recorded video is stretched

Open HorbachAndrii opened this issue 4 years ago • 7 comments

What were you trying to do?

Record video.

Reproduceable Code

<Camera
 ref={cameraRef}
 style={styles.recordVideo}
 device={devices.front}
 video={true}
 audio={true}
 isActive={isActiveRecordVideo}
 preset="iframe-1280x720"
/>


or Full code

import React, {useLayoutEffect, useRef, useState} from 'react';
import {
  Pressable,
  SafeAreaView,
  ScrollView,
  StatusBar,
  StyleSheet,
  Text,
  View,
} from 'react-native';
import {VLCPlayer} from 'react-native-vlc-media-player';
import {Camera, useCameraDevices} from 'react-native-vision-camera';
import {RNCamera} from 'react-native-camera';


const AppVisionCamera = () => {
  const devices = useCameraDevices();

  const [isRecordingVide, setIsRecordingVide] = useState(false);
  const [recordedVideo, setRecordedVideo] = useState(null);

  const cameraRef = useRef();

  useLayoutEffect(() => {
    const getPermissions = async () => {
      const cameraPermission = await Camera.getCameraPermissionStatus();
      if (cameraPermission === 'not-determined') {
        const newCameraPermission = await Camera.requestCameraPermission();
        console.log('newCameraPermission', newCameraPermission);
      }
      const microphonePermission = await Camera.getMicrophonePermissionStatus();
      console.log('microphonePermission', microphonePermission);
      if (microphonePermission === 'not-determined') {
        const newMicrophonePermission =
          await Camera.requestMicrophonePermission();
        console.log('newMicrophonePermission', newMicrophonePermission);
      }
    };
    getPermissions();
  }, []);

  const onStartRecording = async () => {
    setRecordedVideo(null);
    setIsRecordingVide(true);
    console.log('cameraRef', cameraRef.current);
    cameraRef.current.startRecording({
      fileType: 'mp4',
      onRecordingFinished: async (video) => {
        console.log('onRecordingFinished', video);
        setRecordedVideo(video.path);
      },
      onRecordingError: (error) => {
        console.error('onRecordingError', error);
      },
    });
  };

  const onStopRecording = async () => {
    await cameraRef.current.stopRecording();
    setIsRecordingVide(false);
  };

  return (
    <SafeAreaView style={StyleSheet.absoluteFill}>
      <StatusBar barStyle="dark-content"/>
      <ScrollView contentInsetAdjustmentBehavior="automatic">
        
          <View style={styles.viewRecordVideo}>
            {devices.front && (
              <Camera
                ref={cameraRef}
                style={styles.recordVideo}
                device={devices.front}
                video={true}
                audio={true}
                isActive={true}
                preset="high"
              />
            )}
          </View>

        <View style={styles.viewButtons}>
          {isRecordingVide ? (
            <Pressable onPress={onStopRecording}>
              <Text style={styles.buttonText}>Stop record</Text>
            </Pressable>
          ) : (
            <Pressable onPress={onStartRecording}>
              <Text style={styles.buttonText}>Start record</Text>
            </Pressable>
          )}
        </View>

        <View style={styles.viewPlayer}>
          {recordedVideo && (
            <VLCPlayer
              style={styles.player}
              resizeMode="contain"
              repeat={true}
              source={{uri: recordedVideo}}
            />
          )}
        </View>
        <View style={styles.viewButtons}>
          <Pressable
            onPress={() => setRecordedVideo(null)}>
            <Text style={styles.buttonText}>Remove video</Text>
          </Pressable>
        </View>
      </ScrollView>
    </SafeAreaView>
  );
};


const styles = StyleSheet.create({
  viewPlayer: {
    width: '100%',
    height: 220,
  },
  player: {
    flex: 1,
  },

  viewRecordVideo: {
    width: '100%',
    height: 300,
  },
  recordVideo: {
    flex: 1,
  },

  viewButtons: {
    flex: 1,
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'center',
    width: '100%',
    height: 50,
    backgroundColor: `black`
  },
  buttonText: {
    padding: 10,
    fontSize: 20,
    color: 'white',
    borderWidth: 1,
    borderColor: 'white',
    borderRadius: 8,
  },
});


export default AppVisionCamera;

What happened instead?

When I playback recorded video with preset="iframe-1280x720 or iframe-960x540" I have stretched video. You can see a bug on this video

Relevant log output

No response

Device

iPhone 7 (IOS 15.0)

VisionCamera Version

2.8.0

Additional information

HorbachAndrii avatar Sep 23 '21 13:09 HorbachAndrii

update: When I added props fps={24} to Camera component, video doesn't stretched anymore

HorbachAndrii avatar Sep 23 '21 13:09 HorbachAndrii

Are you sure that the video is not just streched because your <Video> component is stretched? What resizeMode did you pass to the <Video> component?

mrousavy avatar Sep 24 '21 07:09 mrousavy

yes, I'm sure. I did download the recorded video and watched it on my computer and the video also was be stretched.

HorbachAndrii avatar Sep 24 '21 07:09 HorbachAndrii

Does it work if you don't use the preset?

mrousavy avatar Sep 27 '21 08:09 mrousavy

If I don't use preset, recording video works well. I mean recorded video will not be stretched.

HorbachAndrii avatar Sep 28 '21 10:09 HorbachAndrii

For me preset seems to work fine with mp4, however when adding videoCodec as h264 (so it can be viewed in chrome) is when the video stretches.

Any ideas if it can be resolved?

We need to record in mp4 not mov because of a service we use, however chrome will only show videos in h264

   flash: "off",
   fileType: "mp4",
   onRecordingFinished,
   onRecordingError,
 };

 if (availableCodes.includes("h264")) {
   cameraOptions.videoCodec = "h264"; // video stretches if codec is h264
 }```

  ```<Camera
     ref={camera}
     style={StyleSheet.absoluteFill}
     device={device}
     preset="iframe-1280x720"
     orientation="portrait"
     onError={onCameraError}
     video
     audio
     isActive={isActive}
   />```

dylan-westbury avatar May 26 '22 04:05 dylan-westbury

@dylan-westbury

For works well. Using react-native-vision-camera: 2.12.1

const newVideoPath = await new Promise((resolve, reject) => {
  cameraRef.current.startRecording({
    fileType: `mp4`,
    videoCodec: Platform.OS === `android` ? undefined : `h264`,
    onRecordingFinished: (video) => {
      resolve(video.path);
    },
    onRecordingError: (error) => {
      reject(error);
    },
  });
});
<Camera
  style={styles.camera}
  ref={cameraRef}
  device={device}
  video={true}
  audio={true}
  isActive={true}
  fps={25}
  preset="iframe-960x540"
  orientation="portrait"
  onInitialized={() => setCameraIsReady(true)}
  onError={(error) => {
    console.log(`Camera onError`, error);
  }}
/>

HorbachAndrii avatar May 26 '22 08:05 HorbachAndrii

have "stretched" video on iphone 12 mini iOS 16.4.1 in case if recording uses h264 codec and camera preset is medium or low. In case if no preset video is ok. Adding fps={25} fixed the issue.

recording- cameraRef.current.startRecording({ // flash: flash, videoCodec: 'h264', fileType: 'mp4', onRecordingError: (error) => { console.error('### Recording failed!', error) }, onRecordingFinished: (video) => { console.log(Recording successfully finished! ${video.path}) onMediaCaptured(video) }, })

    camera- `<CameraView
      ref={cameraRef}
      device={device}
      isActive={true}
      onInitialized={onInitialized}
      onError={(err) => {
        console.log('### error:', err)
      }}
      enableZoomGesture={false}
      photo={true}
      video={true}
      audio={true}
      orientation="portrait"
      preset="medium"
  />`
    
    this works well - `<CameraView
      ref={cameraRef}
      device={device}
      isActive={true}
      onInitialized={onInitialized}
      onError={(err) => {
        console.log('### error:', err)
      }}
      enableZoomGesture={false}
      photo={true}
      video={true}
      audio={true}
      orientation="portrait"
      preset="medium"
      fps={25}
    />`

TexxUkr avatar May 15 '23 18:05 TexxUkr

Hey!

After 8 hours of debugging, I finally found the culprit! I fixed the preview stretching issue in this PR: https://github.com/mrousavy/react-native-vision-camera/pull/2377

If you appreciate my dedication and free support, please consider 💖 sponsoring me on GitHub 💖 so I can keep providing fixes and building out new features for my open-source libraries in my free time.

mrousavy avatar Jan 11 '24 15:01 mrousavy