iOS CVPixelBufferCreate 創建 CVPixelBufferRef 時屏幕拉伸或像素偏移(花屏)

先說結論:

? ? ?CVPixelBufferCreate 創建的 CVPixelBufferRef 可能由以下的原因導致的:

1.pixelFormatType 格式錯誤,換一下格式嘗試

2.width和height 非 32 的整數倍

3.視頻幀的寬高比非標準比例(4:3,16:9,1:1)

另外說明,我沒找到比較有權威的對應文檔和教程,上面是我通過測試得出的結論,如果有錯誤,還請批評指正

一、pixelFormatType 格式錯誤?

kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange 是nv12 的格式 yyyyuvuv

kCVPixelFormatType_420YpCbCr8Planar 是i420的格式 yyyyuuvv

需要注意的是,并不是每一個枚舉值在iOS上都是支持的,可能存在不支持的情況

二、width和height 非 32 的整數倍

CVReturn result = CVPixelBufferCreate(kCFAllocatorDefault,1920,1080,kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange,   //  NV12(__bridge CFDictionaryRef)(pixelAttributes),&pixelBuffer);

像素的存儲格式通常是一行一行存儲的,當寬度為了實現32的整數倍做出調整時,從幀數據復制的時候,就要在多出的那部分做對應的填充。縮小也是一樣的,要去放棄多余的數據

比如原視頻是 寬4 高4的視頻,你調成寬8高8的時候

yyyy? ? ? ? ? ? ? ? ? ? ? ? yyyyyyyy (后面四個y是自己填充的)

yyyy? ? ? ? ? ? ? ? ? ? ? ? yyyyyyyy (后面四個y是自己填充的)

uuuu? ? ?->>? ? ? ? ? ? ?uuuuuuuu (后面四個u是自己填充的)

vvvv? ? ? ? ? ? ? ? ? ? ? ? vvvvvvvv?(后面四個v是自己填充的)

例子可能不太恰當,但是意思比較清楚的。后面會有代碼舉例

三、視頻幀的寬高比非標準比例(4:3,16:9,1:1)

這個解決辦法和上一條是一樣的,去調整寬高,來實現比例的要求。

例子:

//例子是 I420 數據轉成 NV12 的 CVPixelBufferRef
//width 原視頻的寬
//height 原視頻的高
//buffer NSData 類型的原視頻的幀數據。格式為I420NSDictionary *pixelAttributes = @{(NSString *)kCVPixelBufferIOSurfacePropertiesKey:@{}};//調整后的widthint inner_width = 0;//調整后的heightint inner_height = 0;//視頻比例不是 16:9 , 4:3 , 1:1 ,寬高不是32的整數倍時,將寬高統一調整為1920和1080.//因為項目要求,所有視頻都不會比1920x1080大,故這里只是放大,無需縮小if (width*1.0 / height*1.0 != 16.0/9 || width*1.0 / height*1.0 != 1.0 || width*1.0 / height*1.0 != 4.0/3 || width%32 != 0 || height%32 != 0 ) {inner_width = 1920;inner_height = 1080;}else{inner_width = width;inner_height = height;}CVPixelBufferRef pixelBuffer = NULL;CVReturn result = CVPixelBufferCreate(kCFAllocatorDefault,inner_width,inner_height,kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange,   //  NV12(__bridge CFDictionaryRef)(pixelAttributes),&pixelBuffer);if (result != kCVReturnSuccess) {//CVPixelBufferRef 初始化失敗NSLog(@"Unable to create cvpixelbuffer %d", result);}// 復制 buffer.bytes 數據uint8_t* pdata = (uint8_t*)buffer.bytes;CVPixelBufferLockBaseAddress(pixelBuffer, 0);// Y 數據填充unsigned char *yDestPlane = (unsigned char *)CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0);for (int i = 0, k = 0; i < inner_height; i++) {for (int j = 0; j< inner_width; j++) {if (inner_width > width && j >= width) {// 擴大的那部分 width 用該行最后一個像素填充if (i >= height) {// 高度大于視頻的實際高度,說明該行沒有幀數據,則用實際視頻幀的最后一行最后一個像素填充yDestPlane[k++] = pdata[height*width];continue;}yDestPlane[k++] = pdata[i*width + width];continue;}if (inner_height > height && i >= height) {// 高度大于視頻的實際高度,說明改行沒有幀數據,則用實際視頻幀的最后一行最后一個像素填充yDestPlane[k++] = pdata[height * width];continue;}yDestPlane[k++] = pdata[i*width + j];}}// UV 數據填充unsigned char *uvDestPlane = (unsigned char *)CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1);for (int i = 0, k = 0; i < inner_height / 2; i++) {for (int j = 0; j< inner_width / 2; j ++) {if (inner_width > width && j >= width/2) {if (i > height/2) {// 高度大于視頻的實際高度,說明改行沒有幀數據,則用實際視頻幀的最后一行最后一個像素填充uvDestPlane[k++] = pdata[height *width/4  + width * height];uvDestPlane[k++] = pdata[height *width/4  + width * height * 5 / 4];}else{// 高度不高于視頻的實際高度,說明改行有幀數據,則用實際視頻幀的該行最后一個像素填充uvDestPlane[k++] = pdata[i *width/2 + width/2 + width * height];uvDestPlane[k++] = pdata[i *width/2 + width/2 + width * height * 5 / 4];}continue;}if (inner_height > height && i >= height/2) {// 高度大于視頻的實際高度,說明改行沒有幀數據,則用實際視頻幀的最后一行最后一個像素填充uvDestPlane[k++] = pdata[height *width/4 + width * height];uvDestPlane[k++] = pdata[height *width/4 + width * height * 5 / 4];continue;}// 高度不高于視頻的實際高度,說明改行有幀數據,則用實際視頻幀像素填充uvDestPlane[k++] = pdata[i *width/2 + j + width * height];uvDestPlane[k++] = pdata[i *width/2 + j + width * height * 5 / 4];}}CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
//pixelBuffer 構造完成,用于后續使用

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/712504.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/712504.shtml
英文地址,請注明出處:http://en.pswp.cn/news/712504.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

今天面試招了個18K的人,從騰訊出來的果然都有兩把刷子···

公司前段時間缺人&#xff0c;也面了不少測試&#xff0c;前面一開始瞄準的就是中級的水準&#xff0c;也沒指望來大牛&#xff0c;提供的薪資在15-20k&#xff0c;面試的人很多&#xff0c;但平均水平很讓人失望。看簡歷很多都是4年工作經驗&#xff0c;但面試中&#xff0c;不…

docker save 命令 docker load 命令 快速復制容器

docker save 命令 docker load 命令 1、docker save 命令2、docker load 命令 1、docker save 命令 docker save 命令用于在系統上把正在使用的某個容器鏡像 導出成容器鏡像文件保存下載&#xff0c;以便在其他系統上導入這個容器鏡像文件 以便快速在其他服務器上啟動相同的容…

讀書筆記:《思考 . 快與慢》- 1 系統1 系統2

《思考 . 快與慢》 [美] 丹尼爾 . 卡尼曼 著 胡曉姣 李愛民 何夢瑩 譯 這本書會改變你的思考方式 利用閑談發現和分析別人犯的錯誤比分析自己的錯誤更容易&#xff0c;也更有意思 在人生最輝煌的時候&#xff0c;我們很難對自己的信念和需求產生懷疑&#xff0c;越是在最…

【Web】Java反序列化之CC2——commons-collections4的新鏈之一

目錄 關于commons-collections4 一個重要的思維模型 觸發Transform的關鍵類&#xff1a;TransformingComparator 反序列化的入口&#xff1a;PriorityQueue Exp 關于commons-collections4 commons-collections4 是 Apache Commons 組件庫中的一個項目&#xff0c;它是對舊…

在Linux上定時執行腳本

在Linux上定時執行腳本通常可以使用 ?cron?任務來實現。?cron?是一個系統服務&#xff0c;用于在預定時間自動執行命令或腳本。下面是如何在Linux上設置定時執行腳本的步驟&#xff1a; 編寫腳本&#xff1a;首先&#xff0c;你需要編寫需要定時執行的腳本文件&#xff0c;…

找不到msvcp140.dll無法運行程序如何處理?分享5種解決方法

在計算機系統運行過程中&#xff0c;如果無法找到必要的動態鏈接庫文件msvcp140.dll&#xff0c;可能會引發一系列的問題與故障。這個特定的dll文件是Microsoft Visual C Redistributable Package的一部分&#xff0c;對于許多基于此編譯環境開發的應用程序至關重要。缺失msvcp…

C++的常用排序(未完待續)

注&#xff1a;本文以升序為例 一、冒泡排序 1.1 操作方法 步驟1比較相鄰元素&#xff0c;如果前者比后者大&#xff0c;則交換它們。步驟2對頭到尾&#xff0c;對所有元素按序執行一輪這樣的操作(這樣可以找到第一最大值)步驟3再從第一個元素開始&#xff0c;重復上述比較操…

jax可微分編程的筆記(8)

jax可微分編程的筆記(8) 第八章 循環神經網絡 神經網絡是可微分編程中最為重要的模型構造形式&#xff0c;也是當代 深度學習的基本組成部分&#xff0c;深度學習中的“深度”一詞&#xff0c;便是對 神經網絡的層數的形容。 8.1 神經網絡的生物學基礎 通過層層近似&#x…

智能駕駛規劃控制理論學習02-基于搜索的路徑規劃方法

目錄 一、路徑搜索問題 二、圖論基礎 三、圖搜索方法 1、廣度優先搜索&#xff08;BFS&#xff09; bfs與dfs的區別 bfs的搜索過程 bfs的算法實現 2、迪杰斯特拉算法&#xff08;Dijkstra&#xff09; 核心思想 優先級隊列 Dijkstra搜索過程 Dijkstra優缺點…

【.NET Core】深入理解IO - FileSteam流

【.NET Core】深入理解IO - FileSteam流 文章目錄 【.NET Core】深入理解IO - FileSteam流一、IO流概述二、文件流FileStream2.1 FileStream概述2.2 FileStream檢測流位置更改2.3 FileStream構造函數2.4 FileStream常用屬性2.5 FileStream.Read方法2.6 FileStream.Write方法2.7…

插混、油混、增程式、輕混、強混,啥區別

這里寫自定義目錄標題 隨著我國新能源汽車的大力推進&#xff0c;電車可以說是世界未來的主流&#xff0c;只不過現在是處在一個過渡時代 這是個好時代&#xff0c;因為我們見證并體驗著歷史過渡的細節 這是個不好的時代&#xff0c;因為我們可能只是未來新新人類的試驗品 幫他…

MyBatis 學習(三)之 MyBatis 全局配置文件

目錄 1 MyBatis 全局配置文件 2 properties 元素 3 setting 設置 4 typeAlianses 別名處理器 5 typeHandler 類型處理器 6 objectFacotry 對象工廠&#xff08;了解&#xff09; 7 plugins 插件&#xff08;了解&#xff09; 8 environments 運行環境 9 databaseIdPro…

今日arXiv最熱大模型論文:點擊即可播放!港中文發布大模型寫歌神器!

一首歌&#xff0c;包含作詞作曲兩個部分。擅長作詞or作曲就已經很牛了。比如方文山是周杰倫的御用作詞人&#xff0c;而周杰倫寫過很多耳熟能詳的曲子。而兼具作詞作曲才華的全能創作人卻是難得一見。 最近港中文發布了一款歌曲創作大模型SongComposer&#xff0c;作詞作曲都…

自測-1 打印沙漏

文章預覽&#xff1a; 題目算法代碼 題目 算法 以前做過這個&#xff0c;那次是c語言寫的&#xff0c;一點一點處理一層一層完成&#xff0c;這次我換了一種語言用了另一種思想使用遞歸去寫&#xff0c;還是我們要先求出應該有多少層這個很容易&#xff0c;中間輸出部分我們算…

常見查找算法Java實現

順序&#xff08;線性&#xff09;查找二分查找/折半查找插值查找斐波那契查找 線性查找 判斷數列是否包含要求&#xff0c;如果找到了&#xff0c;就提示找到了&#xff0c;并給出下標值 // 線性查找 public static ArrayList<Integer> seqSearch(int[] arr, int value…

解決 npm install 報錯的問題

在使用 npm 安裝依賴包時&#xff0c;有時候會遇到各種報錯問題&#xff0c;以下是一些常見的報錯及解決方法&#xff1a; 1. ENOENT: no such file or directory 如果出現類似 ENOENT: no such file or directory 的報錯&#xff0c;可能是因為某些文件或目錄缺失或路徑錯誤…

動態規劃課堂3-----簡單多狀態問題(買賣股票最佳時機)

目錄 引入&#xff1a; 例題1&#xff1a;按摩師&#xff08;打家劫舍I&#xff09; 例題2&#xff1a;打家劫舍II 例題3&#xff1a;刪除并獲得點數 例題4&#xff1a;粉刷房子 例題5&#xff1a;買賣股票的最佳時機含冷凍 結語&#xff1a; 引入&#xff1a; 相信看到…

深度學習 精選筆記(8)梯度消失和梯度爆炸

學習參考&#xff1a; 動手學深度學習2.0Deep-Learning-with-TensorFlow-bookpytorchlightning ①如有冒犯、請聯系侵刪。 ②已寫完的筆記文章會不定時一直修訂修改(刪、改、增)&#xff0c;以達到集多方教程的精華于一文的目的。 ③非常推薦上面&#xff08;學習參考&#x…

帶你快速初步了解Python列表

1.列表 列表主要是用來存儲多個數據&#xff0c;是有序的集合 2.創建列表 """ 語法&#xff1a;變量名 [數據1,數據2,數據3......] 注意&#xff1a;列表中的數據類型可以是各種不同的數據類型 """ 創建空列表 list1 [] print(list1) …

Gitlab: 私有化部署

目錄 1. 說明 2. 資源要求 3. 安裝 4. 配置實踐 4.1 服務器 4.2 人員與項目 4.2 部署準備 4.2.1 訪問變量及用戶賬號設置 4.2.2 Runner設置 4.2.3 要點 5. 應用項目 CI/CD 6. 參考 1. 說明 gitlab是一個強大且免費的代碼管理/部署工具&#xff0c;能統一集成代碼倉…