建與播放配置實(shí)踐)
簡(jiǎn)介CEF-win64版本5563是一份基于Chromium嵌入式框架的Windows 64位開發(fā)資源面向需要在桌面應(yīng)用中嵌入瀏覽器內(nèi)核、視頻播放能力或進(jìn)行CEF二次集成的C開發(fā)者并針對(duì)Visual Studio 2019環(huán)境預(yù)編譯自帶H.264/H.265編解碼支持。壓縮包約278MB共1055個(gè)文件以h頭文件、cc/cpp源文件、lib與dll庫文件為主同時(shí)包含pak資源、cmake構(gòu)建配置、gypi路徑配置、測(cè)試代碼及Doxyfile文檔生成配置可支撐本地編譯、定制和文檔查閱。文件目錄層次清晰頭文件與源碼分離便于按模塊檢索對(duì)于使用VS2019的Windows 64位開發(fā)者可直接通過CMake生成工程結(jié)合include與tests目錄快速上手減少自行編譯CEF的繁瑣環(huán)境配置。README與LICENSE文件提供安裝與合規(guī)指引適合需要離線集成、深度定制或快速體驗(yàn)CEF功能的中高級(jí)開發(fā)者。已有463人學(xué)習(xí)下載。 干桌面開發(fā)的兄弟應(yīng)該都遇到過這種事產(chǎn)品經(jīng)理說“網(wǎng)頁里嵌個(gè)視頻播放器H264、H265都得能播”你翻出CEF工程跑起來一測(cè)H264直接白屏H265連白屏都省了控制臺(tái)一堆Unsupported audio/video codec。沒錯(cuò)問題就出在CEF的win64默認(rèn)構(gòu)建上——開源版的CEF并不自帶H264/265解碼能力這不是你代碼寫錯(cuò)了而是Chromium在編譯策略上把專利編碼格式“處理”掉了。這篇文章就是來解決這個(gè)事的。我把自己在Windows 64位環(huán)境下把CEF調(diào)成“能播H264/H265”的完整思路、驗(yàn)證手段和踩坑記錄都整理出來給被同一個(gè)問題卡住的朋友做個(gè)參考。不管你是剛接觸CEF的新人還是已經(jīng)在CEF里被音視頻折騰過幾次的開發(fā)者這篇都值得花幾分鐘看完。1. 先把需求拆透為什么CEF的win64版本默認(rèn)不認(rèn)H264/H2651.1 開掉專利解碼器是Chromium默認(rèn)構(gòu)建的“標(biāo)準(zhǔn)動(dòng)作”先搞明白問題的根源。CEF全稱Chromium Embedded Framework本質(zhì)就是把Chromium內(nèi)核拆出來嵌到自己的桌面程序里。但Chromium本身是一個(gè)“雙軌制”項(xiàng)目谷歌官方在構(gòu)建Chrome時(shí)會(huì)帶上H264、AAC這類專利編碼格式的解碼器而開源的Chromium項(xiàng)目為了讓代碼在法律層面更干凈通過一個(gè)叫proprietary_codecs的編譯開關(guān)來決定“要不要打包這些受專利保護(hù)的模塊”。CEF官方提供的預(yù)編譯二進(jìn)制包默認(rèn)走的是“干凈路線”proprietary_codecsfalseffmpeg_branding也不是Chrome版本。這就導(dǎo)致你在CEF里放一個(gè)MP4文件瀏覽器內(nèi)核明明有完整的video標(biāo)簽卻沒有對(duì)應(yīng)的解碼器去解封裝、解視頻流最后只能給你一個(gè)“不支持播放”的結(jié)局。而H265/HEVC比H264更特殊它的專利池更亂授權(quán)費(fèi)用更貴Chromium官方正式開啟HEVC硬解支持也才幾年的時(shí)間所以CEF預(yù)編譯包里對(duì)H265的態(tài)度基本就是“別指望默認(rèn)有”。1.2 win64平臺(tái)有哪些額外要注意的坑64位CEF相比32位在音視頻這件事上多了幾層風(fēng)險(xiǎn)。首先是DLL匹配問題CEF運(yùn)行時(shí)的libcef.dll、ffmpeg.dll、V8庫等文件版本必須嚴(yán)格匹配你要是從不同渠道拼湊一個(gè)“看起來能用的ffmpeg.dll”塞進(jìn)去輕則啟動(dòng)崩潰重則CEF直接拒絕加載。其次是GPU進(jìn)程問題win64版本的CEF在調(diào)用系統(tǒng)硬解時(shí)走的是GPU進(jìn)程系統(tǒng)Media Foundation的鏈路Windows版本、顯卡驅(qū)動(dòng)、Chromium版本任何一方掉鏈子視頻就是黑屏。第三是分發(fā)環(huán)境差異你自己機(jī)器上能播不代表客戶的win64系統(tǒng)裝了同樣版本的解碼器。1.3 哪些場(chǎng)景下你才真的需要H264/H265支持不是所有CEF應(yīng)用都需要解這兩個(gè)格式。如果你的程序只加載內(nèi)嵌頁面視頻全部來自流媒體服務(wù)而且服務(wù)端做轉(zhuǎn)碼那CEF只需要支持播放器前端解碼可以交給系統(tǒng)的WebRTC或者播放器SDK。需要H264/H265解碼的場(chǎng)景通常是這幾類桌面軟件內(nèi)嵌了“本地文件預(yù)覽”功能比如網(wǎng)盤客戶端、視頻剪輯工具、資源管理器增強(qiáng)工具用戶雙擊一個(gè)本地MP4/MKV就得直接開播。程序要展示監(jiān)控?cái)z像頭或視頻會(huì)議拉流H264是絕大多數(shù)硬件編碼器的輸出格式H265則用于高壓縮比的4K/8K設(shè)備。內(nèi)部管理系統(tǒng)里集成了視頻培訓(xùn)、課件、錄屏回放功能HR后臺(tái)傳上來的就是H265編碼的MP4文件。在這些場(chǎng)景下如果你的CEF不支持對(duì)應(yīng)編碼唯一的下場(chǎng)就是被迫調(diào)外部播放器用戶體驗(yàn)直接斷崖式下跌。2. 選型實(shí)踐拿到支持H264/H265的CEF win64版本2.1 先給你的CEF做個(gè)“體檢”別憑感覺來這里我建議先用一個(gè)最簡(jiǎn)單的方法確認(rèn)當(dāng)前CEF對(duì)H264/H265的支持情況在CEF加載的頁面里跑一段JavaScript探針。核心思路是創(chuàng)建video元素調(diào)用canPlayType方法給它傳帶不同編碼參數(shù)的MIME字符串根據(jù)返回值判斷內(nèi)核手里有沒有對(duì)應(yīng)的解碼器。function checkSupportedCodecs() { var v document.createElement(video); var codecList { H264 Baseline: video/mp4; codecsavc1.42E01E, H264 High: video/mp4; codecsavc1.640028, H265 Main: video/mp4; codecshvc1.1.6.L93.B0, H265 Main10: video/mp4; codecshev1.2.4.L120.90, AAC Audio: audio/mp4; codecsmp4a.40.5 }; for (var key in codecList) { var result v.canPlayType(codecList[key]); console.log(key : (result || 不支持的格式)); } } checkSupportedCodecs();返回probably代表當(dāng)前環(huán)境一定能解maybe表示理論上可解取決于容器的具體封裝返回空字符串則是完全不支持。我見過太多團(tuán)隊(duì)排查了半天代碼最后發(fā)現(xiàn)自己用的還是CEF原始構(gòu)建壓根沒做任何處理這一把探針下去就全明白了。2.2 三條獲取“帶解碼”CEF的路徑從省事到費(fèi)事路徑一找現(xiàn)成的社區(qū)/商業(yè)構(gòu)建版CEF。在Windows開發(fā)圈里有一些基于CEF源碼自己額外編譯了proprietary_codecs的發(fā)行版這些版本內(nèi)部打包了可解碼H264和H265的FFmpeg模塊。好處是省時(shí)間但坑也明顯你很難核實(shí)它的FFmpeg到底從哪個(gè)Chromium版本拉出來的萬一構(gòu)建者魔改了二進(jìn)制安全性也沒法保證。建議只在內(nèi)部工具類項(xiàng)目或你有渠道拿到構(gòu)建方承諾的場(chǎng)景下使用面向客戶分發(fā)前一定要做DLL版權(quán)掃描和病毒掃描。路徑二自己動(dòng)手編譯CEF開啟專利解碼器開關(guān)。這是“一勞永逸”的方案也是我試過最穩(wěn)的。CEF官方提供了自動(dòng)化構(gòu)建工具automate-git.py你在Windows上準(zhǔn)備Visual Studio環(huán)境后在GN生成構(gòu)建參數(shù)時(shí)給兩條關(guān)鍵配置gn gen out/Release_GN_x64 --argsis_official_buildtrue proprietary_codecstrue ffmpeg_branding\Chrome\proprietary_codecstrue決定FFmpeg模塊把H264/265、AAC等專利解碼器編進(jìn)去ffmpeg_branding設(shè)置為Chrome會(huì)讓FFmpeg使用與Chrome一致的編譯配置。編譯時(shí)長(zhǎng)看機(jī)器性能從半小時(shí)到幾小時(shí)都有但結(jié)果是可控的你拿到了一個(gè)完整的、版本完全匹配的CEF win64構(gòu)建H264和H265都能播。自己編譯最麻煩的是第一次拉源碼、同步depot_tools依賴的時(shí)間成本以及網(wǎng)絡(luò)不穩(wěn)定時(shí)重試的身心折磨。路徑三不換CEF只替換/補(bǔ)充FFmpeg模塊。這也是很多人的實(shí)操思路。CEF的FFmpeg功能集中在ffmpeg.dll這一個(gè)文件里理論上你用另一個(gè)支持相同Chromium版本但開啟了專利解碼器的ffmpeg.dll替換原文件CEF就能解鎖H264/H265。wwwffmpeg.dll這個(gè)文件非常敏感它和CEF的Chromium版本綁定混用不同版本的ffmpeg.dll到其他CEF庫會(huì)導(dǎo)致崩潰。我甚至見過有人從某個(gè)“魔改版Chrome”里抽FFmpeg塞進(jìn)CEF結(jié)果CEF啟動(dòng)時(shí)直接Google Chrome框架崩潰。所以這條路只推薦熟練掌握DLL依賴調(diào)試的人嘗試你要做好隨時(shí)用dumpbin /dependents查看依賴的心理準(zhǔn)備。2.3 編譯過程中有哪些被文檔一筆帶過的細(xì)節(jié)自己編譯CEF時(shí)有幾個(gè)細(xì)節(jié)你提前知道能少走很多彎路。一個(gè)是用automate-git.py腳本時(shí)注意在命令行里顯式指定--branch你的目標(biāo)分支這個(gè)分支決定了你要用的Chromium大版本比如CEF 115對(duì)應(yīng)的Chromium 115不同分支的API和FFmpeg版本差異極大。另一個(gè)是GN參數(shù)里ffmpeg_branding用“Chrome”會(huì)引入Chrome所帶的額外解碼能力但要留意這會(huì)改變FFmpeg對(duì)某些格式的優(yōu)先選擇比如部分視頻原本走軟解啟用Chrome branding后可能優(yōu)先走系統(tǒng)硬解硬解不穩(wěn)定時(shí)就變回軟解這個(gè)切換邏輯在日志里很難看出來。再有一個(gè)容易被忽略的is_official_buildtrue會(huì)啟用一些優(yōu)化和保險(xiǎn)絲熔斷機(jī)制構(gòu)建產(chǎn)物體積會(huì)比普通debug大不少但在做音視頻分發(fā)時(shí)這是合理代價(jià)。如果你只是為了內(nèi)網(wǎng)快速測(cè)試不妨先用is_official_buildfalse配proprietary_codecstrue來跑通鏈路產(chǎn)物體積小調(diào)試信息也全等穩(wěn)定了再出正式構(gòu)建。2.4 關(guān)于許可證問題必須先說清楚既然H264/H265涉及專利那我就直話直說就算你通過編譯開關(guān)把解碼器編進(jìn)去了也只是“技術(shù)上能用”而已。如果你只是做內(nèi)部自用工具問題不大但如果你的軟件要對(duì)外公開發(fā)行哪怕免費(fèi)H264/H265的專利授權(quán)仍然是繞不開的環(huán)節(jié)。H264的專利池還好一些很多大公司都有批量授權(quán)H265的專利授權(quán)方更分散商用分發(fā)前一定要讓公司的法務(wù)出面確認(rèn)授權(quán)條款。這里我沒有任何法律意見但我的經(jīng)驗(yàn)是在國內(nèi)做小工具、免費(fèi)軟件硬解碼商用視頻確實(shí)有風(fēng)險(xiǎn)上線前務(wù)必走合規(guī)評(píng)估。3. 配置與驗(yàn)證讓CEF真正把H264/H265跑起來3.1 啟動(dòng)參數(shù)和Feature開關(guān)怎么配拿到帶解碼能力的CEF以后還需要給CEF設(shè)置合理的啟動(dòng)參數(shù)。H264相對(duì)簡(jiǎn)單基本只要FFmpeg里有解碼器CEF自己就能解。問題集中在H265/HEVC因?yàn)镃hromium為了控制性能開銷默認(rèn)不會(huì)輕易啟用HEVC的軟件解碼路徑尤其當(dāng)視頻分辨率超過4K時(shí)軟解是跑不動(dòng)的必須在啟動(dòng)參數(shù)里開啟系統(tǒng)硬解相關(guān)Feature。一個(gè)比較穩(wěn)的啟動(dòng)參數(shù)組合長(zhǎng)這樣CefSettings settings; CefString(settings.command_line_args_disabled) 0; CefString(settings.browser_subprocess_path) LC:\\your_path\\cef_subprocess.exe; // 在cef_initialize之前通過CommandLine追加 auto command_line CefCommandLine::CreateCommandLine(); command_line-AppendSwitchWithValue(enable-features, PlatformHEVCDecoderSupport,HEVCDemuxing,HEVCParser); command_line-AppendSwitch(enable-hardware-overlays);這里解釋一下三個(gè)Feature的意思PlatformHEVCDecoderSupport表示允許CEF去調(diào)用Windows系統(tǒng)Media Foundation里注冊(cè)的HEVC解碼器也就是說系統(tǒng)自帶的“HEVC視頻擴(kuò)展”如果裝了CEF就能用起來HEVCDemuxing是讓解析器認(rèn)識(shí)MP4里的HEVC軌道不然連解封裝都過不去HEVCParser是告訴FFmpeg層能解析HEVC NAL單元。這三個(gè)缺一個(gè)都會(huì)造成“文件能識(shí)別、畫面死活出不來”的狀態(tài)。當(dāng)你的目標(biāo)機(jī)器Windows系統(tǒng)版本較老或者沒裝微軟HEVC擴(kuò)展時(shí)硬解路徑會(huì)失效此時(shí)可以增加disable-featuresPlatformHEVCDecoderSupport強(qiáng)制走FFmpeg軟解代價(jià)是CPU占用會(huì)明顯上升。3.2 硬件加速的檢查點(diǎn)很多H265視頻在win64 CEF上黑屏不是你配置錯(cuò)了而是GPU進(jìn)程壓根沒起來。CEF的--disable-gpu參數(shù)一旦開了H265硬解基本廢掉而Windows遠(yuǎn)程桌面環(huán)境又默認(rèn)禁用GPU加速經(jīng)常出現(xiàn)“開發(fā)機(jī)上能播、客戶遠(yuǎn)程測(cè)試就黑屏”的奇怪現(xiàn)象。到CEF應(yīng)用里打開chrome://gpu頁面檢查Graphics Feature Status相關(guān)項(xiàng)里Video Decode是否處于Hardware accelerated狀態(tài)。如果顯示Software only或者Disabled說明GPU進(jìn)程沒有正常初始化這時(shí)候得排查顯卡驅(qū)動(dòng)是否匹配、CEF的--disable-gpu是否被某些框架誤加、是否運(yùn)行在無獨(dú)顯的虛擬機(jī)里。硬件加速這一關(guān)過不了你編譯打包的解碼器再全也沒有用武之地。3.3 在真實(shí)項(xiàng)目里怎么組織“軟解/硬解”的兜底邏輯實(shí)際項(xiàng)目里你不能把希望只押在一個(gè)解碼鏈路上。我現(xiàn)在的做法是CEF里先嘗試系統(tǒng)硬解如果能在啟動(dòng)參數(shù)里開啟Feature就開啟同時(shí)監(jiān)聽播放器的error事件做降級(jí)。比如頁面里用video元素播放H265失敗時(shí)捕獲video.onerror后把當(dāng)前視頻地址發(fā)給C層由C層調(diào)用一個(gè)自己實(shí)現(xiàn)的FFmpeg硬解播放器或者干脆喚起系統(tǒng)播放器。說白了就是“CEF能解就解不能解就退路接管”這套兜底在客戶現(xiàn)場(chǎng)救了我很多次。4. 高頻問題與排查技巧實(shí)錄4.1 H264能播、H265黑屏但音頻正常這個(gè)問題我排查過很多遍癥狀非常一致視頻文件被CEF正確解析了音頻有機(jī)會(huì)播放音頻解碼器走的是AAC很多CEF構(gòu)建里AAC和H264一起綁定而HEVC沒綁進(jìn)去或者音軌視頻軌壓根沒被解出來。先別急著調(diào)代碼打開chrome://media-internals看一下“Audio decoder”和“Video decoder”分別是什么。如果Video decoder顯示FFmpegVideoDecoder且沒有報(bào)錯(cuò)但畫面仍然黑屏可以試試加上--disable-accelerated-video-decode強(qiáng)制關(guān)閉硬解改用軟解播放。如果加了這個(gè)參數(shù)后畫面立刻正常了那問題就鎖定在系統(tǒng)的HEVC硬解和CEF的GPU進(jìn)程配合上去更新顯卡驅(qū)動(dòng)、裝微軟的HEVC擴(kuò)展多半能解決。4.2 播放視頻時(shí)CEF崩潰或GPU進(jìn)程反復(fù)重啟表現(xiàn)是播放到中途整個(gè)窗口變白然后自動(dòng)恢復(fù)或者干脆彈“頁面無響應(yīng)”。這種情況大概率是GPU進(jìn)程崩了后又自動(dòng)拉起而頁面沒來得及恢復(fù)渲染。常見誘因是顯卡對(duì)視頻硬件解碼的顯存處理有Bug往深了查會(huì)看到gpu_process_host.cc里的異常退出日志。處理辦法分兩步第一步加上--disable-gpu-compositing看看是否讓GPU進(jìn)程別做合成第二步如果還崩直接在啟動(dòng)參數(shù)里加--disable-gpu徹底禁用GPU進(jìn)程讓所有視頻都走軟解。注意CEF里禁用GPU進(jìn)程后html渲染會(huì)變卡但至少播放視頻不崩潰適合拿來先穩(wěn)住現(xiàn)場(chǎng)。4.3 CEF進(jìn)程關(guān)不掉的排查思路我猜不少人和我一樣被CefSharp/CEF的多進(jìn)程模型折騰過頭。CEF應(yīng)用一旦跑起來會(huì)派生出主進(jìn)程、GPU進(jìn)程、渲染進(jìn)程、網(wǎng)絡(luò)進(jìn)程等一大堆子進(jìn)程有些子進(jìn)程的名字還是同一個(gè)exe。網(wǎng)上搜“prome cef 進(jìn)程如何關(guān)掉”這類問題的人多半是遇到了關(guān)閉主窗口后任務(wù)管理器里還有一堆殘留進(jìn)程CPU和內(nèi)存居高不下的情況。其實(shí)根因大多數(shù)是CefShutdown被調(diào)用了但某個(gè)渲染進(jìn)程因?yàn)檎谔幚鞪S回調(diào)或下載任務(wù)而沒有及時(shí)退出。我的排查習(xí)慣是先用多進(jìn)程管理工具比如System Informer把CEF子進(jìn)程樹拉出來看進(jìn)程命令行里的--typerenderer、--typegpu-process等參數(shù)確認(rèn)殘留的是哪類進(jìn)程。然后在自己代碼里確保主窗口關(guān)閉事件里先把所有Browser對(duì)象調(diào)用CloseBrowser(true)等所有Browser的OnBeforeClose回調(diào)觸發(fā)后再執(zhí)行CefShutdown()。如果還殘留就在程序退出前手動(dòng)遍歷子進(jìn)程列表逐個(gè)調(diào)用WaitForSingleObject等它自己退等超時(shí)后再使用TerminateProcess兜底。有一點(diǎn)切記別對(duì)別人程序的同名exe亂下殺手先把進(jìn)程路徑比對(duì)好再動(dòng)手。關(guān)于進(jìn)程模型CEF提供了一個(gè)CefSettings.single_process開關(guān)把子進(jìn)程合并到主進(jìn)程里跑這樣退出時(shí)就不存在殘留了。但官方明確說這個(gè)選項(xiàng)只適合調(diào)試真實(shí)環(huán)境下強(qiáng)烈不建議開因?yàn)殇秩具M(jìn)程和瀏覽器進(jìn)程共用同一進(jìn)程任何插件崩潰都會(huì)連帶主程序一起殉葬。5. 我的實(shí)操心得匯總這東西折騰下來最大的體會(huì)是CEF的H264/H265支持不是一個(gè)“改個(gè)配置就完事”的活兒而是一條從源碼編譯、啟動(dòng)參數(shù)、硬件環(huán)境、進(jìn)程管理都要控制的鏈路。自己做的話你可以先花小半天搞一個(gè)帶解碼的構(gòu)建然后在代碼里留好“軟解/硬解切換”的開關(guān)再針對(duì)進(jìn)程退出做一輪專門的健壯性測(cè)試。我現(xiàn)在包里都會(huì)保留一個(gè)純軟解的啟動(dòng)參數(shù)副本專門應(yīng)對(duì)客戶現(xiàn)場(chǎng)顯卡驅(qū)動(dòng)不可控的情況。至于商業(yè)授權(quán)早確認(rèn)早安心別等產(chǎn)品快上線了再被法務(wù)拉住談版權(quán)的事。如果后面有時(shí)間我打算把“CEF播放H265時(shí)的性能指標(biāo)采集”也整理一下包括硬解啟動(dòng)耗時(shí)、掉幀率、GPU顯存占用這些數(shù)據(jù)怎么統(tǒng)計(jì)。這玩意兒在做大并發(fā)預(yù)覽和監(jiān)控墻方案時(shí)特別有用到時(shí)候再單獨(dú)寫一篇。本文還有配套的精品資源點(diǎn)擊獲取