react-native-video
Advanced tools
@@ -18,14 +18,14 @@ // | ||
| } | ||
| let supportedExternalSubtitles = config.externalSubtitles?.filter { subtitle in | ||
| ExternalSubtitlesUtils.isSubtitleTypeSupported(subtitle: subtitle) | ||
| } | ||
| if supportedExternalSubtitles?.isEmpty == true { | ||
| return AVPlayerItem(asset: asset) | ||
| } | ||
| if asset.url.pathExtension == "m3u8" { | ||
| let supportedExternalSubtitles = config.externalSubtitles?.filter { subtitle in | ||
| ExternalSubtitlesUtils.isSubtitleTypeSupported(subtitle: subtitle) | ||
| } | ||
| if supportedExternalSubtitles?.isEmpty == true { | ||
| return AVPlayerItem(asset: asset) | ||
| } else { | ||
| return try await ExternalSubtitlesUtils.modifyStreamManifestWithExternalSubtitles( | ||
| for: asset, config: config) | ||
| } | ||
| } | ||
@@ -32,0 +32,0 @@ |
@@ -16,2 +16,3 @@ import AVFoundation | ||
| print("[ReactNativeVideo] Unsupported external subtitle. Expected VTT. uri: \(subtitle.uri)") | ||
| return false | ||
@@ -24,69 +25,63 @@ } | ||
| ) async throws -> AVPlayerItem { | ||
| let subtitlesAssets = try config.externalSubtitles?.map { subtitle in | ||
| let supportedSubtitles = (config.externalSubtitles ?? []).filter { subtitle in | ||
| isSubtitleTypeSupported(subtitle: subtitle) | ||
| } | ||
| let subtitleAssets: [AVURLAsset] = try supportedSubtitles.map { subtitle in | ||
| guard let url = URL(string: subtitle.uri) else { | ||
| throw PlayerError.invalidTrackUrl(url: subtitle.uri).error() | ||
| } | ||
| return AVURLAsset(url: url) | ||
| } | ||
| do { | ||
| let mainVideoTracks = asset.tracks(withMediaType: .video) | ||
| let mainAudioTracks = asset.tracks(withMediaType: .audio) | ||
| let textTracks = | ||
| subtitlesAssets?.flatMap { $0.tracks(withMediaType: .text) } ?? [] | ||
| let mainDuration = try await asset.load(.duration) | ||
| let composition = AVMutableComposition() | ||
| let composition = AVMutableComposition() | ||
| if let videoTrack = mainVideoTracks.first(where: { $0.mediaType == .video }){ | ||
| if let compositionVideoTrack = composition.addMutableTrack( | ||
| withMediaType: .video, | ||
| preferredTrackID: kCMPersistentTrackID_Invalid | ||
| ) { | ||
| try compositionVideoTrack.insertTimeRange( | ||
| CMTimeRange(start: .zero, duration: videoTrack.timeRange.duration), | ||
| of: videoTrack, | ||
| at: .zero | ||
| ) | ||
| } | ||
| } | ||
| let tracks = try await asset.load(.tracks) | ||
| for track in tracks { | ||
| guard let compTrack = composition.addMutableTrack( | ||
| withMediaType: track.mediaType, | ||
| preferredTrackID: kCMPersistentTrackID_Invalid | ||
| ) else { continue } | ||
| if let audioTrack = mainAudioTracks.first(where: { $0.mediaType == .audio }) { | ||
| if let compositionAudioTrack = composition.addMutableTrack( | ||
| withMediaType: .audio, | ||
| preferredTrackID: kCMPersistentTrackID_Invalid | ||
| ) { | ||
| try compositionAudioTrack.insertTimeRange( | ||
| CMTimeRange(start: .zero, duration: audioTrack.timeRange.duration), | ||
| of: audioTrack, | ||
| at: .zero | ||
| ) | ||
| } | ||
| do { | ||
| try compTrack.insertTimeRange( | ||
| CMTimeRange(start: .zero, duration: mainDuration), | ||
| of: track, | ||
| at: .zero | ||
| ) | ||
| } catch { | ||
| print("[ReactNativeVideo] Error inserting main track \(track.mediaType.rawValue): \(error.localizedDescription)") | ||
| } | ||
| } | ||
| for textTrack in textTracks { | ||
| if let compositionTextTrack = composition.addMutableTrack( | ||
| withMediaType: .text, | ||
| preferredTrackID: kCMPersistentTrackID_Invalid | ||
| ) { | ||
| do { | ||
| try compositionTextTrack.insertTimeRange( | ||
| CMTimeRange(start: .zero, duration: textTrack.timeRange.duration), | ||
| of: textTrack, | ||
| at: .zero | ||
| ) | ||
| } catch { | ||
| print( | ||
| "[ReactNativeVideo] Failed to insert text track into composition: \(error.localizedDescription). Language: \(textTrack.languageCode ?? "unknown"). Continuing without this subtitle track." | ||
| ) | ||
| continue | ||
| } | ||
| for subtitleAsset in subtitleAssets { | ||
| let track: AVAssetTrack? = try await subtitleAsset.loadTracks(withMediaType: .text).first | ||
| compositionTextTrack.languageCode = textTrack.languageCode | ||
| compositionTextTrack.isEnabled = true | ||
| } | ||
| guard let track else { continue } | ||
| guard let compSubtitleTrack = composition.addMutableTrack( | ||
| withMediaType: track.mediaType, | ||
| preferredTrackID: kCMPersistentTrackID_Invalid | ||
| ) else { continue } | ||
| do { | ||
| let trackRange = try await track.load(.timeRange) | ||
| let effectiveDuration = CMTimeMinimum(trackRange.duration, mainDuration) | ||
| try compSubtitleTrack.insertTimeRange( | ||
| CMTimeRange(start: .zero, duration: effectiveDuration), | ||
| of: track, | ||
| at: .zero | ||
| ) | ||
| compSubtitleTrack.languageCode = try await track.load(.languageCode) | ||
| compSubtitleTrack.isEnabled = true | ||
| } catch { | ||
| print("[ReactNativeVideo] Error inserting subtitle track: \(error.localizedDescription)") | ||
| continue | ||
| } | ||
| } | ||
| return await AVPlayerItem(asset: composition) | ||
| } | ||
| return await AVPlayerItem(asset: composition) | ||
| } | ||
@@ -93,0 +88,0 @@ |
+1
-1
| { | ||
| "name": "react-native-video", | ||
| "version": "7.0.0-beta.3", | ||
| "version": "7.0.0-beta.4", | ||
| "description": "<Video /> Component for React Native", | ||
@@ -5,0 +5,0 @@ "source": "./src/index.tsx", |
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
1504171
-0.01%