CEF win64 支持 H264/H265:VS2019 编译与排查

发布时间:2026/10/24 2:48:33
CEF win64 支持 H264/H265:VS2019 编译与排查

简介:面向Windows 64位应用开发者的CEF 5563预编译包,在Visual Studio 2019环境下编译,重点补上了官方预编译版本中缺失的H264/H265视频解码能力,适合需要嵌入浏览器内核的多媒体客户端,如在线教育、直播与视频会议类项目。压缩包共1055个文件、约278MB,以539个.h头文件和359个.cc源文件为主体,另有pak资源包、dll动态库与lib导入库可直接接入运行,gypi路径表、CMake构建脚本、Doxyfile文档配置与README则给出裁剪重编译的入口。目前已有486人学习下载。读者可直接跳过自行编译Chromium的漫长流程,获得可调试的接口头文件、tests中的单元测试用例与完整构建配置,并借助它们理解内部实现机制、按需定制集成方案。

1. CEF win64 支持 H264/H265:VS2019 直接开编前先别急着点生成

CEF win64 版本要支持 H264/H265,很多人第一反应是拿 VS2019 打开工程直接生成,结果播 MP4 黑屏,回头才发现编译参数里根本没开proprietary_codecs。这套环境在桌面客户端里太常见了:内嵌网页、播本地 MP4、接监控视频流,都绕不开 CEF 的 Windows 64 位构建。装不好不会立刻报错,而是运行后视频区域一片黑,日志里也未必有明确提示,排查起来很耗时间。这份 CEF win64 支持 H264/H265 的资源,适合需要把浏览器内核塞进自己 EXE 的开发者,也适合已经拿到预编译包、准备用 VS2019 接工程的人。下面按环境、落盘、GN 参数、编译、排查、验证的顺序走一遍,能照着复现。

2. 环境清单:VS2019、Windows SDK 和 depot_tools 的版本对齐

CEF 的 Windows 构建不是“装个 VS2019 就能编”这么简单。VS2019 只是 IDE 外壳,真正干活的是 MSVC v142 工具集、Windows SDK、GN、Ninja、Python 和 depot_tools。版本错位时,表现往往不是一句“版本不匹配”,而是gclient sync卡住、gn gen找不到编译器、ninja编到一半报 SDK 头文件缺失。我一般先把工具链固定成一张表,再动源码。

组件建议版本/形态检查命令注意点
Visual Studio 201916.11 这类后期版本,安装“使用 C++ 的桌面开发”cl必须勾选 MSVC v142 和 Windows 10 SDK
Windows SDK10.0.19041.0 或资源包记录的同代 SDK看 VS 安装器不要只装最新 SDK 却缺 CEF 分支要求的版本
Python3.8/3.9 的 64 位版本python --version不要用应用商店别名版
depot_tools解压即用,PATH 前置gclient --version不要让旧版 gn/ninja 抢先
Git支持长路径的较新版本git --version源码目录深,长路径要开
Ninja/GN由 depot_tools 自带where gn、where ninja路径应指向 depot_tools

这张表里最容易忽视的是 PATH 顺序。很多机器上装过旧版 GN 或别的构建工具,命令行里gn --version能跑,但跑的是另一个目录的 gn,结果cef_create_projects.bat生成的参数和 CEF 分支对不上。我的做法是把 depot_tools 放到 PATH 最前面,再用where确认。

2.1 先定 64 位工具链,别让 x86 宿主混进来

CEF win64 的资源是 64 位 DLL,自己的宿主 EXE 也必须是 x64。VS2019 里新建工程时,默认可能是 Win32,后面再改平台会带出一串链接错误。我一般先开“x64 Native Tools Command Prompt for VS 2019”,或者从普通 cmd 调vcvarsall.bat切 x64。不要用 x86 开发者命令提示符去编 x64 目标,cl能跑,但后面链接 CEF 的libcef.lib时位数对不上,报错反而不直观。

:: 在 VS2019 的 x64 开发者命令提示符里执行 where cl cl where gn where ninja python --version git --version

where cl应该指向 VS2019 的 MSVC 目录;cl单独执行会输出编译器版本,确认是 x64 宿主。where gn和where ninja应优先落在 depot_tools 目录。python --version输出 3.8 或 3.9 的 64 位版本即可。这里不要图省事用 32 位 Python,depot_tools 里有些脚本对位数和路径很敏感,出问题时日志不够清楚,属于典型的玄学故障。

如果where cl找不到,不是 CEF 的问题,是当前终端没有加载 VS 环境。可以重新打开 x64 开发者命令提示符,或者用 VS2019 安装目录下的vcvarsall.bat初始化。路径里不要带中文和空格,CEF 的 GN 生成和 Ninja 编译对空格路径兼容性一般,能避就避。

2.2 depot_tools 与 Python:PATH 顺序决定 gclient 能不能跑

depot_tools 不是安装程序,解压后把目录放进 PATH 就行。但它会自带gn、ninja、gclient、fetch等脚本,所以 PATH 必须前置。常见错误是系统里已经有一个 Ninja,版本比 depot_tools 自带的新,命令行里看着能用,实际 CEF 生成的 build.ninja 用了旧语法或参数,编到一半才翻车。我一般会先清掉终端里的旧路径,再临时设置:

:: 假设 depot_tools 解压在 D:\cef\depot_tools set DEPOT_TOOLS=D:\cef\depot_tools set PATH=%DEPOT_TOOLS%;%PATH% set DEPOT_TOOLS_WIN_TOOLCHAIN=0 set GYP_MSVS_VERSION=2019 where gn where ninja gclient --version

DEPOT_TOOLS_WIN_TOOLCHAIN=0表示让 depot_tools 使用本机安装的 VS2019,而不是它自己去找一套独立工具链;GYP_MSVS_VERSION=2019是给还走 GYP 兼容路径的脚本看的,CEF 现在主要用 GN,但保留这个变量能减少生成工程时的歧义。PATH前置后,where gn的第一行必须是D:\cef\depot_tools\gn.exe或对应的 bat。gclient --version能输出版本号,说明 Python 和 depot_tools 基本通了。

如果gclient报 Python 相关错误,先看python是不是应用商店别名。别名版 Python 在脚本里经常无法正确解析路径,日志会写成“找不到文件”但实际不是文件缺失。把 Python 换成官方 64 位安装包,安装时勾选“Add Python to PATH”,再重开终端。另一个常见问题是长路径,CEF 源码层级很深,Git 没开长路径时gclient sync会在某个深层目录中断。可以提前执行git config --global core.longpaths true,这不是万能药,但能少踩一个坑。

环境变量不要只写在当前终端。CEF_ROOT这种给 VS 工程用的变量,建议用setx写到用户环境变量,然后重开终端:

:: 路径按自己的资源落盘位置改,不要带空格和中文 setx CEF_ROOT "D:\cef\win64_h264"

setx写入后不会影响已经打开的终端,必须重开。CEF_ROOT后面会在 VS2019 工程的附加包含目录和附加库目录里用$(CEF_ROOT)引用,这样换机器时只改环境变量,不用逐个工程改路径。注意setx有长度限制,路径不要太长;如果资源包放在很深的目录,先挪到D:\cef\这种短路径下。

3. 资源落盘与源码拉取:CEF win64 目录怎么摆、gclient 怎么同步

拿到 CEF win64 支持 H264/H265 的资源后,不要直接双击 DLL 或把整个目录塞进现有工程。先分两块:一块放预编译产物,一块放源码构建树。预编译产物用于快速接工程和验证,源码树用于自己改 GN 参数重编。两块混在一起,后面清理out目录时容易误删资源包里的libcef.dll。

我一般这样摆:

D:\cef\ win64_h264\ # 预编译产物,含 libcef.dll、include、libcef.lib、pak、locales src\ # CEF 源码构建树 test\ # 本地验证页和测试 mp4 depot_tools\ # depot_tools

预编译目录先设CEF_ROOT,VS2019 工程直接引用。源码目录设另一个变量CEF_SRC,只给构建脚本用。两个变量分开,后面排查“到底是用了旧 DLL 还是新编的 DLL”时不会混。

3.1 预编译包和源码树分开存放

预编译包解压后,先确认目录里有include、libcef.dll、libcef.lib、cef.pak、locales这些常见内容。不要只看libcef.dll在不在,CEF 启动时还要加载资源文件和本地化 pak,缺一个就可能闪退或白屏。把整个 Release 目录作为运行目录,不要只拷一个 DLL 到自己 EXE 旁边。

VS2019 工程里这样配:

:: 在工程属性里使用,不是单独执行的脚本 :: C/C++ -> 常规 -> 附加包含目录 $(CEF_ROOT) :: 链接器 -> 常规 -> 附加库目录 $(CEF_ROOT) :: 链接器 -> 输入 -> 附加依赖项 libcef.lib;libcef_dll_wrapper.lib;

$(CEF_ROOT)指向预编译包根目录,libcef.lib是导入库,libcef_dll_wrapper.lib是 CEF 的 C++ 封装层,需要自己用源码里的libcef_dll_wrapper工程编出来,或者用资源包已经编好的版本。附加依赖项里两个库的顺序不要随便调,libcef.lib在前,wrapper 在后。运行库选项也要和 CEF 产物一致,CEF 常见构建是静态运行库,自己的工程如果混用/MD和/MT,会出现一堆重复符号或运行时崩溃。

如果工程是 x64,附加库目录里不要混入 32 位 lib。检查方法不是看文件名,而是看链接报错:LNK1112: module machine type 'x86' conflicts with target machine type 'x64'就是位数混了。把 32 位目录从附加库目录里删掉,只保留 win64 资源。

3.2 切分支与同步:别在 detached HEAD 上直接编

源码构建树建议用fetch cef生成,再切到资源包记录的分支。不要随手git checkout一个标签后直接在 detached HEAD 上编,后面gclient sync会把依赖拉到不匹配的版本。资源包里如果带了CEF_BRANCH.txt之类的记录,先读出来,再执行:

:: 进入源码构建树,分支名从资源包记录里取,不要自己猜 cd /d D:\cef\src set CEF_BRANCH=资源包记录的分支名 git checkout %CEF_BRANCH% gclient sync --with_branch_heads --with_tags

git checkout切到对应分支,gclient sync --with_branch_heads --with_tags会把 Chromium 依赖、第三方库和标签同步到该分支要求的状态。--with_branch_heads拉分支头,--with_tags拉标签,首次同步时间会比较长。如果只是复现资源包,不想保留本地改动,可以加-D让 gclient 删除多余文件,但第一次不要加,先让同步完整跑完。

同步过程中最怕网络中断后直接重跑。中断后先看.gclient和src目录是否完整,再执行gclient sync -D清理残留。不要手动删src\third_party里的目录,CEF 的依赖关系不是靠目录名判断的,删错一个后面会在编译期报找不到头文件。同步完成后,gclient runhooks一般会自动跑,如果没跑,手动执行一次,确保 GN 和工具链钩子就位。

提示:源码目录和预编译目录不要放在同一个盘符根目录下再互相引用,路径层级越短越稳。D:\cef\src比D:\work\projects\cef\src少很多长路径问题。

4. GN 参数配置:proprietary_codecs、ffmpeg_branding 与 HEVC 开关

CEF 默认构建为了合规和体积,常常不带 H264/H265 这类专有编码支持。表现出来就是网页里<video>标签的canPlayType返回空字符串,或者 MP4 能加载但只有声音没有画面。要支持 H264,核心参数是proprietary_codecs=true和ffmpeg_branding="Chrome";要支持 H265,还要看当前 CEF 分支有没有对应的 HEVC 开关,常见的是enable_platform_hevc和enable_hevc_demuxing。不同分支参数名可能变,不能硬塞,要先查。

4.1 先看参数是否存在,再写 GN_DEFINES

GN 参数不是随便写的,不存在的参数会让gn gen直接报错。我的习惯是先建一个临时 out 目录,只带基础参数生成一次,再用gn args --list查 HEVC 相关项:

:: 在 CEF 源码树根目录执行 set GN_DEFINES=is_official_build=true proprietary_codecs=true ffmpeg_branding=Chrome gn gen out\check_args --args="%GN_DEFINES%" gn args out\check_args --list | findstr /i "hevc proprietary_codecs ffmpeg_branding"

gn gen生成临时构建目录,--args里的is_official_build=true表示按正式构建优化,proprietary_codecs=true打开专有编码,ffmpeg_branding=Chrome让 FFmpeg 走完整品牌配置。gn args --list把当前分支认识的参数列出来,findstr过滤 HEVC、proprietary_codecs、ffmpeg_branding。如果 HEVC 相关项有输出,说明当前分支认这些参数;如果没有输出,不要硬写进GN_DEFINES,否则生成阶段就会失败。

确认参数存在后,再写正式构建参数。H265 的开关在不同分支上可能是平台解码、解复用开关,或者由 FFmpeg 品牌配置间接决定。我一般会把能查到的 HEVC 开关显式打开,并在资源包记录里写清楚,避免下次重编时忘记:

:: 正式构建参数,HEVC 开关按上一步查到的名字保留 set GN_DEFINES=is_official_build=true proprietary_codecs=true ffmpeg_branding=Chrome enable_platform_hevc=true enable_hevc_demuxing=true set GN_ARGUMENTS=--ide=vs2019 --sln=cef --filters=//cef/* call cef_create_projects.bat

GN_DEFINES是 CEF 构建脚本读取的参数集合,GN_ARGUMENTS让生成器产出 VS2019 工程和cef.sln,--filters=//cef/*只生成 CEF 相关工程,避免把整个 Chromium 的工程都塞进解决方案。cef_create_projects.bat在源码树根目录或tools目录下,找不到时先where cef_create_projects.bat,不要凭记忆写死路径。

如果生成阶段报某个 GN 参数无效,先把该参数从GN_DEFINES里删掉,重新生成,再查当前分支的构建配置文件。常见误用是照着别的分支的教程抄参数,结果自己的分支没有这个开关,GN 直接拒绝。参数取舍的原则是:H264 必须有proprietary_codecs和ffmpeg_branding,H265 先确认分支支持,再决定走平台解码还是软件解码。

4.2 生成 VS2019 工程与 ninja 目标

cef_create_projects.bat跑完后,源码树里会出现out\Release_GN_x64之类的构建目录。先不要急着编整个解决方案,用 Ninja 编一个cefclient目标验证工具链。cefclient是 CEF 自带的示例程序,能跑起来说明 DLL、pak、编码参数基本对齐。

:: 编 cefclient,内存不足时把 -j 调小 ninja -C out\Release_GN_x64 -j 4 cefclient

-C切换到构建目录,-j 4控制并发,机器内存小的时候不要开满,否则链接阶段容易崩。第一次编译时间很长,不要因为几分钟没输出就中断。编完后到out\Release_GN_x64下找cefclient.exe,同目录还应该有libcef.dll、chrome_elf.dll、icudtl.dat、snapshot_blob.bin、cef.pak、locales等运行资源。缺资源时cefclient.exe可能闪退,不会给你完整报错。

需要生成可分发的二进制包时,再用 CEF 的打包脚本。打包前确认GN_DEFINES还是支持 H264/H265 的那一套,不要打包时又跑到另一个 out 目录:

:: 生成分发包,输出目录按脚本提示确认 call make_distrib.bat

make_distrib.bat会把libcef.dll、头文件、导入库、资源文件按 CEF 分发包结构整理出来。打包完成后不要只看压缩包生成了没有,解压一份到干净目录,用cefclient.exe加载本地视频验证。很多“编出来能跑、发给别人就黑屏”的问题,都是打包时漏了locales或ffmpeg.dll这类依赖。

VS2019 工程接入时,如果用的是自己编的 wrapper,注意 wrapper 的编译选项要和 CEF 产物一致。CEF 的 C++ 封装层对运行库、异常处理、C++ 标准比较敏感,混用容易在CefInitialize附近崩。我的做法是先用资源包里配好的 wrapper,确认能跑,再替换成自己编的版本,出问题能快速定位是 DLL 还是 wrapper。

5. 排查:CEF 编译和 H264/H265 播放的 5 个常见坑

CEF 的故障有个特点:编译期报错还算友好,运行期黑屏、闪退、白屏往往没有明确日志。下面 5 条是装这套 win64 支持 H264/H265 环境时最容易遇到的,按“现象 → 原因 → 解决”记,后面再遇到能少绕。

5.1 编译期报错:SDK、长路径和 ninja 并发

坑一:gclient sync报 Python 找不到或脚本中断。现象是同步到一半停住,日志里出现python不是内部或外部命令,或者某个.py文件无法执行。原因通常是 PATH 里的 Python 是应用商店别名版,或者装的是 32 位版本,depot_tools 解析路径失败。解决是把官方 64 位 Python 3.8/3.9 装好并前置到 PATH,重开终端,删掉不完整的.gclient和src残留后重新同步。不要用“再跑一次”硬扛,残留状态会让下一次同步更乱。

坑二:cef_create_projects.bat报gn不是内部或外部命令。现象是脚本刚启动就退出,或者提示找不到 GN。原因是 depot_tools 没在 PATH 最前面,系统里的旧 GN 抢先,或者终端根本没加载 depot_tools。解决是用where gn确认第一行指向 depot_tools,不是别的构建工具目录;把set PATH=%DEPOT_TOOLS%;%PATH%放在脚本最前面。如果where gn有多行,把旧路径从系统环境变量里临时移除,再重开终端。

坑三:ninja编译报MSB8036或找不到 Windows SDK。现象是生成工程成功,编译到某个目标时提示找不到 SDK 版本或windows.h。原因是 VS2019 没装对应的 Windows 10 SDK,或者GYP_MSVS_VERSION指向了别的 VS 版本。解决是打开 VS 安装器,勾选 MSVC v142 和 CEF 分支要求的 Windows SDK,重新执行cef_create_projects.bat。不要只改工程属性里的 SDK 版本,CEF 的 GN 生成阶段也会读环境变量,两边不一致时会在链接期再炸一次。

坑四:编译到一半ninja被系统杀掉或链接器内存不足。现象是并发编译时窗口直接消失,或者报out of memory。原因是-j开太大,Chromium 的链接目标很吃内存。解决是把ninja -C out\Release_GN_x64 -j 4 cefclient的并发调小,先编cefclient这种单目标,不要一上来编整个解决方案。机器内存小于 16GB 时,-j 2更稳。不要一边编译一边开虚拟机或大型 IDE,链接阶段很容易被挤爆。

5.2 运行期黑屏:DLL、沙箱和编码开关

坑五:cefclient.exe闪退,报0xc000007b或0x8007007e。现象是双击就退,事件查看器里看到模块加载失败。原因是 32/64 位 DLL 混用,或者运行目录缺少chrome_elf.dll、libcef.dll、icudtl.dat这类依赖。解决是先确认宿主 EXE 和libcef.dll都是 x64,再用依赖查看工具看缺失模块;把 CEF 的 Release 目录整体作为运行目录,不要只拷 EXE 和libcef.dll。如果从预编译包换到自己编的包,先清掉旧 DLL,避免加载到缓存里的旧版本。

坑六:H264 视频黑屏,但页面和音频正常。现象是<video>能加载,canPlayType('video/mp4; codecs="avc1.42E01E"')返回空,或者播放器只有声音。原因是构建时没开proprietary_codecs=true和ffmpeg_branding=Chrome,或者打包时用了另一个没开参数的 out 目录。解决是回到 GN 参数,确认gn args out\Release_GN_x64 --list里proprietary_codecs为 true、ffmpeg_branding为 Chrome,删掉旧 out 目录重新生成和编译。不要只替换libcef.dll,FFmpeg 相关动态库和 pak 也要一起换。

坑七:H265 黑屏,H264 正常。现象是同一套 CEF 播 H264 没问题,播 H265 返回空或首帧不出来。原因分两层:构建参数没开 HEVC 相关开关,或者测试机没有平台 HEVC 解码能力。解决是先查当前分支的 HEVC 参数是否存在,显式打开后重编;再用一段编码参数更保守的 H265 测试流验证。如果canPlayType返回空但实际能播,以实际首帧为准;如果实际也黑屏,先换测试机排除平台解码差异,再查资源包是否带了对应的解码依赖。

坑八:开发机正常,拷到别的机器白屏。现象是自己机器上cefclient.exe能播,发到测试机就白屏或闪退。原因是运行目录少文件,常见是locales、swiftshader、ffmpeg.dll或vk_swiftshader.dll没带全。解决是按 CEF 分发包的目录结构整体拷贝,不要只拷libcef.dll;在干净机器上先用cefclient.exe跑本地 HTML,确认资源完整后再接业务 EXE。发布前用依赖检查工具扫一遍,别等用户装了才报缺 DLL。

6. 装完怎么验证:用本地 video 标签把 H264/H265 跑通

验证不要一上来就接业务页面,先用本地 HTML 和本地 MP4 把编码能力单独测出来。把测试页和视频放在同一个目录,避免网络、跨域、MIME 类型干扰。页面里同时探测 H264 和 H265 的canPlayType,再实际播放 30 秒,看首帧、拖动、暂停是否正常。

<!doctype html> <meta charset="utf-8"> <pre id="out"></pre> <video id="v" controls autoplay muted width="640"></video> <script> const v = document.getElementById('v'); // 两个 codec 字符串分别对应 H264 和 H265 的常见基线 const h264 = v.canPlayType('video/mp4; codecs="avc1.42E01E"'); const h265 = v.canPlayType('video/mp4; codecs="hvc1.1.6.L93.B0"'); document.getElementById('out').textContent = `H264=${h264 || 'no'} H265=${h265 || 'no'}`; v.src = 'sample.mp4'; // 与 HTML 同目录,先排除路径和网络因素 </script>

canPlayType返回"probably"或"maybe"表示浏览器认为能播,返回空字符串表示不支持。这个探测只是能力判断,最终以实际画面为准。用cefclient.exe --url=file:///D:/cef/test/check.html加载,先看页面上的 H264/H265 结果,再看视频有没有首帧。如果 H264 返回空,基本就是 GN 参数没开;如果 H264 正常、H265 空,再查 HEVC 开关和测试机解码能力。

发布前我会固定跑一张检查表:宿主 EXE 和libcef.dll是否都是 x64;运行目录是否带齐locales、cef.pak、icudtl.dat;canPlayType的 H264 是否非空;本地 MP4 是否能出首帧并拖动;换一台干净机器是否同样能播。表格里任何一项不过,就不把包发给业务侧。

检查项通过标准
位数宿主 EXE、libcef.dll、wrapper 均为 x64
资源locales、pak、icudtl.dat、chrome_elf.dll齐全
H264 探测canPlayType返回非空
H265 探测构建参数和测试机都排除后仍能出首帧
干净机器不装 VS2019 也能启动并播放本地视频

从那以后我每次接 CEF 都先跑一遍canPlayType和 30 秒本地视频,再谈业务页面,后悔药少吃很多。这套 CEF win64 支持 H264/H265 的构建和配套脚本我放在资源包里,按项目标题取用即可,解压后先核对分支和libcef.dll版本,再按上面的环境变量接进 VS2019 工程。希望帮到你。

本文还有配套的精品资源,点击获取