Swift - обходной путь / альтернатива M3u8 для воспроизведения сегмента mp4 или объединения сегментов в mp4 - PullRequest
0 голосов
/ 10 октября 2019

Я использовал AVAssetExportSession для загрузки URL-адреса сеанса, но проблема в том, что вы не можете загрузить прямой эфир, поэтому, чтобы обойти его, живой поток разделен на 10 секунд сегменты mp4, которые загружаются с помощью m3u8создать URL-адреса. Затем я использую AVAssetExportSession для объединения этих сегментов mp4.

Я могу объединить эти клипы один за другим в один файл mp4, что мне и нужно, но чем больше размер файла, тем дольше он занимаеттак как я имею дело с тысячами сегментов, что становится непрактичным.

Я думал об использовании AVplayerLooper , но я не могу пролистать, перемотать или переместиться через сегмент mp4, как одно видео.

Есть ли способ объединить клипы mp4 вместе, чтобы воспроизвести как одно видео, как это делает m3u8 без слияния? или есть быстрый способ объединения видео?

Примечание : сервер использует FFmpeg, но мне не разрешено использовать FFmpeg или модули в приложении.

нижефункция объединения видео

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()
            }
        }
    }
}
...