CVPixelBuffer的創建 數據填充 以及數據讀取

来源:http://www.cnblogs.com/psklf/archive/2017/10/20/7700834.html
-Advertisement-
Play Games

CVPixelBufferRef YUV NV12 pixelFormatType 創建 數據填充 數據讀取 CGImageRef to CVPixelBufferRef ...


CVPixelBuffer的創建數據填充以及數據讀取

CVPixelBuffer 在音視頻編解碼以及圖像處理過程中應用廣泛,有時需要讀取內部數據,很少的時候需要自行創建並填充數據,下麵簡單敘述。

創建

創建時調用的方法主要是這個:

CVReturn CVPixelBufferCreate(CFAllocatorRef allocator,
                                size_t width,
                                size_t height,
                                OSType pixelFormatType, 
                                CFDictionaryRef pixelBufferAttributes, 
                                CVPixelBufferRef  _Nullable *pixelBufferOut);

提供必須的參數即可,

XX pixelFormatType 常用的這幾個:


/* NV12 */

  kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange = '420v', 
  /* Bi-Planar Component Y'CbCr 8-bit 4:2:0, video-range (luma=[16,235] chroma=[16,240]).
  baseAddr points to a big-endian CVPlanarPixelBufferInfo_YCbCrBiPlanar struct */

  kCVPixelFormatType_420YpCbCr8BiPlanarFullRange  = '420f',
  /* Bi-Planar Component Y'CbCr 8-bit 4:2:0, full-range (luma=[0,255] chroma=[1,255]).
     baseAddr points to a big-endian CVPlanarPixelBufferInfo_YCbCrBiPlanar struct */ 

/* YUV420P */

  kCVPixelFormatType_420YpCbCr8Planar = 'y420',  
  /* Planar Component Y'CbCr 8-bit 4:2:0. 
  baseAddr points to a big-endian CVPlanarPixelBufferInfo_YCbCrPlanar struct */

因為我想要創建NV12格式的buffer,所以沒有使用那個直接提供數據的創建函數,後續提供。如果數據格式爲420P的話,直接指定數據地址也可以。

XX pixelBufferAttributes

這個參數是optinal的,提供所有額外的信息。Core Video根據提供的參數來創建合適的數據,我看到網上的代碼往往是這樣提供的:

NSDictionary *pixelAttributes = @{(id)kCVPixelBufferIOSurfacePropertiesKey : @{}};

說明如下:

Provide a value for this key if you want Core Video to use the 
IOSurface framework to allocate the pixel buffer. 
(See IOSurface.) 
Provide an empty dictionary to use default IOSurface options.

數據填充

以 NV12 格式的數據填充舉例說明。

在訪問buffer內部裸數據的地址時(讀或寫都一樣),需要先將其鎖上,用完了再放開,如下:

CVPixelBufferLockBaseAddress(pixelBuffer, 0);

// To touch the address of pixel...

CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);

Y通道(Luminance)與 UV通道(Chrominance)分開填充數據,而且需要註意後者是UV交錯排列的。在填充數據時還需要考慮到數據對齊的問題,當視頻幀的寬高並不是某個對齊基數的倍數時(比如16),內部具體如何分配記憶體是不確定的,保險的做法就是逐行數據填充。這裡我放上填充Chrominance通道數據的例子:

size_t bytesPerRowChrominance = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 1);

long chrominanceWidth = CVPixelBufferGetWidthOfPlane(pixelBuffer, 1);
long chrominanceHeight = CVPixelBufferGetHeightOfPlane(pixelBuffer, 1);

// Chrominance
uint8_t *uvDestPlane = (uint8_t *) CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1);
memset(uvDestPlane, 0x80, chrominanceHeight * bytesPerRowChrominance);

for (int row = 0; row < chrominanceHeight; ++row) {
    memcpy(uvDestPlane + row * bytesPerRowChrominance,
            uvDataPtr + row * _outVideoWidth,
            _outVideoWidth);
}

free(uvDataPtr);

在逐行copy數據的時候,pixel內部地址每個迴圈步進 current_row * bytesPerRowChrominance 的大小,這是pixelbuffer內部的記憶體排列。然後我的數據來源記憶體排列是緊密排列不考慮記憶體多少位對齊的問題的,所以每次的步進是 current_row * _outVideoWidth 也就是真正的視頻幀的寬度。每次copy的大小也應該是真正的寬度。對於這個通道來說,寬度和高度都是亮度通道的一半,每個元素有UV兩個信息,所以這個通道每一行占用空間和亮度通道應該是一樣的。也就是每一行copy數據的大小是這樣算出來的:_outVideoWidth / 2 * 2.

數據讀取

數據讀取和數據填充正好是相反的操作,操作流程相似,先獲取pixelBuffer的一些具體信息,判斷信息無誤後繼續讀取數據。
unsigned long planes = CVPixelBufferGetPlaneCount(pixelRef); 若通道數目錯誤顯然邏輯已經錯誤,無需繼續。同樣是先鎖住BaseAddress,然後獲取其bytesPerRowChrominance等信息,然後按行讀取數據即可。切記,仍然需要按行讀取數據。

補充:從 Image 創建 PixelBuffer

直接附上可運行的代碼:


size_t height;
size_t width;

NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey,
    [NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey,
    nil];
CVPixelBufferRef pxbuffer = NULL;

CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, width,
        height, kCVPixelFormatType_32ARGB, (__bridge CFDictionaryRef) options,
        &pxbuffer);

NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL);

CVPixelBufferLockBaseAddress(pxbuffer, 0);
void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);
NSParameterAssert(pxdata != NULL);

CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();

CGContextRef context = CGBitmapContextCreate(pxdata, width,
        height, 8, 4 * width, rgbColorSpace,
        kCGImageAlphaNoneSkipFirst);
NSParameterAssert(context);
CGContextConcatCTM(context, CGAffineTransformMakeRotation(0));
CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image),
            CGImageGetHeight(image)), image);
CGColorSpaceRelease(rgbColorSpace);
CGContextRelease(context);

CVPixelBufferUnlockBaseAddress(pxbuffer, 0);

創建格式爲 kCVPixelFormatType_32ARGB 的 pixelBuffer,創建一個CGContextRef 對象,並將其內部地址設置爲pixelBuffer的內部地址。使用 CGContextDrawImage() 函數將原始圖片的數據繪製到我們創建的context上面,完成。


參考資料:

大神的文章,很詳細:讀寫CVPixelBufferRef

Create CVPixelBuffer from YUV with IOSurface backed

How to convert from YUV to CIImage for iOS

How do I export UIImage array as a movie?


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、註:一般倒計時的時間都是後臺傳來的然後渲染到頁面,這裡有2個簡單的倒計時方式 二、如何使用 ...
  • vue的實例對象 首先用js的new關鍵字實例化一個vue el: vue組件或對象裝載在頁面的位置,可通過id或class或標簽名 template: 裝載的內容。HTML代碼/包含指令或者其他組件的HTML片段,template將是我們使用的模板 data: 數據通過data引入到組件中 在組件 ...
  • 我們都知道,JS 中沒有的類的概念。 而 函數 則是 JS 中 很重要,很重要,很重要的一點。 理解 函數 也是非常有必要的。 先來看看 函數的定義。 如下: 上面講到了“函數的定義”,但是要怎麼理解“函數聲明”與“函數表達式”的不同呢? 讓我們看看什麼是“函數提升”?。 “函數提升”,會把當前作用 ...
  • 在使用Validform v5.3.2時(http://validform.rjboy.cn/) 問題:可以為空,但不為空時需要按照指定格式驗證數據 查看文檔: 5.2.1版本之後,datatype支持:1、直接綁定正則:如可用這樣寫datatype="/\w{3,6}/i",要求是3到6位的字母, ...
  • 非同步實時搜索jquery select插件 一、先看看效果。 二、做此插件的原因。 1.數據量過大(幾千、幾萬條),無法一次性全部載入。 2.現有插件各不相同,無法滿足功能需求。 3.美觀性,可控性不足。 三、如何使用。 1.html和js 2.實例。 3.詳細配置。 還有一些其它的api,詳細請看 ...
  • 品牌:超凡魔術師h5案例地址:http://www.199case.com/caseview.aspx?id=2668 1、內容:一個以”超凡魔術師“為主題的視頻+回答類的推文,用戶可以通過觀看一段一個人物在表演魔術的視頻,在其間用戶可以選擇兩個選項中的一項與之進行互動。 2、亮點:這篇推文最大的亮 ...
  • 1、java堆得Young區由哪些組成: Java堆由Perm區和Heap區組成,Heap區由Old區和New區(也叫Young區)組成,New區由Eden區、From區和To區(Survivor)組成。 2、實現ContentProvider需要實現哪些方法: insert、delete、quer ...
  • #菜單 pod 'LGSideMenuController' # 刷新 pod 'MJRefresh' # 網路請求 pod 'AFNetworking', '~> 3.0' # 圖片緩存 pod 'SDWebImage', '~> 4.0' # 數據解析 pod 'MJExtension' # 網 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...