MediaSource.cpp 22.6 KB
Newer Older
1
/*
xiongziliang committed
2
 * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
3 4 5
 *
 * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
 *
xiongziliang committed
6 7 8
 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
9 10 11
 */

#include "MediaSource.h"
xiongziliang committed
12
#include "Record/MP4Reader.h"
13
#include "Util/util.h"
14
#include "Network/sockutil.h"
15
#include "Network/TcpSession.h"
xiongziliang committed
16 17
using namespace toolkit;
namespace mediakit {
18

xiongziliang committed
19 20
recursive_mutex s_media_source_mtx;
MediaSource::SchemaVhostAppStreamMap s_media_source_map;
21

22 23 24 25 26 27 28 29 30 31 32 33 34 35
string getOriginTypeString(MediaOriginType type){
#define SWITCH_CASE(type) case type : return #type
    switch (type) {
        SWITCH_CASE(MediaOriginType::unknown);
        SWITCH_CASE(MediaOriginType::rtmp_push);
        SWITCH_CASE(MediaOriginType::rtsp_push);
        SWITCH_CASE(MediaOriginType::rtp_push);
        SWITCH_CASE(MediaOriginType::pull);
        SWITCH_CASE(MediaOriginType::ffmpeg_pull);
        SWITCH_CASE(MediaOriginType::mp4_vod);
        SWITCH_CASE(MediaOriginType::device_chn);
    }
}

xiongziliang committed
36 37 38 39
MediaSource::MediaSource(const string &schema, const string &vhost, const string &app, const string &stream_id){
    GET_CONFIG(bool, enableVhost, General::kEnableVhost);
    if (!enableVhost) {
        _vhost = DEFAULT_VHOST;
xiongziliang committed
40
    } else {
xiongziliang committed
41
        _vhost = vhost.empty() ? DEFAULT_VHOST : vhost;
xiongziliang committed
42
    }
xiongziliang committed
43 44 45
    _schema = schema;
    _app = app;
    _stream_id = stream_id;
46
    _create_stamp = time(NULL);
xiongziliang committed
47 48 49 50 51 52 53
}

MediaSource::~MediaSource() {
    unregist();
}

const string& MediaSource::getSchema() const {
xiongziliang committed
54
    return _schema;
xiongziliang committed
55 56 57
}

const string& MediaSource::getVhost() const {
xiongziliang committed
58
    return _vhost;
xiongziliang committed
59 60 61 62
}

const string& MediaSource::getApp() const {
    //获取该源的id
xiongziliang committed
63
    return _app;
xiongziliang committed
64 65 66
}

const string& MediaSource::getId() const {
xiongziliang committed
67
    return _stream_id;
xiongziliang committed
68 69
}

70 71 72 73
int MediaSource::getBytesSpeed(){
    return _speed.getSpeed();
}

74 75 76 77 78 79 80 81 82
uint64_t MediaSource::getCreateStamp() const {
    return _create_stamp;
}

uint64_t MediaSource::getAliveSecond() const {
    //使用Ticker对象获取存活时间的目的是防止修改系统时间导致回退
    return _ticker.createdTime() / 1000;
}

xiongziliang committed
83
vector<Track::Ptr> MediaSource::getTracks(bool ready) const {
84 85 86
    auto listener = _listener.lock();
    if(!listener){
        return vector<Track::Ptr>();
xiongziliang committed
87
    }
88
    return listener->getTracks(const_cast<MediaSource &>(*this), ready);
xiongziliang committed
89 90 91 92 93 94 95 96 97 98
}

void MediaSource::setListener(const std::weak_ptr<MediaSourceEvent> &listener){
    _listener = listener;
}

const std::weak_ptr<MediaSourceEvent>& MediaSource::getListener() const{
    return _listener;
}

99 100 101 102 103 104 105
int MediaSource::totalReaderCount(){
    auto listener = _listener.lock();
    if(!listener){
        return readerCount();
    }
    return listener->totalReaderCount(*this);
}
xiongziliang committed
106

107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
MediaOriginType MediaSource::getOriginType() const {
    auto listener = _listener.lock();
    if (!listener) {
        return MediaOriginType::unknown;
    }
    return listener->getOriginType(const_cast<MediaSource &>(*this));
}

string MediaSource::getOriginUrl() const {
    auto listener = _listener.lock();
    if (!listener) {
        return "";
    }
    return listener->getOriginUrl(const_cast<MediaSource &>(*this));
}

std::shared_ptr<SockInfo> MediaSource::getOriginSock() const {
    auto listener = _listener.lock();
    if (!listener) {
        return nullptr;
    }
    return listener->getOriginSock(const_cast<MediaSource &>(*this));
}

xiongziliang committed
131
bool MediaSource::seekTo(uint32_t stamp) {
xiongziliang committed
132 133 134 135
    auto listener = _listener.lock();
    if(!listener){
        return false;
    }
xiongziliang committed
136
    return listener->seekTo(*this, stamp);
xiongziliang committed
137 138 139 140 141 142 143 144 145 146
}

bool MediaSource::close(bool force) {
    auto listener = _listener.lock();
    if(!listener){
        return false;
    }
    return listener->close(*this,force);
}

147
void MediaSource::onReaderChanged(int size) {
xiongziliang committed
148
    auto listener = _listener.lock();
149 150
    if (listener) {
        listener->onReaderChanged(*this, size);
151
    }
xiongziliang committed
152 153
}

154 155 156
bool MediaSource::setupRecord(Recorder::type type, bool start, const string &custom_path){
    auto listener = _listener.lock();
    if (!listener) {
157
        WarnL << "未设置MediaSource的事件监听者,setupRecord失败:" << getSchema() << "/" << getVhost() << "/" << getApp() << "/" << getId();
158 159 160 161 162 163 164 165 166 167 168 169 170
        return false;
    }
    return listener->setupRecord(*this, type, start, custom_path);
}

bool MediaSource::isRecording(Recorder::type type){
    auto listener = _listener.lock();
    if(!listener){
        return false;
    }
    return listener->isRecording(*this, type);
}

171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
void MediaSource::startSendRtp(const string &dst_url, uint16_t dst_port, uint32_t ssrc, bool is_udp, const function<void(const SockException &ex)> &cb){
    auto listener = _listener.lock();
    if (!listener) {
        cb(SockException(Err_other, "尚未设置事件监听器"));
        return;
    }
    return listener->startSendRtp(*this, dst_url, dst_port, ssrc, is_udp, cb);
}

bool MediaSource::stopSendRtp() {
    auto listener = _listener.lock();
    if (!listener) {
        return false;
    }
    return listener->stopSendRtp(*this);
}

xiongziliang committed
188
void MediaSource::for_each_media(const function<void(const MediaSource::Ptr &src)> &cb) {
xiongziliang committed
189
    decltype(s_media_source_map) copy;
xiongziliang committed
190
    {
xiongziliang committed
191
        //拷贝s_media_source_map后再遍历,考虑到是高频使用的全局单例锁,并且在上锁时会执行回调代码
xiongziliang committed
192
        //很容易导致多个锁交叉死锁的情况,而且该函数使用频率不高,拷贝开销相对来说是可以接受的
xiongziliang committed
193 194
        lock_guard<recursive_mutex> lock(s_media_source_mtx);
        copy = s_media_source_map;
xiongziliang committed
195 196 197
    }

    for (auto &pr0 : copy) {
xiongziliang committed
198 199 200 201 202 203 204 205 206 207 208 209 210 211
        for (auto &pr1 : pr0.second) {
            for (auto &pr2 : pr1.second) {
                for (auto &pr3 : pr2.second) {
                    auto src = pr3.second.lock();
                    if(src){
                        cb(src);
                    }
                }
            }
        }
    }
}

template<typename MAP, typename FUNC>
212
static bool searchMedia(MAP &map, const string &schema, const string &vhost, const string &app, const string &id, FUNC &&func) {
xiongziliang committed
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
    auto it0 = map.find(schema);
    if (it0 == map.end()) {
        //未找到协议
        return false;
    }
    auto it1 = it0->second.find(vhost);
    if (it1 == it0->second.end()) {
        //未找到vhost
        return false;
    }
    auto it2 = it1->second.find(app);
    if (it2 == it1->second.end()) {
        //未找到app
        return false;
    }
    auto it3 = it2->second.find(id);
    if (it3 == it2->second.end()) {
        //未找到streamId
        return false;
    }
    return func(it0, it1, it2, it3);
}
235

xiongziliang committed
236 237 238 239 240 241 242 243 244 245 246
template<typename MAP, typename IT0, typename IT1, typename IT2>
static void eraseIfEmpty(MAP &map, IT0 it0, IT1 it1, IT2 it2) {
    if (it2->second.empty()) {
        it1->second.erase(it2);
        if (it1->second.empty()) {
            it0->second.erase(it1);
            if (it0->second.empty()) {
                map.erase(it0);
            }
        }
    }
247
}
xiongziliang committed
248

xiongziliang committed
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
static MediaSource::Ptr find_l(const string &schema, const string &vhost_in, const string &app, const string &id, bool create_new) {
    string vhost = vhost_in;
    GET_CONFIG(bool,enableVhost,General::kEnableVhost);
    if(vhost.empty() || !enableVhost){
        vhost = DEFAULT_VHOST;
    }

    MediaSource::Ptr ret;
    {
        lock_guard<recursive_mutex> lock(s_media_source_mtx);
        //查找某一媒体源,找到后返回
        searchMedia(s_media_source_map, schema, vhost, app, id,
                    [&](MediaSource::SchemaVhostAppStreamMap::iterator &it0, MediaSource::VhostAppStreamMap::iterator &it1,
                        MediaSource::AppStreamMap::iterator &it2, MediaSource::StreamMap::iterator &it3) {
            ret = it3->second.lock();
            if (!ret) {
                //该对象已经销毁
                it2->second.erase(it3);
                eraseIfEmpty(s_media_source_map, it0, it1, it2);
                return false;
            }
            return true;
        });
    }

274 275 276
    if(!ret && create_new && schema != HLS_SCHEMA){
        //未查找媒体源,则读取mp4创建一个
        //播放hls不触发mp4点播(因为HLS也可以用于录像,不是纯粹的直播)
xiongziliang committed
277 278 279 280 281 282 283 284
        ret = MediaSource::createFromMP4(schema, vhost, app, id);
    }
    return ret;
}

static void findAsync_l(const MediaInfo &info, const std::shared_ptr<TcpSession> &session, bool retry,
                        const function<void(const MediaSource::Ptr &src)> &cb){
    auto src = find_l(info._schema, info._vhost, info._app, info._streamid, true);
285
    if (src || !retry) {
286 287 288 289 290
        cb(src);
        return;
    }

    void *listener_tag = session.get();
xiongziliang committed
291
    weak_ptr<TcpSession> weak_session = session;
292

293
    GET_CONFIG(int, maxWaitMS, General::kMaxStreamWaitTimeMS);
xiongziliang committed
294
    auto on_timeout = session->getPoller()->doDelayTask(maxWaitMS, [cb, listener_tag]() {
295 296
        //最多等待一定时间,如果这个时间内,流未注册上,那么返回未找到流
        NoticeCenter::Instance().delListener(listener_tag, Broadcast::kBroadcastMediaChanged);
297 298 299 300
        cb(nullptr);
        return 0;
    });

xiongziliang committed
301
    auto cancel_all = [on_timeout, listener_tag]() {
302
        //取消延时任务,防止多次回调
xiongziliang committed
303
        on_timeout->cancel();
304 305 306 307
        //取消媒体注册事件监听
        NoticeCenter::Instance().delListener(listener_tag, Broadcast::kBroadcastMediaChanged);
    };

xiongziliang committed
308 309
    function<void()> close_player = [cb, cancel_all]() {
        cancel_all();
310 311 312 313
        //告诉播放器,流不存在,这样会立即断开播放器
        cb(nullptr);
    };

xiongziliang committed
314 315 316
    auto on_regist = [weak_session, info, cb, cancel_all](BroadcastMediaChangedArgs) {
        auto strong_session = weak_session.lock();
        if (!strong_session) {
317
            //自己已经销毁
xiongziliang committed
318
            cancel_all();
319 320 321
            return;
        }

xiongziliang committed
322 323 324 325 326
        if (!bRegist ||
            sender.getSchema() != info._schema ||
            sender.getVhost() != info._vhost ||
            sender.getApp() != info._app ||
            sender.getId() != info._streamid) {
327 328 329 330
            //不是自己感兴趣的事件,忽略之
            return;
        }

xiongziliang committed
331
        cancel_all();
332

333
        //播发器请求的流终于注册上了,切换到自己的线程再回复
xiongziliang committed
334 335
        strong_session->async([weak_session, info, cb]() {
            auto strongSession = weak_session.lock();
336
            if (!strongSession) {
337 338 339 340
                return;
            }
            DebugL << "收到媒体注册事件,回复播放器:" << info._schema << "/" << info._vhost << "/" << info._app << "/" << info._streamid;
            //再找一遍媒体源,一般能找到
341
            findAsync_l(info, strongSession, false, cb);
342 343
        }, false);
    };
344

345
    //监听媒体注册事件
xiongziliang committed
346
    NoticeCenter::Instance().addListener(listener_tag, Broadcast::kBroadcastMediaChanged, on_regist);
347
    //广播未找到流,此时可以立即去拉流,这样还来得及
xiongziliang committed
348
    NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastNotFoundStream, info, static_cast<SockInfo &>(*session), close_player);
349
}
xiongziliang committed
350 351 352 353 354

void MediaSource::findAsync(const MediaInfo &info, const std::shared_ptr<TcpSession> &session,const function<void(const Ptr &src)> &cb){
    return findAsync_l(info, session, true, cb);
}

355 356 357 358
MediaSource::Ptr MediaSource::find(const string &schema, const string &vhost, const string &app, const string &id) {
    return find_l(schema, vhost, app, id, false);
}

359 360 361 362 363 364 365 366 367 368 369 370
MediaSource::Ptr MediaSource::find(const string &vhost, const string &app, const string &stream_id){
    auto src = MediaSource::find(RTMP_SCHEMA, vhost, app, stream_id);
    if (src) {
        return src;
    }
    src = MediaSource::find(RTSP_SCHEMA, vhost, app, stream_id);
    if (src) {
        return src;
    }
    return MediaSource::find(HLS_SCHEMA, vhost, app, stream_id);
}

xiongziliang committed
371
void MediaSource::emitEvent(bool regist){
372 373
    auto listener = _listener.lock();
    if (listener) {
xiongziliang committed
374 375 376 377 378
        //触发回调
        listener->onRegist(*this, regist);
    }
    //触发广播
    NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaChanged, regist, *this);
379
    InfoL << (regist ? "媒体注册:" : "媒体注销:") << _schema << " " << _vhost << " " << _app << " " << _stream_id;
xiongziliang committed
380 381 382 383 384 385 386
}

void MediaSource::regist() {
    {
        //减小互斥锁临界区
        lock_guard<recursive_mutex> lock(s_media_source_mtx);
        s_media_source_map[_schema][_vhost][_app][_stream_id] = shared_from_this();
387
    }
xiongziliang committed
388
    emitEvent(true);
389
}
xiongziliang committed
390 391

//反注册该源
392
bool MediaSource::unregist() {
xiongziliang committed
393 394
    bool ret;
    {
xiongziliang committed
395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
        //减小互斥锁临界区
        lock_guard<recursive_mutex> lock(s_media_source_mtx);
        ret = searchMedia(s_media_source_map, _schema, _vhost, _app, _stream_id,
                          [&](SchemaVhostAppStreamMap::iterator &it0, VhostAppStreamMap::iterator &it1,
                              AppStreamMap::iterator &it2, StreamMap::iterator &it3) {
          auto strong_self = it3->second.lock();
          if (strong_self && this != strong_self.get()) {
              //不是自己,不允许反注册
              return false;
          }
          it2->second.erase(it3);
          eraseIfEmpty(s_media_source_map, it0, it1, it2);
          return true;
      });
    }

    if (ret) {
        emitEvent(false);
xiongziliang committed
413 414 415
    }
    return ret;
}
xiongziliang committed
416 417 418

/////////////////////////////////////MediaInfo//////////////////////////////////////

419
void MediaInfo::parse(const string &url_in){
420
    _full_url = url_in;
421 422 423 424 425 426 427
    string url = url_in;
    auto pos = url.find("?");
    if (pos != string::npos) {
        _param_strs = url.substr(pos + 1);
        url.erase(pos);
    }

428
    auto schema_pos = url.find("://");
xiongziliang committed
429 430 431
    if (schema_pos != string::npos) {
        _schema = url.substr(0, schema_pos);
    } else {
432 433
        schema_pos = -3;
    }
xiongziliang committed
434 435
    auto split_vec = split(url.substr(schema_pos + 3), "/");
    if (split_vec.size() > 0) {
436 437
        auto vhost = split_vec[0];
        auto pos = vhost.find(":");
xiongziliang committed
438 439
        if (pos != string::npos) {
            _host = _vhost = vhost.substr(0, pos);
440
            _port = vhost.substr(pos + 1);
xiongziliang committed
441
        } else {
442
            _host = _vhost = vhost;
443
        }
xiongziliang committed
444
        if (_vhost == "localhost" || INADDR_NONE != inet_addr(_vhost.data())) {
445 446 447
            //如果访问的是localhost或ip,那么则为默认虚拟主机
            _vhost = DEFAULT_VHOST;
        }
448
    }
xiongziliang committed
449
    if (split_vec.size() > 1) {
450
        _app = split_vec[1];
451
    }
xiongziliang committed
452 453 454 455
    if (split_vec.size() > 2) {
        string stream_id;
        for (int i = 2; i < split_vec.size(); ++i) {
            stream_id.append(split_vec[i] + "/");
456
        }
xiongziliang committed
457 458
        if (stream_id.back() == '/') {
            stream_id.pop_back();
459
        }
460 461 462 463 464 465
        _streamid = stream_id;
    }

    auto params = Parser::parseArgs(_param_strs);
    if (params.find(VHOST_KEY) != params.end()) {
        _vhost = params[VHOST_KEY];
466
    }
467

xiongziliang committed
468 469
    GET_CONFIG(bool, enableVhost, General::kEnableVhost);
    if (!enableVhost || _vhost.empty()) {
470
        //如果关闭虚拟主机或者虚拟主机为空,则设置虚拟主机为默认
471
        _vhost = DEFAULT_VHOST;
472 473 474
    }
}

xiongziliang committed
475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494
MediaSource::Ptr MediaSource::createFromMP4(const string &schema, const string &vhost, const string &app, const string &stream, const string &file_path , bool check_app){
    GET_CONFIG(string, appName, Record::kAppName);
    if (check_app && app != appName) {
        return nullptr;
    }
#ifdef ENABLE_MP4
    try {
        MP4Reader::Ptr pReader(new MP4Reader(vhost, app, stream, file_path));
        pReader->startReadMP4();
        return MediaSource::find(schema, vhost, app, stream);
    } catch (std::exception &ex) {
        WarnL << ex.what();
        return nullptr;
    }
#else
    WarnL << "创建MP4点播失败,请编译时打开\"ENABLE_MP4\"选项";
    return nullptr;
#endif //ENABLE_MP4
}

xiongziliang committed
495 496
/////////////////////////////////////MediaSourceEvent//////////////////////////////////////

497 498 499 500 501 502
void MediaSourceEvent::onReaderChanged(MediaSource &sender, int size){
    if (size || totalReaderCount(sender)) {
        //还有人观看该视频,不触发关闭事件
        return;
    }
    //没有任何人观看该视频源,表明该源可以关闭了
xiongziliang committed
503
    GET_CONFIG(string, record_app, Record::kAppName);
504
    GET_CONFIG(int, stream_none_reader_delay, General::kStreamNoneReaderDelayMS);
505
    //如果mp4点播, 无人观看时我们强制关闭点播
xiongziliang committed
506
    bool is_mp4_vod = sender.getApp() == record_app;
507
    weak_ptr<MediaSource> weak_sender = sender.shared_from_this();
508

509 510 511
    _async_close_timer = std::make_shared<Timer>(stream_none_reader_delay / 1000.0, [weak_sender, is_mp4_vod]() {
        auto strong_sender = weak_sender.lock();
        if (!strong_sender) {
512 513 514 515
            //对象已经销毁
            return false;
        }

516 517
        if (strong_sender->totalReaderCount()) {
            //还有人观看该视频,不触发关闭事件
518
            return false;
519
        }
520

521
        if (!is_mp4_vod) {
522 523
            //直播时触发无人观看事件,让开发者自行选择是否关闭
            WarnL << "无人观看事件:"
524 525 526 527 528 529
                  << strong_sender->getSchema() << "/"
                  << strong_sender->getVhost() << "/"
                  << strong_sender->getApp() << "/"
                  << strong_sender->getId();
            NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastStreamNoneReader, *strong_sender);
        } else {
530 531
            //这个是mp4点播,我们自动关闭
            WarnL << "MP4点播无人观看,自动关闭:"
532 533 534 535 536
                  << strong_sender->getSchema() << "/"
                  << strong_sender->getVhost() << "/"
                  << strong_sender->getApp() << "/"
                  << strong_sender->getId();
            strong_sender->close(false);
537
        }
538 539
        return false;
    }, nullptr);
xiongziliang committed
540 541
}

542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565
MediaOriginType MediaSourceEventInterceptor::getOriginType(MediaSource &sender) const {
    auto listener = _listener.lock();
    if (!listener) {
        return MediaOriginType::unknown;
    }
    return listener->getOriginType(sender);
}

string MediaSourceEventInterceptor::getOriginUrl(MediaSource &sender) const {
    auto listener = _listener.lock();
    if (!listener) {
        return "";
    }
    return listener->getOriginUrl(sender);
}

std::shared_ptr<SockInfo> MediaSourceEventInterceptor::getOriginSock(MediaSource &sender) const {
    auto listener = _listener.lock();
    if (!listener) {
        return nullptr;
    }
    return listener->getOriginSock(sender);
}

xiongziliang committed
566 567 568 569
bool MediaSourceEventInterceptor::seekTo(MediaSource &sender, uint32_t stamp) {
    auto listener = _listener.lock();
    if (!listener) {
        return false;
570
    }
xiongziliang committed
571 572 573 574 575 576 577
    return listener->seekTo(sender, stamp);
}

bool MediaSourceEventInterceptor::close(MediaSource &sender, bool force) {
    auto listener = _listener.lock();
    if (!listener) {
        return false;
578
    }
xiongziliang committed
579 580 581 582 583 584 585 586 587 588 589
    return listener->close(sender, force);
}

int MediaSourceEventInterceptor::totalReaderCount(MediaSource &sender) {
    auto listener = _listener.lock();
    if (!listener) {
        return sender.readerCount();
    }
    return listener->totalReaderCount(sender);
}

590
void MediaSourceEventInterceptor::onReaderChanged(MediaSource &sender, int size) {
xiongziliang committed
591 592
    auto listener = _listener.lock();
    if (!listener) {
593 594 595
        MediaSourceEvent::onReaderChanged(sender, size);
    } else {
        listener->onReaderChanged(sender, size);
xiongziliang committed
596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619
    }
}

void MediaSourceEventInterceptor::onRegist(MediaSource &sender, bool regist) {
    auto listener = _listener.lock();
    if (listener) {
        listener->onRegist(sender, regist);
    }
}

bool MediaSourceEventInterceptor::setupRecord(MediaSource &sender, Recorder::type type, bool start, const string &custom_path) {
    auto listener = _listener.lock();
    if (!listener) {
        return false;
    }
    return listener->setupRecord(sender, type, start, custom_path);
}

bool MediaSourceEventInterceptor::isRecording(MediaSource &sender, Recorder::type type) {
    auto listener = _listener.lock();
    if (!listener) {
        return false;
    }
    return listener->isRecording(sender, type);
620
}
621

622 623 624 625 626 627 628 629
vector<Track::Ptr> MediaSourceEventInterceptor::getTracks(MediaSource &sender, bool trackReady) const {
    auto listener = _listener.lock();
    if (!listener) {
        return vector<Track::Ptr>();
    }
    return listener->getTracks(sender, trackReady);
}

630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646
void MediaSourceEventInterceptor::startSendRtp(MediaSource &sender, const string &dst_url, uint16_t dst_port, uint32_t ssrc, bool is_udp, const function<void(const SockException &ex)> &cb){
    auto listener = _listener.lock();
    if (listener) {
        listener->startSendRtp(sender, dst_url, dst_port, ssrc, is_udp, cb);
    } else {
        MediaSourceEvent::startSendRtp(sender, dst_url, dst_port, ssrc, is_udp, cb);
    }
}

bool MediaSourceEventInterceptor::stopSendRtp(MediaSource &sender){
    auto listener = _listener.lock();
    if (listener) {
        return listener->stopSendRtp(sender);
    }
    return false;
}

xiongziliang committed
647 648
/////////////////////////////////////FlushPolicy//////////////////////////////////////

649
static bool isFlushAble_default(bool is_video, uint32_t last_stamp, uint32_t new_stamp, int cache_size) {
650 651
    if (new_stamp + 500 < last_stamp) {
        //时间戳回退比较大(可能seek中),由于rtp中时间戳是pts,是可能存在一定程度的回退的
xiongziliang committed
652 653 654
        return true;
    }

655 656
    //时间戳发送变化或者缓存超过1024个,sendmsg接口一般最多只能发送1024个数据包
    return last_stamp != new_stamp || cache_size >= 1024;
xiongziliang committed
657 658
}

659
static bool isFlushAble_merge(bool is_video, uint32_t last_stamp, uint32_t new_stamp, int cache_size, int merge_ms) {
660 661
    if (new_stamp + 500 < last_stamp) {
        //时间戳回退比较大(可能seek中),由于rtp中时间戳是pts,是可能存在一定程度的回退的
xiongziliang committed
662 663 664
        return true;
    }

665
    if (new_stamp > last_stamp + merge_ms) {
xiongziliang committed
666 667 668 669
        //时间戳增量超过合并写阈值
        return true;
    }

670 671 672
    //缓存数超过1024个,这个逻辑用于避免时间戳异常的流导致的内存暴增问题
    //而且sendmsg接口一般最多只能发送1024个数据包
    return cache_size >= 1024;
xiongziliang committed
673 674
}

675 676 677 678 679
bool FlushPolicy::isFlushAble(bool is_video, bool is_key, uint32_t new_stamp, int cache_size) {
    bool flush_flag = false;
    if (is_key && is_video) {
        //遇到关键帧flush掉前面的数据,确保关键帧为该组数据的第一帧,确保GOP缓存有效
        flush_flag = true;
680
    } else {
681 682 683 684 685 686 687
        GET_CONFIG(int, mergeWriteMS, General::kMergeWriteMS);
        if (mergeWriteMS <= 0) {
            //关闭了合并写或者合并写阈值小于等于0
            flush_flag = isFlushAble_default(is_video, _last_stamp[is_video], new_stamp, cache_size);
        } else {
            flush_flag = isFlushAble_merge(is_video, _last_stamp[is_video], new_stamp, cache_size, mergeWriteMS);
        }
688 689
    }

690 691
    if (flush_flag) {
        _last_stamp[is_video] = new_stamp;
xiongziliang committed
692
    }
693
    return flush_flag;
xiongziliang committed
694 695
}

xiongziliang committed
696
} /* namespace mediakit */