2014-04-06 8 views
6

Używam istniejącej wartości AVCaptureStillImageOutput powiązanej z AVCaptureSession w celu uzyskania obrazów statycznych. Następnie muszę napisać je do AVAssetWriter i na koniec uzyskać plik wideo wypełniony klatkami w odstępach 1-sekundowych.AVAssetWriter ignoruje wartość transformaty

Wszystko działa dobrze, oprócz wyjściowych wymiarów wideo w trybie portretu. Gdy urządzenie jest w trybie poziomym - wszystko jest w porządku, ponieważ metoda captureStillImageAsynchronouslyFromConnection generuje CMSampleBuffer z wymiarami 1920x1080 (na przykład), ale gdy urządzenie pracuje w trybie portretowym, nadal generuje obrócone CMSampleBuffer o tych samych wymiarach (1920x1080). Potrafię obracać końcowe wideo wyjściowe z właściwością .transform AVAssetWriterInput i działa dobrze, ale ostateczne wideo ma nieprawidłowe wymiary (1920x1080), ale powinno być 1080x1920.

Zorientowałem się, że problem występuje w CMSampleBuffer captureStillImageAsynchronouslyFromConnection, który zawsze ma wymiary krajobrazu. Wtedy wejście AVAssetWriter ignoruje skonfigurowaną szerokość i wysokość i używa wymiarów CMSampleBuffer.

Czy ktoś wie, jak to naprawić?

UWAGA: Wiem, że można przechwycić przechwycony bufor za pomocą funkcji vImage lub Core Graphics, ale chciałbym uniknąć tej metody ze względu na względy wydajności. Mój problem wygląda kwestii konfiguracji lub błąd w 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

Znalazłeś rozwiązanie? – tna0y

+0

Czy sprawdziłeś, czy orientacja została wykryta poprawnie? Możesz sprawdzić ustawienie [[UIDevice currentDevice]], jeśli nie jest ono prawidłowo wykrywane. – Rami

+0

czy to działa poprawnie w przypadku klatek krajobrazowych i kończy się niepowodzeniem tylko w przypadku klatek portretowych? Czy jest odwrotnie? – uchiha

Odpowiedz

1

mogę nagrywać tylko w trybie pionowym i udało mi się uniknąć tego problemu poprzez uzyskanie obrócone danych pikseli bezpośrednio z aparatu za pomocą setVideoOrientation na AVCaptureConnection do przejdź do AVAssetWriter (patrz https://developer.apple.com/library/ios/qa/qa1744/_index.html)

+0

Czy porównałeś przechwytywanie obrazów przy użyciu AVCaptureStillImageOutput i po prostu próbujesz wyodrębnić obrazy z filmu (który prawdopodobnie tworzysz przy pomocy AVAssetWriter)? – Crashalot