mrousavy / react-native-vision-camera

๐Ÿ“ธ A powerful, high-performance React Native Camera library.
https://react-native-vision-camera.com
MIT License
7.28k stars 1.07k forks source link

๐Ÿ› onRecordingFinished returns width: 0, height: 0 on every recording #3115

Open ChristopherGabba opened 1 month ago

ChristopherGabba commented 1 month ago

What's happening?

No matter which camera I use (front or back) on my iPhone 12 physical device, I'm getting the width and height of 0.

const onRecordingFinished = useCallback(
    async (video: VideoFile) => {
      console.log("Finished recording with", JSON.stringify(video, null, 4))
      setVideoUrl(video.path)
    },
    [setVideoUrl],
  )
Finished recording with {
    "path": "file:///private/var/mobile/Containers/Data/Application/19DBB76D-4103-4B38-AC3A-C57B843D3189/tmp/14C46EA6-AD67-4E6B-88C2-C1BFCFE7C83D.mp4",
    "width": 0,
    "height": 0,
    "duration": 5.033449333
}

Reproduceable Code

import { observer } from "mobx-react-lite"
import React, { FC, useCallback, useEffect, useMemo, useRef, useState } from "react"
import { View, ViewStyle } from "react-native"
import { DraggableOverlay } from "./DraggableOverlay"
import { MediaPlayer } from "./MediaPlayer"
import { AppStackScreenProps } from "app/navigators"
import { aS, colors, layout } from "../../theme"
import {
  Camera,
  CameraCaptureError,
  CameraRuntimeError,
  VideoFile,
  useCameraDevice,
  useCameraFormat,
  useFrameProcessor,
} from "react-native-vision-camera"
import {
  Face,
  useFaceDetector,
  FaceDetectionOptions,
} from "react-native-vision-camera-face-detector"
import { Worklets } from "react-native-worklets-core"
import {
  useIsForeground,
  useTimeout,
  useVideoLoadingError,
  useRecordingVolumeManager,
} from "app/hooks"
import { SharedTransitionAndSwipeDownWrapper } from "app/screens/MediaScreens/SharedTransitionAndSwipeDownWrapper"
import { reportCrash } from "app/utils/crashReporting"
import { CountdownTimer } from "./CountdownTimer"
import { PlayerStates } from "./media.types"
import { TimerStatus } from "./timer.types"
import { VolumeManager } from "react-native-volume-manager"
import { useIsFocused } from "@react-navigation/native"
import { EndRecordingButton } from "./EndRecordingButton"
import { TimerBar } from "./TimerBar"
import { AVPlaybackStatus, Audio, Video } from "expo-av"
import { trackAnalytics } from "app/utils/analytics"
import * as Haptics from "expo-haptics"
import { SmileData, generateLaughData } from "app/utils/generateLaughData"
import { generateThumbnailFromVideo } from "app/utils/generateThumbnail"
import NetInfo from "@react-native-community/netinfo"
import { fixLocalPath } from "app/utils/commonFunctions"
import { BlurView } from "expo-blur"

interface RecordingProps extends AppStackScreenProps<"RecordingTest"> {}

export const RecordingTestScreen: FC<RecordingProps> = observer(function RecordingTestScreen(
  _props, // @demo remove-current-line
) {
  const { navigation } = _props
  // #region - initializations
  const cameraRef = useRef<Camera | null>(null)

  const [mediaPlayerReady, setMediaPlayerReady] = useState(false)
  const [cameraReady, setCameraReady] = useState(false)

  const faceDetectionOptions = useRef<FaceDetectionOptions>({
    // detection options
    classificationMode: "all",
  }).current
  const videoFrameCount = useRef(0)
  const [smilePeakTimestamp, setSmilePeakTimestamp] = useState<number>()
  const { detectFaces } = useFaceDetector(faceDetectionOptions)
  const smileData = useRef<SmileData[]>([])
  const isFocused = useIsFocused()
  const isForeground = useIsForeground()

  const isActive = useMemo(() => {
    return isFocused && isForeground
  }, [isFocused, isForeground])

  const device = useCameraDevice("back")
  const [targetFps] = useState(30)

  // console.log(JSON.stringify(device, (k, v) => k === "formats" ? [] : v, 2))
  const format = useCameraFormat(device, [
    { videoStabilizationMode: "standard" },
    { fps: targetFps },
    { videoAspectRatio: 16 / 9 },
    { videoResolution: { width: 308, height: 548 } },
    { photoAspectRatio: 16 / 9 },
    { photoResolution: { width: 308, height: 548 } },
  ])

  // #endregion

  const { isUsingHeadphones } = useRecordingVolumeManager({ isMuted: false })

  const [playStatus, setPlayStatus] = useState<PlayerStates>("unstarted")
  const [initialCountTimerStatus, setInitialCountdownTimerStatus] =
    useState<TimerStatus>("unstarted")

  const [videoUrl, setVideoUrl] = useState("")

  const [mediaError, setMediaError] = useState(false)
  const [cameraError, setCameraError] = useState<
    CameraCaptureError | CameraRuntimeError | unknown
  >()

  useEffect(() => {
    if (cameraReady && mediaPlayerReady) {
      setInitialCountdownTimerStatus("play")
    }
  }, [cameraReady, mediaPlayerReady])

  /**
   * This keeps track of the overall video duration as soon as
   * the play status is set to "play",
   * TODO: add automatic pause sequencing here on video buffer
   */
  useTimeout({
    initiate: playStatus === "playing",
    initialValue: 30,
    onCountdownComplete: () => {
      setPlayStatus("completed")
    },
  })

  useEffect(() => {
    if (!isForeground && !videoUrl) {
      cameraRef.current?.stopRecording()
      navigation.goBack()
    }
  }, [isForeground, videoUrl])

  const onPlayerReady = useCallback(() => {
    setMediaPlayerReady(true)
  }, [setMediaPlayerReady])

  const onRecordingFinished = useCallback(
    async (video: VideoFile) => {
      console.log("Finished recording with", JSON.stringify(video, null, 4))
      const { smilePeakTimestamp } = generateLaughData({
        smileData: smileData.current,
        frameRate: targetFps,
      })
      const recordedPath = fixLocalPath(video.path)
      const fallbackTimestamp = video.duration * 0.95
      const thumbnailTimestamp = Math.round(smilePeakTimestamp ?? fallbackTimestamp)

      const thumbnail = await generateThumbnailFromVideo(recordedPath, thumbnailTimestamp)

      if (!thumbnail) {
        setCameraError("Thumbnail Failure")
        return
      }
      setSmilePeakTimestamp(smilePeakTimestamp)
      setVideoUrl(video.path)
    },
    [setCameraError, setSmilePeakTimestamp, setVideoUrl],
  )

  /**
   * Begin the recording sequence and media playback
   */

  async function startEverything() {
    setInitialCountdownTimerStatus("stop")
    setPlayStatus("playing")
    await Audio.setAudioModeAsync({
      playsInSilentModeIOS: true,
    })
    cameraRef.current?.startRecording({
      fileType: "mp4",
      onRecordingFinished,
      onRecordingError: (error) => {
        setPlayStatus("stopped")
        setCameraError(error)
        alert(error)
      },
    })
  }

  /**
   * Callback to tell the camera to stop recording and
   * the video to stop playing
   */
  async function stopEverything() {
    try {
      setPlayStatus("stopped")
      await cameraRef.current?.stopRecording()
      await Audio.setAudioModeAsync({
        playsInSilentModeIOS: true,
        allowsRecordingIOS: false,
      })
      navigation.goBack()
    } catch (error) {
      reportCrash({ error, method: "stopEverything", screen: "Recording" })
    }
  }

  async function cancelEverything() {
    try {
      setPlayStatus("stopped")
      await cameraRef.current?.cancelRecording()
    } catch (error) {
      reportCrash({ error, method: "cancelEverything", screen: "Recording" })
    }
  }

  const onPlayerError = useCallback(
    async (error: string) => {
      setMediaError(true)
      cancelEverything()
      reportCrash({
        error,
        method: "onPlayerError",
        screen: "Recording",
      })
    },
    [setMediaError],
  )

  const onCameraError = useCallback(
    (error: CameraRuntimeError) => {
      Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error)
      switch (error.code) {
        case "session/audio-in-use-by-other-app":
          {
            alert("The camera or microphone is in use by another app")
            setPlayStatus("stopped")
            navigation.goBack()
          }
          return
        default: {
          trackAnalytics({
            event: "Camera Error",
            properties: {
              Error: error.code,
            },
          })
          reportCrash({
            error,
            method: "onCameraError",
            screen: "Recording",
          })
        }
      }
    },
    [setPlayStatus],
  )

  const handlePlayerStateChange = useCallback(
    (e: AVPlaybackStatus) => {
      if (e.isLoaded) {
        if (e.isBuffering) {
          cameraRef.current?.pauseRecording()
        } else if (e.isPlaying) {
          cameraRef.current?.resumeRecording()
        }
      }
    },
    [cameraRef.current, initialCountTimerStatus],
  )

  const onPreviewStarted = useCallback(() => {
    setCameraReady(true)
  }, [setCameraReady])

  const handleDetectedFaces = Worklets.createRunOnJS((faces: Face[]) => {
    videoFrameCount.current++
    if (faces.length === 0) return
    smileData.current.push({
      frame: videoFrameCount.current,
      probability: faces[0].smilingProbability,
    })
  })

  const frameProcessor = useFrameProcessor(
    (frame) => {
      "worklet"
      const faces = detectFaces(frame)
      // ... chain frame processors
      // ... do something with frame
      handleDetectedFaces(faces)
    },
    [handleDetectedFaces],
  )

  const onSwipeDownComplete = useCallback(() => {
    navigation.goBack()
  }, [])

  return (
    <SharedTransitionAndSwipeDownWrapper
      reset={playStatus === "playing"}
      disabled={playStatus !== "unstarted"}
      onSwipeDownComplete={onSwipeDownComplete}
    >
      <View style={$container}>
        <View style={$mediaContainer}>
          <Video
            shouldPlay={playStatus === "playing"}
            style={{ width: "100%", height: "100%" }}
            source={{
              uri: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4",
            }}
            onError={onPlayerError}
            volume={isUsingHeadphones ? 0.6 : 1.0}
            onReadyForDisplay={onPlayerReady}
            onPlaybackStatusUpdate={handlePlayerStateChange}
          />
          <TimerBar durationInSeconds={30} shouldPlay={playStatus === "playing"} />
        </View>
        <EndRecordingButton
          onPress={stopEverything}
          disabled={playStatus === "unstarted" || playStatus === "stopped"}
        />

        <DraggableOverlay visible={!videoUrl}>
          {device && (
            <Camera
              ref={cameraRef}
              video={true}
              audio={true}
              lowLightBoost={device?.supportsLowLightBoost}
              photo={true}
              format={format}
              isActive={isActive}
              device={device}
              exposure={0}
              outputOrientation="preview"
              frameProcessor={frameProcessor}
              style={$camera}
              onPreviewStarted={onPreviewStarted}
              onError={onCameraError}
            />
          )}
        </DraggableOverlay>
      </View>
      {playStatus === "unstarted" && (
        <BlurView
          style={{
            position: "absolute",
            width: "100%",
            height: "100%",
            justifyContent: "center",
            alignItems: "center",
          }}
          intensity={85}
        >
          <CountdownTimer
            initialValue={3}
            status={initialCountTimerStatus}
            setStatus={setInitialCountdownTimerStatus}
            onTimerComplete={startEverything}
          />
        </BlurView>
      )}
    </SharedTransitionAndSwipeDownWrapper>
  )
})

const $finalCountdownContainer: ViewStyle = {
  position: "absolute",
  bottom: aS(195),
  right: aS(10),
}

const $container: ViewStyle = {
  flex: 1,
  width: "100%",
  height: "100%",
}

const $mediaContainer: ViewStyle = {
  flexBasis: "79%",
  justifyContent: "center",
  alignItems: "center",
  backgroundColor: colors.background,
  width: layout.screenWidth,
  height: layout.screenHeight,
  zIndex: 0,
}

const $camera: ViewStyle = {
  flex: 1,
  backgroundColor: "white",
}

Relevant log output

Looking up Frame Processor Plugin "detectFaces"...
Frame Processor Plugin "detectFaces" found! Initializing...
2024-08-03 17:23:04.233 ReelFeel[51789/0x16d5af000] [lvl=3] +[MLKITx_CCTClearcutUploader crashIfNecessary] Multiple instances of CCTClearcutUploader were instantiated. Multiple uploaders function correctly but have an adverse affect on battery performance due to lock contention.
Initialized TensorFlow Lite runtime.
INFO: Initialized TensorFlow Lite runtime.
Created TensorFlow Lite XNNPACK delegate for CPU.
INFO: Created TensorFlow Lite XNNPACK delegate for CPU.
17:23:04.567: [info] ๐Ÿ“ธ VisionCamera.constantsToExport(): Found 5 initial Camera Devices.
๐ŸŸข Creating JS object for module 'ExpoVideoView'
CGAffineTransformInvert: singular matrix.
[E] <MMKV.cpp:985::getDouble> reach end, m_position: 2, m_size: 2
17:23:04.704: [info] ๐Ÿ“ธ VisionCamera.didSetProps(_:): Updating 26 props: [onInitialized, cameraId, enableBufferCompression, preview, onOutputOrientationChanged, onCodeScanned, onStarted, lowLightBoost, backgroundColor, isActive, isMirrored, onViewReady, onError, onStopped, video, onPreviewOrientationChanged, onPreviewStopped, enableFrameProcessor, onPreviewStarted, format, flex, audio, outputOrientation, exposure, photo, onShutter]
17:23:04.705: [info] ๐Ÿ“ธ VisionCamera.configurePreviewOrientation(_:): Updating Preview rotation: landscapeLeft...
17:23:04.705: [info] ๐Ÿ“ธ VisionCamera.configureOutputOrientation(_:): Updating Outputs rotation: landscapeLeft...
17:23:04.705: [info] ๐Ÿ“ธ VisionCamera.configure(_:): configure { ... }: Waiting for lock...
17:23:04.708: [info] ๐Ÿ“ธ VisionCamera.configure(_:): configure { ... }: Updating CameraSession Configuration... Difference(inputChanged: true, outputsChanged: true, videoStabilizationChanged: true, orientationChanged: true, formatChanged: true, sidePropsChanged: true, torchChanged: true, zoomChanged: true, exposureChanged: true, audioSessionChanged: true, locationChanged: true)
17:23:04.708: [info] ๐Ÿ“ธ VisionCamera.configureDevice(configuration:): Configuring Input Device...
17:23:04.708: [info] ๐Ÿ“ธ VisionCamera.configureDevice(configuration:): Configuring Camera com.apple.avfoundation.avcapturedevice.built-in_video:0...
17:23:04.723: [debug] ๐Ÿ“ธ VisionCamera.sensorOrientation: Sensor Orientation changed from landscapeLeft -> portrait
17:23:04.723: [info] ๐Ÿ“ธ VisionCamera.configurePreviewOrientation(_:): Updating Preview rotation: portrait...
17:23:04.723: [info] ๐Ÿ“ธ VisionCamera.configureOutputOrientation(_:): Updating Outputs rotation: portrait...
17:23:04.723: [info] ๐Ÿ“ธ VisionCamera.configureDevice(configuration:): Successfully configured Input Device!
17:23:04.723: [info] ๐Ÿ“ธ VisionCamera.configureOutputs(configuration:): Configuring Outputs...
17:23:04.723: [info] ๐Ÿ“ธ VisionCamera.configureOutputs(configuration:): Adding Photo output...
17:23:04.728: [info] ๐Ÿ“ธ VisionCamera.configureOutputs(configuration:): Adding Video Data output...
17:23:04.729: [info] ๐Ÿ“ธ VisionCamera.configurePreviewOrientation(_:): Updating Preview rotation: portrait...
17:23:04.729: [info] ๐Ÿ“ธ VisionCamera.configureOutputOrientation(_:): Updating Outputs rotation: portrait...
17:23:04.729: [info] ๐Ÿ“ธ VisionCamera.configureOutputs(configuration:): Successfully configured all outputs!
17:23:04.731: [info] ๐Ÿ“ธ VisionCamera.setTargetOutputOrientation(_:): Setting target output orientation from device to preview...
17:23:04.731: [info] ๐Ÿ“ธ VisionCamera.configureFormat(configuration:device:): Configuring Format (4224x2384 | 960x540@60.0 (ISO: 33.0..3168.0))...
17:23:04.732: [info] ๐Ÿ“ธ VisionCamera.configureFormat(configuration:device:): Successfully configured Format!
17:23:04.734: [info] ๐Ÿ“ธ VisionCamera.getPixelFormat(for:): Available Pixel Formats: ["420v", "420f", "BGRA", "&8v0", "&8f0", "&BGA"], finding best match... (pixelFormat="yuv", enableHdr={false}, enableBufferCompression={false})
17:23:04.734: [info] ๐Ÿ“ธ VisionCamera.getPixelFormat(for:): Using PixelFormat: 420f...
17:23:04.984: [info] ๐Ÿ“ธ VisionCamera.init(frame:session:): Preview Layer started previewing.
17:23:04.985: [info] ๐Ÿ“ธ VisionCamera.configure(_:): Beginning AudioSession configuration...
17:23:04.986: [info] ๐Ÿ“ธ VisionCamera.configureAudioSession(configuration:): Configuring Audio Session...
17:23:04.986: [info] ๐Ÿ“ธ VisionCamera.configureAudioSession(configuration:): Adding Audio input...
17:23:04.989: [info] ๐Ÿ“ธ VisionCamera.configure(_:): Beginning Location Output configuration...
17:23:04.999: [info] ๐Ÿ“ธ VisionCamera.configureAudioSession(configuration:): Adding Audio Data output...
17:23:05.001: [info] ๐Ÿ“ธ VisionCamera.configure(_:): Committed AudioSession configuration!
17:23:05.061: [info] ๐Ÿ“ธ VisionCamera.configure(_:): Finished Location Output configuration!
Main thread blocked by synchronous property query on not-yet-loaded property (NaturalSize) for HTTP(S) asset. This could have been a problem if this asset were being read from a slow network.
Main thread blocked by synchronous property query on not-yet-loaded property (PreferredTransform) for HTTP(S) asset. This could have been a problem if this asset were being read from a slow network.
[I] <libMMKV.mm:301::-[MMKV onMemoryWarning]> cleaning on memory warning mmkv.default
[I] <MMKV.cpp:307::clearMemoryCache> clearMemoryCache [mmkv.default]
[I] <MemoryFile.cpp:104::close> closing fd[0x10], /var/mobile/Containers/Data/Application/D91FE63C-1122-46D1-98E4-BA3FF7A9AF82/Documents/mmkv/mmkv.default
WARNING: Logging before InitGoogleLogging() is written to STDERR
I0803 17:23:08.729192 1834676224 JSIExecutor.cpp:348] Memory warning (pressure level: TRIM_MEMORY_RUNNING_CRITICAL) received by JS VM, running a GC
tcp_input [C11.1.1.1:3] flags=[R] seq=2283506070, ack=0, win=0 state=LAST_ACK rcv_nxt=2283506071, snd_una=2703863518
tcp_input [C11.1.1.1:3] flags=[R] seq=2283506070, ack=0, win=0 state=LAST_ACK rcv_nxt=2283506071, snd_una=2703863518
tcp_input [C11.1.1.1:3] flags=[R] seq=2283506071, ack=0, win=0 state=LAST_ACK rcv_nxt=2283506071, snd_una=2703863518
tcp_input [C11.1.1.1:3] flags=[R] seq=2283506071, ack=0, win=0 state=CLOSED rcv_nxt=2283506071, snd_una=2703863518
tcp_output [C10.1.1.1:3] flags=[R.] seq=3961394724, ack=1667659849, win=2047 state=CLOSED rcv_nxt=1667659849, snd_una=3961394661
17:23:11.673: [info] ๐Ÿ“ธ VisionCamera.startRecording(options:onVideoRecorded:onError:): Starting Video recording...
17:23:11.682: [info] ๐Ÿ“ธ VisionCamera.startRecording(options:onVideoRecorded:onError:): Will record to temporary file: file:///private/var/mobile/Containers/Data/Application/D91FE63C-1122-46D1-98E4-BA3FF7A9AF82/tmp/0AE474EB-D396-47BC-9585-40D0E1474418.mp4
17:23:11.683: [info] ๐Ÿ“ธ VisionCamera.init(url:fileType:metadataProvider:clock:orientation:completion:): Creating RecordingSession... (orientation: landscapeLeft)
17:23:11.685: [info] ๐Ÿ“ธ VisionCamera.startRecording(options:onVideoRecorded:onError:): Enabling Audio for Recording...
17:23:11.685: [info] ๐Ÿ“ธ VisionCamera.activateAudioSession(): Activating Audio Session...
17:23:11.707: [info] ๐Ÿ“ธ VisionCamera.updateCategory(_:mode:options:): Changing AVAudioSession category from AVAudioSessionCategoryPlayback -> AVAudioSessionCategoryPlayAndRecord
17:23:11.714: [info] ๐Ÿ“ธ VisionCamera.initializeAudioTrack(withSettings:format:): Initializing Audio AssetWriter with settings: ["AVEncoderBitRateStrategyKey": AVAudioBitRateStrategy_Variable, "AVSampleRateKey": 44100, "AVNumberOfChannelsKey": 1, "AVEncoderQualityForVBRKey": 91, "AVFormatIDKey": 1633772320, "AVEncoderBitRatePerChannelKey": 96000]
17:23:11.721: [info] ๐Ÿ“ธ VisionCamera.initializeAudioTrack(withSettings:format:): Initialized Audio AssetWriter.
17:23:11.742: [info] ๐Ÿ“ธ VisionCamera.recommendedVideoSettings(forOptions:): Getting recommended video settings for AVFileType(_rawValue: public.mpeg-4) file...
17:23:11.847: [info] ๐Ÿ“ธ VisionCamera.updateCategory(_:mode:options:): AVAudioSession category changed!
17:23:11.871: [info] ๐Ÿ“ธ VisionCamera.activateAudioSession(): Audio Session activated!
17:23:11.979: [info] ๐Ÿ“ธ VisionCamera.initializeVideoTrack(withSettings:): Initializing Video AssetWriter with settings: ["AVVideoWidthKey": 960, "AVVideoCompressionPropertiesKey": {
    AllowFrameReordering = 1;
    AllowOpenGOP = 1;
    AverageBitRate = 4727808;
    ExpectedFrameRate = 30;
    MaxAllowedFrameQP = 41;
    MaxKeyFrameIntervalDuration = 1;
    MinAllowedFrameQP = 15;
    MinimizeMemoryUsage = 1;
    Priority = 80;
    ProfileLevel = "HEVC_Main_AutoLevel";
    RealTime = 1;
    RelaxAverageBitRateTarget = 1;
}, "AVVideoCodecKey": hvc1, "AVVideoHeightKey": 540]
17:23:11.986: [info] ๐Ÿ“ธ VisionCamera.initializeVideoTrack(withSettings:): Initialized Video AssetWriter.
17:23:11.986: [info] ๐Ÿ“ธ VisionCamera.start(): Starting Asset Writer...
17:23:16.172: [info] ๐Ÿ“ธ VisionCamera.start(): Asset Writer started!
17:23:16.172: [info] ๐Ÿ“ธ VisionCamera.start(): Asset Writer session started at 301972.368540291.
17:23:16.175: [info] ๐Ÿ“ธ VisionCamera.start(): Requesting video timeline start at 301972.369260666...
17:23:16.175: [info] ๐Ÿ“ธ VisionCamera.start(): Requesting audio timeline start at 301972.371443208...
17:23:16.175: [info] ๐Ÿ“ธ VisionCamera.startRecording(options:onVideoRecorded:onError:): RecordingSesssion started in 4501.861ms!
17:23:16.175: [info] ๐Ÿ“ธ VisionCamera.pause(): Pausing video timeline at 301972.3714855...
17:23:16.175: [info] ๐Ÿ“ธ VisionCamera.pause(): Pausing audio timeline at 301972.371496375...
17:23:16.175: [info] ๐Ÿ“ธ VisionCamera.pause(): Pausing video timeline at 301972.37157425...
17:23:16.175: [info] ๐Ÿ“ธ VisionCamera.pause(): Pausing audio timeline at 301972.371587333...
17:23:16.175: [info] ๐Ÿ“ธ VisionCamera.resume(): Resuming video timeline at 301972.371615916...
17:23:16.175: [info] ๐Ÿ“ธ VisionCamera.resume(): Resuming audio timeline at 301972.3716285...
17:23:16.181: [info] ๐Ÿ“ธ VisionCamera.resume(): Resuming video timeline at 301972.378242125...
17:23:16.181: [info] ๐Ÿ“ธ VisionCamera.resume(): Resuming audio timeline at 301972.378295958...
17:23:16.182: [info] ๐Ÿ“ธ VisionCamera.resume(): Resuming video timeline at 301972.378313708...
17:23:16.182: [info] ๐Ÿ“ธ VisionCamera.resume(): Resuming audio timeline at 301972.3783235...
17:23:16.182: [info] ๐Ÿ“ธ VisionCamera.resume(): Resuming video timeline at 301972.378338375...
17:23:16.182: [info] ๐Ÿ“ธ VisionCamera.resume(): Resuming audio timeline at 301972.378347291...
17:23:16.182: [info] ๐Ÿ“ธ VisionCamera.resume(): Resuming video timeline at 301972.378455541...
17:23:16.182: [info] ๐Ÿ“ธ VisionCamera.resume(): Resuming audio timeline at 301972.37849925...
17:23:16.182: [info] ๐Ÿ“ธ VisionCamera.resume(): Resuming video timeline at 301972.3785575...
17:23:16.182: [info] ๐Ÿ“ธ VisionCamera.resume(): Resuming audio timeline at 301972.378593208...
17:23:16.182: [info] ๐Ÿ“ธ VisionCamera.resume(): Resuming video timeline at 301972.378618291...
17:23:16.182: [info] ๐Ÿ“ธ VisionCamera.resume(): Resuming audio timeline at 301972.378713166...
17:23:16.183: [info] ๐Ÿ“ธ VisionCamera.isTimestampWithinTimeline(timestamp:): audio Timeline: First timestamp: 301972.2975208333
17:23:16.185: [info] ๐Ÿ“ธ VisionCamera.isTimestampWithinTimeline(timestamp:): video Timeline: First timestamp: 301972.347921333
17:23:16.199: [info] ๐Ÿ“ธ VisionCamera.stop(): Stopping Asset Writer with status "writing"...
17:23:16.199: [info] ๐Ÿ“ธ VisionCamera.stop(): Requesting video timeline stop at 301972.395569958...
17:23:16.199: [info] ๐Ÿ“ธ VisionCamera.stop(): Requesting audio timeline stop at 301972.395595375...
[I] <MMKV_IO.cpp:214::loadMetaInfoAndCheck> meta file [mmkv.default] has flag [0]
[I] <MemoryFile.cpp:98::open> open fd[0x1e], /var/mobile/Containers/Data/Application/D91FE63C-1122-46D1-98E4-BA3FF7A9AF82/Documents/mmkv/mmkv.default
[I] <MemoryFile.cpp:203::mmap> mmap to address [0x119400000], oldPtr [0x0], [/var/mobile/Containers/Data/Application/D91FE63C-1122-46D1-98E4-BA3FF7A9AF82/Documents/mmkv/mmkv.default]
[I] <MemoryFile_OSX.cpp:35::tryResetFileProtection> protection on [/var/mobile/Containers/Data/Application/D91FE63C-1122-46D1-98E4-BA3FF7A9AF82/Documents/mmkv/mmkv.default] is NSFileProtectionCompleteUntilFirstUserAuthentication
[I] <MMKV_IO.cpp:84::loadFromFile> loading [mmkv.default] with 216708 actual size, file size 524288, InterProcess 0, meta info version:4
[I] <MMKV_IO.cpp:89::loadFromFile> loading [mmkv.default] with crc 98401342 sequence 582 version 4
[I] <MMKV_IO.cpp:133::loadFromFile> loaded [mmkv.default] with 7 key-values
17:23:16.248: [info] ๐Ÿ“ธ VisionCamera.markAsFinished(lastTimestamp:stopTimestamp:): Last timestamp arrived at 301972.414583083 (0.019013125 seconds after stop()) - video Timeline is now finished!
17:23:16.248: [debug] ๐Ÿ“ธ VisionCamera.markAsFinished(lastTimestamp:stopTimestamp:): 301972.369260666: โบ๏ธ Started
301972.3714855: โธ๏ธ Paused
301972.37157425: โธ๏ธ Paused
301972.371615916: โ–ถ๏ธ Resumed
301972.378242125: โ–ถ๏ธ Resumed
301972.378313708: โ–ถ๏ธ Resumed
301972.378338375: โ–ถ๏ธ Resumed
301972.378455541: โ–ถ๏ธ Resumed
301972.3785575: โ–ถ๏ธ Resumed
301972.378618291: โ–ถ๏ธ Resumed
301972.395569958: โน๏ธ Stopped
17:23:16.255: [info] ๐Ÿ“ธ VisionCamera.append(buffer:): Marking video track as finished - target duration: CMTime(value: 26178876, timescale: 1000000000, flags: __C.CMTimeFlags(rawValue: 1), epoch: 0), actual duration: CMTime(value: 33200417, timescale: 1000000000, flags: __C.CMTimeFlags(rawValue: 1), epoch: 0) (0.007021541 seconds longer than expected)
[E] <MMKV.cpp:985::getDouble> reach end, m_position: 2, m_size: 2
17:23:16.289: [info] ๐Ÿ“ธ VisionCamera.markAsFinished(lastTimestamp:stopTimestamp:): Last timestamp arrived at 301972.4041875 (0.008592125 seconds after stop()) - audio Timeline is now finished!
17:23:16.289: [debug] ๐Ÿ“ธ VisionCamera.markAsFinished(lastTimestamp:stopTimestamp:): 301972.371443208: โบ๏ธ Started
301972.371496375: โธ๏ธ Paused
301972.371587333: โธ๏ธ Paused
301972.3716285: โ–ถ๏ธ Resumed
301972.378295958: โ–ถ๏ธ Resumed
301972.3783235: โ–ถ๏ธ Resumed
301972.378347291: โ–ถ๏ธ Resumed
301972.37849925: โ–ถ๏ธ Resumed
301972.378593208: โ–ถ๏ธ Resumed
301972.378713166: โ–ถ๏ธ Resumed
301972.395595375: โน๏ธ Stopped
17:23:16.290: [info] ๐Ÿ“ธ VisionCamera.append(buffer:): Marking audio track as finished - target duration: CMTime(value: 24020042, timescale: 1000000000, flags: __C.CMTimeFlags(rawValue: 1), epoch: 0), actual duration: CMTime(value: 85201208, timescale: 1000000000, flags: __C.CMTimeFlags(rawValue: 3), epoch: 0) (0.061181166 seconds longer than expected)
17:23:16.305: [info] ๐Ÿ“ธ VisionCamera.finish(): Stopping AssetWriter with status "writing"...
17:23:16.309: [info] ๐Ÿ“ธ VisionCamera.finish(): Asset Writer session stopped at 301972.38112175.
17:23:16.323: [info] ๐Ÿ“ธ VisionCamera.finish(): Asset Writer finished writing!
17:23:16.323: [info] ๐Ÿ“ธ VisionCamera.startRecording(options:onVideoRecorded:onError:): RecordingSession finished with status completed.
17:23:16.324: [info] ๐Ÿ“ธ VisionCamera.deactivateAudioSession(): Deactivating Audio Session...
'Finished recording with', '{\n    "path": "file:///private/var/mobile/Containers/Data/Application/D91FE63C-1122-46D1-98E4-BA3FF7A9AF82/tmp/0AE474EB-D396-47BC-9585-40D0E1474418.mp4",\n    "width": 0,\n    "height": 0,\n    "duration": 0.033200417\n}'
๐ŸŸข Creating JS object for module 'ExpoVideoThumbnails'
17:23:16.333: [info] ๐Ÿ“ธ VisionCamera.deactivateAudioSession(): Audio Session deactivated!

Camera Device

{
  "position": "back",
  "hardwareLevel": "full",
  "maxZoom": 123.75,
  "id": "com.apple.avfoundation.avcapturedevice.built-in_video:0",
  "sensorOrientation": "portrait",
  "formats": [],
  "supportsFocus": true,
  "supportsRawCapture": false,
  "neutralZoom": 1,
  "physicalDevices": [
    "wide-angle-camera"
  ],
  "isMultiCam": false,
  "supportsLowLightBoost": false,
  "maxExposure": 8,
  "minFocusDistance": 12,
  "minExposure": -8,
  "name": "Back Camera",
  "hasFlash": true,
  "minZoom": 1,
  "hasTorch": true
}

Device

iPhone 12 Physical

VisionCamera Version

4.5.1

Can you reproduce this issue in the VisionCamera Example app?

Yes, I can reproduce the same issue in the Example app here

Additional information

maintenance-hans[bot] commented 1 month ago

Guten Tag, Hans here.

It seems you are encountering a bug with onRecordingFinished returning width and height of 0. Please ensure that the camera settings and permissions are correctly configured in your application. It would be helpful to provide more details about your setup or any specific steps that lead to this issue.

Additionally, if you wish for more in-depth support from ze mrousavy and ze team, consider supporting the project by sponsoring. This helps keep ze project active and allows for quicker responses on issues.

Danke schรถn!

Note: If you think I made a mistake by closing this issue, please ping @mrousavy to take a look.

vishalyad16 commented 1 month ago

@ChristopherGabba How can I reduce the size of a video that is 151 MB for a 1-minute recording? The bitRate setting does not seem to be working. https://github.com/mrousavy/react-native-vision-camera/issues/3113

ChristopherGabba commented 1 month ago

I have provided my entire setup in the details above, not sure what else I could provide. I'm also following all the steps in the docs unless I missed something that I'm not seeing.

Maybe this is related a pre-defined video resolution in the camera format (useCameraFormat). In that case shouldn't this return the predefined resolution?

stewartiee commented 1 month ago

I'm seeing the same after trying to upgrade from 4.3.2 -> latest.

Seems to be a bug introduced in 4.4.0, since that's where it starts to break for me, returning {width: 0, height: 0}.

Edit: Also appears to work on Android, just not iOS.

INFO {"format": {"autoFocusSystem": "phase-detection", "fieldOfView": 69.46971893310547, "maxFps": 60, "maxISO": 3264, "minFps": 1, "minISO": 34, "photoHeight": 2340, "photoWidth": 4160, "supportsDepthCapture": false, "supportsPhotoHdr": false, "supportsVideoHdr": false, "videoHeight": 540, "videoStabilizationModes": ["auto", "cinematic", "off", "standard", "cinematic-extended"], "videoWidth": 960}} INFO {"videoFile": {"duration": 1.666647041, "height": 0, "path": "file:///private/var/mobile/Containers/Data/Application/30BA39A7-BF93-4BE7-B19C-2EDF73B610B7/tmp/0AA41CE1-CFD4-49D5-9016-8EB9101FDAD3.mov", "width": 0}}

@mrousavy Sorry, it said about to ping you if we think this is still an issue.

mrousavy commented 1 month ago

sorry the bot probably shouldn't have closed this.

thanks for letting me know, I'll try to find some time to look into this. sponsoring me will prioritize that ;)

ChristopherGabba commented 1 month ago

thanks for letting me know, I'll try to find some time to look into this. sponsoring me will prioritize that ;)

Done -- Even though this issue is relatively low priority, doesn't affect me that much just wanted to show some appreciation!

mrousavy commented 1 month ago

Thanks so much Christopher! :) ๐Ÿ™ โค๏ธ

mrousavy commented 1 month ago

Hm, I'm browsing the diff but I really can't see anything that might've broken the naturalSize getter, for me it's also always returning 0 now... Are you guys both sure that 4.3.2 worked fine?

mrousavy commented 1 month ago

Could this be an Xcode bug? lol.. I don't see how naturalSize can suddenly be 0x0 https://github.com/mrousavy/react-native-vision-camera/blob/77e98178f84824a0b1c76785469413b64dc96046/package/ios/Core/Recording/Track.swift#L59-L61

stewartiee commented 1 month ago

Hm, I'm browsing the diff but I really can't see anything that might've broken the naturalSize getter, for me it's also always returning 0 now... Are you guys both sure that 4.3.2 worked fine?

Yeah, you're totally correct. I'm not sure what I was seeing yesterday, but is indeed broken on 4.3.2 too.

ChristopherGabba commented 1 month ago

I unfortunately bumped mine from 4.0.4 all the way to 4.5.1 in one big jump. I truthfully cannot confirm if the issue was there in 4.0.4 but I never remember seeing it until this new version. So I can't be of much help in the immediate until I revert versions and bump up until I find it.

mrousavy commented 1 month ago

Okay I'll take another look at the changelog, maybe something was missing in the video configuration options

mrousavy commented 3 weeks ago

Hey @ChristopherGabba sorry this is going to take a bit longer than usually because I'm in the middle of finishing Nitro Modules, and then I'm going to leave for a 5 day vacation. It's on my TODO list, promised!

ChristopherGabba commented 3 weeks ago

@mrousavy nitro on brother, no worries! Enjoy your vacation

jcgoodru commented 1 day ago

Can confirm this is happening on Android as well (Pixel 5 emulator)