AVPlayer/MPMoviePlayerController 的字幕

问题描述 投票:0回答:6

我正在使用 m3u8 视频格式来流式传输视频,现在我需要显示相同的字幕。

我在Apple文档中搜索,发现可以通过使用

closedCaptionDisplayEnabled
AVPlayer
属性来实现这一点。

我有兴趣知道字幕的格式应该是什么? .srt 格式可以吗?

我也可以使用

MPMoviePlayerController
达到同样的效果吗?

如有任何帮助,我们将不胜感激。

mpmovieplayercontroller avfoundation avplayer subtitle transport-stream
6个回答
36
投票

更新 03/06/2020: 在 GitHub 上,jbweimar 创建了一个示例项目,该项目使用看起来非常有前途的

AVAssetResourceLoaderDelegate
方法:https://github.com/jbweimar/external-webvtt-example


2018 年 10 月 30 日更新: 值得检查 Apple 工程师的回答(感谢 @allenlini 指出)。他提出了一个涉及

AVAssetResourceLoaderDelegate
的解决方案。我自己没有尝试过,但这可能是比我下面的更好的解决方案。


原答案:

似乎在 m3u8 流描述中引用 WebVTT 文件是官方支持的方式。 “事后”添加它们似乎不受官方支持(请参阅Apple 工程师的声明(页面底部))。

但是,这并不意味着您无法让它工作;-)。 在 Chris Adamson 的 这个精彩的演示文稿 示例项目 (ZIP)、Apple 开发者论坛上的这篇文章 和 Abdul Azeem 的 Ray Wenderlich 教程 的帮助下,我能够让它工作。这是 Abdul Azeem 示例代码和 Chris 示例项目的修改版本。

注意如何使用

AVMediaTypeText

 而不是 
AVMediaTypeSubtitle
。这似乎是 iOS 中的一个错误。

// 1 - Load video asset AVAsset *videoAsset = [AVURLAsset assetWithURL:[[NSBundle mainBundle] URLForResource:@"video" withExtension:@"mp4"]]; // 2 - Create AVMutableComposition object. This object will hold your AVMutableCompositionTrack instances. AVMutableComposition *mixComposition = [[AVMutableComposition alloc] init]; // 3 - Video track AVMutableCompositionTrack *videoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; [videoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration) ofTrack:[[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:kCMTimeZero error:nil]; // 4 - Subtitle track AVURLAsset *subtitleAsset = [AVURLAsset assetWithURL:[[NSBundle mainBundle] URLForResource:@"subtitles" withExtension:@"vtt"]]; AVMutableCompositionTrack *subtitleTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeText preferredTrackID:kCMPersistentTrackID_Invalid]; [subtitleTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration) ofTrack:[[subtitleAsset tracksWithMediaType:AVMediaTypeText] objectAtIndex:0] atTime:kCMTimeZero error:nil]; // 5 - Set up player AVPlayer *player = [AVPlayer playerWithPlayerItem: [AVPlayerItem playerItemWithAsset:mixComposition]];
    

7
投票
这是

@JohannesFahrenkrug 答案 的 Swift 版本。希望这对某人有用:

let localVideoAsset = Bundle.main.url(forResource: "L1C1P1C3", withExtension: "mp4") //Create AVMutableComposition let videoPlusSubtitles = AVMutableComposition() //Adds video track let videoTrack = videoPlusSubtitles.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid) try? videoTrack?.insertTimeRange(CMTimeRangeMake(kCMTimeZero, localVideoAsset.duration), of: localVideoAsset.tracks(withMediaType: .video)[0], at: kCMTimeZero) //Adds subtitle track let subtitleAsset = AVURLAsset(url: Bundle.main.url(forResource: "L1C1P1C3", withExtension: ".mp4.vtt")!) let subtitleTrack = videoPlusSubtitles.addMutableTrack(withMediaType: .text, preferredTrackID: kCMPersistentTrackID_Invalid) try? subtitleTrack?.insertTimeRange(CMTimeRangeMake(kCMTimeZero, localVideoAsset.duration), of: subtitleAsset.tracks(withMediaType: .text)[0], at: kCMTimeZero)
    

2
投票
AVPlayer 和 MPMoviePlayerController 都可以显示字幕。

区别似乎在于,对于 AVPlayer,您可以使用 closeCaptionDisplayEnabled 属性控制是否显示字幕。

使用 MPMoviePlayerController,用户可以使用设置应用程序中的开关来控制是否显示字幕。您在应用程序中无法对此进行编程控制。


2
投票
添加字幕时出现音频错误。更新版本如下;

注意: 只能将本地项目(资产)插入到 AVMutableComposition 中,远程项目(如 HTTP 视频流)在 iOS 15 之前将无法工作。

视频和字幕文件

将 HTTP 流插入 AVMutableComposition

斯威夫特5

func play() { guard let videoUrl = Bundle.main.url(forResource: "ElephantsDream", withExtension: "mp4")?.absoluteURL, let subtitleUrl = Bundle.main.url(forResource: "subtitles-en", withExtension: "vtt")?.absoluteURL else { return } let videoAsset = AVURLAsset(url: videoUrl) let subtitleAsset = AVURLAsset(url: subtitleUrl) // Create AVMutableComposition object. This object will hold your AVMutableCompositionTrack instances. let mixComposition = AVMutableComposition() let videoTrack = mixComposition.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid) let audioTrack = mixComposition.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid) let subtitleTrack = mixComposition.addMutableTrack(withMediaType: .text, preferredTrackID: kCMPersistentTrackID_Invalid) do { try videoTrack?.insertTimeRange(CMTimeRangeMake(start: .zero, duration: videoAsset.duration), of: videoAsset.tracks(withMediaType: .video).first!, at: .zero) try audioTrack?.insertTimeRange(CMTimeRangeMake(start: .zero, duration: videoAsset.duration), of: videoAsset.tracks(withMediaType: .audio).first!, at: .zero) try subtitleTrack?.insertTimeRange(CMTimeRangeMake(start: .zero, duration: subtitleAsset.duration), of: subtitleAsset.tracks(withMediaType: .text).first!, at: .zero) } catch let err { print(err.localizedDescription) } let player = AVPlayer(playerItem: AVPlayerItem(asset: mixComposition)) let vc = AVPlayerViewController() vc.player = player present(vc, animated: true) { vc.player?.play() } }
如果您想使用服务器端视频和字幕,您需要像这样使用。

iOS 15

func play() { if #available(iOS 15.0.0, *) { let videoUrl = URL(string: "https://wwww.acme.com/video/elephantsdream.mov")! let subtitleUrl = URL(string: "https://wwww.acme.com/subtitle/subtitles-en.vtt")! let videoAsset = AVURLAsset(url: videoUrl) let subtitleAsset = AVURLAsset(url: subtitleUrl) let mixComposition = AVMutableComposition() let videoTrack = mixComposition.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid) let audioTrack = mixComposition.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid) let subtitleTrack = mixComposition.addMutableTrack(withMediaType: .text, preferredTrackID: kCMPersistentTrackID_Invalid) Task { if let videoTrackItem = try await videoAsset.loadTracks(withMediaType: .video).first { try videoTrack?.insertTimeRange(CMTimeRangeMake(start: .zero, duration: videoAsset.duration), of: videoTrackItem, at: .zero) } if let audioTrackItem = try await videoAsset.loadTracks(withMediaType: .audio).first { try audioTrack?.insertTimeRange(CMTimeRangeMake(start: .zero, duration: videoAsset.duration), of: audioTrackItem, at: .zero) } if let subtitleTrackItem = try await subtitleAsset.loadTracks(withMediaType: .text).first { try subtitleTrack?.insertTimeRange(CMTimeRangeMake(start: .zero, duration: videoAsset.duration), of: subtitleTrackItem, at: .zero) } DispatchQueue.main.async { let player = AVPlayer(playerItem: AVPlayerItem(asset: mixComposition)) let vc = AVPlayerViewController() vc.player = player self.present(vc, animated: true) { vc.player?.play() } } } } }
    

0
投票
WWDC 2013 iOS 应用程序使用 WebVTT 文件作为其字幕(

归功于 Nicholas Riley 发现了这一点)。无论出于何种原因,每次会话大约有 50 个(具体数字各不相同)。

我不知道 AVFoundation 或 MPMoviePlayer 级别是否支持 WebVTT,或者应用程序是否自行下载和解析字幕文件。

快速搜索“webvtt m3u8”会发现对

此 HTTP Live Streaming Draft 的引用,这表明您可能能够通过简单地引用 m3u8 播放列表中的 WebVTT 文件来完成这项工作。不过,我没有给您提供示例,因为我无法轻松猜测 WWDC 会话的 m3u8 URL。


0
投票
如果有人需要最新的 Swift 和自定义 SwiftUI 视图(为 SwiftUI 包装的 AVplayerController),这就是更改,感谢 @perpeer:

let videoAsset = AVURLAsset(url: videoUrl) let subtitleAsset = AVURLAsset(url: subtitleUrl) let mixComposition = AVMutableComposition() let videoTrack = mixComposition.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid) let audioTrack = mixComposition.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid) let subtitleTrack = mixComposition.addMutableTrack(withMediaType: .text, preferredTrackID: kCMPersistentTrackID_Invalid) Task { if let videoTrackItem = try await videoAsset.loadTracks(withMediaType: .video).first { try await videoTrack?.insertTimeRange(CMTimeRangeMake(start: .zero, duration: videoAsset.load(.duration)), of: videoTrackItem, at: .zero) } if let audioTrackItem = try await videoAsset.loadTracks(withMediaType: .audio).first { try await audioTrack?.insertTimeRange(CMTimeRangeMake(start: .zero, duration: videoAsset.load(.duration)), of: audioTrackItem, at: .zero) } if let subtitleTrackItem = try await subtitleAsset.loadTracks(withMediaType: .text).first { try await subtitleTrack?.insertTimeRange(CMTimeRangeMake(start: .zero, duration: videoAsset.load(.duration)), of: subtitleTrackItem, at: .zero) } DispatchQueue.main.async { let player = AVPlayer(playerItem: AVPlayerItem(asset: mixComposition)) let vc = AVPlayerViewController() vc.player = player self.present(vc, animated: true) { vc.player?.play() } } }
尝试使用本地和远程网址,它可以工作,主要是你的字幕必须带有 .vtt 扩展名

© www.soinside.com 2019 - 2024. All rights reserved.