Merge pull request #2679 from nbennink/fix/disable-sideloaded-texttracks
fix(texttracks): unable to disable sideloaded texttracks in the AVPlayer
This commit is contained in:
commit
41731a8117
@ -12,11 +12,13 @@ enum RCTPlayerOperations {
|
||||
static func setSideloadedText(player:AVPlayer?, textTracks:[TextTrack]?, criteria:SelectedTrackCriteria?) {
|
||||
let type = criteria?.type
|
||||
let textTracks:[TextTrack]! = textTracks ?? RCTVideoUtils.getTextTrackInfo(player)
|
||||
let trackCount:Int! = player?.currentItem?.tracks.count ?? 0
|
||||
|
||||
// The first few tracks will be audio & video track
|
||||
let firstTextIndex:Int = 0
|
||||
for firstTextIndex in 0..<(player?.currentItem?.tracks.count ?? 0) {
|
||||
if player?.currentItem?.tracks[firstTextIndex].assetTrack?.hasMediaCharacteristic(.legible) ?? false {
|
||||
var firstTextIndex:Int = 0
|
||||
for i in 0..<(trackCount) {
|
||||
if player?.currentItem?.tracks[i].assetTrack?.hasMediaCharacteristic(.legible) ?? false {
|
||||
firstTextIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
@ -24,7 +26,8 @@ enum RCTPlayerOperations {
|
||||
var selectedTrackIndex:Int = RCTVideoUnset
|
||||
|
||||
if (type == "disabled") {
|
||||
// Do nothing. We want to ensure option is nil
|
||||
// Select the last text index which is the disabled text track
|
||||
selectedTrackIndex = trackCount - firstTextIndex
|
||||
} else if (type == "language") {
|
||||
let selectedValue = criteria?.value as? String
|
||||
for i in 0..<textTracks.count {
|
||||
@ -53,7 +56,7 @@ enum RCTPlayerOperations {
|
||||
|
||||
// in the situation that a selected text track is not available (eg. specifies a textTrack not available)
|
||||
if (type != "disabled") && selectedTrackIndex == RCTVideoUnset {
|
||||
let captioningMediaCharacteristics = MACaptionAppearanceCopyPreferredCaptioningMediaCharacteristics(.user) as! CFArray
|
||||
let captioningMediaCharacteristics = MACaptionAppearanceCopyPreferredCaptioningMediaCharacteristics(.user)
|
||||
let captionSettings = captioningMediaCharacteristics as? [AnyHashable]
|
||||
if ((captionSettings?.contains(AVMediaCharacteristic.transcribesSpokenDialogForAccessibility)) != nil) {
|
||||
selectedTrackIndex = 0 // If we can't find a match, use the first available track
|
||||
@ -68,7 +71,7 @@ enum RCTPlayerOperations {
|
||||
}
|
||||
}
|
||||
|
||||
for i in firstTextIndex..<(player?.currentItem?.tracks.count ?? 0) {
|
||||
for i in firstTextIndex..<(trackCount) {
|
||||
var isEnabled = false
|
||||
if selectedTrackIndex != RCTVideoUnset {
|
||||
isEnabled = i == selectedTrackIndex + firstTextIndex
|
||||
|
@ -37,16 +37,17 @@ enum RCTVideoUtils {
|
||||
return 0
|
||||
}
|
||||
|
||||
static func urlFilePath(filepath:NSString!) -> NSURL! {
|
||||
static func urlFilePath(filepath:NSString!, searchPath:FileManager.SearchPathDirectory) -> NSURL! {
|
||||
if filepath.contains("file://") {
|
||||
return NSURL(string: filepath as String)
|
||||
}
|
||||
|
||||
// if no file found, check if the file exists in the Document directory
|
||||
let paths:[String]! = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
|
||||
let paths:[String]! = NSSearchPathForDirectoriesInDomains(searchPath, .userDomainMask, true)
|
||||
var relativeFilePath:String! = filepath.lastPathComponent
|
||||
// the file may be multiple levels below the documents directory
|
||||
let fileComponents:[String]! = filepath.components(separatedBy: "Documents/")
|
||||
let directoryString:String! = searchPath == .cachesDirectory ? "Library/Caches/" : "Documents";
|
||||
let fileComponents:[String]! = filepath.components(separatedBy: directoryString)
|
||||
if fileComponents.count > 1 {
|
||||
relativeFilePath = fileComponents[1]
|
||||
}
|
||||
@ -192,6 +193,7 @@ enum RCTVideoUtils {
|
||||
static func getValidTextTracks(asset:AVAsset, assetOptions:NSDictionary?, mixComposition:AVMutableComposition, textTracks:[TextTrack]?) -> [TextTrack] {
|
||||
let videoAsset:AVAssetTrack! = asset.tracks(withMediaType: AVMediaType.video).first
|
||||
var validTextTracks:[TextTrack] = []
|
||||
|
||||
if let textTracks = textTracks, textTracks.count > 0 {
|
||||
for i in 0..<textTracks.count {
|
||||
var textURLAsset:AVURLAsset!
|
||||
@ -199,7 +201,9 @@ enum RCTVideoUtils {
|
||||
if textUri.lowercased().hasPrefix("http") {
|
||||
textURLAsset = AVURLAsset(url: NSURL(string: textUri)! as URL, options:(assetOptions as! [String : Any]))
|
||||
} else {
|
||||
textURLAsset = AVURLAsset(url: RCTVideoUtils.urlFilePath(filepath: textUri as NSString?) as URL, options:nil)
|
||||
let isDisabledTrack:Bool! = textTracks[i].type == "disabled"
|
||||
let searchPath:FileManager.SearchPathDirectory = isDisabledTrack ? .cachesDirectory : .documentDirectory;
|
||||
textURLAsset = AVURLAsset(url: RCTVideoUtils.urlFilePath(filepath: textUri as NSString?, searchPath: searchPath) as URL, options:nil)
|
||||
}
|
||||
let textTrackAsset:AVAssetTrack! = textURLAsset.tracks(withMediaType: AVMediaType.text).first
|
||||
if (textTrackAsset == nil) {continue} // fix when there's no textTrackAsset
|
||||
@ -215,9 +219,43 @@ enum RCTVideoUtils {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let emptyVttFile:TextTrack? = self.createEmptyVttFile()
|
||||
if (emptyVttFile != nil) {
|
||||
validTextTracks.append(emptyVttFile!)
|
||||
}
|
||||
|
||||
return validTextTracks
|
||||
}
|
||||
|
||||
/*
|
||||
* Create an useless / almost empty VTT file in the list with available tracks. This track gets selected when you give type: "disabled" as the selectedTextTrack
|
||||
* This is needed because there is a bug where sideloaded texttracks cannot be disabled in the AVPlayer. Loading this VTT file instead solves that problem.
|
||||
* For more info see: https://github.com/react-native-community/react-native-video/issues/1144
|
||||
*/
|
||||
static func createEmptyVttFile() -> TextTrack? {
|
||||
let fileManager = FileManager.default
|
||||
let cachesDirectoryUrl = fileManager.urls(for: .cachesDirectory, in: .userDomainMask)[0]
|
||||
let filePath = cachesDirectoryUrl.appendingPathComponent("empty.vtt").path
|
||||
|
||||
if !fileManager.fileExists(atPath: filePath) {
|
||||
let stringToWrite = "WEBVTT\n\n1\n99:59:59.000 --> 99:59:59.001\n."
|
||||
|
||||
do {
|
||||
try stringToWrite.write(to: URL(fileURLWithPath: filePath), atomically: true, encoding: String.Encoding.utf8)
|
||||
} catch {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return TextTrack([
|
||||
"language": "disabled",
|
||||
"title": "EmptyVttFile",
|
||||
"type": "text/vtt",
|
||||
"uri": filePath,
|
||||
])
|
||||
}
|
||||
|
||||
static func delay(seconds: Int = 0) -> Promise<Void> {
|
||||
return Promise<Void>(on: .global()) { fulfill, reject in
|
||||
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double(Int64(seconds)) / Double(NSEC_PER_SEC), execute: {
|
||||
|
@ -5,7 +5,7 @@ import React
|
||||
class RCTVideoManager: RCTViewManager {
|
||||
|
||||
override func view() -> UIView {
|
||||
return RCTVideo(eventDispatcher: bridge.eventDispatcher())
|
||||
return RCTVideo(eventDispatcher: bridge.eventDispatcher() as! RCTEventDispatcher)
|
||||
}
|
||||
|
||||
func methodQueue() -> DispatchQueue {
|
||||
|
Loading…
Reference in New Issue
Block a user