ios9 - - copyPixelBufferForItemTime :itemTimeForDisplay: null value

标签 ios9 avasset avplayeritem cvpixelbuffer

我遇到的问题是当我的应用程序尝试获取 CVPixelBufferRef 时,我使用 iOS9 sdk 编译我的应用程序来自 AVPlayerItemVideoOutput- copyPixelBufferForItemTime:itemTimeForDisplay:函数在加载视频并创建所有实例时,我不时得到一个空值。

使用 iOS 8 我的应用程序运行良好,但是使用 iOS9 给我带来了问题,即使我的应用程序版本在应用程序商店中可供下载且使用 iOS 8 SDK 编译时,在安装时也给了我同样的问题IOS9.

当问题发生时,我得到一个空值 getCVPixelBufferRef ,如果我按下主页按钮并且当我再次打开应用程序并激活应用程序时应用程序进入后台AVPlayerItemVideoOutput给我空值的实例 CVPixelBufferRef开始工作正常,问题解决了。

这是我在其中复制问题的 YouTube 视频:

https://www.youtube.com/watch?v=997zG08_DMM&feature=youtu.be

以下是用于创建所有项目实例的示例代码:

NSURL *url ;
url = [[NSURL alloc] initFileURLWithPath:[_mainVideo objectForKey:@"file"]];

NSDictionary *pixBuffAttributes = @{(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange)};
_videoOutput = [[AVPlayerItemVideoOutput alloc] initWithPixelBufferAttributes:pixBuffAttributes];
_myVideoOutputQueue = dispatch_queue_create("myVideoOutputQueue", DISPATCH_QUEUE_SERIAL);
[_videoOutput setDelegate:self queue:_myVideoOutputQueue];

_player = [[AVPlayer alloc] init];


// Do not take mute button into account
NSError *error = nil;
BOOL success = [[AVAudioSession sharedInstance]
                setCategory:AVAudioSessionCategoryPlayback
                error:&error];
if (!success) {
   // NSLog(@"Could not use AVAudioSessionCategoryPlayback", nil);
}

asset = [AVURLAsset URLAssetWithURL:url options:nil];


if(![[NSFileManager defaultManager] fileExistsAtPath:[[asset URL] path]]) {
   // NSLog(@"file does not exist");
}

NSArray *requestedKeys = [NSArray arrayWithObjects:kTracksKey, kPlayableKey, nil];

[asset loadValuesAsynchronouslyForKeys:requestedKeys completionHandler:^{

    dispatch_async( dispatch_get_main_queue(),
                   ^{
                       /* Make sure that the value of each key has loaded successfully. */
                       for (NSString *thisKey in requestedKeys)
                       {
                           NSError *error = nil;
                           AVKeyValueStatus keyStatus = [asset statusOfValueForKey:thisKey error:&error];
                           if (keyStatus == AVKeyValueStatusFailed)
                           {
                               [self assetFailedToPrepareForPlayback:error];
                               return;
                           }
                       }

                       NSError* error = nil;
                       AVKeyValueStatus status = [asset statusOfValueForKey:kTracksKey error:&error];
                       if (status == AVKeyValueStatusLoaded)
                       {
                           //_playerItem = [AVPlayerItem playerItemWithAsset:asset];


                           [_playerItem addOutput:_videoOutput];
                           [_player replaceCurrentItemWithPlayerItem:_playerItem];
                           [_videoOutput requestNotificationOfMediaDataChangeWithAdvanceInterval:ONE_FRAME_DURATION];

                           /* When the player item has played to its end time we'll toggle
                            the movie controller Pause button to be the Play button */
                           [[NSNotificationCenter defaultCenter] addObserver:self
                                                                    selector:@selector(playerItemDidReachEnd:)
                                                                        name:AVPlayerItemDidPlayToEndTimeNotification
                                                                      object:_playerItem];

                           seekToZeroBeforePlay = NO;

                           [_playerItem addObserver:self
                                         forKeyPath:kStatusKey
                                            options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
                                            context:AVPlayerDemoPlaybackViewControllerStatusObservationContext];

                           [_player addObserver:self
                                     forKeyPath:kCurrentItemKey
                                        options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
                                        context:AVPlayerDemoPlaybackViewControllerCurrentItemObservationContext];

                           [_player addObserver:self
                                     forKeyPath:kRateKey
                                        options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
                                        context:AVPlayerDemoPlaybackViewControllerRateObservationContext];


                           [self initScrubberTimer];

                           [self syncScrubber];


                       }
                       else
                       {
                         //  NSLog(@"%@ Failed to load the tracks.", self);
                       }
                   });
}];

这是给我空像素缓冲区的示例代码
CVPixelBufferRef pixelBuffer =
[_videoOutput
 copyPixelBufferForItemTime:[_playerItem currentTime]
itemTimeForDisplay:nil];

NSLog(@"the pixel buffer is %@", pixelBuffer);
NSLog (@"the _videoOutput is %@", _videoOutput.description);
CMTime dataTime = [_playerItem currentTime];
//NSLog(@"the current time is %f", dataTime);
return pixelBuffer;

最佳答案

我遇到了同样的问题,并在此线程中找到了答案:https://forums.developer.apple.com/thread/27589#128476

在添加输出之前,您必须等待视频准备好播放,否则它将失败并返回 nil。我的快速代码如下所示:

func retrievePixelBufferToDraw() -> CVPixelBuffer? {
  guard let videoItem = player.currentItem else { return nil }
  if videoOutput == nil || self.videoItem !== videoItem {
    videoItem.outputs.flatMap({ return $0 as? AVPlayerItemVideoOutput }).forEach {
      videoItem.remove($0)
    }
    if videoItem.status != AVPlayerItemStatus.readyToPlay {
      // see https://forums.developer.apple.com/thread/27589#128476
      return nil
    }

    let pixelBuffAttributes = [
      kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange,
      ] as [String: Any]

    let videoOutput = AVPlayerItemVideoOutput.init(pixelBufferAttributes: pixelBuffAttributes)
    videoItem.add(videoOutput)
    self.videoOutput = videoOutput
    self.videoItem = videoItem
  }
  guard let videoOutput = videoOutput else { return nil }

  let time = videoItem.currentTime()
  if !videoOutput.hasNewPixelBuffer(forItemTime: time) { return nil }
  return videoOutput.copyPixelBuffer(forItemTime: time, itemTimeForDisplay: nil)
}

关于ios9 - - copyPixelBufferForItemTime :itemTimeForDisplay: null value,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33036609/

相关文章:

iOS 9 UIImagePickerController statusBar 白色

ios - AVAssetWriter 可以透明写入文件吗?

ios - 重播 AVPlayerItem/AVPlayer 无需重新下载

ios - UITableViewAutomaticDimension 在 iOS 9 中无法正常工作

ios - 相机屏幕仅显示空白的黑色图像

ios - 从使用 AVAssetImageGenerator 获得的视频或拇指获取方向

ios - 如何确定CoreFoundation _CFXNotificationPost崩溃

ios - 视频停止并从头开始播放而不是暂停,swift AVPlayer

ios - Xcode Swift - iOS 10 和 iOS 9 文本大小问题

ios - 我怎么知道 generateCGImagesAsynchronously 何时完全完成?