How to get the Y component from CMSampleBuffer resulted from the AVCaptureSession?

前端 未结 4 1597
隐瞒了意图╮
隐瞒了意图╮ 2020-12-13 11:18

Hey there, I am trying to access raw data from iphone camera using AVCaptureSession. I follow the guide provided by Apple (link here).

The raw data from the samplebu

4条回答
  •  不思量自难忘°
    2020-12-13 12:09

    If you only need the luminance channel, I recommend against using BGRA format, as it comes with a conversion overhead. Apple suggest using BGRA if you're doing rendering stuff, but you don't need it for extracting the luminance information. As Brad already mentioned, the most efficient format is the camera-native YUV format.

    However, extracting the right bytes from the sample buffer is a bit tricky, especially regarding the iPhone 3G with it's interleaved YUV 422 format. So here is my code, which works fine with the iPhone 3G, 3GS, iPod Touch 4 and iPhone 4S.

    #pragma mark -
    #pragma mark AVCaptureVideoDataOutputSampleBufferDelegate Methods
    #if !(TARGET_IPHONE_SIMULATOR)
    - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection;
    {
        // get image buffer reference
        CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
    
        // extract needed informations from image buffer
        CVPixelBufferLockBaseAddress(imageBuffer, 0);
        size_t bufferSize = CVPixelBufferGetDataSize(imageBuffer);
        void *baseAddress = CVPixelBufferGetBaseAddress(imageBuffer);
        CGSize resolution = CGSizeMake(CVPixelBufferGetWidth(imageBuffer), CVPixelBufferGetHeight(imageBuffer));
    
        // variables for grayscaleBuffer 
        void *grayscaleBuffer = 0;
        size_t grayscaleBufferSize = 0;
    
        // the pixelFormat differs between iPhone 3G and later models
        OSType pixelFormat = CVPixelBufferGetPixelFormatType(imageBuffer);
    
        if (pixelFormat == '2vuy') { // iPhone 3G
            // kCVPixelFormatType_422YpCbCr8     = '2vuy',    
            /* Component Y'CbCr 8-bit 4:2:2, ordered Cb Y'0 Cr Y'1 */
    
            // copy every second byte (luminance bytes form Y-channel) to new buffer
            grayscaleBufferSize = bufferSize/2;
            grayscaleBuffer = malloc(grayscaleBufferSize);
            if (grayscaleBuffer == NULL) {
                NSLog(@"ERROR in %@:%@:%d: couldn't allocate memory for grayscaleBuffer!", NSStringFromClass([self class]), NSStringFromSelector(_cmd), __LINE__);
                return nil; }
            memset(grayscaleBuffer, 0, grayscaleBufferSize);
            void *sourceMemPos = baseAddress + 1;
            void *destinationMemPos = grayscaleBuffer;
            void *destinationEnd = grayscaleBuffer + grayscaleBufferSize;
            while (destinationMemPos <= destinationEnd) {
                memcpy(destinationMemPos, sourceMemPos, 1);
                destinationMemPos += 1;
                sourceMemPos += 2;
            }       
        }
    
        if (pixelFormat == '420v' || pixelFormat == '420f') {
            // kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange = '420v', 
            // kCVPixelFormatType_420YpCbCr8BiPlanarFullRange  = '420f',
            // Bi-Planar Component Y'CbCr 8-bit 4:2:0, video-range (luma=[16,235] chroma=[16,240]).  
            // Bi-Planar Component Y'CbCr 8-bit 4:2:0, full-range (luma=[0,255] chroma=[1,255]).
            // baseAddress points to a big-endian CVPlanarPixelBufferInfo_YCbCrBiPlanar struct
            // i.e.: Y-channel in this format is in the first third of the buffer!
            int bytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(imageBuffer, 0);
            baseAddress = CVPixelBufferGetBaseAddressOfPlane(imageBuffer,0);
            grayscaleBufferSize = resolution.height * bytesPerRow ;
            grayscaleBuffer = malloc(grayscaleBufferSize);
            if (grayscaleBuffer == NULL) {
                NSLog(@"ERROR in %@:%@:%d: couldn't allocate memory for grayscaleBuffer!", NSStringFromClass([self class]), NSStringFromSelector(_cmd), __LINE__);
                return nil; }
            memset(grayscaleBuffer, 0, grayscaleBufferSize);
            memcpy (grayscaleBuffer, baseAddress, grayscaleBufferSize); 
        }
    
        // do whatever you want with the grayscale buffer
        ...
    
        // clean-up
        free(grayscaleBuffer);
    }
    #endif
    

提交回复
热议问题