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

簡述

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

常見用法

復(fù)制 CVPixelBuffer

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

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對(duì)象附加到 CVBuffer 以存儲(chǔ)其他信息聂儒。
提供附加信息的增刪改查及復(fù)制方法虎锚。

Retain Count

修改 CVBuffer 的引用計(jì)數(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)存中的幾個(gè)平面數(shù)據(jù)初始化緩沖,或者使用IOSurface(跨進(jìn)程共享)初始化一個(gè)緩沖涧卵。
那么需要注意的是勤家,后幾種方式由于是引用了一段內(nèi)存,所以緩沖釋放不會(huì)釋放引用的內(nèi)存柳恐,而使通過回調(diào)通知開發(fā)者處理緩沖釋放事件伐脖。

Inspect

查看緩沖參數(shù),如基址乐设、平面基址讼庇、寬高、每行字節(jié)數(shù)近尚,判斷緩沖類型蠕啄、平面數(shù)、平面大小等戈锻。

Modify

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

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

像素格式說明。在需要自定義像素格式時(shí)开瞭,才使用該說明對(duì)象懒震。

Create

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

Retrieve

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

Time Management

Inspect Host Clock

檢查主機(jī)時(shí)鐘个扰,包括當(dāng)前系統(tǒng)時(shí)間、系統(tǒng)時(shí)間更新頻率葱色、系統(tǒng)時(shí)間最小增量递宅。

CVTime

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

typedef struct
{
    int64_t     timeValue;//時(shí)間分母
    int32_t     timeScale;//時(shí)間分子
    int32_t     flags;//可以表示起始時(shí)間苍狰,或者未知時(shí)間办龄、無限時(shí)間
} CVTime;

CVTimeStamp

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

CVDisplayLink

類似 CADisplayLink淋昭。
是一個(gè)與屏幕刷新同步調(diào)用的 Timer俐填。

CVMetalTextureCache

Create

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

CVMetalTexture

Inspect

獲取相關(guān)屬性

OpenGL/OpenGL ES

廢棄

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市歇式,隨后出現(xiàn)的幾起案子驶悟,更是在濱河造成了極大的恐慌,老刑警劉巖材失,帶你破解...
    沈念sama閱讀 216,591評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件痕鳍,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡龙巨,警方通過查閱死者的電腦和手機(jī)笼呆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來旨别,“玉大人抄邀,你說我怎么就攤上這事≈玳唬” “怎么了境肾?”我有些...
    開封第一講書人閱讀 162,823評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長胆屿。 經(jīng)常有香客問我奥喻,道長,這世上最難降的妖魔是什么非迹? 我笑而不...
    開封第一講書人閱讀 58,204評(píng)論 1 292
  • 正文 為了忘掉前任环鲤,我火速辦了婚禮,結(jié)果婚禮上憎兽,老公的妹妹穿的比我還像新娘冷离。我一直安慰自己吵冒,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評(píng)論 6 388
  • 文/花漫 我一把揭開白布西剥。 她就那樣靜靜地躺著痹栖,像睡著了一般。 火紅的嫁衣襯著肌膚如雪瞭空。 梳的紋絲不亂的頭發(fā)上揪阿,一...
    開封第一講書人閱讀 51,190評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音咆畏,去河邊找鬼南捂。 笑死,一個(gè)胖子當(dāng)著我的面吹牛旧找,可吹牛的內(nèi)容都是我干的溺健。 我是一名探鬼主播,決...
    沈念sama閱讀 40,078評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼钮蛛,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼矿瘦!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起愿卒,我...
    開封第一講書人閱讀 38,923評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤缚去,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后琼开,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體易结,經(jīng)...
    沈念sama閱讀 45,334評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評(píng)論 2 333
  • 正文 我和宋清朗相戀三年柜候,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了搞动。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,727評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡渣刷,死狀恐怖鹦肿,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情辅柴,我是刑警寧澤箩溃,帶...
    沈念sama閱讀 35,428評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站碌嘀,受9級(jí)特大地震影響涣旨,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜股冗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評(píng)論 3 326
  • 文/蒙蒙 一霹陡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦烹棉、人聲如沸攒霹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽催束。三九已至,卻和暖如春辅髓,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背少梁。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評(píng)論 1 269
  • 我被黑心中介騙來泰國打工洛口, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人凯沪。 一個(gè)月前我還...
    沈念sama閱讀 47,734評(píng)論 2 368
  • 正文 我出身青樓第焰,卻偏偏與公主長得像,于是被迫代替她去往敵國和親妨马。 傳聞我的和親對(duì)象是個(gè)殘疾皇子挺举,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

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