2012-03-01 6 views
4

私は非常に簡単なことをやろうとしています。私は、フルスクリーンでビデオレイヤーを表示したいと思います。そして、1秒に1回、CMSampleBufferRefでUIImageを更新します。しかし私は2つの異なる問題に遭遇しています。最初の1であることを変える:キャプチャ出力プロトコルから画像を呼び出すと画像が更新されないのはなぜですか?

[connection setVideoMaxFrameDuration:CMTimeMake(1, 1)]; 
[connection setVideoMinFrameDuration:CMTimeMake(1, 1)]; 

また、ビデオプレビュー層を変更します、私はそれが唯一のAV基盤がデリゲートに情報を送るところでレートを変更するだろうと思ったが、セッション全体に影響を及ぼしているようです(それはより明白に見える)。これにより、毎秒私のビデオが更新されます。私はそれらの行を省略することができ、それを処理する別のメソッドにCMSampleBufferRefを毎秒送信するように、デリゲートにタイマーを追加するだけです。しかし、これが正しいアプローチであるかどうかは分かりません。

私の第二の問題は、UIImageViewが更新されていない、あるいは時にはそれが一度だけ更新した後に変更されないということです。私はそれを更新するには、このメソッドを使用しています:私はリンゴの例から取った

- (void)captureOutput:(AVCaptureOutput *)captureOutput 
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer 
     fromConnection:(AVCaptureConnection *)connection { 
    //NSData *jpeg = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:sampleBuffer] ; 
    UIImage *image = [self imageFromSampleBuffer:sampleBuffer]; 
    [imageView setImage:image]; 
    // Add your code here that uses the image. 
    NSLog(@"update"); 
} 

。このメソッドは、更新メッセージを読んでチェックする毎秒正しく呼び出されています。しかし、イメージは全く変化していません。また、sampleBufferが自動的に破棄されるか、またはそれを解放する必要がありますか? ビューがロードDID:UIImageに

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    // Do any additional setup after loading the view, typically from a nib. 

    session = [[AVCaptureSession alloc] init]; 

    // Add inputs and outputs. 
    if ([session canSetSessionPreset:AVCaptureSessionPreset640x480]) { 
     session.sessionPreset = AVCaptureSessionPreset640x480; 
    } 
    else { 
     // Handle the failure. 
     NSLog(@"Cannot set session preset to 640x480"); 
    } 

    AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; 

    NSError *error = nil; 
    AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error]; 

    if (!input) { 
     // Handle the error appropriately. 
     NSLog(@"Could create input: %@", error); 
    } 

    if ([session canAddInput:input]) { 
     [session addInput:input]; 
    } 
    else { 
     // Handle the failure. 
     NSLog(@"Could not add input"); 
    } 

    // DATA OUTPUT 
    dataOutput = [[AVCaptureVideoDataOutput alloc] init]; 

    if ([session canAddOutput:dataOutput]) { 
     [session addOutput:dataOutput]; 

     dataOutput.videoSettings = 
     [NSDictionary dictionaryWithObject: [NSNumber numberWithInt:kCVPixelFormatType_32BGRA] 
            forKey: (id)kCVPixelBufferPixelFormatTypeKey]; 
     //dataOutput.minFrameDuration = CMTimeMake(1, 15); 
     //dataOutput.minFrameDuration = CMTimeMake(1, 1); 
     AVCaptureConnection *connection = [dataOutput connectionWithMediaType:AVMediaTypeVideo]; 

     [connection setVideoMaxFrameDuration:CMTimeMake(1, 1)]; 
     [connection setVideoMinFrameDuration:CMTimeMake(1, 1)]; 

    } 
    else { 
     // Handle the failure. 
     NSLog(@"Could not add output"); 
    } 
    // DATA OUTPUT END 

    dispatch_queue_t queue = dispatch_queue_create("MyQueue", NULL); 
    [dataOutput setSampleBufferDelegate:self queue:queue]; 
    dispatch_release(queue); 


    captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session]; 

    [captureVideoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspect]; 

    [captureVideoPreviewLayer setBounds:videoLayer.layer.bounds]; 
    [captureVideoPreviewLayer setPosition:videoLayer.layer.position]; 

    [videoLayer.layer addSublayer:captureVideoPreviewLayer]; 

    [session startRunning]; 
} 

隠密CMSampleBufferRefを:あなたは私を与えることができます任意の助けを事前に

- (UIImage *) imageFromSampleBuffer:(CMSampleBufferRef) sampleBuffer 
{ 
    // Get a CMSampleBuffer's Core Video image buffer for the media data 
    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); 
    // Lock the base address of the pixel buffer 
    CVPixelBufferLockBaseAddress(imageBuffer, 0); 

    // Get the number of bytes per row for the pixel buffer 
    void *baseAddress = CVPixelBufferGetBaseAddress(imageBuffer); 

    // Get the number of bytes per row for the pixel buffer 
    size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer); 
    // Get the pixel buffer width and height 
    size_t width = CVPixelBufferGetWidth(imageBuffer); 
    size_t height = CVPixelBufferGetHeight(imageBuffer); 

    // Create a device-dependent RGB color space 
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 

    // Create a bitmap graphics context with the sample buffer data 
    CGContextRef context = CGBitmapContextCreate(baseAddress, width, height, 8, 
               bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst); 
    // Create a Quartz image from the pixel data in the bitmap graphics context 
    CGImageRef quartzImage = CGBitmapContextCreateImage(context); 
    // Unlock the pixel buffer 
    CVPixelBufferUnlockBaseAddress(imageBuffer,0); 

    // Free up the context and color space 
    CGContextRelease(context); 
    CGColorSpaceRelease(colorSpace); 

    // Create an image object from the Quartz image 
    UIImage *image = [UIImage imageWithCGImage:quartzImage]; 

    // Release the Quartz image 
    CGImageRelease(quartzImage); 

    return (image); 
} 

おかげ

これは、他の2つの重要な方法です。 captureOutput:didOutputSampleBuffer:fromConnection:メソッドのドキュメントから

答えて

8

この方法は、出力のsampleBufferCallbackQueueプロパティで指定されたディスパッチキューに呼ばれています。

これは、あなたがこのようなメインキューにそれを行う必要があり、この方法では、バッファを使用してUIを更新する必要がある場合ことを意味します

- (void)captureOutput:(AVCaptureOutput *)captureOutput 
didOutputSampleBuffer: (CMSampleBufferRef)sampleBuffer 
     fromConnection:(AVCaptureConnection *)connection { 

    UIImage *image = [self imageFromSampleBuffer:sampleBuffer]; 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     [imageView setImage:image]; 
    }); 
} 

EDIT:あなたの最初の質問について: をI私は問題を理解しているのか分からないが、1秒に1回だけイメージを更新したい場合は、 "didOutputSampleBuffer"メソッドと比較する "lastImageUpdateTime"値を持たせることができ、それ以外の場合はサンプルバッファを無視します。

+0

私が望んでメイントレッドacomplishにそれを移動するには、トレッドの良い学習サイトを知ることが起こるのか?私は彼らに全く新しいです。また、最初の質問は、私はリアルタイムで表示されるビデオが欲しいですが、私は重度のprossesingを行う予定とiphoneがそれを処理することができない可能性があるため、毎秒1フレームを処理したい。だから私はどのようにビデオfpsを通常に設定し、毎秒1回出力ルーチンをキャプチャするのか分からない。 – Pochi

+0

私はアップルのドキュメントはあなたが得ることができる最高だと思います。【発送キュー](https://developer.apple.com/library/mac/#documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html#//apple_ref/doc/uid/TP40008091-CH102-SW1)と[Threading](https://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/Multithreading/Introduction/Introduction.html)を参照してください。あなたの他の問題については、私の答えで提案した技術がうまくいくと思います。 – adig

関連する問題