1

我正在尝试使用AVFoundation. 这行得通。我还尝试在视频中添加叠加层,例如包含日期的文本标签。

例如:保存的视频不仅是相机看到的,还有时间戳。

这是我保存视频的方式:

func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) {
    saveVideo(toURL: movieURL!)
  }

  private func saveVideo(toURL url: URL) {
    PHPhotoLibrary.shared().performChanges({
      PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: url)
    }) { (success, error) in
      if(success) {
        print("Video saved to Camera Roll.")
      } else {
        print("Video failed to save.")
      }
    }
  }

我有movieOuput一个AVCaptureMovieFileOutput. 我的预览图层不包含任何子图层。我尝试将时间戳标签的图层添加到 previewLayer,但这没有成功。

我已经尝试过Ray Wenderlich 的示例以及这个堆栈溢出问题。最后,我也试过这个教程,但都无济于事。

如何在相机胶卷中保存的视频中为我的视频添加叠加层?

4

2 回答 2

6

如果没有更多信息,听起来您要的是水印。不是叠加层。

水印是视频上将与视频一起保存的标记。叠加层通常显示为预览层上的子视图,不会与视频一起保存。

在这里查看:https ://stackoverflow.com/a/47742108/8272698

func addWatermark(inputURL: URL, outputURL: URL, handler:@escaping (_ exportSession: AVAssetExportSession?)-> Void) {
    let mixComposition = AVMutableComposition()
    let asset = AVAsset(url: inputURL)
    let videoTrack = asset.tracks(withMediaType: AVMediaType.video)[0]
    let timerange = CMTimeRangeMake(kCMTimeZero, asset.duration)

        let compositionVideoTrack:AVMutableCompositionTrack = mixComposition.addMutableTrack(withMediaType: AVMediaType.video, preferredTrackID: CMPersistentTrackID(kCMPersistentTrackID_Invalid))!

    do {
        try compositionVideoTrack.insertTimeRange(timerange, of: videoTrack, at: kCMTimeZero)
        compositionVideoTrack.preferredTransform = videoTrack.preferredTransform
    } catch {
        print(error)
    }

    let watermarkFilter = CIFilter(name: "CISourceOverCompositing")!
    let watermarkImage = CIImage(image: UIImage(named: "waterMark")!)
    let videoComposition = AVVideoComposition(asset: asset) { (filteringRequest) in
        let source = filteringRequest.sourceImage.clampedToExtent()
        watermarkFilter.setValue(source, forKey: "inputBackgroundImage")
        let transform = CGAffineTransform(translationX: filteringRequest.sourceImage.extent.width - (watermarkImage?.extent.width)! - 2, y: 0)
        watermarkFilter.setValue(watermarkImage?.transformed(by: transform), forKey: "inputImage")
        filteringRequest.finish(with: watermarkFilter.outputImage!, context: nil)
    }

    guard let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPreset640x480) else {
        handler(nil)

        return
    }

    exportSession.outputURL = outputURL
    exportSession.outputFileType = AVFileType.mp4
    exportSession.shouldOptimizeForNetworkUse = true
    exportSession.videoComposition = videoComposition
    exportSession.exportAsynchronously { () -> Void in
        handler(exportSession)
    }
}

以及如何调用该函数。

let outputURL = NSURL.fileURL(withPath: "TempPath")
let inputURL = NSURL.fileURL(withPath: "VideoWithWatermarkPath")
addWatermark(inputURL: inputURL, outputURL: outputURL, handler: { (exportSession) in
    guard let session = exportSession else {
        // Error 
        return
    }
    switch session.status {
        case .completed:
        guard NSData(contentsOf: outputURL) != nil else {
            // Error
            return
        }

        // Now you can find the video with the watermark in the location outputURL

        default:
        // Error
    }
})

让我知道此代码是否适合您。它在 swift 3 中,因此需要进行一些更改。我目前正在我的应用程序上使用此代码。尚未将其更新到 swift 5

于 2019-11-15T20:31:31.430 回答
2

我没有可以利用 AVFoundation 的 Swift 实际开发环境。因此,我无法为您提供任何示例代码。

为了在录制时添加元数据(日期、位置、时间戳、水印、帧速率等)作为视频的覆盖,您必须在录制时逐帧、实时处理视频馈送。您很可能必须将帧存储在缓冲区中并在实际记录它们之前对其进行处理。

现在谈到元数据,有两种类型,静态和动态。对于像水印这样的静态类型,它应该很容易,因为所有的帧都会得到相同的东西。

但是,对于时间戳或 GPS 位置等动态元数据类型,需要考虑一些事项。处理视频帧需要计算能力和时间。因此,取决于动态数据的类型以及获取它们的方式,有时处理后的值可能不是正确的值。例如,如果您在 1:00:01 获得一帧,则处理它并为其添加时间戳。假设处理时间戳需要 2 秒。您获得的下一帧是在 1:00:02,但您要到 1:00:03 才能处理它,因为处理前一帧需要 2 秒。因此,取决于您如何获得新帧的新时间戳,该时间戳值可能不是您想要的值。

对于处理动态元数据,您还应该考虑硬件滞后。例如,该软件应该为每一帧添加实时 GPS 位置数据,并且在开发或测试中没有任何滞后。然而,在现实生活中,用户在连接不良的区域使用该软件,并且他的手机在获取他的 GPS 位置时会出现延迟。他的一些滞后时间长达 5 秒。在那种情况下你会怎么做?您是否为 GPS 定位设置了超时时间并使用了最后一个好位置?你报告错误吗?当 GPS 数据可用时,您是否推迟处理该帧(这可能会破坏实时记录)并使用昂贵的算法来尝试预测该帧的用户位置?

除了需要考虑的那些之外,我这里还有一些我认为可能对您有所帮助的参考资料。我认为来自 medium.com 的那个看起来不错。

https://medium.com/ios-os-x-development/ios-camera-frames-extraction-d2c0f80ed05a

为当前录制的视频添加水印并使用水印保存

录制视频时将动态文本渲染到 CVPixelBufferRef

于 2019-11-15T00:48:30.093 回答