MediaSink.cpp 5.16 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
 */
xiongziliang committed
10

11 12
#include "MediaSink.h"

13
//最多等待未初始化的Track 10秒,超时之后会忽略未初始化的Track
14 15 16 17 18
#define MAX_WAIT_MS_READY 10000

//如果添加Track,最多等待3秒
#define MAX_WAIT_MS_ADD_TRACK 3000

19 20 21 22

namespace mediakit{

void MediaSink::addTrack(const Track::Ptr &track_in) {
23
    lock_guard<recursive_mutex> lck(_mtx);
24
    //克隆Track,只拷贝其数据,不拷贝其数据转发关系
25 26 27
    auto track = track_in->clone();
    auto codec_id = track->getCodecId();
    _track_map[codec_id] = track;
xiongziliang committed
28 29
    _all_track_ready = false;
    _track_ready_callback[codec_id] = [this, track]() {
30 31
        onTrackReady(track);
    };
32
    _ticker.resetTime();
xiongziliang committed
33

34
    track->addDelegate(std::make_shared<FrameWriterInterfaceHelper>([this](const Frame::Ptr &frame) {
xiongziliang committed
35
        if (_all_track_ready) {
xiongziliang committed
36
            onTrackFrame(frame);
xiongziliang committed
37 38 39
        } else {
            //还有Track未就绪,先缓存之
            _frame_unread[frame->getCodecId()].emplace_back(Frame::getCacheAbleFrame(frame));
40
        }
xiongziliang committed
41
    }));
42 43
}

44
void MediaSink::resetTracks() {
xiongziliang committed
45
    lock_guard<recursive_mutex> lck(_mtx);
xiongziliang committed
46
    _all_track_ready = false;
47
    _track_map.clear();
xiongziliang committed
48
    _track_ready_callback.clear();
49
    _ticker.resetTime();
50
    _max_track_size = 2;
xiongziliang committed
51
    _frame_unread.clear();
52 53
}

54
void MediaSink::inputFrame(const Frame::Ptr &frame) {
55
    lock_guard<recursive_mutex> lck(_mtx);
56
    auto it = _track_map.find(frame->getCodecId());
57 58 59
    if (it == _track_map.end()) {
        return;
    }
60
    it->second->inputFrame(frame);
xiongziliang committed
61
    checkTrackIfReady(nullptr);
62 63 64 65
}

void MediaSink::checkTrackIfReady_l(const Track::Ptr &track){
    //Track由未就绪状态转换成就绪状态,我们就触发onTrackReady回调
xiongziliang committed
66 67
    auto it_callback = _track_ready_callback.find(track->getCodecId());
    if (it_callback != _track_ready_callback.end() && track->ready()) {
68
        it_callback->second();
xiongziliang committed
69
        _track_ready_callback.erase(it_callback);
70 71
    }
}
72

73
void MediaSink::checkTrackIfReady(const Track::Ptr &track){
xiongziliang committed
74
    if (!_all_track_ready && !_track_ready_callback.empty()) {
75 76 77 78 79 80
        if (track) {
            checkTrackIfReady_l(track);
        } else {
            for (auto &pr : _track_map) {
                checkTrackIfReady_l(pr.second);
            }
81 82 83
        }
    }

xiongziliang committed
84
    if(!_all_track_ready){
85 86
        if(_ticker.elapsedTime() > MAX_WAIT_MS_READY){
            //如果超过规定时间,那么不再等待并忽略未准备好的Track
87
            emitAllTrackReady();
88 89 90
            return;
        }

xiongziliang committed
91
        if(!_track_ready_callback.empty()){
92 93
            //在超时时间内,如果存在未准备好的Track,那么继续等待
            return;
94 95
        }

96
        if(_track_map.size() == _max_track_size){
97
            //如果已经添加了音视频Track,并且不存在未准备好的Track,那么说明所有Track都准备好了
98
            emitAllTrackReady();
99
            return;
100
        }
101 102 103

        if(_track_map.size() == 1 && _ticker.elapsedTime() > MAX_WAIT_MS_ADD_TRACK){
            //如果只有一个Track,那么在该Track添加后,我们最多还等待若干时间(可能后面还会添加Track)
104
            emitAllTrackReady();
105 106 107 108 109
            return;
        }
    }
}

110
void MediaSink::addTrackCompleted(){
xiongziliang committed
111 112
    lock_guard<recursive_mutex> lck(_mtx);
    _max_track_size = _track_map.size();
113
    checkTrackIfReady(nullptr);
114 115 116
}

void MediaSink::emitAllTrackReady() {
xiongziliang committed
117
    if (_all_track_ready) {
118 119 120
        return;
    }

121
    DebugL << "all track ready use " << _ticker.elapsedTime() << "ms";
xiongziliang committed
122
    if (!_track_ready_callback.empty()) {
123
        //这是超时强制忽略未准备好的Track
xiongziliang committed
124
        _track_ready_callback.clear();
125
        //移除未准备好的Track
126 127
        for (auto it = _track_map.begin(); it != _track_map.end();) {
            if (!it->second->ready()) {
xiongziliang committed
128
                WarnL << "track not ready for a long time, ignored: " << it->second->getCodecName();
129 130 131 132 133 134 135
                it = _track_map.erase(it);
                continue;
            }
            ++it;
        }
    }

136
    if (!_track_map.empty()) {
137
        //最少有一个有效的Track
xiongziliang committed
138
        _all_track_ready = true;
139
        onAllTrackReady();
xiongziliang committed
140 141 142 143 144 145 146 147 148 149 150 151

        //全部Track就绪,我们一次性把之前的帧输出
        for(auto &pr : _frame_unread){
            if (_track_map.find(pr.first) == _track_map.end()) {
                //该Track已经被移除
                continue;
            }
            pr.second.for_each([&](const Frame::Ptr &frame) {
                onTrackFrame(frame);
            });
        }
        _frame_unread.clear();
152 153 154
    }
}

xiongziliang committed
155 156
vector<Track::Ptr> MediaSink::getTracks(bool trackReady) const{
    vector<Track::Ptr> ret;
157
    lock_guard<recursive_mutex> lck(_mtx);
158
    for (auto &pr : _track_map){
xiongziliang committed
159 160
        if(trackReady && !pr.second->ready()){
            continue;
161
        }
xiongziliang committed
162
        ret.emplace_back(pr.second);
163
    }
xiongziliang committed
164
    return std::move(ret);
165 166
}

167 168

}//namespace mediakit