ios - AVAssetWriter 和 AVAssetWriterInputPixelBufferAdaptor appendingPixelBuffer 组合失败

标签 ios avasset

我正在尝试使用为 encoding asset writer 提供的示例的组合。以及 pixelBufferFromCGImage 提供的样本在我正在导出的 AVAsset 上覆盖 UIImage。

问题是,尽管此调用的 True 结果

[adaptor appendPixelBuffer:buffer withPresentationTime:kCMTimeZero];

导出的 avasset 已损坏,产生意外的大小,随后访问它失败并显示“此媒体可能已损坏”。

如果我避免尝试使用 appendPixelBuffer 调用,则导出本身是成功的。但是,将它定位在调度队列之前或其中会产生相同的故障。

希望不要在此处重复发布,但此处堆栈溢出中的其他示例似乎并未解决此特定组合故障。谢谢,代码如下

导出编码 :
 AVAsset *sourceAsset = [AVAsset assetWithURL:outputUrl];

NSError *error = nil;

NSString *fileName = [NSString stringWithFormat:@"non_transform_%f.mov", [[NSDate date] timeIntervalSince1970]];
NSString *combinedPath = [NSString stringWithFormat:@"file://localhost%@/%@", [[GroupDiskManager sharedManager] getFolderPath], fileName];

NSURL *outputURL = [NSURL URLWithString:combinedPath];
NSLog(@"combined path: %@", combinedPath);

AVAssetWriter *videoWriter = [[AVAssetWriter alloc] initWithURL:outputURL fileType:AVFileTypeQuickTimeMovie error:&error];


AVAssetTrack *videoTrack = [[sourceAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
AVAssetTrack *audioTrack = [[sourceAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];


NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:
                               AVVideoCodecH264, AVVideoCodecKey,
                               [NSNumber numberWithInt:1280], AVVideoWidthKey,
                               [NSNumber numberWithInt:720], AVVideoHeightKey,
                               nil];

AVAssetWriterInput* videoWriterInput = [[AVAssetWriterInput
                                         assetWriterInputWithMediaType:AVMediaTypeVideo
                                         outputSettings:videoSettings] retain];






NSMutableDictionary *attributes = [[NSMutableDictionary alloc] init];
[attributes setObject:[NSNumber numberWithUnsignedInt:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange] forKey:(NSString*)kCVPixelBufferPixelFormatTypeKey];
[attributes setObject:[NSNumber numberWithUnsignedInt:1280] forKey:(NSString*)kCVPixelBufferWidthKey];
[attributes setObject:[NSNumber numberWithUnsignedInt:720] forKey:(NSString*)kCVPixelBufferHeightKey];


AVAssetWriterInputPixelBufferAdaptor *adaptor = [AVAssetWriterInputPixelBufferAdaptor
                                                 assetWriterInputPixelBufferAdaptorWithAssetWriterInput:videoWriterInput
                                                 sourcePixelBufferAttributes:attributes];


NSParameterAssert(videoWriterInput);
NSParameterAssert([videoWriter canAddInput:videoWriterInput]);
videoWriterInput.expectsMediaDataInRealTime = NO;
[videoWriter addInput:videoWriterInput];

NSError *aerror = nil;

NSDictionary *videoOptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange] forKey:(id)kCVPixelBufferPixelFormatTypeKey];
AVAssetReaderTrackOutput *asset_reader_output = [[AVAssetReaderTrackOutput alloc] initWithTrack:videoTrack outputSettings:videoOptions];

AVAssetReader *reader = [[AVAssetReader alloc] initWithAsset:sourceAsset error:&aerror];
[reader addOutput:asset_reader_output];



AVAssetWriterInput* audioWriterInput = [[AVAssetWriterInput
                                         assetWriterInputWithMediaType:AVMediaTypeAudio
                                         outputSettings:nil] retain];
AVAssetReader *audioReader = [[AVAssetReader assetReaderWithAsset:sourceAsset error:&error] retain];




AVAssetReaderOutput *audioReaderOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:audioTrack outputSettings:nil];
[audioReader addOutput:audioReaderOutput];
NSParameterAssert(audioWriterInput);
NSParameterAssert([videoWriter canAddInput:audioWriterInput]);
audioWriterInput.expectsMediaDataInRealTime = YES;
[videoWriter addInput:audioWriterInput];
[videoWriter startWriting];
[videoWriter startSessionAtSourceTime:kCMTimeZero];
[reader startReading];


CVPixelBufferRef buffer = [ImageToMovieManager pixelBufferFromCGImage:[UIImage imageNamed:@"234_1280x720_3.jpg"].CGImage size:CGSizeMake(1280, 720)];
BOOL theResult = [adaptor appendPixelBuffer:buffer withPresentationTime:kCMTimeZero];

if (theResult == NO) //failes on 3GS, but works on iphone 4
    NSLog(@"failed to append buffer");

if(buffer) {
    CVBufferRelease(buffer);
}




dispatch_queue_t _processingQueue = dispatch_queue_create("_processingQueue", NULL);
[videoWriterInput requestMediaDataWhenReadyOnQueue:_processingQueue usingBlock:
 ^{
     NSLog(@"requestMediaDataWhenReadyOnQueue");

     [self retain];

     while ([videoWriterInput isReadyForMoreMediaData]) {



         CMSampleBufferRef sampleBuffer;
         if ([reader status] == AVAssetReaderStatusReading &&
             (sampleBuffer = [asset_reader_output copyNextSampleBuffer])) {

             BOOL result = [videoWriterInput appendSampleBuffer:sampleBuffer];
             CFRelease(sampleBuffer);

             if (!result) {
                 NSLog(@" result == nil Cancel!");
                 NSLog(@"videoWriter.error: %@", videoWriter.error);
                 [reader cancelReading];
                 break;

             }
         } else {
             NSLog(@"[videoWriterInput markAsFinished]");

             [videoWriterInput markAsFinished];

             switch ([reader status]) {
                 case AVAssetReaderStatusReading:
                     NSLog(@"reading");
                     // the reader has more for other tracks, even if this one is done
                     break;

                 case AVAssetReaderStatusCompleted:
                     NSLog(@"AVAssetReaderStatusCompleted");

                     [audioReader startReading];
                     dispatch_queue_t mediaInputQueue = dispatch_queue_create("mediaInputQueue", NULL);
                     [audioWriterInput requestMediaDataWhenReadyOnQueue:mediaInputQueue usingBlock:^
                      {

                          while (audioWriterInput.readyForMoreMediaData) {
                              CMSampleBufferRef nextBuffer;
                              if ([audioReader status] == AVAssetReaderStatusReading &&
                                  (nextBuffer = [audioReaderOutput copyNextSampleBuffer])) {
                                  if (nextBuffer) {
                                      [audioWriterInput appendSampleBuffer:nextBuffer];
                                  }
                              }else{
                                  [audioWriterInput markAsFinished];
                                  switch ([audioReader status]) {
                                      case AVAssetReaderStatusCompleted:
                                          NSLog(@"AVAssetReaderStatusCompleted!!");
                                          [videoWriter finishWriting];
                                          [VideoManager videoSavedWithURL:outputURL withError:(NSError *)error];
                                          break;
                                  }
                              }
                          }

                      }
                      ];
                     break;

                 case AVAssetReaderStatusFailed:
                     NSLog(@"AVAssetReaderStatusFailed");
                     [videoWriter cancelWriting];
                     break;
             }
             break;
         }
     }
 }

 ];

pixelBufferFromCGImageCode
 CGSize frameSize = CGSizeMake(CGImageGetWidth(image), CGImageGetHeight(image));
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                         [NSNumber numberWithBool:NO], kCVPixelBufferCGImageCompatibilityKey,
                         [NSNumber numberWithBool:NO], kCVPixelBufferCGBitmapContextCompatibilityKey,
                         nil];
CVPixelBufferRef pxbuffer = NULL;
CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, frameSize.width,
                                      frameSize.height,  kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, (CFDictionaryRef) options,
                                      &pxbuffer);
NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL);

CVPixelBufferLockBaseAddress(pxbuffer, 0);
void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);


CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(pxdata, frameSize.width,
                                             frameSize.height, 8, 4*frameSize.width, rgbColorSpace,
                                             kCGImageAlphaNoneSkipLast);

CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image),
                                       CGImageGetHeight(image)), image);
CGColorSpaceRelease(rgbColorSpace);
CGContextRelease(context);

CVPixelBufferUnlockBaseAddress(pxbuffer, 0);

return pxbuffer;

最佳答案

至少,pixelFormat 应该指定为 kCVPixelFormatType_32BGRA 而不是 kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange。

关于ios - AVAssetWriter 和 AVAssetWriterInputPixelBufferAdaptor appendingPixelBuffer 组合失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13333798/

相关文章:

ios - 视频方向纵向模式不起作用

ios - AVExportSession 导出视频超慢

ios - 从视频生成缩略图最终总是在 UIImageView 中旋转

ios - 在表格 View 中使用 swift 的 iAds

ios - 从 collectionView 返回什么(_ :viewForSupplementaryElementOfKind:at:) when you want to return nothing?

ios - 在 iOS 后台更新位置

ios - 如何防止触发多个位置通知

ios - 使用AVAssetReader按时间值获取特定帧

ios - 使用 CIFilter 在 CALayer 层次结构中渲染视频

ios - 如何更改 TableView 的部分索引标题的 accessibilityLabel?