【问题标题】:Create frames from video in Swift (iOS)在 Swift (iOS) 中从视频创建帧
【发布时间】:2021-01-04 22:55:01
【问题描述】:

有一个持续时间为 3 秒的视频文件。我需要创建 30 帧 - UIImages。每 0.1 秒捕获一次图像。 我尝试使用 AVAssetImageGenerator 和 CMTimeMake,但我总是得到 30 个相似的图像,或者 15 个相似的图像和 15 个相似的图像。

请帮助了解如何从该视频中制作这种幻灯片。或者也许有更好的方法来做到这一点。

请看下面的代码:

static func generate_Thumbnails(forVideoWithURL url : URL) -> [UIImage]? {
    let asset = AVAsset(url: url)
    var result: [UIImage] = []
    let assetImgGenerator = AVAssetImageGenerator(asset: asset)
    assetImgGenerator.appliesPreferredTrackTransform = true
    for i in 1...30 {
        let time: CMTime = CMTimeMake(value: Int64(i), timescale: 10)
        do {
            let img: CGImage = try assetImgGenerator.copyCGImage(at: time, actualTime: nil)
            let frameImg: UIImage = UIImage(cgImage: img)
            result.append(frameImg)
        } catch {
            //return nil
        }
    }
    return result
}

【问题讨论】:

  • 可能是因为您没有要求低时间容忍度。
  • @matt 你能解释一下吗?
  • 这只是一个想法。请参阅docs:“生成图像的实际时间在 [requestedTime-requestedTimeToleranceBefore, requestedTime+requestedTimeToleranceAfter] 范围内,可能与请求的时间不同以提高效率。”听起来可能很相关。

标签: ios swift video-processing avassetimagegenerator


【解决方案1】:

我还没有阅读 AVAssetImageGenerator 的文档,但实际上我每秒只能生成 1 张图像。因此,您应该能够在 1、2 和 3 秒(但不是 30 秒)时获得图像。这是我用来生成图像的代码,和你的很相似。

private func getPreviewImage(forURL url: URL, atSeconds seconds: Double) -> UIImage? {
        let asset = AVURLAsset(url: url)
        let generator = AVAssetImageGenerator(asset: asset)
        generator.appliesPreferredTrackTransform = true

        let timestamp = CMTime(seconds: seconds, preferredTimescale: 100)

        do {
            let imageRef = try generator.copyCGImage(at: timestamp, actualTime: nil)
            return UIImage(cgImage: imageRef)
        }
        catch let error as NSError
        {
            print("Image generation failed with error \(error)")
            return nil
        }
    }

【讨论】:

  • 谢谢。看来你是对的,我无法在 1 秒内更频繁地拍照。
【解决方案2】:

我尝试了Amin Benarieb 的解决方案,它似乎有效:

static func toImages(fromVideoUrl url: URL) -> [UIImage]? {
    let asset = AVAsset(url: url)
    guard let reader = try? AVAssetReader(asset: asset) else { return nil }
    let videoTrack = asset.tracks(withMediaType: .video).first!
    let outputSettings = [String(kCVPixelBufferPixelFormatTypeKey): NSNumber(value: kCVPixelFormatType_32BGRA)]
    let trackReaderOutput = AVAssetReaderTrackOutput(track: videoTrack, outputSettings: outputSettings)
    reader.add(trackReaderOutput)
    reader.startReading()
    var images = [UIImage]()
    while reader.status == .reading {
        autoreleasepool {
            if let sampleBuffer = trackReaderOutput.copyNextSampleBuffer() {
                if let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) {
                    let ciImage = CIImage(cvImageBuffer: imageBuffer)
                    images.append(UIImage(ciImage: ciImage))
                }
            }
        }
    }
    return images
}

【讨论】:

  • 非常感谢!我会用那个。就我而言,唯一的问题是我必须将每张图片旋转 90 度,因为它会从垂直视频中生成水平图像。但是图像的旋转并不是什么大问题。再次感谢您!
猜你喜欢
  • 2017-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-25
  • 2022-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多