2014-04-06 22 views
6

我使用綁定到AVCaptureSession的現有AVCaptureStillImageOutput來獲取靜止圖像。 然後,我需要將它們寫入AVAssetWriter,最後以1秒爲間隔獲取充滿幀的視頻文件。AVAssetWriter忽略變換值

除肖像模式下的輸出視頻尺寸外,一切正常。 當設備處於橫向模式時 - 一切正常,因爲captureStillImageAsynchronouslyFromConnection會生成尺寸爲1920x1080(例如)的CMSampleBuffer,但是當設備處於縱向模式時,它仍會生成具有相同尺寸(1920x1080)的旋轉CMSampleBuffer。 我可以使用AVAssetWriterInput的.transform屬性旋轉最終輸出視頻,它工作正常,但最終的視頻尺寸錯誤(1920x1080),但應該是1080x1920。

我已經知道問題出在CaptureStillImageAsynchronouslyFromConnection的CMSampleBuffer中,它總是具有橫向尺寸。然後AVAssetWriter的輸入忽略配置的寬度和高度,並使用CMSampleBuffer的尺寸。

有人知道如何解決這個問題嗎?

注意:我知道可以用vImage或Core Graphics函數旋轉捕獲的緩衝區,但是我想避免這種方法,因爲性能方面的考慮。 我的問題是像配置問題或錯誤的iOS ...在縱向模式下

- (void) setupLongLoopWriter 
{ 
self.currentFragment.filename2 = [VideoCapture getFilenameForNewFragment]; 
NSString *path = [NSString stringWithFormat:@"%@/%@", [GMConfig getVideoCapturesPath], self.currentFragment.filename2]; 

CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(self.currentCamera.activeFormat.formatDescription); 

CGSize videoWriterFrameSize = CGSizeMake(dimensions.width, dimensions.height); 

float rotationAngle = 0.0; 

switch ((UIDeviceOrientation)[self.currentFragment.orientation unsignedIntValue]) 
{ 
    case UIDeviceOrientationUnknown: 
    case UIDeviceOrientationPortrait: 
    case UIDeviceOrientationFaceUp: 
    case UIDeviceOrientationFaceDown: 
     rotationAngle = DEGREES_TO_RADIANS(90); 
     videoWriterFrameSize = CGSizeMake(dimensions.height, dimensions.width); 
     break; 

    case UIDeviceOrientationPortraitUpsideDown: 
     rotationAngle = DEGREES_TO_RADIANS(-90.0); 
     videoWriterFrameSize = CGSizeMake(dimensions.height, dimensions.width); 
     break; 

    case UIDeviceOrientationLandscapeLeft: 
     rotationAngle = 0.0; 
     break; 

    case UIDeviceOrientationLandscapeRight: 
     rotationAngle = DEGREES_TO_RADIANS(180.0); 
     break; 
} 

    // NSLog(@"%.0fx%.0f", videoWriterFrameSize.width, videoWriterFrameSize.height); 

NSError *error = nil; 

self.currentFragment.longLoopWriter = [[AVAssetWriter alloc] initWithURL:[NSURL fileURLWithPath:path] 
                 fileType:AVFileTypeQuickTimeMovie 
                  error:&error]; 
NSParameterAssert(self.currentFragment.longLoopWriter); 

NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys: 
           AVVideoCodecH264, AVVideoCodecKey, 
           AVVideoScalingModeResizeAspect, AVVideoScalingModeKey, 
           [NSNumber numberWithInt:videoWriterFrameSize.width], AVVideoWidthKey, 
           [NSNumber numberWithInt:videoWriterFrameSize.height], AVVideoHeightKey, 
           nil]; 

AVAssetWriterInput* writerInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo 
                    outputSettings:videoSettings]; 
writerInput.expectsMediaDataInRealTime = YES; 

if (rotationAngle != 0.0) 
    writerInput.transform = CGAffineTransformMakeRotation (rotationAngle); 


NSDictionary *sourcePixelBufferAttributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys: 
                 [NSNumber numberWithInt:kCVPixelFormatType_32ARGB], kCVPixelBufferPixelFormatTypeKey, nil]; 

self.currentFragment.longLoopWriterAdaptor = [AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:writerInput sourcePixelBufferAttributes:sourcePixelBufferAttributesDictionary]; 

NSParameterAssert(writerInput); 
NSParameterAssert([self.currentFragment.longLoopWriter canAddInput:writerInput]); 


[self.currentFragment.longLoopWriter addInput:writerInput]; 

if([self.currentFragment.longLoopWriter startWriting] == NO) 
    NSLog(@"Failed to start long loop writing!"); 

[self.currentFragment.longLoopWriter startSessionAtSourceTime:kCMTimeZero]; 
} 

- (void) captureLongLoopFrame 
{ 
if ([GMConfig sharedConfig].longLoopFrameDuration == 0.0) { 
    [self.longLoopCaptureTimer invalidate]; 
    self.longLoopCaptureTimer = nil; 

    return; 
} 

if (self.captureSession.isRunning == NO || self.currentFragment.longLoopWriterAdaptor == nil) 
    return; 

[self.shutterOutput captureStillImageAsynchronouslyFromConnection:[self.shutterOutput.connections objectAtIndex:0] 
               completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) { 
    if (imageDataSampleBuffer != NULL && error == nil) { 
     /* 
     CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(CMSampleBufferGetFormatDescription(imageDataSampleBuffer)); 
     CGSize videoWriterFrameSize = CGSizeMake(dimensions.width, dimensions.height); 

     NSLog(@"Image buffer size: %.0fx%.0f", videoWriterFrameSize.width, videoWriterFrameSize.height); 
     */ 

     double offset = [[NSDate date] timeIntervalSinceDate:self.currentFragment.start]; 
     CMTime presentationTime = CMTimeMake(offset*1000, 1000); 

     CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(imageDataSampleBuffer); 




     if (self.currentFragment.longLoopWriterAdaptor.assetWriterInput.readyForMoreMediaData == YES) { 
      if([self.currentFragment.longLoopWriterAdaptor appendPixelBuffer:imageBuffer withPresentationTime:presentationTime] == NO) { 
       NSLog(@"Error adding frame to long loop!"); 
      } 
     } 

     NSLog(@"Long loop updated at %0.1f", CMTimeGetSeconds(presentationTime)); 
    } 
}]; 
} 
+0

您是否找到了解決方案? – tna0y

+0

您是否檢查方向是否正確檢測?如果未正確檢測到[[UIDevice currentDevice]方向],您可以檢查它。 – Rami

+0

這是工作正常的景觀幀和失敗只爲肖像幀?或者是相反的? – uchiha

回答

1

我的記錄,我能夠通過對AVCaptureConnection到setVideoOrientation直接從相機獲取旋轉像素數據來避免這個問題傳遞給AVAssetWriter(請參閱https://developer.apple.com/library/ios/qa/qa1744/_index.html

for (AVCaptureConnection *connection in [videoOutput connections]) { 
      for (AVCaptureInputPort *port in [connection inputPorts]) { 
       if ([[port mediaType] isEqual:AVMediaTypeVideo]) { 

        [connection setVideoOrientation:AVCaptureVideoOrientationPortrait]; 

       } 
      } 
} 
+0

您是否使用AVCaptureStillImageOutput比較捕獲圖像,並試圖從視頻中提取靜止圖像(推測您正在使用AVAssetWriter創建)? – Crashalot