OBS源码阅读 --RTMP

来源:互联网 发布:方正字体包 mac 编辑:程序博客网 时间:2024/06/10 05:33

原文链接

首先,我们来看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回调处理采集到的视频;

0 0
原创粉丝点击