DVR配置详解:https://github.com/ossrs/srs/wiki/v3_CN_DVR
推流到源站时会调用SrsOrginHub对象提供的initialize, on_publish, on_metadata, on_video, on_audio,on_unpublish函数。
1.SrsOriginHub::initialize初始化时会调用SrsDvr::initialize
srs_error_t SrsDvr::initialize(SrsOriginHub* h, SrsRequest* r)
{
srs_error_t err = srs_success;
req = r;
hub = h;
SrsConfDirective* conf = _srs_config->get_dvr_apply(r->vhost);
actived = srs_config_apply_filter(conf, r);
srs_freep(plan);
if ((err = SrsDvrPlan::create_plan(r->vhost, &plan)) != srs_success) {
return srs_error_wrap(err, "create plan");
}
std::string path = _srs_config->get_dvr_path(r->vhost);
SrsDvrSegmenter* segmenter = NULL;
if (srs_string_ends_with(path, ".mp4")) {
segmenter = new SrsDvrMp4Segmenter();
} else {
segmenter = new SrsDvrFlvSegmenter();
}
if ((err = plan->initialize(hub, segmenter, r)) != srs_success) {
return srs_error_wrap(err, "plan initialize");
}
return err;
}
首先调用SrvDvrPlan::create_plan根据配置文件来确定使用session(整个流录制成一个文件SrsDvrSessionPlan)还是segment(按照时长分段录制成多个文件SrsDvrSegmentPlan )的计划,这里只分析SrsDvrSessionPlan。
接着创建SrsDvrSegmenter,这里只分析flv文件录像SrsDvrFlvSegementer。
最后调用plan->initialize。SrsDvrSessionPlan直接使用基类的SrsDvrPlan::initialize;SrsDvrSegmentPlan重写了initialize方法在调用完SrsDvrPlan::initialize后接着从config文件中读取wait_keyframe, cduration配置参数。
SrsDvrPlan::initialize实现如下
srs_error_t SrsDvrPlan::initialize(SrsOriginHub* h, SrsDvrSegmenter* s, SrsRequest* r)
{
srs_error_t err = srs_success;
hub = h;
req = r;
segment = s;
if ((err = segment->initialize(this, r)) != srs_success) {
return srs_error_wrap(err, "segmenter");
}
if ((err = async->start()) != srs_success) {
return srs_error_wrap(err, "async");
}
return err;
}
SrsDvrPlan::initialize首先调用SrsDvrSegmenter::initialize获取配置文件中的jitter_algorithm, wait_keyframe两个参数
接着调用async->start()开启协程,async是一个任务处理的协程。最终进入协程的循环处理中。
srs_error_t SrsAsyncCallWorker::cycle()
{
srs_error_t err = srs_success;
while (true) {
if ((err = trd->pull()) != srs_success) {
return srs_error_wrap(err, "async call worker");
}
if (tasks.empty()) {
srs_cond_wait(wait);
}
std::vector<ISrsAsyncCallTask*> copy = tasks;
tasks.clear();
std::vector<ISrsAsyncCallTask*>::iterator it;
for (it = copy.begin(); it != copy.end(); ++it) {
ISrsAsyncCallTask* task = *it;
int ret = ERROR_SUCCESS;
if ((ret = task->call()) != ERROR_SUCCESS) {
srs_warn("ignore async callback %s, ret