戰(zhàn))
簡(jiǎn)介DSPack 2.34 是面向 Delphi 2010 開發(fā)者的組件包長(zhǎng)期活躍于 Delphi 社區(qū)用于擴(kuò)展 IDE 能力簡(jiǎn)化網(wǎng)絡(luò)通信TCP/UDP/HTTP/FTP、多線程TThread、數(shù)據(jù)庫訪問ODBC/ADO和串口控制等復(fù)雜功能的實(shí)現(xiàn)該版本已經(jīng)過實(shí)際項(xiàng)目測(cè)試兼容性有保障適合需要快速構(gòu)建高性能 Windows 應(yīng)用的系統(tǒng)開發(fā)者。資源壓縮包體積輕量?jī)H 1.75MB共 319 個(gè)文件主體由 95 個(gè) PAS 源代碼、40 個(gè) DPR 工程文件、39 個(gè) DFM 窗體文件組成另有批處理腳本、DCU 編譯單元和少量圖片資源可支撐組件安裝、示例運(yùn)行與二次開發(fā)目錄結(jié)構(gòu)便于按需檢索。目前已有 327 人瀏覽學(xué)習(xí)。包內(nèi)附帶可直接運(yùn)行的示例工程覆蓋網(wǎng)絡(luò)、數(shù)據(jù)庫、串口與多媒體等常見場(chǎng)景可參考組件的調(diào)用方式和調(diào)試流程同時(shí)提供注冊(cè)與清理腳本便于快速安裝和測(cè)試組件環(huán)境。將壓縮包導(dǎo)入 Delphi 2010 后可直接拖拽使用網(wǎng)絡(luò)、串口和多媒體組件大幅減少底層封裝工作量。1. Delphi 2010 還能用 DSPack 2.34老工程視頻方案的最后一根稻草前陣子接手一個(gè)停留在 Delphi 2010 的老監(jiān)控系統(tǒng)要在不升級(jí) IDE、不引入大型框架的前提下加入視頻回放和單幀抓取??疾炝艘蝗M件新庫不是依賴 FireMonkey 就是早放棄 Win32直到翻出 DSPack 2.34 這版仍在維護(hù)周期內(nèi)兼容 Delphi 2010 的 DirectShow 封裝庫重新編譯、裝組件、跑通播放和截幀整個(gè)過程驗(yàn)證下來完全可用。它解決的問題非常具體在 32 位進(jìn)程里用 DirectShow 做播放、采集、抓幀不需要換編譯環(huán)境不需要額外 runtime特別適合還在維護(hù)老 Delphi 工程、或必須鎖定 IDE 版本的視頻開發(fā)場(chǎng)景。下面按我實(shí)測(cè)的完整流程展開每一步盡量寫清操作和參數(shù)。2. DSPack 2.34 為什么能跑在 Delphi 2010 上DirectShow 封裝與 Unicode 邊界2.1 組件骨架TFilterGraph、TVideoWindow、TSampleGrabber 的角色DSPack 的思路是把 Windows 多媒體層的 DirectShow COM 接口包成 Delphi 類讓窗體設(shè)計(jì)器直接放組件操作。最常見的三個(gè)組件是 TFilterGraph、TVideoWindow、TSampleGrabber。TFilterGraph 對(duì)應(yīng) Filter Graph Manager負(fù)責(zé)把源文件、解碼器、渲染器編排成一條可播放的管線核心接口是 IGraphBuilder。TVideoWindow 是視頻渲染窗口對(duì)應(yīng) IVideoWindow負(fù)責(zé)把畫面畫到指定控件上。TSampleGrabber 則是插在管線中間的抓幀器可以在視頻數(shù)據(jù)流過時(shí)拿到原始樣本。它們?nèi)邊f(xié)作關(guān)系類似一條流水線源 Filter 讀文件解碼 Filter 做格式變換渲染 Filter 把畫面輸出到窗口。TFilterGraph 把節(jié)點(diǎn)的連接邏輯隱藏起來開發(fā)者只需調(diào) RenderFile 或 RenderGraph它內(nèi)部會(huì)根據(jù)媒體類型去系統(tǒng)注冊(cè)表搜索能連接的 filter。我要強(qiáng)調(diào)一個(gè)容易被繞暈的邊界TFilterGraph 管全圖TFilter 只管單個(gè)節(jié)點(diǎn)。一個(gè)圖里可以有多個(gè) TFilter 實(shí)例但圖管理器只有一個(gè) TFilterGraph 實(shí)例。長(zhǎng)期用下來我的習(xí)慣是標(biāo)準(zhǔn)播放場(chǎng)景無腦用 TFilterGraph 的自動(dòng)連接一旦涉及非標(biāo)準(zhǔn)格式或需要自定義解碼順序才手動(dòng)創(chuàng)建 TFilter 實(shí)例、指定輸入輸出 Pin。DSPack 把控制權(quán)留給了開發(fā)者但大多數(shù)項(xiàng)目根本走不到手動(dòng)拉線那一步。2.2 DirectShow 處理鏈條源、變換、渲染三層再展開講一下這個(gè)管線模型方便后面代碼落地。完整的 Filter Graph 分三層源 Filter 讀取文件、攝像頭或網(wǎng)絡(luò)流輸出壓縮或未壓縮的媒體樣本變換 Filter 完成解碼、格式轉(zhuǎn)換DSPack 自帶一批 transform filter也能用系統(tǒng)里注冊(cè)的第三方解碼器渲染 Filter 把媒體數(shù)據(jù)送到顯卡或聲卡視頻走 Video Renderer / VMR7 / VMR9音頻走 Audio Renderer。每個(gè) filter 的輸入輸出 Pin 之間要協(xié)商媒體類型比如視頻的 RGB24、YUY2音頻的 PCM以及壓縮流的 subtype GUID。協(xié)商失敗時(shí) Graph Builder 會(huì)嘗試插入轉(zhuǎn)換 filter比如從 YUY2 轉(zhuǎn) RGB24 的 Color Space Converter這是 DirectShow 自動(dòng)配置的核心能力也是 TFilterGraph.RenderFile 最省事的原因。調(diào)試的時(shí)候有個(gè)辦法非常好用TFilterGraph.Graph 屬性直接暴露 IGraphBuilder 接口可以用它枚舉當(dāng)前圖里的 filter 和 pin 連接情況。我習(xí)慣連接失敗后先把圖 dump 出來看是哪個(gè) pin 沒匹配上比瞎猜快得多。2.3 Unicode 邊界Delphi 2010 字符串模型變更帶來的坑Delphi 2009 開始默認(rèn) string 變成 UnicodeString這對(duì)老組件是個(gè)大地震。DSPack 2.34 的大量源碼在編寫時(shí)用的是 PChar 邏輯放到 Delphi 2010 里PChar 默認(rèn)是 PAnsiChar而 DirectShow 的 COM 接口期望的是寬字符串 LPCWSTR。兩邊在接口邊界上一錯(cuò)位就出現(xiàn)了我前面說的中文路徑失敗、文件找不到這類問題。具體現(xiàn)象是調(diào) RenderFile 傳含中文或特殊字符的路徑時(shí)DirectShow 返回 VFW_E_NOT_FOUND 或 VFW_E_CANNOT_CONNECT哪怕文件確實(shí)存在。我實(shí)測(cè)發(fā)現(xiàn)直接用 WideString 顯式聲明再傳指針就行不要讓 Delphi 在邊界處隱式轉(zhuǎn)換 ANSI。var Path: WideString; begin Path : C:\測(cè)試視頻\sample.avi; FilterGraph1.RenderFile(PWideChar(Path)); end;邏輯說明這里先把路徑聲明為 WideString再取 PWideChar 指針傳給 RenderFile確保 DirectShow 收到的是寬字符不經(jīng)過任何 ANSI 轉(zhuǎn)換。參數(shù)說明RenderFile 是 TFilterGraph 的自動(dòng)建圖入口傳完整路徑即可。路徑存在但含中文時(shí)用這個(gè)寫法能繞開大部分編碼問題如果路徑不含中文普通字符串直接傳也問題不大。2.4 為什么選 2.34 而不是其他版本對(duì)比過幾條路線順便說明選型理由。Delphi 2010 自帶的 TMediaPlayer 走 MCI 播放單純放個(gè) AVI 沒問題但截幀、攝像頭采集、自定義媒體源完全用不上。FFmpeg 的 Delphi 封裝性能好但要引入額外 DLL 和線程模型管理對(duì)一個(gè)幾萬行的老 VCL 工程來說太重。DSPack 2.34 則是完整的 DirectShow 封裝播放、截幀、采集都能在同一個(gè) COM 模型下處理API 風(fēng)格統(tǒng)一。方案播放截幀采集Delphi 2010 原生編譯外部依賴DSPack 2.34支持支持支持是無TMediaPlayer支持否否是MCI 系統(tǒng)組件FFmpeg 封裝支持支持支持需第三方動(dòng)態(tài)庫上面表格里能直觀看到唯一同時(shí)滿足播放、截幀、采集且無動(dòng)態(tài)庫依賴的就是 DSPack 2.34。它最后一代完整支持 Delphi 2009/2010 的包文件是 2.34這也是我鎖定這個(gè)版本的理由。3. 安裝配置從源碼包到 Component 菜單的完整流程3.1 裝之前先確認(rèn)環(huán)境源碼包拿到手先別急著點(diǎn)安裝花幾分鐘確認(rèn)三件事機(jī)器上裝的是 Delphi 2010 Update 5 或更高版本系統(tǒng)至少是 Win7 以上Windows SDK 里的 DirectShow 頭文件版本不要太舊。DSPack 源碼自帶兩個(gè)關(guān)鍵的包文件DSPACK_D2010.DPK 是運(yùn)行時(shí)包DSPACK_D2010_DESIGN.DPK 是設(shè)計(jì)時(shí)包。前者負(fù)責(zé)編譯鏈接后者負(fù)責(zé)把組件注冊(cè)到 IDE 面板。源碼目錄里通常有 source、packages、samples 還有 filter 幾個(gè)目錄分別是主要單元源碼、包工程文件、演示工程和部分附帶 filter 源。安裝前重點(diǎn)檢查 packages 目錄下的 .dpk 文件是否齊全比如有沒有 .dproj 工程文件這會(huì)影響 Delphi 2010 打開時(shí)的格式兼容。我吃過一次虧拿到源碼包后沒看說明直接在 IDE 里雙擊 .dpk 就點(diǎn) Install結(jié)果報(bào)錯(cuò)提示 design 包依賴 runtime 包。這個(gè)順序問題幾乎是每個(gè)第一次裝 DSPack 的人都會(huì)遇到的。3.2 編譯 runtime 與 design 包安裝的順序必須是先編譯 runtime 包再編譯 design 包并安裝。在 Delphi 2010 里操作文件 → 打開項(xiàng)目 → 定位到 packages 目錄下的 DSPACK_D2010.DPK。項(xiàng)目管理器里右鍵這個(gè)包先選 Compile這一步會(huì)生成 DSUtil.dcu、DSVideo.dcu 等運(yùn)行時(shí)文件。編譯成功后再打開 DSPACK_D2010_DESIGN.DPK同樣先 Compile然后右鍵 Install。等 IDE 提示組件包已注冊(cè)DSPack 頁面就會(huì)出現(xiàn)在組件面板上。cd /d %~dp0 regsvr32 /s filter\*.ax echo DSPack filters registered.邏輯說明這是一段批量注冊(cè)腳本把 DSPack 自帶的 DirectShow filter.ax 文件通常放在 filter 子目錄注冊(cè)到系統(tǒng)。Windows 7 及以上系統(tǒng)建議用管理員權(quán)限打開命令行再執(zhí)行否則注冊(cè)會(huì)靜默失敗。參數(shù)說明/s 表示靜默模式不彈出成功提示/u 可用來反注冊(cè)。如果機(jī)器是 64 位系統(tǒng)且 IDE 是 32 位DSPack 的 .ax 組件通常注冊(cè)到 SysWOW64 目錄即可不需要跑到 System32 里。包文件全部編譯完成后還有一步必須做把 DSPack 的 source 目錄加入 IDE 的 Library 搜索路徑。打開 IDE 工具 → 選項(xiàng) → 庫路徑追加 source 目錄路徑。這一步漏掉的話新建工程引用 DSPack 單元時(shí)Delphi 會(huì)提示找不到 DSUtil.dcu。3.3 安裝后的環(huán)境檢查清單裝完別急著寫業(yè)務(wù)代碼先跑一遍自帶 Demo我踩過的坑里有一半出在沒驗(yàn)證基礎(chǔ)環(huán)境。打開 samples 下的視頻播放示例工程編譯運(yùn)行后傳入一個(gè)現(xiàn)有 AVI 文件路徑。能正常播放并拖動(dòng)進(jìn)度條說明三條鏈路都沒問題第一個(gè)是 IDE 集成說明包文件安裝正確第二個(gè)是 DirectShow 基本鏈路說明系統(tǒng)里渲染器和解碼器可用第三個(gè)是 filter 注冊(cè)狀態(tài)說明 Graph 構(gòu)建能正常匹配。檢查工程平臺(tái)選項(xiàng)也在此列。Delphi 2010 支持 Win32 和 Win64 目標(biāo)但 DSPack 2.34 的源碼只面向 32 位平臺(tái)。在 Project → Options → Delphi Compiler 里確認(rèn) Target 是 32-bit Windows這點(diǎn)我在 Win64 目標(biāo)下翻過車后面避坑章節(jié)詳細(xì)寫。還有一個(gè)容易被忽略的檢查項(xiàng)確認(rèn)系統(tǒng)里已注冊(cè)的 DirectShow 解碼器是否干擾 RenderGraph。可以用系統(tǒng)自帶的 GraphEdit 工具打開同一個(gè) AVI 查看圖結(jié)構(gòu)如果自動(dòng)匹配拉到第三方解碼器或奇怪的變換 filter播放可能卡頓或黑屏。這時(shí)候就要走手動(dòng)建圖的路線而不是繼續(xù)依賴自動(dòng)連接。4. 寫第一個(gè)播放器RenderGraph 一行出畫面到手動(dòng)拉線4.1 最小可運(yùn)行的播放器代碼新建一個(gè) VCL 應(yīng)用往窗體上放 TFilterGraph、TVideoWindow、TButton 和一個(gè) TPanel按鈕點(diǎn)擊事件里寫下面這段procedure TForm1.btnPlayClick(Sender: TObject); begin FilterGraph1.Active : False; FilterGraph1.ClearGraph; FilterGraph1.RenderFile(C:\videos\sample.avi); VideoWindow1.FilterGraph : FilterGraph1; VideoWindow1.Owner : Panel1; VideoWindow1.Visible : True; FilterGraph1.Play; end;邏輯說明第一步把濾波圖管理器停掉并清空上次的圖第二步調(diào) RenderFile 讓 DirectShow 自動(dòng)建圖第三步把 VideoWindow 綁定到 FilterGraph 并指定它把畫面畫到 Panel1 上最后 Play 開始播放。參數(shù)說明RenderFile 接受完整文件路徑路徑含中文或空格時(shí)按第 2 章里 WideString 的寫法傳參更穩(wěn)。VideoWindow1.Owner 必須是已創(chuàng)建好的窗口化控件一般用 Panel不能畫到普通 Label 上。Visible 必須設(shè)為 True否則視頻畫面不顯示但聲音會(huì)正常播放這是個(gè)容易誤判的現(xiàn)象。4.2 手動(dòng) Filter Graph 連接方式需要精確控制 filter 鏈時(shí)RenderFile 的自動(dòng)建圖就不夠用了。常見做法是先用 RenderFile 把基礎(chǔ)鏈路拉起來再把 SampleGrabber 插入指定位置比如截幀或預(yù)覽前級(jí)處理。procedure TForm1.BuildGraph; var Grabber: TSampleGrabber; begin FilterGraph1.Active : False; FilterGraph1.ClearGraph; FilterGraph1.RenderFile(C:\videos\sample.avi); Grabber : TSampleGrabber.Create(nil); try Grabber.FilterGraph : FilterGraph1; Grabber.SetMediaType(VIDEOINFOHEADER); FilterGraph1.AddFilter(Grabber, MyGrabber); FilterGraph1.ConnectPins(Source, Output, MyGrabber, Input); FilterGraph1.Play; finally Grabber.Free; end; end;邏輯說明這段代碼先讓 RenderFile 自動(dòng)建好源和渲染段再新建 SampleGrabber 加入圖里用 ConnectPins 把源 Filter 的輸出 Pin 接到 Grabber 的輸入 Pin。Grabber 的 filter name 用字符串標(biāo)識(shí)ConnectPins 通過這個(gè)名字定位。參數(shù)說明SetMediaType 必須設(shè)置否則 Grabber 不知道輸出什么媒體類型回調(diào)不會(huì)觸發(fā)VIDEOINFOHEADER 是最通用的設(shè)置包含畫面尺寸、顏色格式和幀率。ConnectPins 的參數(shù)是濾波器名和 Pin 名實(shí)際名稱可能因 filter 的實(shí)現(xiàn)而不同調(diào)試時(shí)用 GraphEdit 查看準(zhǔn)確的 Pin 名再填。接完后實(shí)測(cè)發(fā)現(xiàn)Grabber 插入后如果媒體類型不匹配DirectShow 可能自動(dòng)插入轉(zhuǎn)換 filter播放仍正常但沒有回調(diào)。這種情況下要把 Grabber 的輸出類型設(shè)成和下游一致或者干脆在 Grabber 之后手動(dòng)連接 Renderer。4.3 參數(shù)調(diào)整播放窗口、音量與音視頻同步TFilterGraph 上有幾個(gè)高頻參數(shù)值得專門說明。AutoMon 屬性控制是否按視頻原始尺寸自動(dòng)調(diào)整播放窗口設(shè)為 False 時(shí)畫面會(huì)適應(yīng) Owner 控件尺寸設(shè)為 True 時(shí)可能撐爆或截?cái)喈嬅?。Volume 設(shè)置音頻音量范圍是 -10000 到 0單位是百分之一分貝這里最容易踩坑很多人傳正數(shù)發(fā)現(xiàn)沒聲音其實(shí)必須用負(fù)數(shù)。Balance 控制左右聲道平衡-10000 全左10000 全右。播放定位時(shí)用 Seek 方法進(jìn)度參數(shù)基于 TimeFormat。默認(rèn) TimeFormat 是 TIME_FORMAT_MEDIA_TIME單位是 100 納秒配合 GetDuration 獲取總時(shí)長(zhǎng)可以精確換算進(jìn)度條比例。音視頻同步問題我也遇到過文件較大時(shí)畫面和聲音不同步常見原因是系統(tǒng)默認(rèn)渲染器在 VMR9 模式下需要更精確的時(shí)鐘源或者是顯卡驅(qū)動(dòng)渲染隊(duì)列緩沖太大。處理方式有兩個(gè)一是把 TFilterGraph 的 SyncMode 設(shè)為 smClock強(qiáng)制使用系統(tǒng)時(shí)鐘二是把 VMR 的 CompositionMode 打開讓渲染器自己做合成減少畫面延遲。5. 避坑記錄Delphi 2010 調(diào) DSPack 常見問題與排查5.1 編譯報(bào)錯(cuò)Cannot find unit DSUtil.dcu現(xiàn)象新建工程后引用 DSPack 單元編譯提示找不到 DSUtil.dcu但安裝階段明明沒報(bào)錯(cuò)。原因source 目錄沒有加入 IDE 的 Library 搜索路徑或者 runtime 包編譯產(chǎn)物沒有生成到默認(rèn)輸出目錄。解決回到安裝章節(jié)把 source 目錄追加到工具 → 選項(xiàng) → 庫路徑然后重新編譯 DSPACK_D2010.DPK確認(rèn) DCU 文件確實(shí)生成。檢查 Search Path 里有沒有殘留舊版本的 DSUtil.pas有就清掉避免編譯時(shí)取到舊文件。5.2 視頻窗口黑屏但有聲音現(xiàn)象播放能聽到聲音視頻窗口里全是黑色線程沒有卡死。原因VideoWindow1.Owner 指向的 Panel 尚未創(chuàng)建或者在窗口初始化之前就調(diào)用了 Play。VMR 模式下渲染器對(duì)窗口句柄的創(chuàng)建時(shí)機(jī)非常敏感窗體還沒顯示時(shí)綁定窗口畫面就丟了。解決保證在 FormShow 之后再創(chuàng)建綁定不要把綁定邏輯放在 FormCreate 里。綁定后顯式設(shè)置 VideoWindow1.Visible : True并確認(rèn) Panel 的 DoubleBuffered 屬性已在窗體顯示前打開否則畫面可能閃爍或不出圖。5.3 中文路徑播放失敗現(xiàn)象RenderFile 傳含中文的文件路徑時(shí)返回 VFW_E_NOT_FOUND換成純英文路徑就正常。原因Delphi 2010 的字符串在邊界處被轉(zhuǎn)成 ANSIDirectShow 期望的是寬字符。DSPack 2.34 源碼內(nèi)部對(duì) PChar 的處理沒有完全適配 Unicode 字符串模型路徑一旦出 ASCII 范圍就亂碼。解決傳參時(shí)把路徑聲明成 WideString用 PWideChar 傳進(jìn) RenderFile。如果路徑中既有中文又有空格避免手寫拼接用 ExtractFilePath 和 ExtractFileName 組合后再轉(zhuǎn) WideString減少中間層轉(zhuǎn)換。5.4 64 位編譯直接翻車現(xiàn)象把 Project Target 切到 64-bit Windows重新編譯報(bào)大量類型不匹配錯(cuò)誤多半是 Cardinal / LongWord 和 NativeUInt 互轉(zhuǎn)問題。原因DSPack 2.34 的源碼只支持 32 位編譯沒有為 Delphi 2010 的 Win64 目標(biāo)做過適配。解決工程目標(biāo)平臺(tái)鎖死在 32-bit Windows。在 Project Options 里把 Target 設(shè)為 Win32不用嘗試用條件編譯去修補(bǔ)源碼兼容性工作量遠(yuǎn)大于收益。5.5 SampleGrabber 收不到回調(diào)現(xiàn)象Grabber 加進(jìn)圖中播放正常但回調(diào)函數(shù)一次也不觸發(fā)。原因沒設(shè)置媒體類型或 Grabber 的 BufferSize 太小回調(diào)被丟棄或者設(shè)置了 OneShot 模式后只在第一幀回調(diào)一次后續(xù)全無。解決先檢查 Grabber.SetMediaType 是否傳入 VIDEOINFOHEADER再確認(rèn) BufferSize 至少能容納一幀 RGB24 數(shù)據(jù)。調(diào)試時(shí)先把 OneShot 設(shè)為 True 驗(yàn)證單幀回調(diào)通過后再改成連續(xù)模式。5.6 音頻采集沒有聲音輸出現(xiàn)象程序里 TAudioCapture 能采集到波形數(shù)據(jù)但外放沒有聲音。原因聲卡驅(qū)動(dòng)默認(rèn)輸出格式和 Audio Renderer 協(xié)商失敗或者采集鏈路到渲染器之間走了錯(cuò)誤的 filter 路徑。解決在采集源和渲染器之間加一個(gè) SampleGrabber 做格式中轉(zhuǎn)或者手動(dòng)指定音頻渲染器的輸出格式為 PCM。部分主板驅(qū)動(dòng)默認(rèn)開啟獨(dú)占模式需要在聲卡控制面板里關(guān)閉應(yīng)用程序獨(dú)占控制否則 DSPack 拿不到混音數(shù)據(jù)。6. 進(jìn)階SampleGrabber 截幀與 Buffer 回調(diào)緩沖實(shí)戰(zhàn)SampleGrabber 的 Buffer 回調(diào)是做視頻抓幀最直接的手段。先實(shí)現(xiàn)一個(gè)回調(diào)類繼承自 TInterfacedObject 并實(shí)現(xiàn) ISampleGrabberCB 接口的三個(gè)方法type TFrameCallback class(TInterfacedObject, ISampleGrabberCB) function SampleCB(Time: Double; pSample: IMediaSample): HResult; stdcall; function BufferCB(Time: Double; pBuffer: PByte; Len: Integer): HResult; stdcall; end; function TFrameCallback.BufferCB(Time: Double; pBuffer: PByte; Len: Integer): HResult; begin // 在這里把 Len 字節(jié)的 RGB24 數(shù)據(jù)寫入文件 Result : S_OK; end;邏輯說明BufferCB 在每一幀經(jīng)過 Grabber 時(shí)被調(diào)用pBuffer 指向一幀原始像素?cái)?shù)據(jù)Len 是緩沖長(zhǎng)度Time 是媒體時(shí)間戳。SampleCB 在樣本級(jí)觸發(fā)不需要處理媒體類型時(shí)就避開它BufferCB 更可控。參數(shù)說明回調(diào)注冊(cè)需要調(diào)用 Grabber.SetCallBack(TFrameCallback.Create, 0)。第二個(gè)參數(shù)為 0 表示只回調(diào) BufferCB為 1 表示回調(diào) SampleCB?;卣{(diào)類注意保持引用有效不能讓對(duì)象在回調(diào)觸發(fā)前被釋放否則直接訪問非法內(nèi)存。實(shí)際操作時(shí)把回調(diào)里拿到的 Buffer 根據(jù)當(dāng)前視頻分辨率計(jì)算出幀大小校驗(yàn) Len 是否等于 Width × Height × 3不對(duì)就丟棄。這個(gè)校驗(yàn)幫我排掉過不完整幀某次項(xiàng)目里沒校驗(yàn)抓出來的相冊(cè)庫里混了一堆半截圖從那以后我每次在回調(diào)里都強(qiáng)制校驗(yàn)幀尺寸和寬度高度走一幀驗(yàn)證一幀再入庫。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取