Я пытаюсь добавить 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");
}];
}
Большую часть времени он прекрасно работает, но иногда он вылетает. Я мог бы разбить аварийную ситуацию следующим образом:
- Для большинства экспортов создается только один блок, в то время как цикл while обрабатывает кадр за кадром, и в конце блок выходит.
- Существует экспорт, в котором используется более одного блока. Блок создается, обрабатывает 4 или 5 изображений, затем покидает цикл while с [self.assetWriterInput isReadyForMoreMediaData == NO. Создается новый блок, который обрабатывает еще несколько кадров, а затем покидает цикл while.
- Бывает, что иногда создается не один блок, а два, и оба работают параллельно.
Я получаю следующий вывод:
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, где второй блок пытается также добавить буфер пикселей.
Кто-нибудь знает, как это происходит и что с этим делать?