TheWidlarzGroup / react-native-video

A <Video /> component for react-native
http://thewidlarzgroup.github.io/react-native-video/
MIT License
7.14k stars 2.88k forks source link

[BUG]: EXC_BREAKPOINT RCTVideo.playerItemPrepareText for dead local files #3889

Closed iserzh closed 1 week ago

iserzh commented 3 months ago

Version

6.2.0

What platforms are you having the problem on?

iOS

System Version

17.5.1

On what device are you experiencing the issue?

Real device, Simulator

Architecture

Old architecture

What happened?

iOS Application is crashing when trying to load dead files from iCloud. I guess the best solution is to handle such kind of files and emit the onError callback

This error appears at this line

if (self._textTracks == nil) || self._textTracks?.isEmpty == true || (uri.hasSuffix(".m3u8")) {
  return await self.playerItemPropegateMetadata(AVPlayerItem(asset: asset))
}

with error for asset

Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value

Reproduction

repository link

Reproduction

It's hard to reproduce because there are no steps to make the video file dead as it bugs itself.

Here is how this asset might look

Just render this video as shown in the samples

Video
  source={{ uri: sourceUri }}
  style={[styles.video, { height }]}
  ref={videoRef}
  onError={onError}
/>
freeboub commented 3 months ago

Can you clarify what is a dead video for you ?

iserzh commented 3 months ago

@freeboub as I show on the screenshot - video that can't be loaded even with the native Photo app

freeboub commented 3 months ago

@iserzh so it is just a corrupted file ? Which format do you use ? Mp4 ?

iserzh commented 3 months ago

@freeboub yep, it's mp4

freeboub commented 3 months ago

OK, clear thank you for all informations. but if you can provide a corrupted video url, it would really be easier to debug ...

iserzh commented 3 months ago

@freeboub it's a local file from PhotoLibrary

freeboub commented 3 months ago

Ok, thank you, So I cannot reproduce it :/ I am trying to identify what can be the issue, but I am not able to point some line of code yet ... Can you provide the callstack displayed in xcode please ? I would like to understand where the crash is in: playerItemPropegateMetadata Maybe last log before the crash can be also useful

freeboub commented 3 months ago

maybe you can try this patch:

diff --git a/ios/Video/RCTVideo.swift b/ios/Video/RCTVideo.swift
index dc980600..def56ed9 100644
--- a/ios/Video/RCTVideo.swift
+++ b/ios/Video/RCTVideo.swift
@@ -587,39 +587,50 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
     }

     func playerItemPropegateMetadata(_ playerItem: AVPlayerItem!) async -> AVPlayerItem {
-        var mapping: [AVMetadataIdentifier: Any] = [:]
-
-        if let title = _source?.customMetadata?.title {
-            mapping[.commonIdentifierTitle] = title
-        }
+        do {
+            var mapping: [AVMetadataIdentifier: Any] = [:]

-        if let artist = _source?.customMetadata?.artist {
-            mapping[.commonIdentifierArtist] = artist
-        }
+            if let title = _source?.customMetadata?.title {
+                mapping[.commonIdentifierTitle] = title
+            }

-        if let subtitle = _source?.customMetadata?.subtitle {
-            mapping[.iTunesMetadataTrackSubTitle] = subtitle
-        }
+            if let artist = _source?.customMetadata?.artist {
+                mapping[.commonIdentifierArtist] = artist
+            }

-        if let description = _source?.customMetadata?.description {
-            mapping[.commonIdentifierDescription] = description
-        }
+            if let subtitle = _source?.customMetadata?.subtitle {
+                mapping[.iTunesMetadataTrackSubTitle] = subtitle
+            }

-        if let imageUri = _source?.customMetadata?.imageUri,
-           let imageData = await RCTVideoUtils.createImageMetadataItem(imageUri: imageUri) {
-            mapping[.commonIdentifierArtwork] = imageData
-        }
+            if let description = _source?.customMetadata?.description {
+                mapping[.commonIdentifierDescription] = description
+            }

-        if #available(iOS 12.2, *), !mapping.isEmpty {
-            playerItem.externalMetadata = RCTVideoUtils.createMetadataItems(for: mapping)
-        }
+            if let imageUri = _source?.customMetadata?.imageUri,
+               let imageData = try await RCTVideoUtils.createImageMetadataItem(imageUri: imageUri) {
+                mapping[.commonIdentifierArtwork] = imageData
+            }

-        #if os(tvOS)
-            if let chapters = _chapters {
-                playerItem.navigationMarkerGroups = RCTVideoTVUtils.makeNavigationMarkerGroups(chapters)
+            if #available(iOS 12.2, *), !mapping.isEmpty {
+                playerItem.externalMetadata = try RCTVideoUtils.createMetadataItems(for: mapping)
             }
-        #endif

+            #if os(tvOS)
+                if let chapters = _chapters {
+                    playerItem.navigationMarkerGroups = try RCTVideoTVUtils.makeNavigationMarkerGroups(chapters)
+                }
+            #endif
+        } catch {
+            DebugLog("An error occurred: \(error.localizedDescription)")
+
+            self.onVideoError?(["error": error.localizedDescription])
+            self.isSetSourceOngoing = false
+            self.applyNextSource()
+
+            if let player = self._player {
+                NowPlayingInfoCenterManager.shared.removePlayer(player: player)
+            }
+        }
         return playerItem
     }
iserzh commented 3 months ago

@freeboub unfortunately I also can't debug it since it was on the customer's device and only a trace from Sentry is available. I will try to simulate corrupted file and get back to you

github-actions[bot] commented 3 weeks ago

This issue is stale because it has been open for 30 days with no activity. If there won't be any activity in the next 14 days, this issue will be closed automatically.

github-actions[bot] commented 1 week ago

This issue was closed because it has been inactive for 14 days since being marked as stale.