Как использовать AVPlayerLooper с AVPlayerItemVideoOutput?

принимает шаблон и AVQueuePlayerв качестве параметров настройки, то он внутренне манипулирует элементами очереди, и проигрыватель постоянно меняет свой .

Это отлично работает с , который принимает этот зацикленный проигрыватель в качестве параметра и просто отображает его, но как я могу использовать его с , который прикрепляется к AVPlayerItem, которых внутри игрока несколько? Как воспроизвести то же самое AVPlayerLayerделает внутренне?

AVPlayerLooperпример установки из документации

      NSString *videoFile = [[NSBundle mainBundle] pathForResource:@"example" ofType:@"mov"];
NSURL *videoURL = [NSURL fileURLWithPath:videoFile];

_playerItem = [AVPlayerItem playerItemWithURL:videoURL];
_player = [AVQueuePlayer queuePlayerWithItems:@[_playerItem]];
_playerLooper = [AVPlayerLooper playerLooperWithPlayer:_player templateItem:_playerItem];
_playerLayer = [AVPlayerLayer playerLayerWithPlayer:_player];
_playerLayer.frame = self.view.bounds;
[self.view.layer addSublayer:_playerLayer];
[_player play];

Вот как AVPlayerItemVideoOutputпредполагается использовать

      [item addOutput:_videoOutput];

Единственный обходной путь, который я придумал, - это наблюдать за изменениями currentItemи каждый раз отсоединяйте видеовыход от старого элемента и присоединяйте его к новому, как в примере ниже, но это, по-видимому, нейтрализует воспроизведение без пауз, которого я пытаюсь добиться.

      - (void)observeValueForKeyPath:(NSString*)path
                      ofObject:(id)object
                        change:(NSDictionary*)change
                       context:(void*)context {
   if (context == currentItemContext) {
      AVPlayerItem* newItem = [change objectForKey:NSKeyValueChangeNewKey];
      AVPlayerItem* oldItem = [change objectForKey:NSKeyValueChangeOldKey];
      if(oldItem.status == AVPlayerItemStatusReadyToPlay) {
          [newItem removeOutput:_videoOutput];
      }
      if(newItem.status == AVPlayerItemStatusReadyToPlay) {
          [newItem addOutput:_videoOutput];
      }
      [self removeItemObservers:oldItem];
      [self addItemObservers:newItem];
   }
}

Для большего контекста я пытаюсь придумать исправление для плагина видео_плеера флаттера https://github.com/flutter/flutter/issues/72878 .

Код плагина можно найти здесь https://github.com/flutter/plugins/blob/172338d02b177353bf517e5826cf6a25b5f0d887/packages/video_player/video_player/ios/Classes/FLTVideoPlayerPlugin.m

1 ответ

Вы можете сделать это, создав подкласс AVQueuePlayer(yay OOP) и создавать и добавлять туда s по мере необходимости. я никогда не видел несколько AVPlayerItemVideoOutputs раньше, но потребление памяти кажется разумным, и все работает.

      @interface OutputtingQueuePlayer : AVQueuePlayer
@end

@implementation OutputtingQueuePlayer

- (void)insertItem:(AVPlayerItem *)item afterItem:(nullable AVPlayerItem *)afterItem;
{
    if (item.outputs.count == 0) {
        NSLog(@"Creating AVPlayerItemVideoOutput");
        AVPlayerItemVideoOutput *videoOutput = [[AVPlayerItemVideoOutput alloc] initWithOutputSettings:nil]; // or whatever
        [item addOutput:videoOutput];
    }
    [super insertItem:item afterItem:afterItem];
}
@end

Доступ к текущему выходу осуществляется следующим образом:

      AVPlayerItemVideoOutput *videoOutput = _player.currentItem.outputs.firstObject;
CVPixelBufferRef pixelBuffer = [videoOutput copyPixelBufferForItemTime:_player.currentTime itemTimeForDisplay:nil];
// do something with pixelBuffer here
CVPixelBufferRelease(pixelBuffer);

и конфигурация становится:

      _playerItem = [AVPlayerItem playerItemWithURL:videoURL];
_player = [OutputtingQueuePlayer queuePlayerWithItems:@[_playerItem]];
_playerLooper = [AVPlayerLooper playerLooperWithPlayer:_player templateItem:_playerItem];
_playerLayer = [AVPlayerLayer playerLayerWithPlayer:_player];
[self.view.layer addSublayer:_playerLayer];
[_player play];
Другие вопросы по тегам