OBS源码阅读 --RTMP

5 篇文章 0 订阅

原文链接

首先,我们来看window-basic-main-outputs.cpp,在SimpleOutput构造函数中,调用

streamOutput = obs_output_create("rtmp_output", "simple_stream", nullptr, nullptr);创建一个RTMP输出流;

该输出流的结构体定义在rtmp-stream.c中:

struct obs_output_info rtmp_output_info = {
.id                 = "rtmp_output",
.flags              = OBS_OUTPUT_AV |
                     OBS_OUTPUT_ENCODED |
                     OBS_OUTPUT_SERVICE |
                     OBS_OUTPUT_MULTI_TRACK,
.get_name           = rtmp_stream_getname,
.create             = rtmp_stream_create,
.destroy            = rtmp_stream_destroy,
.start              = rtmp_stream_start,
.stop               = rtmp_stream_stop,
.encoded_packet     = rtmp_stream_data,
.get_defaults       = rtmp_stream_defaults,
.get_properties     = rtmp_stream_properties,
.get_total_bytes    = rtmp_stream_total_bytes_sent,
.get_dropped_frames = rtmp_stream_dropped_frames
};


在obs_output_create中,会将该结构信息保存到obs->data.first_output中,后面的分析应该可以看到哪里用到这个指针变量;


接下来根据配置文件创建视频编码器,一般都是创建obs_x264编码器:LoadStreamingPreset_h264==>obs_video_encoder_create==>create_encoder,在create_encoder中,将创建的编码器信息存放到obs->data.first_encoder中,后面分析哪里调用这个指针处理;


然后创建音频编码器:CreateAACEncoder==>obs_audio_encoder_create==>create_encoder,在create_encoder中,将创建的编码器信息存放到obs->data.first_encoder中;

然后将几个OBSSignal链接到对应的处理函数上:

streamDelayStarting.Connect(obs_output_get_signal_handler(streamOutput), "starting", OBSStreamStarting, this);
streamStopping.Connect(obs_output_get_signal_handler(streamOutput), "stopping", OBSStreamStopping, this);
startStreaming.Connect(obs_output_get_signal_handler(streamOutput), "start", OBSStartStreaming, this);
stopStreaming.Connect(obs_output_get_signal_handler(streamOutput), "stop", OBSStopStreaming, this);

对于OBSSingal还不是很熟悉,下面来看看它主要做个什么功能的:

从字面上看,貌似他是用于信号处理,主要包括下面一些成员变量:

signal_handler_t  *handler;
const char        *signal;
signal_callback_t callback;
void              *param;

最主要的函数:signal_handler_connect

streamDelayStarting.Connect(obs_output_get_signal_handler(streamOutput), "starting", OBSStreamStarting, this);

这句代码的主要意思就是将streamOutput(rtmp 流)的starting信号挂到OBSStreamStarting处理函数中;当发出starting信号时,调用OBSStreamStarting处理;


来看看signal_handler_signal函数,这个函数就是触发信号的函数:

void signal_handler_signal(signal_handler_t *handler, const char *signal, calldata_t *params)
{
struct signal_info *sig = getsignal_locked(handler, signal);


if (!sig)
return;


pthread_mutex_lock(&sig->mutex);
sig->signalling = true;


for (size_t i = 0; i < sig->callbacks.num; i++) {
struct signal_callback *cb = sig->callbacks.array+i;
if (!cb->remove)
cb->callback(cb->data, params);
}


for (size_t i = sig->callbacks.num; i > 0; i--) {
struct signal_callback *cb = sig->callbacks.array+i-1;
if (cb->remove)
da_erase(sig->callbacks, i-1);
}


sig->signalling = false;
pthread_mutex_unlock(&sig->mutex);
}

每个signal_handler就是一个存储signal_info的链表,里面又包含signal_callback数组(哎,其实没必要搞这么麻烦,通常用上10个的数组应该也就够了,不过本着程序员严谨的精神,还是不错的):

struct signal_handler {
struct signal_info *first;
pthread_mutex_t    mutex;
};

struct signal_info {
struct decl_info               func;
DARRAY(struct signal_callback) callbacks;
pthread_mutex_t                mutex;
bool                           signalling;
struct signal_info             *next;
};

struct signal_callback {
signal_callback_t callback;
void              *data;
bool              remove;
};

在signal_handler_signal函数中,先通过getsignal_locked获取到信号量找到对应名称的信号,然后遍历信号调用其回调(也就是在这里调用之前注册的处理函数的)进行处理:

for (size_t i = 0; i < sig->callbacks.num; i++) {
struct signal_callback *cb = sig->callbacks.array+i;
if (!cb->remove)
cb->callback(cb->data, params);
}

在obs-output.c中调用obs_output_begin_data_capture进行数据捕获时,调用signal_start发出start信号;它会调用hook_data_capture函数启动捕获;

下面看看hook_data_capture函数的处理方法


下面看看hook_data_capture函数:





在video_output_cur_frame中,会调用input->callback回调处理采集到的视频;

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值