如何在Swift中录制视频时添加叠加?

e1xvtsh3  于 2022-12-10  发布在  Swift
关注(0)|答案(3)|浏览(195)

我正在尝试使用AVFoundation在Swift中录制并保存一段视频。这很好用。我还尝试在视频中添加一个覆盖层,比如包含日期的文本标签。
例如:所保存的视频不仅是摄像机所看到的,而且也是时间戳。
以下是我保存视频的方式:

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

我有一个movieOuputAVCaptureMovieFileOutput。我的预览图层不包含任何子图层。我尝试将时间戳标签的图层添加到previewLayer,但没有成功。
我试过Ray Wenderlich's examplethis stack overflow question,最后,我也试过this tutorial,都无济于事。
如何将覆盖添加到已保存在相机胶卷中的视频中?

eblbsuwk

eblbsuwk1#

如果没有更多的信息,听起来你所要求的是水印。而不是覆盖。
水印是视频上的标记,将与视频一起保存。覆盖通常显示为预览层上的子视图,不会与视频一起保存。
点击此处查看: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

92vpleto

92vpleto2#

我没有一个可以使用AVFoundation的Swift的实际开发环境。因此,我不能提供任何示例代码给你。
要在录制时将 meta数据(日期、位置、时间戳、水印、帧速率等)作为覆盖层添加到视频中,您必须在录制时逐帧实时处理视频源。最有可能的是,您必须将帧存储在缓冲区中,并在实际录制之前对其进行处理。
现在,当谈到 meta数据,有两种类型,静态和动态。对于静态类型,如水印,这应该是很容易的,因为所有的帧将得到同样的东西。
然而,对于时间戳或GPS位置等动态 meta数据类型,需要考虑一些事项。处理视频帧需要计算能力和时间。因此,根据动态数据的类型和获取方式,有时处理的值可能不是正确的值。例如,如果您在1:00:01获取一个帧,您处理它并向其添加时间戳。假设处理时间戳花了2秒。您获取的下一个帧是1:00:02,但您直到1:00:03才能处理它,因为处理前一个帧花了2秒。因此,根据您获取新帧的新时间戳的方式,该时间戳值可能不是您想要的值。
对于动态 meta数据的处理,还需要考虑硬件的滞后性,比如说,软件应该在每一帧中添加实时的GPS定位数据,在开发和测试中没有任何滞后,但是在真实的生活中,用户在一个连接不好的区域使用软件。而他的手机在获取GPS位置时会出现延迟。有些延迟持续时间长达5秒。在这种情况下,你会怎么做?你会为GPS位置设置超时并使用上一次的好位置吗?你会报告错误吗?您是否将该帧推迟到以后GPS数据可用时处理(这可能会破坏现场录制),并使用昂贵算法来尝试预测该帧的用户位置?
除了那些需要考虑的,我这里有一些参考资料,我认为可能会对你有所帮助。我认为www.example.com上的那个medium.com看起来很不错。
https://medium.com/ios-os-x-development/ios-camera-frames-extraction-d2c0f80ed05a
Adding watermark to currently recording video and save with watermark
Render dynamic text onto CVPixelBufferRef while recording video

jgwigjjp

jgwigjjp3#

添加到@Kevin Ng,您可以使用UIViewController和UIView在视频帧上进行覆盖。
UIViewController将具有:
1.使用视频流属性

private var videoSession: AVCaptureSession?

1.属性来使用复盖(UIView类别)

private var myOverlay: MyUIView{view as! MyUIView}

1.用于视频输出队列属性

private let videoOutputQueue = DispatchQueue(label: 
"outputQueue", qos: .userInteractive)

1.创建视频会话方法
1.处理和显示覆盖图的方法
UIView将具有用作覆盖所需的特定于任务的帮助器方法。例如,如果您正在进行手部检测,则此覆盖类可以具有用于在坐标上绘制点的帮助器方法(ViewController类将检测手部特征的坐标,进行必要的坐标转换,然后将坐标传递给UIView类以将坐标显示为覆盖)

相关问题