【问题标题】:iOS - Reversing video file (.mov)iOS - 反转视频文件 (.mov)
【发布时间】:2012-08-30 09:26:40
【问题描述】:

要求

这听起来有点不同,但这是我想要实现的。我想反向制作电影(.mov)文件。就像我们如何倒带电影文件一样。我还希望保持与我的视频所包含的帧速率相同。

注意:我不只是想以相反的顺序播放视频文件。我想生成以相反顺序播放的新电影文件。

我的探索

我想到了以下步骤来执行相同的操作。

  1. 使用AVAssetExportSession 制作具有特定帧速率的视频文件块
  2. 使用AVMutableCompositionAVAssetExportSession 将所有这些视频块合并到一个电影文件中。
  3. 在合并过程中还将每个文件的音频合并到新的视频文件中。

使用上述步骤,我可以反向生成视频文件,但我有以下担忧。

  1. 如果视频持续时间较长,则需要大量时间。
  2. 完成此过程还会消耗大量 CPU 周期和内存。

有没有人有任何其他优化的方式来实现这一点?任何建议将不胜感激。

【问题讨论】:

  • 有什么直接的方法可以直接反转视频数据缓冲区,它会反转整个视频文件?
  • 您如何使用 AVAssetExportSession 和 AVMutableComposition 以相反的顺序生成新的电影文件?这些类中颠倒顺序的设置是什么?
  • 你找到答案了吗?我目前正在寻找同样的东西。我的问题在这里stackoverflow.com/questions/27363888/avfoundation-reverse-video

标签: ios video avassetexportsession avmutablecomposition


【解决方案1】:

这是我的解决方案,也许它可以帮助你。 https://github.com/KayWong/VideoReverse

【讨论】:

  • @KayWong 你的算法的时间结果是什么?
【解决方案2】:

Swift 5,感谢 Andy Hin,因为我基于 http://www.andyhin.com/post/5/reverse-video-avfoundation

    class func reverseVideo(inURL: URL, outURL: URL, queue: DispatchQueue, _ completionBlock: ((Bool)->Void)?) {
        let asset = AVAsset.init(url: inURL)
        guard
            let reader = try? AVAssetReader.init(asset: asset),
            let videoTrack = asset.tracks(withMediaType: .video).first
        else {
            assert(false)
            completionBlock?(false)
            return
        }

        let width = videoTrack.naturalSize.width
        let height = videoTrack.naturalSize.height

        let readerSettings: [String : Any] = [
            String(kCVPixelBufferPixelFormatTypeKey) : kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange,
        ]
        let readerOutput = AVAssetReaderTrackOutput.init(track: videoTrack, outputSettings: readerSettings)
        reader.add(readerOutput)
        reader.startReading()

        var buffers = [CMSampleBuffer]()
        while let nextBuffer = readerOutput.copyNextSampleBuffer() {
            buffers.append(nextBuffer)
        }
        let status = reader.status
        reader.cancelReading()
        guard status == .completed, let firstBuffer = buffers.first else {
            assert(false)
            completionBlock?(false)
            return
        }
        let sessionStartTime = CMSampleBufferGetPresentationTimeStamp(firstBuffer)

        let writerSettings: [String:Any] = [
            AVVideoCodecKey : AVVideoCodecType.h264,
            AVVideoWidthKey : width,
            AVVideoHeightKey: height,
        ]
        let writerInput: AVAssetWriterInput
        if let formatDescription = videoTrack.formatDescriptions.last {
            writerInput = AVAssetWriterInput.init(mediaType: .video, outputSettings: writerSettings, sourceFormatHint: (formatDescription as! CMFormatDescription))
        } else {
            writerInput = AVAssetWriterInput.init(mediaType: .video, outputSettings: writerSettings)
        }
        writerInput.transform = videoTrack.preferredTransform
        writerInput.expectsMediaDataInRealTime = false

        guard
            let writer = try? AVAssetWriter.init(url: outURL, fileType: .mp4),
            writer.canAdd(writerInput)
        else {
            assert(false)
            completionBlock?(false)
            return
        }

        let pixelBufferAdaptor = AVAssetWriterInputPixelBufferAdaptor.init(assetWriterInput: writerInput, sourcePixelBufferAttributes: nil)
        let group = DispatchGroup.init()

        group.enter()
        writer.add(writerInput)
        writer.startWriting()
        writer.startSession(atSourceTime: sessionStartTime)

        var currentSample = 0
        writerInput.requestMediaDataWhenReady(on: queue) {
            for i in currentSample..<buffers.count {
                currentSample = i
                if !writerInput.isReadyForMoreMediaData {
                    return
                }
                let presentationTime = CMSampleBufferGetPresentationTimeStamp(buffers[i])
                guard let imageBuffer = CMSampleBufferGetImageBuffer(buffers[buffers.count - i - 1]) else {
                    WLog("VideoWriter reverseVideo: warning, could not get imageBuffer from SampleBuffer...")
                    continue
                }
                if !pixelBufferAdaptor.append(imageBuffer, withPresentationTime: presentationTime) {
                    WLog("VideoWriter reverseVideo: warning, could not append imageBuffer...")
                }
            }

            // finish
            writerInput.markAsFinished()
            group.leave()
        }

        group.notify(queue: queue) {
            writer.finishWriting {
                if writer.status != .completed {
                    WLog("VideoWriter reverseVideo: error - \(String(describing: writer.error))")
                    completionBlock?(false)
                } else {
                    completionBlock?(true)
                }
            }
        }
    }

【讨论】:

    【解决方案3】:

    您需要参考 AVFoundation 库来完成您的任务..

    我只用AVAssetExportSessionAVMutableComposition 完成了30 秒的视频编辑。

    这是您需要参考的链接,它的帮助非常充分。

    http://www.subfurther.com/blog/category/avfoundation/

    如果您想参考 WWDC 会议 PDF 来编辑媒体,那会更好。

    此链接总来源:https://developer.apple.com/videos/wwdc/2010/ 此链接涵盖使用 AVFoundation 编辑媒体

    关于内存周期.. 导出时也会消耗更多内存。

    【讨论】:

    • 提供一些源代码确实可以改善您的答案。尤其是当你设法解决它时。
    • @Vijayts 源代码链接可在上述链接中找到。如果你刚刚尝试打开。
    猜你喜欢
    • 2023-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多