2016-06-10 27 views
2

Wie kann ich bei Verwendung eines CIFilter mit einem AVVideoComposition auf die aktuelle Frame-Nummer im AVAsynchronousCIImageFilteringRequest Callback zugreifen?Wie greifen Sie auf die Bildnummer in AVAsynchronousCIImageFilteringRequest zu?

Das Beste, was ich tun konnte, ist die Rahmennummer aus der Zeit zu schätzen:

^(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) 
} 

Aber das ist für mich nicht genau genug. Gibt es eine Möglichkeit, auf die Bildnummer zuzugreifen?

Antwort

2

Der Schlüssel ist, die frameDuration auf der AVMutableVideoComposition, um die der zugrunde liegenden AVAssetTrack entsprechen. Wenn Sie dies tun, werden die Werte von compositionTime sogar Vielfache von minFrameDuration sein und es wird keine Rundungsprobleme geben.

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

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

vidComp.frameDuration = self.avAssetTrack.minFrameDuration; 

In meinem Fall eines ~ 60 fps MP4 Film, avAssetTrack.minFrameDuration = (1001/60000), aber vidComp.frameDuration = (1501/90000), bevor ich es aktualisieren. Dies führte zu einer langsamen Drift von 'compositionTime' im Callback, was zu gelegentlichen wiederholten Frames führte.

+0

Ich bin gespannt, wie Sie vidComp.frameDuration sind einstellen, da sie nur gelesen hat. –

+0

Es ist nicht schreibgeschützt in einer 'AVMutableVideoComposition' (im Gegensatz zu einer' AVVideoComposition'). –

0

Wie wäre es (a Hacky)

__block int frameNum = 0; 

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

     // (Calculate filter parameters based on frame number) 

     frameNum++; 
    }]; 

?

Es gibt zwei Annahmen hier:

  1. Handler in der gleichen Reihenfolge wie der Rahmen genannt werden
  2. Handler ist nicht mehr als ein Thread zu einem Zeitpunkt genannt

I Ich weiß nicht, ob dies sichere Annahmen sind oder nicht.

p.s. Bildwiederholraten sind oft variabel, so dass Min-, Max- und Bilddauer irreführend sein können.

UPDATE die AVComposition von der Frage ist für seekable Wiedergabe in einem AVPlayer bestimmt ist, die Annahme verletzt 1.

+0

Das Video wird über einen AVPlayerView wiedergegeben, so dass der Benutzer überall im Video suchen oder FF oder umgekehrt wiedergeben kann. Auch in diesen Fällen muss die Bildnummer bekannt sein. –

+0

Soweit ich sagen kann, wenn Sie 'vidComp.frameDuration' einstellen, ist' compositionTime' im Callback immer genau ein Vielfaches davon, auch wenn die Bildrate der Videos, die zusammengesetzt werden, variabel ist. –

+0

Oh. Ich sollte hinzufügen, dass meine Antwort definitiv nicht für die willkürliche Wiedergabe funktioniert. Das ist ein cooler Trick mit 'frameDuration' /' compositionTime'. Kannst du deine Antwort schon annehmen? –