前言
obs系列文章入口:https://blog.csdn.net/qq_33844311/article/details/121479224
目前使用最广泛的视频编码格式依然是h264编码,开源的编码库有x264、 OpenH264,obs-studio使用的libx264编码,webRTC使用OpenH264。具体两者之间的优劣,这里不做讨论。这篇blog主要分析一下obs是怎么将libx264作为编码器,以及用于直播低延迟编码的x264参数设置。
x264编码器的创建
设置好断点,点击UI开始推流,得到以下堆栈。可以看到x264编码器的创建是在obs_output_initialize_encoders() 函数里面创建视频编码器和音频编码器。
> obs-x264.dll!obs_x264_create(obs_data * settings, obs_encoder * encoder) 行 688 C
obs.dll!obs_encoder_initialize_internal(obs_encoder * encoder) 行 462 C
obs.dll!obs_encoder_initialize(obs_encoder * encoder) 行 507 C
obs.dll!obs_output_initialize_encoders(obs_output * output, unsigned int flags) 行 2100 C 创建视频编码器和音频编码器
obs-outputs.dll!rtmp_stream_start(void * data) 行 1158 C
obs.dll!obs_output_actual_start(obs_output * output) 行 256 C
obs.dll!obs_output_start(obs_output * output) 行 293 C
obs64.exe!AdvancedOutput::StartStreaming(obs_service * service) 行 1836 C++
obs64.exe!OBSBasic::StartStreaming() 行 6449 C++
obs64.exe!OBSBasic::on_streamButton_clicked() 行 7559 C++
obs64.exe!OBSBasic::qt_static_metacall(QObject * _o, QMetaObject::Call _c, int _id, void * * _a) 行 1305 C++
obs64.exe!OBSBasic::qt_metacall(QMetaObject::Call _c, int _id, void * * _a) 行 1500 C++
[外部代码]
obs64.exe!run_program(std::basic_fstream<char,std::char_traits<char>> & logFile, int argc, char * * argv) 行 2143 C++
obs64.exe!main(int argc, char * * argv) 行 2839 C++
obs64.exe!WinMain(HINSTANCE__ * __formal, HINSTANCE__ * __formal, char * __formal, int __formal) 行 97 C++
obs_x264_create() 创建x264编码器
static void *obs_x264_create(obs_data_t *settings, obs_encoder_t *encoder)
{
struct obs_x264 *obsx264 = bzalloc(sizeof(struct obs_x264));
obsx264->encoder = encoder;
// 设置编码器参数
if (update_settings(obsx264, settings, false)) {
//调用x264的api创建编码器上下文 x264_t *context
//参考:https://blog.csdn.net/weixin_34256074/article/details/90656698
obsx264->context = x264_encoder_open(&obsx264->params);
if (obsx264->context == NULL)
warn("x264 failed to load");
else
//加载SPS/PPS/SEI这些H.264码流的头信息
load_headers(obsx264);
} else {
warn("bad settings specified");
}
// 打开编码器失败判断
if (!obsx264->context) {
bfree(obsx264);
return NULL;
}
// windows平台该接口无用,其他平台看源码具体实现吧
obsx264->performance_token = os_request_high_performance("x264 encoding");
return obsx264;
}
x264编码视频帧
通过调用堆栈分析,在视频编码线程中调用 obs_x264_encode 完成视频编码。
obs视频编码线程的介绍参考这篇文章:https://blog.csdn.net/qq_33844311/article/details/121745673
> obs-x264.dll!obs_x264_encode(void * data, encoder_frame * frame, encoder_packet * packet, bool * received_packet) 行 764 C
obs.dll!do_encode(obs_encoder * encoder, encoder_frame * frame) 行 984 C
obs.dll!receive_video(void * param, video_data * frame) 行 1056 C
obs.dll!video_output_cur_frame(video_output * video) 行 143 C
obs.dll!video_thread(void * param) 行 188 C //视频编码线程
w32-pthreads.dll!ptw32_threadStart(void * vthreadParms) 行 225 C
obs_x264_encode() 编码一帧视频
真正的将原始视频帧编码成nalu视频包的接口 obs_x264_encode,主要是通过调用x264的编码api完成原始视频编码。代码比较简单,看注释即可。
static bool obs_x264_encode(void *data, struct encoder_frame *frame,
struct encoder_packet *packet,
bool *received_packet)
{
struct obs_x264 *obsx264 = data;
x264_nal_t *nals;
int nal_count;
int ret;
x264_picture_t pic, pic_out;
if (!frame || !packet || !received_packet)
return false;
// 初始化编码信息,将frame的图像数据指针复制给x264的上下文 pic->img.plane
if (frame)
init_pic_data(obsx264, &pic, frame);
//调用x264的编码api完成原始视频的编码
ret = x264_encoder_encode(obsx264->context, &nals, &nal_count,
(frame ? &pic : NULL), &pic_out);
if (ret < 0) {
warn("encode failed");
return false;
}
// nal_count > 0表示编码成功
*received_packet = (nal_count != 0);
// 将编码后的视频nal拷贝到 packet,送出去打包flv发送
parse_packet(obsx264, packet, nals, nal_count, &pic_out);
return true;
}
x264低延迟编码参数的设置
x264支持非常丰富的编码参数设置,针对不同的场景,有不同的编码参数设置。有三个非常重要的影响编码的速度和编码图像质量的参数。
- preset
- profile
- tune
想要了解更多的x264编码参数的设置,建议多找些资料,多测试不同的编码参数的表现效果(图像质量、编码延迟),找到最适合自己场景的编码参数设置,没有一劳永逸的编码参数设置。
这里提供一个在直播场景低延迟编码的参数设置,以下的设置基本上是编码延迟最低的设置。
缺点:会牺牲一些图像质量。
优点:编码延迟极低。
//=======超低延迟编码参数========
preset=ultrafast
profile=baseline
tune=zerolatency
总结
obs的软件编码使用的x264,软件编码的兼容性最好,在同等码率条件下,图像质量也好于硬件编码。这块儿的代码比较好理解,主要是针对自己的直播场景,或者录制场景,找到适合自己的编码参数。对x264编码原理感兴趣的可以多找些资料研究下,视频编码原理这块我也正在学习。
以上都是个人工作当中对obs-studio开源项目的理解,难免有错误的地方,如果有欢迎指出。
若有帮助幸甚。