2016-07-30 11 views
0

私のアプリでは、ビューに表示されるカメラからビデオをキャプチャするためにUIViewをサブクラス化し、その上にオーバーレイされたUIImageをサブクラス化します。私はAutoLayoutを有効にしていますが、ViewはSimulated Metrics SizeのXIBにリストされているものと同じサイズのままです。推定されたメトリックを推論またはフリーフォームとして残しても、いずれのモデルでも機能しませんが、iPhone 4.7に配置すると、その背景に背景が表示されます。ここでAVCaptureSessionが起こるのViewControllerのためのコードは次のとおりです。XIBで表示すると異なるデバイスでサイズが変更されない

-(void)viewWillAppear:(BOOL)animated { 
    NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft]; 
    [[UIDevice currentDevice] setValue:value forKey:@"orientation"]; 
    NSDate *today = [NSDate date]; 
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; 
    [dateFormatter setDateFormat:@"MMM d hh:mm:ss a"]; 
    // display in 12HR/24HR (i.e. 11:25PM or 23:25) format according to User Settings 
    NSString *currentTime = [dateFormatter stringFromDate:today]; 
    NSError* error4 = nil; 
    AVAudioSession* audioSession = [AVAudioSession sharedInstance]; 
    [audioSession setCategory:AVAudioSessionCategoryAmbient error:&error4]; 
    OSStatus propertySetError = 0; 
    UInt32 allowMixing = true; 
    propertySetError |= AudioSessionSetProperty(kAudioSessionProperty_OtherMixableAudioShouldDuck, sizeof(allowMixing), &allowMixing); 

    // Activate the audio session 
    error4 = nil; 
    if (![audioSession setActive:YES error:&error4]) { 
     NSLog(@"AVAudioSession setActive:YES failed: %@", [error4 localizedDescription]); 
    } 
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
    NSString *documentsDirectoryPath = [paths objectAtIndex:0]; 

    self.session = [[AVCaptureSession alloc] init]; 
    [self.session beginConfiguration]; 
    self.session.sessionPreset = AVCaptureSessionPreset1280x720; 
    self.navigationController.navigationBarHidden = YES; 

    NSError *error = nil; 

    AVCaptureDevice *audioCaptureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio]; 
    NSError *error2 = nil; 
    AVCaptureDeviceInput *audioInput = [AVCaptureDeviceInput deviceInputWithDevice:audioCaptureDevice error:&error2]; 


    AVCaptureDevice *device; 
    AVCaptureDevicePosition desiredPosition = AVCaptureDevicePositionBack; 
    // find the front facing camera 

    device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; 


    // get the input device 
    AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error]; 




    AVCaptureMovieFileOutput *movieFileOutput = [[AVCaptureMovieFileOutput alloc] init]; 

    NSString *archives = [documentsDirectoryPath stringByAppendingPathComponent:@"archives"]; 
    NSString *editedfilename = [[@"ComeOnDown" lastPathComponent] stringByDeletingPathExtension]; 
    NSString *datestring = [[editedfilename stringByAppendingString:@" "] stringByAppendingString:currentTime]; 
    NSLog(@"%@", datestring); 
    NSString *outputpathofmovie = [[archives stringByAppendingPathComponent:datestring] stringByAppendingString:@".mp4"]; 
    NSURL *outputURL = [[NSURL alloc] initFileURLWithPath:outputpathofmovie]; 
    [self.session addInput:audioInput]; 
    [self.session addInput:deviceInput]; 
    [self.session addOutput:movieFileOutput]; 
    [self.session commitConfiguration]; 
    [self.session startRunning]; 




    AVCaptureVideoPreviewLayer *previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.session]; 
    previewLayer.backgroundColor = [[UIColor blackColor] CGColor]; 
    previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; 
    previewLayer.connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight; 

    CALayer *overlayLayer = [CALayer layer]; 
    CALayer *overlayLayer2 = [CALayer layer]; 

    UIImage *overlayImage = [UIImage imageNamed:@"LiveBorder.png"]; 

    [overlayLayer setContents:(id)[overlayImage CGImage]]; 
    overlayLayer.frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height); 
    [overlayLayer setMasksToBounds:YES]; 

     CALayer *rootLayer = [self.view layer]; 
    [rootLayer setMasksToBounds:YES]; 
    [previewLayer setFrame:[rootLayer bounds]]; 
    [rootLayer addSublayer:previewLayer]; 
    [rootLayer addSublayer:overlayLayer]; 
    [rootLayer addSublayer:label2.layer]; 
     movieFileOutput.movieFragmentInterval = kCMTimeInvalid; 

    [movieFileOutput startRecordingToOutputFileURL:outputURL recordingDelegate:self]; 



    //self.session = nil; 
    if (error) { 
     UIAlertView *alertView = [[UIAlertView alloc] initWithTitle: 
            [NSString stringWithFormat:@"Failed with error %d", (int)[error code]] 
                  message:[error localizedDescription] 
                  delegate:nil 
                cancelButtonTitle:@"Dismiss" 
                otherButtonTitles:nil]; 
     [alertView show]; 

    } 
    [super viewWillAppear:YES]; 
} 
-(void)viewWillDisappear:(BOOL)animated { 
    self.navigationController.navigationBarHidden = NO; 

} 

-(void)captureOutput:(AVCaptureFileOutput *)captureOutput didStartRecordingToOutputFileAtURL:(NSURL *)fileURL fromConnections:(NSArray *)connections { 

} 
-(void)video:(NSString *)videoPath didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo{ 
    NSLog(@"Finished with error: %@", error); 
} 
- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error { 
    //finished 
    NSLog(@"Finished"); 
    NSString *proud = [[NSString alloc] initWithString:[outputFileURL path]]; 
    UISaveVideoAtPathToSavedPhotosAlbum(proud, self, @selector(video:didFinishSavingWithError: contextInfo:), (__bridge void *)(proud)); 
} 

-(IBAction)goBackNow { 
    [myAVPlayer stop]; 

    [self.session stopRunning]; 
    // [captureView performSelector:@selector(stopRecording) withObject:nil afterDelay:0.0]; 

    NSString *outputPath = [[NSString alloc] initWithFormat:@"%@/%@", [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0], @"output.mp4"]; 
    UISaveVideoAtPathToSavedPhotosAlbum(outputPath, self, @selector(video:didFinishSavingWithError: contextInfo:), (__bridge void *)(outputPath)); 

    [self.navigationController popToRootViewControllerAnimated:YES]; 
    self.navigationController.navigationBarHidden = NO; 

    //[self.navigationController popToRootViewControllerAnimated:YES]; 
} 
-(void)allDone { 

} 
- (void)didReceiveMemoryWarning { 
    [super didReceiveMemoryWarning]; 
    // Dispose of any resources that can be recreated. 
} 


@end 

そしてここでは、UIViewのサブクラスのコードは次のとおりです。self.viewのサイズは取得していない:

- (void) writeVideoFrameAtTime:(CMTime)time; 
@end 

@implementation ScreenCaptureView 

@synthesize currentScreen, frameRate, delegate; 

- (void) initialize { 
    // Initialization code 
    self.clearsContextBeforeDrawing = YES; 
    self.currentScreen = nil; 
    self.frameRate = 10.0f;  //10 frames per seconds 
    _recording = false; 
    videoWriter = nil; 
    videoWriterInput = nil; 
    avAdaptor = nil; 
    startedAt = nil; 
    bitmapData = NULL; 
} 

- (id) initWithCoder:(NSCoder *)aDecoder { 
    self = [super initWithCoder:aDecoder]; 
    if (self) { 
     [self initialize]; 
    } 
    return self; 
} 

- (id) init { 
    self = [super init]; 
    if (self) { 
     [self initialize]; 
    } 
    return self; 
} 

- (id)initWithFrame:(CGRect)frame { 
    self = [super initWithFrame:frame]; 
    if (self) { 
     [self initialize]; 
    } 
    return self; 
} 

- (CGContextRef) createBitmapContextOfSize:(CGSize) size { 
    CGContextRef context = NULL; 
    CGColorSpaceRef colorSpace; 
    int    bitmapByteCount; 
    int    bitmapBytesPerRow; 

    bitmapBytesPerRow = (size.width * 4); 
    bitmapByteCount  = (bitmapBytesPerRow * size.height); 
    colorSpace = CGColorSpaceCreateDeviceRGB(); 
    if (bitmapData != NULL) { 
     free(bitmapData); 
    } 
    bitmapData = malloc(bitmapByteCount); 
    if (bitmapData == NULL) { 
     fprintf (stderr, "Memory not allocated!"); 
     return NULL; 
    } 

    context = CGBitmapContextCreate (bitmapData, 
            size.width, 
            size.height, 
            8,  // bits per component 
            bitmapBytesPerRow, 
            colorSpace, 
            kCGImageAlphaNoneSkipFirst); 

    CGContextSetAllowsAntialiasing(context,NO); 
    if (context== NULL) { 
     free (bitmapData); 
     fprintf (stderr, "Context not created!"); 
     return NULL; 
    } 
    CGColorSpaceRelease(colorSpace); 

    return context; 
} 

//static int frameCount = 0;   //debugging 
- (void) drawRect:(CGRect)rect { 
    NSDate* start = [NSDate date]; 
    CGContextRef context = [self createBitmapContextOfSize:self.frame.size]; 

    //not sure why this is necessary...image renders upside-down and mirrored 
    CGAffineTransform flipVertical = CGAffineTransformMake(1, 0, 0, -1, 0, self.frame.size.height); 
    CGContextConcatCTM(context, flipVertical); 

    [self.layer renderInContext:context]; 

    CGImageRef cgImage = CGBitmapContextCreateImage(context); 
    UIImage* background = [UIImage imageWithCGImage: cgImage]; 
    CGImageRelease(cgImage); 

    self.currentScreen = background; 

    //debugging 
    //if (frameCount < 40) { 
    //  NSString* filename = [NSString stringWithFormat:@"Documents/frame_%d.png", frameCount]; 
    //  NSString* pngPath = [NSHomeDirectory() stringByAppendingPathComponent:filename]; 
    //  [UIImagePNGRepresentation(self.currentScreen) writeToFile: pngPath atomically: YES]; 
    //  frameCount++; 
    //} 

    //NOTE: to record a scrollview while it is scrolling you need to implement your UIScrollViewDelegate such that it calls 
    //  'setNeedsDisplay' on the ScreenCaptureView. 
    if (_recording) { 
     float millisElapsed = [[NSDate date] timeIntervalSinceDate:startedAt] * 1000.0; 
     [self writeVideoFrameAtTime:CMTimeMake((int)millisElapsed, 1000)]; 
    } 

    float processingSeconds = [[NSDate date] timeIntervalSinceDate:start]; 
    float delayRemaining = (1.0/self.frameRate) - processingSeconds; 

    CGContextRelease(context); 

    //redraw at the specified framerate 
    [self performSelector:@selector(setNeedsDisplay) withObject:nil afterDelay:delayRemaining > 0.0 ? delayRemaining : 0.01]; 
} 

- (void) cleanupWriter { 
    [avAdaptor release]; 
    avAdaptor = nil; 

    [videoWriterInput release]; 
    videoWriterInput = nil; 

    [videoWriter release]; 
    videoWriter = nil; 

    [startedAt release]; 
    startedAt = nil; 

    if (bitmapData != NULL) { 
     free(bitmapData); 
     bitmapData = NULL; 
    } 
} 

- (void)dealloc { 
    [self cleanupWriter]; 
    [super dealloc]; 
} 

- (NSURL*) tempFileURL { 
    NSString* outputPath = [[NSString alloc] initWithFormat:@"%@/%@", [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0], @"output.mp4"]; 
    NSURL* outputURL = [[NSURL alloc] initFileURLWithPath:outputPath]; 
    NSFileManager* fileManager = [NSFileManager defaultManager]; 
    if ([fileManager fileExistsAtPath:outputPath]) { 
     NSError* error; 
     if ([fileManager removeItemAtPath:outputPath error:&error] == NO) { 
      NSLog(@"Could not delete old recording file at path: %@", outputPath); 
     } 
    } 

    [outputPath release]; 
    return [outputURL autorelease]; 
} 

-(BOOL) setUpWriter { 
    NSError* error = nil; 
    videoWriter = [[AVAssetWriter alloc] initWithURL:[self tempFileURL] fileType:AVFileTypeQuickTimeMovie error:&error]; 
    NSParameterAssert(videoWriter); 

    //Configure video 
    NSDictionary* videoCompressionProps = [NSDictionary dictionaryWithObjectsAndKeys: 
              [NSNumber numberWithDouble:1024.0*1024.0], AVVideoAverageBitRateKey, 
              nil ]; 

    NSDictionary* videoSettings = [NSDictionary dictionaryWithObjectsAndKeys: 
            AVVideoCodecH264, AVVideoCodecKey, 
            [NSNumber numberWithInt:self.frame.size.width], AVVideoWidthKey, 
            [NSNumber numberWithInt:self.frame.size.height], AVVideoHeightKey, 
            videoCompressionProps, AVVideoCompressionPropertiesKey, 
            nil]; 

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

    NSParameterAssert(videoWriterInput); 
    videoWriterInput.expectsMediaDataInRealTime = YES; 
    NSDictionary* bufferAttributes = [NSDictionary dictionaryWithObjectsAndKeys: 
             [NSNumber numberWithInt:kCVPixelFormatType_32ARGB], kCVPixelBufferPixelFormatTypeKey, nil]; 

    avAdaptor = [[AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:videoWriterInput sourcePixelBufferAttributes:bufferAttributes] retain]; 

    //add input 
    [videoWriter addInput:videoWriterInput]; 
    [videoWriter startWriting]; 
    [videoWriter startSessionAtSourceTime:CMTimeMake(0, 1000)]; 

    return YES; 
} 

- (void) completeRecordingSession { 
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; 

    [videoWriterInput markAsFinished]; 

    // Wait for the video 
    int status = videoWriter.status; 
    while (status == AVAssetWriterStatusUnknown) { 
     NSLog(@"Waiting..."); 
     [NSThread sleepForTimeInterval:0.5f]; 
     status = videoWriter.status; 
    } 

    @synchronized(self) { 
     BOOL success = [videoWriter finishWriting]; 
     if (!success) { 
      NSLog(@"finishWriting returned NO"); 
     } 

     [self cleanupWriter]; 

     id delegateObj = self.delegate; 
     NSString *outputPath = [[NSString alloc] initWithFormat:@"%@/%@", [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0], @"output.mp4"]; 
     NSURL *outputURL = [[NSURL alloc] initFileURLWithPath:outputPath]; 

     NSLog(@"Completed recording, file is stored at: %@", outputURL); 
     if ([delegateObj respondsToSelector:@selector(recordingFinished:)]) { 
      [delegateObj performSelectorOnMainThread:@selector(recordingFinished:) withObject:(success ? outputURL : nil) waitUntilDone:YES]; 
     } 

     [outputPath release]; 
     [outputURL release]; 
    } 

    [pool drain]; 
} 

- (bool) startRecording { 
    bool result = NO; 
    @synchronized(self) { 
     if (! _recording) { 
      result = [self setUpWriter]; 
      startedAt = [[NSDate date] retain]; 
      _recording = true; 
     } 
    } 

    return result; 
} 

- (void) stopRecording { 
    @synchronized(self) { 
     if (_recording) { 
      _recording = false; 
      [self completeRecordingSession]; 
     } 
    } 
} 

-(void) writeVideoFrameAtTime:(CMTime)time { 
    if (![videoWriterInput isReadyForMoreMediaData]) { 
     NSLog(@"Not ready for video data"); 
    } 
    else { 
     @synchronized (self) { 
      UIImage* newFrame = [self.currentScreen retain]; 
      CVPixelBufferRef pixelBuffer = NULL; 
      CGImageRef cgImage = CGImageCreateCopy([newFrame CGImage]); 
      CFDataRef image = CGDataProviderCopyData(CGImageGetDataProvider(cgImage)); 

      int status = CVPixelBufferPoolCreatePixelBuffer(kCFAllocatorDefault, avAdaptor.pixelBufferPool, &pixelBuffer); 
      if(status != 0){ 
       //could not get a buffer from the pool 
       NSLog(@"Error creating pixel buffer: status=%d", status); 
      } 
      // set image data into pixel buffer 
      CVPixelBufferLockBaseAddress(pixelBuffer, 0); 
      uint8_t* destPixels = CVPixelBufferGetBaseAddress(pixelBuffer); 
      CFDataGetBytes(image, CFRangeMake(0, CFDataGetLength(image)), destPixels); //XXX: will work if the pixel buffer is contiguous and has the same bytesPerRow as the input data 

      if(status == 0){ 
       BOOL success = [avAdaptor appendPixelBuffer:pixelBuffer withPresentationTime:time]; 
       if (!success) 
        NSLog(@"Warning: Unable to write buffer to video"); 
      } 

      //clean up 
      [newFrame release]; 
      CVPixelBufferUnlockBaseAddress(pixelBuffer, 0); 
      CVPixelBufferRelease(pixelBuffer); 
      CFRelease(image); 
      CGImageRelease(cgImage); 
     } 

    } 

} 

@end 

答えて

0

私が観察したものから

までサイズを変更 - (無効)viewDidAppear:(BOOL)はViewWillAppearにコードを置くこと

を助けない

アニメーション

オリエンテーションが変更されるたびにこれを行うこともできます:

 self.view.frame = [[UIScreen mainScreen] bounds]; 
    _prevLayer.frame = [[UIScreen mainScreen] bounds]; 
    _prevLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; 
    [_prevLayer.connection setVideoOrientation:statusBarOrientation]; 
関連する問題