之前写过一篇基于WSL编译windows版FFmpeg的博文:使用Win10 + WSL编译FFmpeg时的依赖库处理 – https://blog.k-res.net/archives/2771.html,记录了一些基本构建操作和一些问题,但是当时的configure并没有开启很多其他依赖项来激活相关功能,这次要记录的是通过开启openssl的方式,增加如https,rtmps等协议的支持,虽然有WSL的加持,大大简化了windows下编译FFmpeg的复杂度,但到了某些依赖,如这次要说的openssl时,还是有些需要注意的地方的,毕竟WSL的方式实际的本质是在一个同时有linux命令但又能执行windows执行程序的特殊环境下执行构建操作,带来方便的同时也带来了一些特有的麻烦:
Continue reading…C, C++, Obj-C
OpenSSL EVP API实现MD5加密C++代码
网上找到的大部分都是旧API,新版OpenSSL推荐使用EVP系列接口,在此记录下EVP方式的MD5哈希实现代码:
#include "openssl/conf.h"
#include "openssl/evp.h"
#include "openssl/err.h"
#include "openssl/engine.h"
void handle_errors()
{
ERR_print_errors_fp(stderr);
abort();
}
std::string md5_str(const std::string & str)
{
const auto * md = EVP_get_digestbyname("MD5");
if (nullptr == md)
{
std::cerr << "Failed to EVP_get_digestbyname MD5!" << std::endl;
return "";
}
unsigned char buf[EVP_MAX_MD_SIZE] = {};
unsigned int olen = EVP_MAX_MD_SIZE;
EVP_MD_CTX * ctx = EVP_MD_CTX_new();
if (nullptr == ctx)
{
std::cerr << "Failed to EVP_MD_CTX_new!" << std::endl;
return "";
}
if (1 != EVP_DigestInit(ctx, md))
{
handle_errors();
return "";
}
if (1 != EVP_DigestUpdate(ctx, str.data(), str.length()))
{
handle_errors();
return "";
}
if (1 != EVP_DigestFinal(ctx, buf, &olen))
{
handle_errors();
return "";
}
EVP_MD_CTX_free(ctx);
return { reinterpret_cast<char*>(buf), olen };
}
int main()
{
OpenSSL_add_all_digests();
const std::string plain = "test1234";
const std::string hash = md5_str(plain);
std::cout << "plain: " << plain << " md5 hash: " << hash << std::endl;
return EXIT_SUCCESS;
}
后面有时间再增加AES等的EVP实现代码
一种FFmpeg提示“dts < pcr, TS is invalid“的解决方法
此问题出现在使用FFmpeg(动态库)输出UDP+TS流且开启muxrate输出CBR时,音频为aac编码,视频为264编码(libx264),视频部分使用vbv-bufsize及vbv-maxrate和nal-hrd=cbr编码CBR码流,可以看到程序刚跑起来FFmpeg的log回调就会疯狂报标题里提到的dts < pcr警告,这个警告的源码位置只有一个,就在libavformat\mpegtsenc.c的mpegts_write_pes这个函数里,但是读了下代码,也没看出来为什么会报这个警告,后来找到了这两篇参考:
FFMPEG转码音视频不同步情况总结 https://blog.csdn.net/liuchen1206/article/details/79461434
ffmpeg 奇葩问题2 https://blog.csdn.net/WaitForDone/article/details/78030095
其中第一篇参考文章里提到了编码速度问题,提到去掉B帧这个操作,而我的应用直接设置了zerolatency的tune相当于也是不带B帧的编码,第二篇文章提到了几个点,一开始直接放到了结果上,疯狂尝试各种qmin、qmax设置,结果都没有见效,而且实际发现我的视频码流并没有文章作者提到的编码出来的视频帧偏大的问题,其实用的就是默认的量化值,每帧大小也基本符合整体目标码率,最后百思不得其解时,试了下直接用ffmpeg命令行进行同样参数的编码操作,发现并没有报这个“dts < pcr”的警告,而且是跑了很长时间后也一次警告都没有,又结合了下第二篇参考文章中提到的delay设置,于是开始比较ffmpeg命令行程序的各种format、codec初始化操作参数,最后终于找到了问题:
Continue reading…使用Win10 + WSL编译FFmpeg时的依赖库处理
Windows 10的Linux子系统WSL安装过程就不做赘述了,网上资料很多。
之前一直认为WSL只是以类似虚拟机或容器化的方式使得能在Windows上运行原生Linux程序,当然,也在WSL上做过如使用ndk交叉编译Android原生程序、动态库的操作,用起来还是挺方便的。直到最近研究FFmpeg的Windows版编译时才发现(参考自:https://www.bilibili.com/read/cv7058269/),原来WSL还有一个“大杀招”:直接运行Windows执行程序exe,如下图所示:
可以看到,在WSL内直接执行VS 2019的编译器程序cl,也是完全没有问题的,基于这种方法,FFmpeg官网上所说的用cygwin,mingw,msys之类的桥接环境构建Win版FFmpeg的麻烦就不复存在了,而且新版FFmpeg源码(博主用的4.3)的configure也做好了对这种编译方式的支持,参考上面的链接,制定上toolchain=msvc等相关参数,剩下的事和nix系统上构建一样就可以顺利完成了,简单方便!
不过,今天要记录的并不是WSL下编译Win版FFmpeg的问题,而是编译时如何引入其它依赖,如openssl,xml2等以获取更多功能支持,尤其是在Win环境下,这些其它依赖库的位置很有可能是一个很随意的位置,而在WSL环境下处理这种依赖的头文件、库文件搜索路径时是有坑的…
Continue reading…关于linux系系统的动态库全局函数重名问题
最近在使用某几个知名厂商的对象存储C SDK时,发现由于这些SDK的内部实现其实基本是一样的,进而导致了各个SDK的so中都或多或少有些被大家共同喜爱的全局函数(符号)名称,最后引发了在部分环境中出现了调用A厂商SDK的上传函数时崩溃在了B厂商SDK的同名全局函数中的问题,最开始感觉很是莫名其妙,后来查了资料发现,首先gcc编译时默认会将全局变量、函数等符号导出在都动态库中,而同时全局函数的加载又是抢占式的,这点通过如下简单试验便可验证:
Continue reading…FFmpeg 4.3.1 hls http(s)配新版Nginx WebDAV 无法删除切片bug
在使用FFmpeg进行hls推流输出时,发现配合新版Nginx (1.21) + WebDav组件的http服务器时,即使指定了m3u8切片数量以及删除无用切片的参数:
hls_list_size 5 -hls_flags delete_segments -hls
也没有在服务端正确删除无用切片,查看Nginx日志,发现每次FFmpeg发起的DELETE文件请求,都会跟随一个这样的报错:
DELETE with body is unsupported!
导致虽然FFmpeg删除文件的http请求到了Nginx,但实际并没有删除掉磁盘上的ts切片文件,时间一长,磁盘空间耗尽,然后就尴尬了…
Continue reading…CentOS 8运行其它环境编译的curl报77错误解决方法
此问题来源于经过Github Actions编译出来的curl执行程序,由于actions默认的构建环境都是Ubuntu的,编译构建出来的新版本curl放到CentOS 8上运行时,会提示类似如下内容的错误(仅限需要用到ssl证书的协议,如https):
curl: (77) error setting certificate verify locations:
CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: none
...
curl: (77) Error reading ca cert file /etc/ssl/certs/ca-certificates.crt - mbedTLS: (-0x3E00) PK - Read/write of file failed
按照网上搜到的说法,重新yum安装ca-certificates之类的都不起作用,查看/etc/ssl/certs目录,发现有如下内容:
Continue reading…C/C++格式化字符串的一个小坑
格式化字符串是个写C/C++代码是很常见的东西,例如下面这段用了printf的简单代码:
#include <string>
int main()
{
std::string test = "hello world!";
printf("%s", test.c_str());
return 0;
}
虽然看起来有点怪,混用了C++的string和C的printf输出,其实换成char *也是可以的,不过,这并不重要,重要的是我有时会偷懒把上面这段代码写成这样:
#include <string>
int main()
{
std::string test = "hello world!";
printf(test.c_str());
return 0;
}
这样写,看起来似乎输出没有问题,两份代码的结果都是输出”hello world!”,并没有什么区别,那标题说的坑到底在哪呢?考虑这种情况,我们的test字符串里放的不再是简单的 hello world! 了,而是比如转义过的URL串,如“http://www.baidu.com/测试”会被转义成“http%3A%2F%2Fwww.baidu.com%2F%E6%B5%8B%E8%AF%95”,此时如果再用偷懒的写法,直接printf这个字符串,显而易见的就会出问题了!
Continue reading…VS2019 16.9版引入的linux项目远程输出路径bug
这是一个Visual Studio 2019(博主发现时的版本是Community 16.9.4)的bug,之前在16.8版本的时候是没有问题的,并且影响的是VS原生的远程linux项目,Make CMake项目不受影响,发现这个问题时着实郁闷了一段时间,总结一句话就是这个选项:
红框内的两个dir,在16.9以前可以同时作用于本地windows项目路径,及同步到远端linux的项目路径,而到了16.9的时候无论怎么修改这两个路径都只有windows侧的路径会响应变化,而sync到linux的路径还会使用默认的这个路径(应该是bug或其它原因,比如,写死了?!),查了半天也没找到解决方法,对简单项目的话只好修改项目设置,都是用默认dir,或者想办法退回16.8版本,其中搜索过程中发现了有人提到这个问题:https://developercommunity.visualstudio.com/t/VS-For-Linux:-Output-files-on-remote-mac/1357691,其中提到已经修改等待发布,在此记录这个影响挺大的问题,后续有更新会同步过来…
UPDATE1: 16.10版本中已修改这个问题,加入了独立控制远端生成路径的选项。
关于typedef指针类型后的非主流const行为(misc-misplaced-const)
这是一个之前没怎么注意过的细节问题,首先,参加如下代码:
struct MyStruct
{
int type;
char name[40];
};
typedef MyStruct * PMyStruct;
int main(int argc, char * argv[])
{
MyStruct my1{0}, my2{0};
const MyStruct * pmy1 = &my1;
pmy1 = &my2;
const PMyStruct pmy2 = &my1;
pmy2 = &my2;
}
很简单的一段代码,但是全引出了一个不寻常的问题:此段代码编译时,第二个pmy2结构体指针会导致编译器(gcc)报错:“error: assignment of read-only variable ‘pmy2’”,此时如果配合有clang-tidy之类的代码扫描工具,会发现pmy2声明赋值位置提示:“Clang-Tidy: ‘pmy2’ declared with a const-qualified typedef; results in the type being ‘MyStruct *const’ instead of ‘const MyStruct *’”(clang-tidy的misc-misplaced-const)!
Continue reading…