OBS源码阅读笔记(六)--推流地址设置

OBS的推流地址是在哪里设置的呢?我们来看看吧:

首先我们反着来推,比较方便查找:

在rtmp_stream.c中,有个connect_thread线程函数,该行数应该就是处理RTMP连接的,那么里面肯定就有关于推流地址的信息:

info("Connecting to RTMP URL %s...", stream->path.array);

RTMP_AddStream(&stream->rtmp, stream->key.array);

上面两个一个是推流的path,另外一个就是key了;


反过来,connect_thread是在rtmp_stream_start中被创建的,而rtmp_stream对象就是其参数void* data,那么,我们看看rtmp_stream_start是在哪里被调用的就可以找到前一步的代码:

.start              = rtmp_stream_start

查找发现,这个函数是注册到了obs_output_info中了,那么我们就要找到这个结构在哪里被创建的,才好进行下一步的反推:

我们可以找到再SimpleOutput对象的构造函数中,会创建rtmp_output结构:

streamOutput = obs_output_create("rtmp_output", "simple_stream", nullptr, nullptr);

并且在obs_output_create中,会调用obs_context_data_insert(&output->context, &obs->data.outputs_mutex, &obs->data.first_output);从而将output_info结构存入first_output的链表中。

那到底start在哪里被调用呢?搜一下吧,搜索start,可以发现obs_output_actual_start中,有调用success = output->info.start(output->context.data);,这很可能就是start的调用地方;

搜下这个函数在哪里调用:obs_output_start这里有调用,而obs_output_start在SimpleOutput的startStreaming中会被调用:

而on_streamButton_clicked中会调用startStreaming,这下总算有点眉目了,反推到最上层的按钮点击事件了;


现在我们再从按钮往前推看看,这样可以理清下流程:

在on_streamButton_clicked中对推流的抽象,主要是抽象为outputHandler(而SimpleOutput就是outputHandler的一个实现);

然后调用outputHandler的StartStreaming,而StartStreaming主要操作的是outputHandler的streamOutput成员,它会调用obs_output_start(streamOutput);

我们看看streamOutput到底是什么?是rtmp_stream吗?

它是一个OBSOutput结构:using OBSOutput = OBSRef<obs_output_t*, obs_output_addref, obs_output_release>;

好吧,我们来分析下怎么办,看来主要还是obs_output_t结构要先了解下,可能obs_output_t中存在对rtmp_stream的封装吧;

回头我们又发现streamOutput是在SimpleOutput中被创建的:streamOutput = obs_output_create("rtmp_output", "simple_stream",nullptr, nullptr);

在obs_output_create中一上来,就先调用const struct obs_output_info *info = find_output(id);就先调用查找注册的obs_output_info,查找注册的obs_output_info;

在obs_output_create中有这么一句if (info) output->context.data = info->create(output->context.settings, output);我们总是发现上面的start调用参数创建的地方啦!并且创建该结构时,会根据output->context.setting和output来,我们分析下这两个里面是否包含推流地址的信息!

额,不好意思,发现找了半天,还是没找到rtmp_stream->path和rtmp_stream->key在哪里设置的;

刚脆搜下stream->key吧,发现了下面几句:

dstr_copy(&stream->path,     obs_service_get_url(service));
dstr_copy(&stream->key,      obs_service_get_key(service));
dstr_copy(&stream->username, obs_service_get_username(service));
dstr_copy(&stream->password, obs_service_get_password(service));

哈哈,总算找到这里了,不过前面的分析还是对理解obs_output_t和obs_output_info有些作用;

这几句是在init_connect被调用的,而init_connect是在rtmp-stream.c的connect_thread中被调用的;

好了,找来找去,最后还是回到了rtmp-stream.c中,那么我们看看obs_service_get_url这个是怎么获取到path和key的呢?

来看看service是怎么回事:

通过service = obs_output_get_service(stream->output);,init_connect中获取到service结构,我们主要还是要看下service是怎么被挂到obs_output_t上的;

看看obs_service的定义:

struct obs_service {
struct obs_context_data         context;
struct obs_service_info         info;
struct obs_weak_service         *control;


/* indicates ownership of the info.id buffer */
bool                            owns_info_id;


bool                            active;
bool                            destroy;
struct obs_output               *output;
};

它已经包含了obs_output的信息;

我们搜索下output->service,发现在obs_output_set_service会设置obs_output_t的service变量,而obs_output_set_service是在SimpleOutput的StartStreaming中被调用的,而StartStreaming的参数就是obs_service_t *service,这个参数就是class OBSBasic : public OBSMainWindow的成员变量惊讶

好吧,在OBSBasic的LoadService中,会创建service = obs_service_create(type, "default_service", settings,hotkey_data);

还有SaveStream1Settings中也会创建service,而且会调用

main->SetService(newService);
main->SaveService();

替换service变量;

在obs_service_create中,会调用service->context.data = service->info.create(service->context.settings, service);对service进行初始化,

而该函数目前了解到,会调用到rtmp_common_service中的create,而在rtmp_common_create中,会调用

rtmp_common_update(data, settings);对设置进行初始化,

service->service = bstrdup(obs_data_get_string(settings, "service"));
service->server  = bstrdup(obs_data_get_string(settings, "server"));
service->key     = bstrdup(obs_data_get_string(settings, "key"));

server就是path变量,key就是key变量;

现在,再看下:

struct obs_service_info rtmp_common_service = {
.id             = "rtmp_common",
.get_name       = rtmp_common_getname,
.create         = rtmp_common_create,
.destroy        = rtmp_common_destroy,
.update         = rtmp_common_update,
.get_properties = rtmp_common_properties,
.get_url        = rtmp_common_url,
.get_key        = rtmp_common_key,
.apply_encoder_settings = rtmp_common_apply_settings,
};

发现了吧?原来obs_service_get_url这些函数最终都是调用这里的rtmp_common_url函数,而这些函数最终返回的就是上面设置的变量;


好了,来总结下吧:

1首先在系统加载时,OBSBasicSetting会调用LoadService加载配置文件中的json,然后根据json配置的rtmp_common,setting,hotkeys等内容,创建default_service,我们看看配置文件长啥样吧:

{

    "settings": {

        "key": "9v0XqR?record=true&filename=10454_9v0XqR",

        "server": "rtmp://push.jingchangkan.tv/jingchangkan/"

    },

    "type": "rtmp_custom"

}

ok,下面看代码:

obs_data_set_default_string(data, "type", "rtmp_common");

type = obs_data_get_string(data, "type");


obs_data_t *settings = obs_data_get_obj(data, "settings");

obs_data_t *hotkey_data = obs_data_get_obj(data, "hotkeys");

service = obs_service_create(type, "default_service", settings, hotkey_data);

这就是了,type是一个string,并且是rtmp_custom,settings是一个obj,然后传入obs_service_create创建服务;

当然还有在SaveStream1Settings也会根据界面的配置创建服务,并且保存到json配置文件中;

2、执行info->create,记录setting中的设置,后面通过obs_service_get_url等可以获取到;

3、这里load的service会记录到OBSBasic的成员变量service中,整个工程中只有一个service在这里记录,SaveStream1Settings也会记录在service中;

4、点击“开始串流“时,触发on_streamButton_clicked(outputHandler在CreateSimpleOutputHandler中被创建outputHandler.reset(advOut ? CreateAdvancedOutputHandler(this) : CreateSimpleOutputHandler(this));)这里就不赘述了;

5、创建SimpleOutput对象的构造函数中,创建streamOutput,而且该output的id是rtmp_output;

6、在on_streamButton_clicked中调用outputHandler->StartStreaming(service)

7、 obs_output_set_service(streamOutput, service);设置好流的服务信息描述(也就是上面创建的service,从service中可以获得推流地址);

8、调用obs_output_start-->obs_output_actual_start,而output->context.data就是rtmp_stream结构,rtmp_stream_create返回的。

9、调用success = output->info.start(output->context.data);  out->context.data在创建的时候就被赋值为一个创建的rtmp_stream变量,而rtmp_stream变量中有回指到output的指针;

10、调用info.start就是创建connect_thread线程;

11、connect_thread线程先调用init_connect,通过output找到service,然后初始化rtmp_stream的推流地址信息;

12、connect_thread线程调用try_connect,就开始调用librtmp库进行推流连接初始化操作啦!


至此,我们了解了OBS整个设置推流地址的流程,中间过程非常绕,但是可以知道,OBS进行了一些分层和分模块:

rtmp_output_info(obs_output_info)<--rtmp_common.c(obs_output_t)

rtmp_common_service(obs_service_info)<--obs_service





评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值