requestMediaDataWhenReadyOnQueue:usingBlock: 并行创建多个块 ->崩溃

发布于 2024-12-14 09:43:39 字数 7367 浏览 0 评论 0原文

我正在尝试将 CGPixelBufferRefs 附加到 AVAssetWriterInput 以创建 QuickTime 影片。

我正在使用以下代码:

BOOL __block shouldContinue = YES;

[self.assetWriterInput requestMediaDataWhenReadyOnQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
usingBlock:^(void)
{
BXLog(@"processing Block");

while ([self.assetWriterInput isReadyForMoreMediaData] && shouldContinue)
{
    BXLog(@"assetWriter isReadyForMoreMediaData, shouldContinue %i", shouldContinue);

    NSError *error = nil;
    CGImageRef image = [inClip copyImageAtIndex:frameCounter withSize:CGSizeZero error:&error];
    CGFloat progress = (CGFloat)frameCounter / (CGFloat)inRange.length;

    if (image != NULL)
    {
        size_t width = CGImageGetWidth(image);
        size_t height = CGImageGetHeight(image);
        CVPixelBufferRef pixelBuffer = [self pixelBufferFromCGImage:image andSize:CGSizeMake(width, height)];

        if (! [self.assetWriterInputPixelBufferAdaptor appendPixelBuffer:pixelBuffer 
          withPresentationTime:CMTimeMake(frameCounter * inClip.lengthOfOneFrame.value,       inClip.lengthOfOneFrame.timescale)])
        {
            [self.assetWriter finishWriting];

             BXLogInDomain(kLogDomainSharing, kLogLevelError, @"Error while appending pixel butter: %@", self.assetWriter.error);
             error = [NSError errorWithDomain:kErrorDomainExport
                                         code:ZBExportAppendImageError 
                                     userInfo:nil];
        }

        CVPixelBufferRelease(pixelBuffer);
    }   
    else
    {
        [self.assetWriter finishWriting];

        BXLogInDomain(kLogDomainSharing, kLogLevelError, @"Error while coping image from clip %@", self.assetWriter.error);
        // create a Framedrop Error - we couldn't find a frame
        error = [NSError errorWithDomain:kErrorDomainExport 
                                    code:ZBExportFrameDropError
                                userInfo:nil];
     }

     [[NSOperationQueue mainQueue] addOperationWithBlock:^(void)
      {
           self.currentProgress = flag ? progress * 0.5 : progress;
      }];

     dispatch_sync(handlerQueue,
      ^(void)
      {
          shouldContinue = inProgressHandler(progress, image);
      });
      BXLog(@"should continue %i", shouldContinue);

      CGImageRelease(image);

      frameCounter++;
      // Movie is finished
      if (frameCounter >= inRange.location + inRange.length)
      {
          [self.assetWriterInput markAsFinished];
          [self.assetWriter finishWriting];
          [[NSOperationQueue mainQueue] addOperationWithBlock:^(void)
           {
               self.currentProgress = 1.0;
           }];
          dispatch_async(handlerQueue, ^(void)
           {
               inCompletionHandler(self.filePath, error);
               dispatch_release(handlerQueue);
           });
          shouldContinue = NO;
      }
      else if (shouldContinue == NO)
      {
         [self.assetWriterInput markAsFinished];
         [self.assetWriter finishWriting];

         // call the completion handler
         if (frameCounter < inRange.location + inRange.length)
         {
             dispatch_async(handlerQueue, ^(void)
              {
                  // cancel error
                  inCompletionHandler(NULL, [NSError errorWithDomain:kErrorDomainEport
                                                                code:ZBExportCancelError
                                                            userInfo:nil]);
                  dispatch_release(handlerQueue);
               });
          }

          // do not export any longer
          // simply calling the completion handler is not enough


      BXLog(@"End of while – should continue %i - asset writer is ready for more media %i", shouldContinue, [self.assetWriterInput isReadyForMoreMediaData]);
    }

    BXLog(@"out of while");

}];

}

大多数时候它运行良好,但有时会崩溃。我可以将崩溃情况分解为以下情况:

  1. 对于大多数导出,仅创建一个块,while 循环逐帧处理,最后块退出。
  2. 有一个出口,其中使用了多个块。创建一个块,处理 4 或 5 个图像,然后使用 [self.assetWriterInput isReadyForMoreMediaData == NO 离开 while 循环。创建一个新块,处理更多帧,然后离开 while 循环。
  3. 有时会发生这样的情况:不是创建一个块,而是创建两个块,并且两个块都并行工作。

我得到以下输出:

2011-11-08 12:42:41.161 iStopMotion[22804:1c003] processing Block
2011-11-08 12:42:41.168 iStopMotion[22804:1c003] assetWriter isReadyForMoreMediaData, shouldContinue 1
2011-11-08 12:42:41.278 iStopMotion[22804:1c003] should continue 1
2011-11-08 12:42:41.279 iStopMotion[22804:1c003] End of while - should continue 1 - asset writer is ready for more media 1
2011-11-08 12:42:41.285 iStopMotion[22804:1c003] assetWriter isReadyForMoreMediaData, shouldContinue 1
2011-11-08 12:42:41.370 iStopMotion[22804:1c003] should continue 1
2011-11-08 12:42:41.391 iStopMotion[22804:1c003] End of while - should continue 1 - asset writer is ready for more media 1
2011-11-08 12:42:41.399 iStopMotion[22804:1c003] assetWriter isReadyForMoreMediaData, shouldContinue 1
2011-11-08 12:42:41.420 iStopMotion[22804:1c003] should continue 1
2011-11-08 12:42:41.422 iStopMotion[22804:1c003] End of while - should continue 1 - asset writer is ready for more media 0
2011-11-08 12:42:41.423 iStopMotion[22804:1c003] out of while
2011-11-08 12:42:41.442 iStopMotion[22804:1e507] processing Block
2011-11-08 12:42:41.457 iStopMotion[22804:1e507] assetWriter isReadyForMoreMediaData, shouldContinue 1
2011-11-08 12:42:41.476 iStopMotion[22804:1e507] should continue 1
2011-11-08 12:42:41.476 iStopMotion[22804:1e507] End of while - should continue 1 - asset writer is ready for more media 0
2011-11-08 12:42:41.477 iStopMotion[22804:1e507] out of while
2011-11-08 12:42:41.498 iStopMotion[22804:1e507] processing Block
2011-11-08 12:42:41.515 iStopMotion[22804:1e507] assetWriter isReadyForMoreMediaData, shouldContinue 1
2011-11-08 12:42:41.541 iStopMotion[22804:1e507] should continue 1
2011-11-08 12:42:41.553 iStopMotion[22804:1e507] End of while - should continue 1 - asset writer is ready for more media 0
2011-11-08 12:42:41.583 iStopMotion[22804:1e507] out of while
2011-11-08 12:42:41.614 iStopMotion[22804:1e507] processing Block
2011-11-08 12:42:41.628 iStopMotion[22804:1e507] assetWriter isReadyForMoreMediaData, shouldContinue 1
2011-11-08 12:42:41.689 iStopMotion[22804:1f107] processing Block
2011-11-08 12:42:41.710 iStopMotion[22804:1f107] assetWriter isReadyForMoreMediaData, shouldContinue 1
2011-11-08 12:42:41.668 iStopMotion[22804:1e507] should continue 1
2011-11-08 12:42:41.730 iStopMotion[22804:1e507] End of while - should continue 1 - asset writer is ready for more media 1
2011-11-08 12:42:41.751 iStopMotion[22804:1f107] should continue 1
2011-11-08 12:42:41.766 iStopMotion[22804:1f107] End of while - should continue 1 - asset writer is ready for more media 0
2011-11-08 12:42:41.789 iStopMotion[22804:1f107] out of while
2011-11-08 12:42:41.766 iStopMotion[22804:1e507] assetWriter isReadyForMoreMediaData, shouldContinue 1

这会引发异常:

'NSInternalInconsistencyException', reason: '*** -[AVAssetWriterInputPixelBufferAdaptor appendPixelBuffer:withPresentationTime:]
A pixel buffer cannot be appended when readyForMoreMediaData is NO.'

看起来 AVAssetWriterInput 正在处理来自第一个块的数据,因此尚未准备好 ForMoreMediaData,其中第二个块也尝试附加像素缓冲区。

有谁知道这是如何发生的以及如何应对?

I am trying to append CGPixelBufferRefs to an AVAssetWriterInput to create a QuickTime movie.

I'm using the following code:

BOOL __block shouldContinue = YES;

[self.assetWriterInput requestMediaDataWhenReadyOnQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
usingBlock:^(void)
{
BXLog(@"processing Block");

while ([self.assetWriterInput isReadyForMoreMediaData] && shouldContinue)
{
    BXLog(@"assetWriter isReadyForMoreMediaData, shouldContinue %i", shouldContinue);

    NSError *error = nil;
    CGImageRef image = [inClip copyImageAtIndex:frameCounter withSize:CGSizeZero error:&error];
    CGFloat progress = (CGFloat)frameCounter / (CGFloat)inRange.length;

    if (image != NULL)
    {
        size_t width = CGImageGetWidth(image);
        size_t height = CGImageGetHeight(image);
        CVPixelBufferRef pixelBuffer = [self pixelBufferFromCGImage:image andSize:CGSizeMake(width, height)];

        if (! [self.assetWriterInputPixelBufferAdaptor appendPixelBuffer:pixelBuffer 
          withPresentationTime:CMTimeMake(frameCounter * inClip.lengthOfOneFrame.value,       inClip.lengthOfOneFrame.timescale)])
        {
            [self.assetWriter finishWriting];

             BXLogInDomain(kLogDomainSharing, kLogLevelError, @"Error while appending pixel butter: %@", self.assetWriter.error);
             error = [NSError errorWithDomain:kErrorDomainExport
                                         code:ZBExportAppendImageError 
                                     userInfo:nil];
        }

        CVPixelBufferRelease(pixelBuffer);
    }   
    else
    {
        [self.assetWriter finishWriting];

        BXLogInDomain(kLogDomainSharing, kLogLevelError, @"Error while coping image from clip %@", self.assetWriter.error);
        // create a Framedrop Error - we couldn't find a frame
        error = [NSError errorWithDomain:kErrorDomainExport 
                                    code:ZBExportFrameDropError
                                userInfo:nil];
     }

     [[NSOperationQueue mainQueue] addOperationWithBlock:^(void)
      {
           self.currentProgress = flag ? progress * 0.5 : progress;
      }];

     dispatch_sync(handlerQueue,
      ^(void)
      {
          shouldContinue = inProgressHandler(progress, image);
      });
      BXLog(@"should continue %i", shouldContinue);

      CGImageRelease(image);

      frameCounter++;
      // Movie is finished
      if (frameCounter >= inRange.location + inRange.length)
      {
          [self.assetWriterInput markAsFinished];
          [self.assetWriter finishWriting];
          [[NSOperationQueue mainQueue] addOperationWithBlock:^(void)
           {
               self.currentProgress = 1.0;
           }];
          dispatch_async(handlerQueue, ^(void)
           {
               inCompletionHandler(self.filePath, error);
               dispatch_release(handlerQueue);
           });
          shouldContinue = NO;
      }
      else if (shouldContinue == NO)
      {
         [self.assetWriterInput markAsFinished];
         [self.assetWriter finishWriting];

         // call the completion handler
         if (frameCounter < inRange.location + inRange.length)
         {
             dispatch_async(handlerQueue, ^(void)
              {
                  // cancel error
                  inCompletionHandler(NULL, [NSError errorWithDomain:kErrorDomainEport
                                                                code:ZBExportCancelError
                                                            userInfo:nil]);
                  dispatch_release(handlerQueue);
               });
          }

          // do not export any longer
          // simply calling the completion handler is not enough


      BXLog(@"End of while – should continue %i - asset writer is ready for more media %i", shouldContinue, [self.assetWriterInput isReadyForMoreMediaData]);
    }

    BXLog(@"out of while");

}];

}

The most time it works great, but sometimes it crashes. I could break down the crash situation to the following:

  1. For most exports, only one block is created, the while loop handels frame by frame and in the end the block exits.
  2. There is an export, where more than one block is used. A block is created, handels 4 or 5 images then leaves the while loop with [self.assetWriterInput isReadyForMoreMediaData == NO. A new block is created, handling some more frame, then leaving while loop.
  3. It happens, that sometimes not one block is created but two and both are working in parallel.

I get the following output:

2011-11-08 12:42:41.161 iStopMotion[22804:1c003] processing Block
2011-11-08 12:42:41.168 iStopMotion[22804:1c003] assetWriter isReadyForMoreMediaData, shouldContinue 1
2011-11-08 12:42:41.278 iStopMotion[22804:1c003] should continue 1
2011-11-08 12:42:41.279 iStopMotion[22804:1c003] End of while - should continue 1 - asset writer is ready for more media 1
2011-11-08 12:42:41.285 iStopMotion[22804:1c003] assetWriter isReadyForMoreMediaData, shouldContinue 1
2011-11-08 12:42:41.370 iStopMotion[22804:1c003] should continue 1
2011-11-08 12:42:41.391 iStopMotion[22804:1c003] End of while - should continue 1 - asset writer is ready for more media 1
2011-11-08 12:42:41.399 iStopMotion[22804:1c003] assetWriter isReadyForMoreMediaData, shouldContinue 1
2011-11-08 12:42:41.420 iStopMotion[22804:1c003] should continue 1
2011-11-08 12:42:41.422 iStopMotion[22804:1c003] End of while - should continue 1 - asset writer is ready for more media 0
2011-11-08 12:42:41.423 iStopMotion[22804:1c003] out of while
2011-11-08 12:42:41.442 iStopMotion[22804:1e507] processing Block
2011-11-08 12:42:41.457 iStopMotion[22804:1e507] assetWriter isReadyForMoreMediaData, shouldContinue 1
2011-11-08 12:42:41.476 iStopMotion[22804:1e507] should continue 1
2011-11-08 12:42:41.476 iStopMotion[22804:1e507] End of while - should continue 1 - asset writer is ready for more media 0
2011-11-08 12:42:41.477 iStopMotion[22804:1e507] out of while
2011-11-08 12:42:41.498 iStopMotion[22804:1e507] processing Block
2011-11-08 12:42:41.515 iStopMotion[22804:1e507] assetWriter isReadyForMoreMediaData, shouldContinue 1
2011-11-08 12:42:41.541 iStopMotion[22804:1e507] should continue 1
2011-11-08 12:42:41.553 iStopMotion[22804:1e507] End of while - should continue 1 - asset writer is ready for more media 0
2011-11-08 12:42:41.583 iStopMotion[22804:1e507] out of while
2011-11-08 12:42:41.614 iStopMotion[22804:1e507] processing Block
2011-11-08 12:42:41.628 iStopMotion[22804:1e507] assetWriter isReadyForMoreMediaData, shouldContinue 1
2011-11-08 12:42:41.689 iStopMotion[22804:1f107] processing Block
2011-11-08 12:42:41.710 iStopMotion[22804:1f107] assetWriter isReadyForMoreMediaData, shouldContinue 1
2011-11-08 12:42:41.668 iStopMotion[22804:1e507] should continue 1
2011-11-08 12:42:41.730 iStopMotion[22804:1e507] End of while - should continue 1 - asset writer is ready for more media 1
2011-11-08 12:42:41.751 iStopMotion[22804:1f107] should continue 1
2011-11-08 12:42:41.766 iStopMotion[22804:1f107] End of while - should continue 1 - asset writer is ready for more media 0
2011-11-08 12:42:41.789 iStopMotion[22804:1f107] out of while
2011-11-08 12:42:41.766 iStopMotion[22804:1e507] assetWriter isReadyForMoreMediaData, shouldContinue 1

This throws an exception:

'NSInternalInconsistencyException', reason: '*** -[AVAssetWriterInputPixelBufferAdaptor appendPixelBuffer:withPresentationTime:]
A pixel buffer cannot be appended when readyForMoreMediaData is NO.'

It looks like the AVAssetWriterInput is processing data from first block and is therefore not readyForMoreMediaData, where the second block tries to append a pixel buffer, too.

Has anyone an idea, how this comes and what to do against it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文