CoreVideo文檔閱讀及常見使用方式

簡述

平時工作中使用 CoreVideo 也不算少,但是一直沒有系統(tǒng)完整地閱讀梳理過它的官方文檔。趁著這段時間較為閑暇,就系統(tǒng)性的學(xué)習(xí)一下官方文檔,并且記錄一些常見用法。

常見用法

復(fù)制 CVPixelBuffer

經(jīng)常我們需要拷貝一個 CVPixelBuffer,但是沒有直接拷貝的方法。這里就是一個緩沖拷貝的實現(xiàn),并且對源和目標(biāo)為不同大小的緩沖情況進行了處理。

bool copyPixelBuffer(CVPixelBufferRef src, CVPixelBufferRef dst) {
    bool ret = true;
    
    CVPixelBufferLockBaseAddress(src, kCVPixelBufferLock_ReadOnly);
    
    unsigned char* pb = (unsigned char*)CVPixelBufferGetBaseAddressOfPlane(src, 0);
    int height = (int)CVPixelBufferGetHeight(src);
    int stride = (int)CVPixelBufferGetBytesPerRow(src);
    int size = (int)CVPixelBufferGetDataSize(src);
    
    while (1) {
        CVReturn cvRet = CVPixelBufferLockBaseAddress(dst, 0);
        if (cvRet != kCVReturnSuccess) {
            ret = false;
            break;
        }
        
        int dst_height = (int)CVPixelBufferGetHeight(dst);
        int dst_stride = (int)CVPixelBufferGetBytesPerRow(dst);
        int dst_size = (int)CVPixelBufferGetDataSize(dst);
        
        if (stride == dst_stride && dst_size == size) {
            unsigned char* temp = (unsigned char*)CVPixelBufferGetBaseAddressOfPlane(dst, 0);
            memcpy(temp, pb, size);
        } else {
            int copy_height = height > dst_height ? dst_height : height;
            int copy_stride = stride > dst_stride ? dst_stride : stride;
            
            unsigned char* offset_dst = (unsigned char*)CVPixelBufferGetBaseAddressOfPlane(dst, 0);
            unsigned char* offset_src = pb;
            for (int i = 0; i < copy_height; i++) {
                memcpy(offset_dst, offset_src, copy_stride);
                offset_src += stride;
                offset_dst += dst_stride;
            }
        }
        
        CVPixelBufferUnlockBaseAddress(dst, 0);
        break;
    }
    
    CVPixelBufferUnlockBaseAddress(src, kCVPixelBufferLock_ReadOnly);
    return ret;
}

通過 CGImage 創(chuàng)建 CVPixelBuffer

CVPixelBufferRef pixelBufferFromCGImage(CGImageRef image) {
    CVPixelBufferRef pxbuffer = NULL;
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey,
                             [NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey,
                             nil];
    
    size_t width =  CGImageGetWidth(image);
    size_t height = CGImageGetHeight(image);
    size_t bytesPerRow = CGImageGetBytesPerRow(image);
    
    CFDataRef  dataFromImageDataProvider = CGDataProviderCopyData(CGImageGetDataProvider(image));
    GLubyte  *imageData = (GLubyte *)CFDataGetBytePtr(dataFromImageDataProvider);
    
    CVPixelBufferCreateWithBytes(kCFAllocatorDefault,width,height,kCVPixelFormatType_32BGRA,imageData,bytesPerRow,NULL,NULL,(__bridge CFDictionaryRef)options,&pxbuffer);
    
    CFRelease(dataFromImageDataProvider);
    
    return pxbuffer;
}

CVPixelBuffer 轉(zhuǎn) CGImage

CGImageRef createCGImageFromCVPixelBuffer(CVPixelBufferRef pixels) {
    
    CVPixelBufferLockBaseAddress(pixels, kCVPixelBufferLock_ReadOnly);
    
    CIImage *ciImage = [CIImage imageWithCVPixelBuffer:pixels];
    CIContext *temporaryContext = [CIContext contextWithOptions:nil];
    CGImageRef videoImage = [temporaryContext createCGImage:ciImage fromRect:CGRectMake(0, 0, CVPixelBufferGetWidth(pixels), CVPixelBufferGetHeight(pixels))];
    
    CVPixelBufferUnlockBaseAddress(pixels, kCVPixelBufferLock_ReadOnly);
    
    return videoImage;
}

創(chuàng)建BGRA/I420/NV12 格式的 CVPixelBufferPool

+ (bool)create32BGRAPixelBufferPool:(CVPixelBufferPoolRef*)pool width:(int)width height:(int)height {
    CFDictionaryRef empty; // empty value for attr value.
    CFMutableDictionaryRef attrs;
    
    empty = CFDictionaryCreate(kCFAllocatorDefault,
                               NULL, NULL, 0,
                               &kCFTypeDictionaryKeyCallBacks,
                               &kCFTypeDictionaryValueCallBacks); // our empty IOSurface properties dictionary
    
    SInt32 cvPixelFormatTypeValue = kCVPixelFormatType_32BGRA;
    CFNumberRef cfPixelFormat = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, (const void*)(&(cvPixelFormatTypeValue)));
    
    SInt32 cvWidthValue = width;
    CFNumberRef cfWidth = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, (const void*)(&(cvWidthValue)));
    SInt32 cvHeightValue = height;
    CFNumberRef cfHeight = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, (const void*)(&(cvHeightValue)));
    
    attrs = CFDictionaryCreateMutable(kCFAllocatorDefault,
                                      4,
                                      &kCFTypeDictionaryKeyCallBacks,
                                      &kCFTypeDictionaryValueCallBacks);
    
    CFDictionarySetValue(attrs, kCVPixelBufferIOSurfacePropertiesKey, empty);
    CFDictionarySetValue(attrs, kCVPixelBufferPixelFormatTypeKey, cfPixelFormat);
    CFDictionarySetValue(attrs, kCVPixelBufferWidthKey, cfWidth);
    CFDictionarySetValue(attrs, kCVPixelBufferHeightKey, cfHeight);
    
    CVReturn ret = CVPixelBufferPoolCreate(kCFAllocatorDefault, nil, attrs, pool);
    
    CFRelease(attrs);
    CFRelease(empty);
    CFRelease(cfPixelFormat);
    CFRelease(cfWidth);
    CFRelease(cfHeight);
    
    if (ret != kCVReturnSuccess) {
        return false;
    }
    
    return true;
}

+ (bool)createI420PixelBufferPool:(CVPixelBufferPoolRef*)pool width:(int)width height:(int)height {
    CFDictionaryRef empty; // empty value for attr value.
    CFMutableDictionaryRef attrs;
    
    empty = CFDictionaryCreate(kCFAllocatorDefault,
                               NULL, NULL, 0,
                               &kCFTypeDictionaryKeyCallBacks,
                               &kCFTypeDictionaryValueCallBacks); // our empty IOSurface properties dictionary
    
    SInt32 cvPixelFormatTypeValue = kCVPixelFormatType_420YpCbCr8PlanarFullRange;
    CFNumberRef cfPixelFormat = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, (const void*)(&(cvPixelFormatTypeValue)));
    
    SInt32 cvWidthValue = width;
    CFNumberRef cfWidth = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, (const void*)(&(cvWidthValue)));
    SInt32 cvHeightValue = height;
    CFNumberRef cfHeight = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, (const void*)(&(cvHeightValue)));
    
    attrs = CFDictionaryCreateMutable(kCFAllocatorDefault,
                                      5,
                                      &kCFTypeDictionaryKeyCallBacks,
                                      &kCFTypeDictionaryValueCallBacks);
    
    CFDictionarySetValue(attrs, kCVPixelBufferIOSurfacePropertiesKey, empty);
    CFDictionarySetValue(attrs, kCVPixelBufferPixelFormatTypeKey, cfPixelFormat);
    CFDictionarySetValue(attrs, kCVPixelBufferWidthKey, cfWidth);
    CFDictionarySetValue(attrs, kCVPixelBufferHeightKey, cfHeight);
#if TARGET_OS_IOS
    CFDictionarySetValue(attrs, kCVPixelBufferOpenGLESCompatibilityKey, kCFBooleanTrue);
#elif TARGET_OS_OSX
    CFDictionarySetValue(attrs, kCVPixelBufferOpenGLCompatibilityKey, kCFBooleanTrue);
#endif
    
    CVReturn ret = CVPixelBufferPoolCreate(kCFAllocatorDefault, nil, attrs, pool);
    
    CFRelease(attrs);
    CFRelease(empty);
    CFRelease(cfPixelFormat);
    CFRelease(cfWidth);
    CFRelease(cfHeight);
    
    if (ret != kCVReturnSuccess) {
        return false;
    }
    
    return true;
}

+ (bool)createNV12PixelBufferPool:(CVPixelBufferPoolRef*)pool width:(int)width height:(int)height {
    CFDictionaryRef empty; // empty value for attr value.
    CFMutableDictionaryRef attrs;
    
    empty = CFDictionaryCreate(kCFAllocatorDefault,
                               NULL, NULL, 0,
                               &kCFTypeDictionaryKeyCallBacks,
                               &kCFTypeDictionaryValueCallBacks); // our empty IOSurface properties dictionary
    
    SInt32 cvPixelFormatTypeValue = kCVPixelFormatType_420YpCbCr8BiPlanarFullRange;
    CFNumberRef cfPixelFormat = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, (const void*)(&(cvPixelFormatTypeValue)));
    
    SInt32 cvWidthValue = width;
    CFNumberRef cfWidth = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, (const void*)(&(cvWidthValue)));
    SInt32 cvHeightValue = height;
    CFNumberRef cfHeight = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, (const void*)(&(cvHeightValue)));
    
    attrs = CFDictionaryCreateMutable(kCFAllocatorDefault,
                                      5,
                                      &kCFTypeDictionaryKeyCallBacks,
                                      &kCFTypeDictionaryValueCallBacks);
    
    CFDictionarySetValue(attrs, kCVPixelBufferIOSurfacePropertiesKey, empty);
    CFDictionarySetValue(attrs, kCVPixelBufferPixelFormatTypeKey, cfPixelFormat);
    CFDictionarySetValue(attrs, kCVPixelBufferWidthKey, cfWidth);
    CFDictionarySetValue(attrs, kCVPixelBufferHeightKey, cfHeight);
#if TARGET_OS_IOS
    CFDictionarySetValue(attrs, kCVPixelBufferOpenGLESCompatibilityKey, kCFBooleanTrue);
#elif TARGET_OS_OSX
    CFDictionarySetValue(attrs, kCVPixelBufferOpenGLCompatibilityKey, kCFBooleanTrue);
#endif
    
    CVReturn ret = CVPixelBufferPoolCreate(kCFAllocatorDefault, nil, attrs, pool);
    
    CFRelease(attrs);
    CFRelease(empty);
    CFRelease(cfPixelFormat);
    CFRelease(cfWidth);
    CFRelease(cfHeight);
    
    if (ret != kCVReturnSuccess) {
        return false;
    }
    
    return true;
}

官方文檔

DataProcessing

CVBuffer

CV 緩沖基類。派生了 CVImageBuffer。

Attachment

You can attach any Core Foundation object to a Core Video buffer to store additional information.
您可以將任何Core Foundation對象附加到 CVBuffer 以存儲其他信息。
提供附加信息的增刪改查及復(fù)制方法。

Retain Count

修改 CVBuffer 的引用計數(shù)值。支持傳空。

CVImageBuffer

提供管理不同類型圖像的接口。

Inspect

查看 Buffer 參數(shù),如顏色空間、顯示大小、編碼尺寸、翻轉(zhuǎn)狀態(tài)等。

Create Color Speaces

由附件創(chuàng)建色彩空間。
色彩空間由附件字典中信息生成。

Data Type

CVImageBufferRef

Converting Between Strings and Integer Code Points

看上去是新添加上去的,轉(zhuǎn)換相關(guān)的方法。

CVPixelBuffer

表示保存在主存的像素。

Create

支持以各種方式創(chuàng)建 PixelBuffer。
如直接初始化一塊空的像素緩沖區(qū),或者直接引用現(xiàn)有的一整段內(nèi)存將其初始化為緩沖,又或者通過內(nèi)存中的幾個平面數(shù)據(jù)初始化緩沖,或者使用IOSurface(跨進程共享)初始化一個緩沖。
那么需要注意的是,后幾種方式由于是引用了一段內(nèi)存,所以緩沖釋放不會釋放引用的內(nèi)存,而使通過回調(diào)通知開發(fā)者處理緩沖釋放事件。

Inspect

查看緩沖參數(shù),如基址、平面基址、寬高、每行字節(jié)數(shù),判斷緩沖類型、平面數(shù)、平面大小等。

Modify

主要是鎖定基址和解鎖基址兩個方法。
需要在 CPU 訪問緩存前后分別調(diào)用。如果使用 GPU 訪問,則不需要鎖定,并且鎖定會影響性能。

Retain Count

同 CVBufferRetain

CVPixelBufferPool

緩沖池,用于優(yōu)化內(nèi)存分配的性能。

Create

創(chuàng)建緩沖池,通過緩沖池創(chuàng)建 PixelBuffer。
并且可以指定創(chuàng)建出的像素緩沖默認(rèn)攜帶指定的 Attributes。

Flush

釋放所有未使用的緩沖區(qū)。

Inspect

獲取緩沖池屬性字典、緩沖屬性字典。

Retain Count

同上

CVPixelFormatDescription

像素格式說明。在需要自定義像素格式時,才使用該說明對象。

Create

創(chuàng)建格式說明。

Retrieve

檢索已知的定義的所有像素格式描述。

Time Management

Inspect Host Clock

檢查主機時鐘,包括當(dāng)前系統(tǒng)時間、系統(tǒng)時間更新頻率、系統(tǒng)時間最小增量。

CVTime

用來表示時間的數(shù)據(jù)結(jié)構(gòu)。

typedef struct
{
    int64_t     timeValue;//時間分母
    int32_t     timeScale;//時間分子
    int32_t     flags;//可以表示起始時間,或者未知時間、無限時間
} CVTime;

CVTimeStamp

用于定義顯示時間戳的數(shù)據(jù)結(jié)構(gòu)。

CVDisplayLink

類似 CADisplayLink。
是一個與屏幕刷新同步調(diào)用的 Timer。

CVMetalTextureCache

Create

創(chuàng)建新紋理緩存、由現(xiàn)有圖片生成紋理緩存、回收/整理當(dāng)前緩存。

CVMetalTexture

Inspect

獲取相關(guān)屬性

OpenGL/OpenGL ES

廢棄

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 作者:熊皮皮 原文鏈接:http://m.itdecent.cn/p/dac9857b34d0 本文記錄讀寫V...
    nenhall閱讀 4,482評論 1 1
  • 最全的iOS面試題及答案 iOS面試小貼士 ———————————————回答好下面的足夠了-----------...
    zweic閱讀 2,804評論 0 73
  • ———————————————回答好下面的足夠了---------------------------------...
    恒愛DE問候閱讀 1,846評論 0 4
  • 我愿做一個永不停歇的浪子 游走于天地之間 直到生命的最后一刻 請將我埋葬于長滿無盡愛與死亡的 黑色曼陀羅花之地 聽...
    二不笑閱讀 267評論 0 0
  • 只要該找到的糖你找到了,能享用的也都享用了,這輩子,就沒白活。 陀思妥耶夫斯基說:我只擔(dān)心一件事,怕我配不上自己所...
    微風(fēng)嘻嘻閱讀 228評論 0 0

友情鏈接更多精彩內(nèi)容