Как перейти от vImage_Buffer к CVPixelBufferRef

Я записываю живое видео в своем приложении для iOS. На другой странице Stackru ( ссылка) я обнаружил, что вы можете использовать vImage_Buffer для работы с моими фреймами.

Проблема в том, что я понятия не имею, как вернуться к CVPixelBufferRef из выведенного vImage_buffer.

Вот код, который приведен в другой статье:

NSInteger cropX0 = 100,
        cropY0 = 100,
        cropHeight = 100,
        cropWidth = 100,
        outWidth = 480,
        outHeight = 480;

CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);                   
CVPixelBufferLockBaseAddress(imageBuffer,0);
void *baseAddress = CVPixelBufferGetBaseAddress(imageBuffer);
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);

vImage_Buffer inBuff;                       
inBuff.height = cropHeight;
inBuff.width = cropWidth;
inBuff.rowBytes = bytesPerRow;

int startpos = cropY0*bytesPerRow+4*cropX0;
inBuff.data = baseAddress+startpos;

unsigned char *outImg= (unsigned char*)malloc(4*outWidth*outHeight);
vImage_Buffer outBuff = {outImg, outHeight, outWidth, 4*outWidth};

vImage_Error err = vImageScale_ARGB8888(&inBuff, &outBuff, NULL, 0);
if (err != kvImageNoError) NSLog(@" error %ld", err);

И теперь мне нужно конвертировать outBuff в CVPixelBufferRef.

Я предполагаю, что мне нужно использовать vImageBuffer_CopyToCVPixelBufferно я не уверен как.

Мои первые попытки провалились с EXC_BAD_ACCESS:

CVPixelBufferUnlockBaseAddress (imageBuffer, 0);

    CVPixelBufferRef pixelBuffer;
    CVPixelBufferCreate(kCFAllocatorSystemDefault, 480, 480, kCVPixelFormatType_32BGRA, NULL, &pixelBuffer);

    CVPixelBufferLockBaseAddress( pixelBuffer, 0 );

    vImage_CGImageFormat format = {
        .bitsPerComponent = 8,
        .bitsPerPixel = 32,
        .bitmapInfo = kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst,  //BGRX8888
        .colorSpace = NULL,    //sRGB
    };

    vImageBuffer_CopyToCVPixelBuffer(&outBuff,
                                     &format,
                                     pixelBuffer,
                                     NULL,
                                     NULL,
                                     kvImageNoFlags); // Here is the crash!


    CVPixelBufferUnlockBaseAddress( pixelBuffer, 0 );

Любая идея?

1 ответ

        NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithBool : YES],           kCVPixelBufferCGImageCompatibilityKey,
                             [NSNumber numberWithBool : YES],           kCVPixelBufferCGBitmapContextCompatibilityKey,
                             [NSNumber numberWithInt  : 480],  kCVPixelBufferWidthKey,
                             [NSNumber numberWithInt  : 480], kCVPixelBufferHeightKey,
                             nil];

            status = CVPixelBufferCreateWithBytes(kCFAllocatorDefault, 480, 480, kCVPixelFormatType_32BGRA, outImg, bytesPerRow, NULL, NULL, (__bridge CFDictionaryRef)options, &pixbuffer);

Вы должны сгенерировать новый pixelBuffer как выше.

  • На всякий случай... если вы хотите, чтобы поток видео в реальном времени CROPPED в ваш интерфейс, используйте AVPlayerLayer,AVCaptureVideoPreviewLayer и / или другие подклассы CALayer, используйте границы слоя, кадр и положение для вашей области 100x100 пикселей до области 480x480.

Примечания к vImage для ВАШЕГО вопроса (разные обстоятельства могут отличаться)

  1. CVPixelBufferCreateWithBytes не будет работать с vImageBuffer_CopyToCVPixelBuffer(), потому что вам нужно скопировать данные vImage_Buffer в "чистый" или "пустой" CVPixelBuffer.

  2. Нет необходимости блокировать / разблокировать - убедитесь, что вы знаете, когда блокировать, а когда не блокировать буферы пикселей.

  3. Ваш inBuff vImage_Buffer просто необходимо инициализировать из данных пиксельного буфера, а не вручную (если вы не знаете, как использовать CGContexts и т. Д. Для инициализации пиксельной сетки)

  4. используйте vImageBuffer_InitWithCVPixelBuffer()

  5. vImageScale_ARGB8888 масштабирует все данные CVPixel до меньшего / большего прямоугольника. Он не будет МАСШТАБИРОВАТЬ часть / область обрезки буфера для другого буфера.

  6. Когда вы используете vImageBuffer_CopyToCVPixelBuffer(), vImageCVImageFormatRef и vImage_CGImageFormat должны быть заполнены правильно.

    CGColorSpaceRef dstColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceITUR_709);

        vImage_CGImageFormat format = {
              .bitsPerComponent = 16,
              .bitsPerPixel = 64,
              .bitmapInfo = (CGBitmapInfo)kCGImageAlphaPremultipliedLast  |  kCGBitmapByteOrder16Big ,
              .colorSpace = dstColorSpace
        };
        vImageCVImageFormatRef vformat = vImageCVImageFormat_Create(kCVPixelFormatType_4444AYpCbCr16,
                                                                    kvImage_ARGBToYpCbCrMatrix_ITU_R_709_2,
                                                                    kCVImageBufferChromaLocation_Center,
                                                                    format.colorSpace,
                                                                    0);
    
        CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault,
                                              480,
                                              480,
                                              kCVPixelFormatType_4444AYpCbCr16,
                                              NULL,
                                              &destBuffer);
    
        NSParameterAssert(status == kCVReturnSuccess && destBuffer != NULL);
    
        err = vImageBuffer_CopyToCVPixelBuffer(&sourceBuffer, &format, destBuffer, vformat, 0, kvImagePrintDiagnosticsToConsole);
    

(ПРИМЕЧАНИЕ - это настройки для 64-битного ProRes с Alpha - настройте для 32-битного)

Другие вопросы по тегам