16

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

我在 Apple Documentation中搜索,发现可以通过使用closedCaptionDisplayEnabled.AVPlayer

我很想知道字幕的格式应该是什么?.srt 格式可以吗?

我也可以实现相同的使用MPMoviePlayerController吗?

任何帮助表示赞赏。

4

5 回答 5

34

2020 年 3 月 6 日更新:在 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]];
于 2016-06-21T13:00:27.887 回答
6

这是@JohannesFahrenkrug answer的 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)
于 2018-08-21T09:57:02.053 回答
2

AVPlayer 和 MPMoviePlayerController 都可以显示字幕。

不同之处似乎在于,使用 AVPlayer,您可以使用 closedCaptionDisplayEnabled 属性控制是否显示字幕。

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

于 2013-02-27T19:44:24.010 回答
0

WWDC 2013 iOS 应用程序使用 WebVTT 文件作为其字幕(感谢Nicholas Riley 的发现)。无论出于何种原因,每个会话大约有 50 个(具体数字不同)。

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

快速搜索“webvtt m3u8”会找到对这个 HTTP Live Streaming Draft的引用,这表明您可以通过简单地引用 m3u8 播放列表中的 WebVTT 文件来完成这项工作。不过,我没有给你一个例子,因为我无法轻易猜出 WWDC 会话的 m3u8 URL。

于 2013-07-27T08:06:22.123 回答
0

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

注意:只能将本地项目(资产)插入 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()
                }
            }
        }
    }
}
于 2022-02-01T09:23:38.043 回答