requestMediaDataWhenReadyOnQueue: usingBlock: создает более одного параллельного блока -> происходит сбой - PullRequest
1 голос
/ 08 ноября 2011

Я пытаюсь добавить 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 изображений, затем покидает цикл while с [self.assetWriterInput isReadyForMoreMediaData == NO. Создается новый блок, который обрабатывает еще несколько кадров, а затем покидает цикл 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, где второй блок пытается также добавить буфер пикселей.

Кто-нибудь знает, как это происходит и что с этим делать?

...