Just for Fun

给未来留点痕迹

随着 AI 辅助编程的发展,从最开始的 AI Completion 自动补全代码,到 AI chat 通过对话分析代码,再到现在的 AI Agent 自动修改项目,自动化程度越来越高。市面上也出现了非常多的 AI 开发工具,如 cursor 等。但作为一个 vimer,自然忍受不了多个工具互相切换对开发思路的打断。在清明节假期花了几天折腾了一下 neovim 的 AI 开发环境。

阅读全文 »

背景

在内部一个嵌入式平台开发项目中,我们需要将 FFmpeg 交叉编译,用于音视频解码等。我们的使用方式是基于 Conan 打包了对应平台的交叉编译工具链(类似 NDK),并通过 Conan 依赖 ffmpeg/5.1.3。在交叉编译时遇到了以下报错:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
./config.h:18:19: error: expected identifier or '(' before 'void'
18 | #define getenv(x) NULL
| ^~~~
./config.h:18:19: error: expected ')' before numeric constant
18 | #define getenv(x) NULL
| ^~~~
...
src/libavutil/libm.h:54:32: error: static declaration of 'cbrt' follows non-static declaration
54 | static av_always_inline double cbrt(double x)
| ^~~~
...
src/libavutil/libm.h:465:40: error: static declaration of 'truncf' follows non-static declaration
465 | static av_always_inline av_const float truncf(float x)
| ^~~~~~

报错日志非常长。除了最开始的 getenv 报错,其他报错都是类似的日志,只是报错的方法不同。统计下来有 cbrtcbrtferfhypotlrintlrintfrintroundroundftrunctruncf 这些方法。这些方法的特点是都是数学处理相关的函数。

阅读全文 »

说明

Git提交信息是维护者对一个代码仓库的历史修改极其重要的了解途径,提交信息不足会大大影响代码的可维护性。但在实际业务开发中,经常出现提交信息编写随意,难以约束的问题。为了保证提交信息的完整性和可用性,我在业务内部对提交格式做一些要求,并提供工具保证规范的落地。该规范更多的针对于C++应用开发场景,可能不适用于所有团队和场景,仅供参考。

阅读全文 »

背景

在涉及到音视频的代码中,我们通常会使用FourCC格式描述一个音视频格式,包括容器格式,编码格式,像素格式等,其可能的定义和部分相关方法如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
enum FourCC : uint32_t;

template <char A, char B, char C, char D>
[[nodiscard]] constexpr FourCC MakeFourCC() {
static_assert((A >= 'A' && A <= 'Z') || (A >= '0' && A <= '9'), "[A-Z0-9]");
static_assert((B >= 'A' && B <= 'Z') || (B >= '0' && B <= '9'), "[A-Z0-9]");
static_assert((C >= 'A' && C <= 'Z') || (C >= '0' && C <= '9'), "[A-Z0-9]");
static_assert((D >= 'A' && D <= 'Z') || (D >= '0' && D <= '9'), "[A-Z0-9]");
return static_cast<FourCC>((static_cast<uint32_t>(A) << 0) |
(static_cast<uint32_t>(B) << 8) |
(static_cast<uint32_t>(C) << 16) |
(static_cast<uint32_t>(D) << 24));
}
enum FourCC : uint32_t {
kNullFourCC = 0,

// Video Codec
kH264 = MakeFourCC<'H', '2', '6', '4'>(),
kH265 = MakeFourCC<'H', '2', '6', '5'>(),

// 省略...
};

using PixelFormat = FourCC;
using ChromaFormat = FourCC;

[[nodiscard]] inline std::string FourCCName(FourCC fourcc) {
std::string name;
name.push_back(static_cast<char>(fourcc & 0xFF));
name.push_back(static_cast<char>((fourcc >> 8) & 0xFF));
name.push_back(static_cast<char>((fourcc >> 16) & 0xFF));
name.push_back(static_cast<char>((fourcc >> 24) & 0xFF));
return name;
}

也就是说,FourCC事实上是一个uint32_t的类型,这就导致在调试时,调试器中显示的变量值是一个整型数字,很难直观看到具体内容,除非将其以十六进制显示后,再依次转换成四个字母或数字。以上文中图片为例,若类型为FourCC的变量codec的值为875967048,转换成16进制为0x34363248,再每两个字符转换成一个字母或数字,可得到462H,即H264的逆序(受大小端影响导致)。

默认效果

阅读全文 »

背景

Windows下有多种用于采集画面的接口,如GDI,DXGI,以及最新的WGC,但这几种接口都缺乏内容过滤的能力,而具备该能力的采集接口目前仅有古老的放大镜接口(Magnification)。放大镜接口性能极差,BUG众多,目前属于基本废弃的状态。但由于内部业务需求的存在,改采集方式仍然是目前主要使用的采集方式之一。

在放大镜接口众多的bug中,存在一个对稳定性影响非常严重的bug,那就是内存泄漏。放大镜接口提供了一对初始化/反初始化接口MagInitializeMagUninitialize,但在实际使用中发现,即使在确保二者正确调用的情况下,每次投屏都会出现内存泄漏,泄露量和分辨率相关,但由于官方文档没有任何资料提及这部分内存要如何释放,网上的资料也没有任何相关说明。在和其他同行的交流中得知,一个可行的规避方案是通过将放大镜接口封装成单例类使用,避免多次调用初始化接口。

但这样做的问题是会导致一旦初始化后,放大镜采集接口就会一直占用数百兆内存得不到释放,该问题对32位应用影响较大。由于Windows下32位应用在不开启3G虚拟内存内存的情况下,可用虚拟内存仅2G,除去可执行文件映射占用,实际情况下普遍可用仅1G作用。而对应音视频软件而言,其本身对内存占用是偏高的,这就导致软件在运行时经常出现虚拟内存不出而内存分配失败,进而出现崩溃。根据内部业务崩溃上报数据来看,超过30%的崩溃是由于虚拟内存不足导致的。所以该方案依然不是最佳选择。

阅读全文 »

问题背景

libyuv是一个google开发的用于进行原始图像数据转换的C++库,其提供了对多种格式(YUV/RGB)图像的多种转换操作(旋转/缩放/镜像/裁剪/格式转换),目前在内部业务中存在一个图像处理器模块,用于基于libyuv进行原始图像数据的处理,如旋转/缩放/格式转换。每新增一种输入输出的支持,需要编写对应的转换函数,很多转换都需要多次调用libyuv接口,其中大部分都是类似的逻辑,差异点主要在于调用的libyuv接口和参数有差异。以NV12转换成BGRA为例,有如下的转换流程图:

转换流程图

可以看到,每新增一种转换格式支持,一方面需要编写大量代码,另一方面需要自行寻找可用的转换路径,libyuv并没有提供任意格式的转换函数,例如NV12Rotate函数是没有提供现成的,因此只能先转换成I420再旋转或基于更底层API实现一个NV12Rotate。在需要支持的输入输出参数种类较少时,手动编写转换步骤代码还可以接受。但随着业务的需要,需要支持的输入输出格式越来越多,目前仅像素格式(pixel format)需要支持的就多达数十种,再考虑到旋转,缩放等,代码迅速膨胀,维护成本也随之迅速上升。

阅读全文 »

背景

我们内部的应用软件发布后,在用户设备上经常会出现崩溃等问题导致闪退,对于这些用户现场发生的问题只能通过日志进行分析,难以排查出问题。日志可能一方面不一定包含异常情况相关的信息,另一方面由于文件缓存等原因,导致崩溃前一段时间的日志不一定及时写入文件,信息存在丢失,因此往往难以排查出问题。

阅读全文 »

周末在修改某一款电子游戏的PVF(游戏内容文件)时,遇到了一个问题,我需要将游戏中的原有的穿戴多件装备才有的套装效果修改为一件装备即可激活套装效果。装备套装描述文件如下图所示。

套装描述文件

可以看到文件类似于XML格式,每个piece set ability描述了穿戴n件套时对应的效果及描述。我需要将分布在多个piece set ability标签中的子标签的内容合并到一个piece set ability标签中。这样就可以实现一件装备即可激活套装效果的功能。

由于游戏中的套装较多,对应文件有170个,单个文件手动修改要40-50秒,所有文件改完需要大约2个小时。这个工作量对于我来说太大了。这里的工作基本上是重复性的,完全可以通过正则表达式来实现自动替换。

阅读全文 »

问题

在参考WebRTC(对应代码为webrtc/modules/desktop_capture/win/screen_capturer_win_magnifier.cc)实现基于放大镜接口(Magnification API)的屏幕画面采集时,遇到了一个仅在Win7下出现的bug。日志显示Win7 32位下调用RegisterClassEX会失败,返回错误0x87,表示参数非法。

阅读全文 »
0%