2014-04-06 10 views
6

Sto utilizzando l'esistente AVCaptureStillImageOutput associato a AVCaptureSession per ottenere immagini fisse. Quindi ho bisogno di scriverli su AVAssetWriter e finalmente ottenere il file video pieno di frame a intervalli di 1 secondo.AVAssetWriter ignora il valore di trasformazione

Tutto funziona correttamente eccetto le dimensioni del video in uscita in modalità verticale. Quando il dispositivo è in modalità orizzontale - tutto va bene, poiché captureStillImageAsynchronouslyFromConnection produce CMSampleBuffer con dimensioni 1920x1080 (ad esempio), ma quando il dispositivo è in modalità verticale, produce ancora CMSampleBuffer ruotato con le stesse dimensioni (1920x1080). Posso ruotare il video di output finale con la proprietà .transform di AVAssetWriterInput e funziona bene, ma il video finale ha dimensioni errate (1920x1080), ma dovrebbe essere 1080x1920.

Ho capito che il problema è in CMSampleBuffer di captureStillImageAsynchronouslyFromConnection, che ha sempre dimensioni orizzontali. Quindi l'input di AVAssetWriter ignora la larghezza e l'altezza configurate e utilizza le dimensioni di CMSampleBuffer.

Qualcuno sa come risolvere il problema?

ATTENZIONE: So che è possibile ruotare il buffer catturato con funzioni vImage o Core Graphics, ma vorrei evitare questo metodo a causa di considerazioni sulle prestazioni. Il mio problema si presenta come problema di configurazione o bug in 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

Hai trovato la soluzione? – tna0y

+0

Hai controllato se l'orientamento viene rilevato correttamente? È possibile controllare [[UIDevice currentDevice] orientation] se non viene rilevato correttamente. – Rami

+0

funziona correttamente per i frame orizzontali e non funziona solo per le cornici verticali? O è il contrario? – uchiha

risposta

1

I record nella modalità ritratto unico e sono stato in grado di evitare questo problema ottenendo i dati dei pixel ruotate direttamente dalla fotocamera utilizzando setVideoOrientation sul AVCaptureConnection a passare a AVAssetWriter (vedi 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

Hai comparato l'acquisizione di immagini usando AVCaptureStillImageOutput e hai appena provato ad estrarre le immagini da un video (che presumibilmente stai creando con AVAssetWriter)? – Crashalot

Problemi correlati