你如何访问 AVAsynchronousCIImageFilteringRequest 中的帧号?

How do you access the frame number inside AVAsynchronousCIImageFilteringRequest?

CIFilterAVVideoComposition 一起使用时,如何在 AVAsynchronousCIImageFilteringRequest 回调中访问当前帧编号?

我能做的最好的事情就是根据时间估计帧数:

^(AVAsynchronousCIImageFilteringRequest * _Nonnull request) {
    double seconds = CMTimeGetSeconds(request.compositionTime);
    double fps = [[_avAsset tracksWithMediaType:AVMediaTypeVideo] firstObject].nominalFrameRate;
    int frame = round(seconds * fps);

    // (Calculate filter parameters based on frame number)
}

但这对我来说不够准确。有没有办法访问帧数?

关键是在 AVMutableVideoComposition 上设置 frameDuration 以匹配基础 AVAssetTrackframeDuration。如果你这样做,那么 compositionTime 的值将是 minFrameDuration 的偶数倍并且不会有任何舍入问题。

AVMutableVideoComposition *vidComp =
    [AVMutableVideoComposition videoCompositionWithAsset:self.avAsset
                            applyingCIFiltersWithHandler:
        ^(AVAsynchronousCIImageFilteringRequest * _Nonnull request) {
            CMTime frame = self.avAssetTrack.minFrameDuration;
            int frameNum = (request.compositionTime.value * frame.timescale) /
                           (request.compositionTime.timescale * frame.value);

            // (Calculate filter parameters based on frame number)
        }];

vidComp.frameDuration = self.avAssetTrack.minFrameDuration;

在我的 ~60 fps MP4 电影的情况下,avAssetTrack.minFrameDuration = (1001/60000),但 vidComp.frameDuration = (1501/90000) 在我更新它之前。这导致回调中 'compositionTime' 的缓慢漂移,导致偶尔出现重复帧。

怎么样(一个hacky)

__block int frameNum = 0;

AVMutableVideoComposition *vidComp = 
    [AVMutableVideoComposition videoCompositionWithAsset:self.avAsset
        applyingCIFiltersWithHandler:^(AVAsynchronousCIImageFilteringRequest * request) {

        // (Calculate filter parameters based on frame number)

        frameNum++;
    }];

?

这里有两个假设:

  1. 您的处理程序的调用顺序与帧的顺序相同
  2. 您的处理程序一次未被多个线程调用

我不知道这些假设是否安全。

p.s。帧速率经常变化,因此最小值、最大值和帧持续时间可能会产生误导。

UPDATE 问题中的 AVComposition 用于在违反假设 1 的 AVPlayer 中进行可搜索播放。