CMSampleBufferGetImageBuffer () всегда возвращает ноль в моем блоке обратного вызова захвата AVCaptureStillImageOutput - PullRequest
0 голосов
/ 30 апреля 2019

Я пишу приложение для микроскопии для MacOS (самое последнее, Obj-C). Я использую AVCaptureSession для предварительного просмотра живого видео с камеры микроскопа на экране, но я также хочу позволить пользователю делать неподвижные изображения, когда они узнают что-то интересное. Я хочу сохранить изображение максимально возможного качества в файл на диске.

Для этого я пытаюсь использовать AVCaptureStillImageOutput, что по заголовкам - то, что мне нужно. Я настроил его и добавил в сеанс захвата следующим образом:

self.stillImageOutput = [[AVCaptureStillImageOutput alloc] init];    
NSDictionary *compressionSettings = @{AVVideoQualityKey : @(1.0)};
NSDictionary *outputSettings = @{ AVVideoCodecKey : AVVideoCodecJPEG,
                                  AVVideoCompressionPropertiesKey : compressionSettings,
                                  AVVideoWidthKey : @(1024),
                                  AVVideoHeightKey : @(768)
                                  };
[self.stillImageOutput setOutputSettings:outputSettings];    
[self.session addOutput: stillImageOutput];

Позже, когда пользователь выбирает снимок - я вызываю этот метод, чтобы попытаться захватить неподвижное изображение:

// Capture a single video frame during a video capture
-(BOOL)captureStillImage: (CGRect)cropRect {
    AVCaptureConnection *videoConnection = nil;
    for (AVCaptureConnection *connection in stillImageOutput.connections) {
        for (AVCaptureInputPort *port in [connection inputPorts]) {
            if ([[port mediaType] isEqual:AVMediaTypeVideo] ) {
                videoConnection = connection;
                break;
            }
        }
        if (videoConnection) { break; }
    }
    if (videoConnection == nil) { return NO };

    [stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler:
     ^(CMSampleBufferRef imageSampleBuffer, NSError *error) {

         CVImageBufferRef imageBufferRef = CMSampleBufferGetImageBuffer(imageSampleBuffer); 
         if(imageBufferRef==nil) // <<< HERE I ALWAYS GET NULL
             return;

         NSCIImageRep *imageRep = [NSCIImageRep imageRepWithCIImage:[CIImage imageWithCVImageBuffer:imageBufferRef]];

         NSImage *compositeImage = [[NSImage alloc] initWithSize:[imageRep size]];
         NSImage *videoFrameImage = [[NSImage alloc] initWithSize:[imageRep size]];
         [videoFrameImage addRepresentation:imageRep];
         NSRect r = NSMakeRect(0.0f, 0.0f, [imageRep size].width, [imageRep size].height);
         [compositeImage lockFocus];
         [videoFrameImage drawAtPoint:NSMakePoint(0.0f, 0.0f) fromRect:r operation:NSCompositeSourceOver fraction:1.0f];
         [compositeImage unlockFocus];

         NSData *tiffImageData = [videoFrameImage TIFFRepresentation];
         NSBitmapImageRep *tiffRep = [NSBitmapImageRep imageRepWithData:tiffImageData];
         NSDictionary *imageProps = [NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:1.0] forKey:NSImageCompressionFactor];
         tiffImageData = [tiffRep representationUsingType:NSJPEGFileType properties:imageProps];

         // Save data to file
         static NSUInteger imageNumber = 0;
         NSString *imageFilePath = [@"/Users/me/Desktop/" stringByAppendingPathComponent: [NSString stringWithFormat:@"image_%lu", imageNumber++]];
         imageFilePath = [imageFilePath stringByAppendingPathExtension:@"JPG"];
         [tiffImageData writeToFile: imageFilePath atomically: NO];
    }];

    return YES;
}

Я нашел похожие вопросы других пользователей - но ответы всегда включали: «вы не применили« OutputSettings », как я, - поэтому я действительно озадачен здесь.

В качестве примечания: если я использую «сокращенный» API:

     NSData *pixelData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];

в моем обратном вызове - это успешно, но pixelData содержит плохое, низкое разрешение и маленькое изображение - конечно, не то качество, которое я вижу в моем предварительном просмотре. Более того - он сжат в формате JPEG, поэтому если я хочу его обрезать, мне нужно будет его декодировать, затем обрезать, а затем снова сжать, что приведет к еще большему снижению и без того низкого качества. Вот почему я пытаюсь использовать объект AVCaptureStillImageOutput.

Может кто-нибудь пролить свет или направить меня к правильным документам по этому поводу? Я уже уделяю этому слишком много времени, и множество задействованных фреймворков (CoreMedia, CoreVideo, CoreImage, AVFoundation) действительно плохо документированы или имеют какую-либо разумную архитектуру, которую можно понять. Ну и дела, я скучаю по компонентам QuickTime и старой APIS.

Помогите пожалуйста? кто-нибудь?

1 Ответ

0 голосов
/ 02 мая 2019

CMSampleBufferGetImageBuffer возвращает ноль, потому что вы запросили сжатые JPEG-изображения с помощью AVVideoCodecJPEG.Буфер семплов не будет содержать буфера необработанных несжатых изображений, он будет содержать одиночный блочный буфер, содержащий данные jpeg.

Вы не хотите использовать AVVideoCodecKey, AVVideoCompressionPropertiesKey и т. Д. В своем словаре,Вы хотите указать CVPixelFormatType и другие параметры, чтобы он возвращал вам несжатые кадры.См. Обсуждение в верхней части заголовка AVVideoSettings.h.

...