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

Я использовал 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()
            }
        }
    }
}

person STerrier    schedule 09.10.2019    source источник


Ответы (1)


В итоге я использовал FFmpeg Mobile для объединения видео, и это работает очень хорошо. Для объединения файла фильма размером 3 ГБ требуется около 1 минуты.

Ссылка ниже на кокоапод: https://github.com/tanersener/mobile-ffmpeg

person STerrier    schedule 14.05.2020