简体   繁体   English

使用 AV 播放器访问单个帧

[英]Accesing Individual Frames using AV Player

In a recent project, I have to access all frames of my video individually using AV Foundation.在最近的一个项目中,我必须使用 AV Foundation 单独访问我的视频的所有帧。 Also, if possible to acess them randomly (like an array)此外,如果可能的话,随机访问它们(如数组)

I tried to research the question but I didn't get anything useful.我试图研究这个问题,但没有得到任何有用的信息。

Note: Is there any useful documentation to get familiar with the AV Foundation ?注意:是否有任何有用的文档来熟悉 AV Foundation ?

You can enumerate the frames of your video serially using AVAssetReader , like this:您可以使用AVAssetReader连续枚举视频的帧,如下所示:

let asset = AVAsset(URL: inputUrl)
let reader = try! AVAssetReader(asset: asset)

let videoTrack = asset.tracksWithMediaType(AVMediaTypeVideo)[0]

// read video frames as BGRA
let trackReaderOutput = AVAssetReaderTrackOutput(track: videoTrack, outputSettings:[String(kCVPixelBufferPixelFormatTypeKey): NSNumber(unsignedInt: kCVPixelFormatType_32BGRA)])

reader.addOutput(trackReaderOutput)
reader.startReading()

while let sampleBuffer = trackReaderOutput.copyNextSampleBuffer() {
    print("sample at time \(CMSampleBufferGetPresentationTimeStamp(sampleBuffer))")
    if let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) {
        // process each CVPixelBufferRef here
        // see CVPixelBufferGetWidth, CVPixelBufferLockBaseAddress, CVPixelBufferGetBaseAddress, etc
    }
}

Random access is more complicated.随机访问比较复杂。 You could use an AVPlayer + AVPlayerItemVideoOutput to get frames from any time t , using copyPixelBufferForItemTime , as described in this answer , but the subtlety lies in how you choose that t .您可以使用AVPlayer + AVPlayerItemVideoOutput从任何时间t获取帧,使用copyPixelBufferForItemTime如本答案所述,但微妙之处在于您如何选择t

If you want to sample the video at uniform intervals, then that's easy, but if you want to land on the same frames/presentation time stamps that the serial AVAssetReader code sees, then you will probably have to preprocess the file with AVAssetReader , to build a frame number -> presentation timestamp map.如果您想以统一的间隔对视频进行采样,那么这很容易,但是如果您想获得串行AVAssetReader代码看到的相同帧/演示时间戳,那么您可能必须使用AVAssetReader预处理文件,以构建帧号 -> 演示时间戳图。 This can be fast if you skip decoding by using nil output settings in AVAssetReaderTrackOutput .如果您在AVAssetReaderTrackOutput使用nil输出设置跳过解码,这会很快。

If you need to get the current frame while playing the video you could add an observer for the player and could get the current frame like this:如果您需要在播放视频时获取当前帧,您可以为播放器添加一个观察者,并可以像这样获取当前帧:

var player: AVPlayer?
var playerController = AVPlayerViewController()
var videoFPS: Int = 0
var currentFrame: Int = 0
var totalFrames: Int?

func configureVideo() {
    guard let videoURL = "" else { return }
    player = AVPlayer(url: videoURL)
    playerController.player = player
    guard player?.currentItem?.asset != nil else {
        return
    }
    let asset = self.player?.currentItem?.asset
    let tracks = asset!.tracks(withMediaType: .video)
    let fps = tracks.first?.nominalFrameRate
    
    self.videoFPS = lround(Double(fps!))
    self.getVideoData()
}
  
func getVideoData() {
    self.player?.addPeriodicTimeObserver(forInterval: CMTimeMake(value: 1,timescale: Int32(self.videoFPS)), queue: DispatchQueue.main) {[weak self] (progressTime) in

        if let duration = self!.player?.currentItem?.duration {

            let durationSeconds = CMTimeGetSeconds(duration)
            let seconds = CMTimeGetSeconds(progressTime)
            if self!.totalFrames == nil {
                self!.totalFrames = lround(Double(self!.videoFPS) * durationSeconds)
            }

            DispatchQueue.main.async {
                if self!.totalFrames != self!.currentFrame {
                    self!.currentFrame = lround(seconds*Double(self!.videoFPS))
                } else {
                    print("Video has ended!!!!!!!!")
                }
                print(self!.currentFrame)
            }
        }
    }
}

After getting the current frame number, you could use an AVAssetImageGenerator to retrieve the specific image.获取当前帧号后,您可以使用AVAssetImageGenerator来检索特定图像。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM