Swift - Workaround/Alternative 到 M3u8 播放 mp4 片段或将片段合并到 mp4

Swift - Workaround/Alternative to M3u8 to play mp4 segment or merge segments into mp4

我使用 AVAssetExportSession 下载了一个会话 URL 但是你不能下载直播的问题,为了解决这个问题,直播被分成了使用 m3u8 下载以创建 URLs 的 10 秒 mp4 片段。然后我使用 AVAssetExportSession 合并那些 mp4 片段。

我可以将这些剪辑一个接一个地合并到一个 mp4 文件中,这正是我想要的,但是随着文件变大,我需要处理数千个片段,这变得不切实际。

我考虑过使用 AVplayerLooper,但我无法像单个视频那样在 mp4 片段中​​擦洗、倒带或快进。

有没有办法像 m3u8 一样,将 mp4 剪辑组合在一起作为一个视频播放,而不合并?或者有没有快速合并视频的方法?

注意:服务器使用FFmpeg但我不允许在应用程序中使用FFmpeg或pods

下面是合并视频的功能

var mp4Array: [AVAsset] = []
var avAssetExportSession: AVAssetExportSession?

var firstAsset: AVAsset?
var secondAsset: AVAsset?

func mergeVideos() {

    firstAsset = mp4Array.first
    secondAsset = mp4Array[1]

    guard let firstAsset = firstAsset, let secondAsset = secondAsset else { return }
    let mixComposition = AVMutableComposition()

    guard let firstTrack = mixComposition.addMutableTrack(withMediaType: .video, preferredTrackID: Int32(kCMPersistentTrackID_Invalid)) else {return}

    do {

        try firstTrack.insertTimeRange(CMTimeRangeMake(start: CMTime.zero, duration: firstAsset.duration),
                                       of: firstAsset.tracks(withMediaType: .video)[0],
                                       at: CMTime.zero)

    } catch {
        print("Couldn't load track 1")
        return
    }

    guard let secondTrack = mixComposition.addMutableTrack(withMediaType: .video, preferredTrackID: Int32(kCMPersistentTrackID_Invalid)) else {return}

    do {
        try secondTrack.insertTimeRange(CMTimeRangeMake(start: CMTime.zero, duration: secondAsset.duration),
                                        of: secondAsset.tracks(withMediaType: .video)[0],
                                        at: firstAsset.duration)
    } catch {
        print("couldn't load track 2")
        return
    }

    let mainInstruction = AVMutableVideoCompositionInstruction()
    mainInstruction.timeRange = CMTimeRangeMake(start: CMTime.zero, duration: CMTimeAdd(firstAsset.duration, secondAsset.duration))

    let firstAssetInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: firstTrack)
    firstAssetInstruction.setOpacity(0.0, at: firstAsset.duration)

    let secondAssetInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: secondTrack)

    mainInstruction.layerInstructions = [firstAssetInstruction, secondAssetInstruction]
    let mainComposition = AVMutableVideoComposition()
    mainComposition.instructions = [mainInstruction]
    mainComposition.frameDuration = CMTimeMake(value: 1, timescale: 30)
    mainComposition.renderSize = firstTrack.naturalSize

    guard let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
    let url = documentDirectory.appendingPathComponent("MergedVideos/mergeVideo\(videoInt).mp4")

    guard let exporter = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality) else {return}

    exporter.outputURL = url
    exporter.outputFileType = AVFileType.mp4
    exporter.shouldOptimizeForNetworkUse = true
    exporter.videoComposition = mainComposition

    exporter.exportAsynchronously {

        if exporter.status == .completed {
            let avasset = AVAsset(url:url)
            self.mergeUrl = avasset
            if self.mp4Array.count > 1{
                print("This add the merged video to the front of the mp4array")
                self.mp4Array.remove(at: 1)
                self.mp4Array.removeFirst()
                self.videoInt = self.videoInt + 1
                self.mp4Array.append(self.mergeUrl!)
                self.mp4Array.bringToFront(item: self.mp4Array.last!)
            }

            if (self.mp4Array.count > 1){
                if self.mergeUrl != nil {
                    self.mergeVideos()
                }
            } else {
                var numberofvideosdeleted = 0
                while (numberofvideosdeleted < self.videoInt - 1){
                    do {
                        print("deleting")
                        let url = documentDirectory.appendingPathComponent("MergedVideos/mergeVideo\(numberofvideosdeleted).mp4")
                        try FileManager.default.removeItem(at: url)
                        numberofvideosdeleted = numberofvideosdeleted + 1
                    } catch {
                        print("Error removing videos")
                    }
                }

                self.deleteCurrentSegementsInFolder()
            }
        }
    }
}

我最终使用 FFmpeg Mobile 来连接视频,效果非常好。连接一个 3GB 的电影文件大约需要 1 分钟。

Link下面是椰足动物: https://github.com/tanersener/mobile-ffmpeg