2013-12-14 06:06:32 +00:00
|
|
|
/*
|
|
|
|
The MIT License (MIT)
|
|
|
|
|
2014-01-01 02:37:12 +00:00
|
|
|
Copyright (c) 2013-2014 winlin
|
2013-12-14 06:06:32 +00:00
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
|
|
this software and associated documentation files (the "Software"), to deal in
|
|
|
|
the Software without restriction, including without limitation the rights to
|
|
|
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
|
|
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
|
|
subject to the following conditions:
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
|
|
copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
|
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
|
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
|
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
2014-03-02 13:49:09 +00:00
|
|
|
#include <srs_app_source.hpp>
|
2013-12-14 06:06:32 +00:00
|
|
|
|
2014-05-29 06:16:34 +00:00
|
|
|
#include <sstream>
|
2013-12-14 06:06:32 +00:00
|
|
|
#include <algorithm>
|
2013-12-15 04:04:28 +00:00
|
|
|
using namespace std;
|
2013-12-14 06:06:32 +00:00
|
|
|
|
2014-03-01 02:42:55 +00:00
|
|
|
#include <srs_kernel_log.hpp>
|
2014-03-01 05:39:27 +00:00
|
|
|
#include <srs_protocol_rtmp_stack.hpp>
|
2013-12-14 06:06:32 +00:00
|
|
|
#include <srs_core_autofree.hpp>
|
2014-03-01 03:24:40 +00:00
|
|
|
#include <srs_protocol_amf0.hpp>
|
2014-05-28 09:37:15 +00:00
|
|
|
#include <srs_kernel_codec.hpp>
|
2014-03-02 13:49:09 +00:00
|
|
|
#include <srs_app_hls.hpp>
|
|
|
|
#include <srs_app_forward.hpp>
|
|
|
|
#include <srs_app_config.hpp>
|
|
|
|
#include <srs_app_encoder.hpp>
|
2014-03-01 06:03:02 +00:00
|
|
|
#include <srs_protocol_rtmp.hpp>
|
2014-04-16 01:28:02 +00:00
|
|
|
#include <srs_app_dvr.hpp>
|
2014-04-17 08:06:49 +00:00
|
|
|
#include <srs_kernel_stream.hpp>
|
2014-04-26 06:47:38 +00:00
|
|
|
#include <srs_app_edge.hpp>
|
2014-06-08 05:03:03 +00:00
|
|
|
#include <srs_kernel_utility.hpp>
|
2014-07-06 01:59:41 +00:00
|
|
|
#include <srs_app_avc_aac.hpp>
|
2013-12-14 06:06:32 +00:00
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
#define CONST_MAX_JITTER_MS 500
|
|
|
|
#define DEFAULT_FRAME_TIME_MS 40
|
2013-12-14 06:06:32 +00:00
|
|
|
|
2014-06-25 09:14:11 +00:00
|
|
|
int _srs_time_jitter_string2int(std::string time_jitter)
|
|
|
|
{
|
|
|
|
if (time_jitter == "full") {
|
|
|
|
return SrsRtmpJitterAlgorithmFULL;
|
|
|
|
} else if (time_jitter == "zero") {
|
|
|
|
return SrsRtmpJitterAlgorithmZERO;
|
|
|
|
} else {
|
|
|
|
return SrsRtmpJitterAlgorithmOFF;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-14 06:06:32 +00:00
|
|
|
SrsRtmpJitter::SrsRtmpJitter()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
last_pkt_correct_time = last_pkt_time = 0;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SrsRtmpJitter::~SrsRtmpJitter()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-06-25 09:14:11 +00:00
|
|
|
int SrsRtmpJitter::correct(SrsSharedPtrMessage* msg, int tba, int tbv, SrsRtmpJitterAlgorithm ag)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
2014-06-25 09:14:11 +00:00
|
|
|
|
2014-06-26 02:13:43 +00:00
|
|
|
// for performance issue
|
|
|
|
if (ag != SrsRtmpJitterAlgorithmFULL) {
|
|
|
|
// all jitter correct features is disabled, ignore.
|
|
|
|
if (ag == SrsRtmpJitterAlgorithmOFF) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// start at zero, but donot ensure monotonically increasing.
|
|
|
|
if (ag == SrsRtmpJitterAlgorithmZERO) {
|
|
|
|
// for the first time, last_pkt_correct_time is zero.
|
|
|
|
// while when timestamp overflow, the timestamp become smaller, reset the last_pkt_correct_time.
|
|
|
|
if (last_pkt_correct_time <= 0 || last_pkt_correct_time > msg->header.timestamp) {
|
|
|
|
last_pkt_correct_time = msg->header.timestamp;
|
|
|
|
}
|
|
|
|
msg->header.timestamp -= last_pkt_correct_time;
|
|
|
|
return ret;
|
2014-06-25 09:14:11 +00:00
|
|
|
}
|
2014-06-26 02:13:43 +00:00
|
|
|
|
|
|
|
// other algorithm, ignore.
|
2014-06-25 09:14:11 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// full jitter algorithm, do jitter correct.
|
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
// set to 0 for metadata.
|
2014-06-26 02:13:43 +00:00
|
|
|
if (!msg->header.is_audio() && !msg->header.is_video()) {
|
2014-03-18 03:32:58 +00:00
|
|
|
msg->header.timestamp = 0;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sample_rate = tba;
|
|
|
|
int frame_rate = tbv;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* we use a very simple time jitter detect/correct algorithm:
|
|
|
|
* 1. delta: ensure the delta is positive and valid,
|
|
|
|
* we set the delta to DEFAULT_FRAME_TIME_MS,
|
|
|
|
* if the delta of time is nagative or greater than CONST_MAX_JITTER_MS.
|
|
|
|
* 2. last_pkt_time: specifies the original packet time,
|
|
|
|
* is used to detect next jitter.
|
|
|
|
* 3. last_pkt_correct_time: simply add the positive delta,
|
|
|
|
* and enforce the time monotonically.
|
|
|
|
*/
|
|
|
|
int64_t time = msg->header.timestamp;
|
|
|
|
int64_t delta = time - last_pkt_time;
|
|
|
|
|
|
|
|
// if jitter detected, reset the delta.
|
|
|
|
if (delta < 0 || delta > CONST_MAX_JITTER_MS) {
|
|
|
|
// calc the right diff by audio sample rate
|
|
|
|
if (msg->header.is_audio() && sample_rate > 0) {
|
|
|
|
delta = (int64_t)(delta * 1000.0 / sample_rate);
|
|
|
|
} else if (msg->header.is_video() && frame_rate > 0) {
|
|
|
|
delta = (int64_t)(delta * 1.0 / frame_rate);
|
|
|
|
} else {
|
|
|
|
delta = DEFAULT_FRAME_TIME_MS;
|
|
|
|
}
|
|
|
|
|
|
|
|
// sometimes, the time is absolute time, so correct it again.
|
|
|
|
if (delta < 0 || delta > CONST_MAX_JITTER_MS) {
|
|
|
|
delta = DEFAULT_FRAME_TIME_MS;
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_info("jitter detected, last_pts=%"PRId64", pts=%"PRId64", diff=%"PRId64", last_time=%"PRId64", time=%"PRId64", diff=%"PRId64"",
|
|
|
|
last_pkt_time, time, time - last_pkt_time, last_pkt_correct_time, last_pkt_correct_time + delta, delta);
|
|
|
|
} else {
|
|
|
|
srs_verbose("timestamp no jitter. time=%"PRId64", last_pkt=%"PRId64", correct_to=%"PRId64"",
|
|
|
|
time, last_pkt_time, last_pkt_correct_time + delta);
|
|
|
|
}
|
|
|
|
|
|
|
|
last_pkt_correct_time = srs_max(0, last_pkt_correct_time + delta);
|
|
|
|
|
|
|
|
msg->header.timestamp = last_pkt_correct_time;
|
|
|
|
last_pkt_time = time;
|
|
|
|
|
|
|
|
return ret;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int SrsRtmpJitter::get_time()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return (int)last_pkt_correct_time;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2013-12-15 10:25:55 +00:00
|
|
|
SrsMessageQueue::SrsMessageQueue()
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
queue_size_ms = 0;
|
|
|
|
av_start_time = av_end_time = -1;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2013-12-15 10:25:55 +00:00
|
|
|
SrsMessageQueue::~SrsMessageQueue()
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
clear();
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2013-12-15 10:25:55 +00:00
|
|
|
void SrsMessageQueue::set_queue_size(double queue_size)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
queue_size_ms = (int)(queue_size * 1000);
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2014-04-29 06:44:07 +00:00
|
|
|
int SrsMessageQueue::enqueue(SrsSharedPtrMessage* msg)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-06-22 12:01:25 +00:00
|
|
|
if (msg->header.is_audio() || msg->header.is_video()) {
|
2014-03-18 03:32:58 +00:00
|
|
|
if (av_start_time == -1) {
|
|
|
|
av_start_time = msg->header.timestamp;
|
|
|
|
}
|
|
|
|
|
|
|
|
av_end_time = msg->header.timestamp;
|
|
|
|
}
|
|
|
|
|
|
|
|
msgs.push_back(msg);
|
|
|
|
|
|
|
|
while (av_end_time - av_start_time > queue_size_ms) {
|
|
|
|
shrink();
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2014-06-22 12:01:25 +00:00
|
|
|
int SrsMessageQueue::dump_packets(int max_count, SrsSharedPtrMessage** pmsgs, int& count)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
if (msgs.empty()) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-06-22 12:01:25 +00:00
|
|
|
srs_assert(max_count > 0);
|
|
|
|
count = srs_min(max_count, (int)msgs.size());
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
|
|
pmsgs[i] = msgs[i];
|
|
|
|
}
|
|
|
|
|
2014-04-29 06:44:07 +00:00
|
|
|
SrsSharedPtrMessage* last = msgs[count - 1];
|
2014-03-18 03:32:58 +00:00
|
|
|
av_start_time = last->header.timestamp;
|
|
|
|
|
|
|
|
if (count == (int)msgs.size()) {
|
|
|
|
msgs.clear();
|
|
|
|
} else {
|
|
|
|
msgs.erase(msgs.begin(), msgs.begin() + count);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2013-12-15 10:25:55 +00:00
|
|
|
void SrsMessageQueue::shrink()
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int iframe_index = -1;
|
|
|
|
|
|
|
|
// issue the first iframe.
|
|
|
|
// skip the first frame, whatever the type of it,
|
|
|
|
// for when we shrinked, the first is the iframe,
|
|
|
|
// we will directly remove the gop next time.
|
|
|
|
for (int i = 1; i < (int)msgs.size(); i++) {
|
2014-04-29 06:44:07 +00:00
|
|
|
SrsSharedPtrMessage* msg = msgs[i];
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
if (msg->header.is_video()) {
|
2014-06-08 14:36:17 +00:00
|
|
|
if (SrsFlvCodec::video_is_keyframe(msg->payload, msg->size)) {
|
2014-03-18 03:32:58 +00:00
|
|
|
// the max frame index to remove.
|
|
|
|
iframe_index = i;
|
|
|
|
|
|
|
|
// set the start time, we will remove until this frame.
|
|
|
|
av_start_time = msg->header.timestamp;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// no iframe, clear the queue.
|
|
|
|
if (iframe_index < 0) {
|
|
|
|
clear();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_trace("shrink the cache queue, size=%d, removed=%d, max=%.2f",
|
|
|
|
(int)msgs.size(), iframe_index, queue_size_ms / 1000.0);
|
|
|
|
|
|
|
|
// remove the first gop from the front
|
|
|
|
for (int i = 0; i < iframe_index; i++) {
|
2014-04-29 06:44:07 +00:00
|
|
|
SrsSharedPtrMessage* msg = msgs[i];
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_freep(msg);
|
|
|
|
}
|
|
|
|
msgs.erase(msgs.begin(), msgs.begin() + iframe_index);
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2013-12-15 10:25:55 +00:00
|
|
|
void SrsMessageQueue::clear()
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-04-29 06:44:07 +00:00
|
|
|
std::vector<SrsSharedPtrMessage*>::iterator it;
|
2013-12-15 10:25:55 +00:00
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
for (it = msgs.begin(); it != msgs.end(); ++it) {
|
2014-04-29 06:44:07 +00:00
|
|
|
SrsSharedPtrMessage* msg = *it;
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_freep(msg);
|
|
|
|
}
|
2013-12-15 10:25:55 +00:00
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
msgs.clear();
|
|
|
|
|
|
|
|
av_start_time = av_end_time = -1;
|
2013-12-15 10:25:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SrsConsumer::SrsConsumer(SrsSource* _source)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
source = _source;
|
|
|
|
paused = false;
|
|
|
|
jitter = new SrsRtmpJitter();
|
|
|
|
queue = new SrsMessageQueue();
|
2014-05-27 11:18:31 +00:00
|
|
|
should_update_source_id = false;
|
2013-12-15 10:25:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SrsConsumer::~SrsConsumer()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
source->on_consumer_destroy(this);
|
|
|
|
srs_freep(jitter);
|
|
|
|
srs_freep(queue);
|
2013-12-15 10:25:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SrsConsumer::set_queue_size(double queue_size)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
queue->set_queue_size(queue_size);
|
2013-12-15 10:25:55 +00:00
|
|
|
}
|
|
|
|
|
2014-05-27 11:18:31 +00:00
|
|
|
void SrsConsumer::update_source_id()
|
|
|
|
{
|
|
|
|
should_update_source_id = true;
|
|
|
|
}
|
|
|
|
|
2013-12-15 10:25:55 +00:00
|
|
|
int SrsConsumer::get_time()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return jitter->get_time();
|
2013-12-15 10:25:55 +00:00
|
|
|
}
|
|
|
|
|
2014-06-25 09:14:11 +00:00
|
|
|
int SrsConsumer::enqueue(SrsSharedPtrMessage* msg, bool atc, int tba, int tbv, SrsRtmpJitterAlgorithm ag)
|
2013-12-15 10:25:55 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-06-22 12:01:25 +00:00
|
|
|
if (!atc) {
|
2014-06-25 09:14:11 +00:00
|
|
|
if ((ret = jitter->correct(msg, tba, tbv, ag)) != ERROR_SUCCESS) {
|
2014-03-26 08:25:02 +00:00
|
|
|
srs_freep(msg);
|
|
|
|
return ret;
|
|
|
|
}
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((ret = queue->enqueue(msg)) != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2013-12-15 10:25:55 +00:00
|
|
|
}
|
|
|
|
|
2014-06-22 12:01:25 +00:00
|
|
|
int SrsConsumer::dump_packets(int max_count, SrsSharedPtrMessage** pmsgs, int& count)
|
2013-12-15 10:25:55 +00:00
|
|
|
{
|
2014-06-22 12:01:25 +00:00
|
|
|
srs_assert(max_count > 0);
|
|
|
|
|
2014-05-27 11:18:31 +00:00
|
|
|
if (should_update_source_id) {
|
|
|
|
srs_trace("update source_id=%d", source->source_id());
|
|
|
|
should_update_source_id = false;
|
|
|
|
}
|
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
// paused, return nothing.
|
|
|
|
if (paused) {
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2014-06-22 12:01:25 +00:00
|
|
|
return queue->dump_packets(max_count, pmsgs, count);
|
2013-12-15 10:25:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int SrsConsumer::on_play_client_pause(bool is_pause)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
srs_trace("stream consumer change pause state %d=>%d", paused, is_pause);
|
|
|
|
paused = is_pause;
|
|
|
|
|
|
|
|
return ret;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SrsGopCache::SrsGopCache()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
cached_video_count = 0;
|
|
|
|
enable_gop_cache = true;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SrsGopCache::~SrsGopCache()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
clear();
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SrsGopCache::set(bool enabled)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
enable_gop_cache = enabled;
|
|
|
|
|
|
|
|
if (!enabled) {
|
|
|
|
srs_info("disable gop cache, clear %d packets.", (int)gop_cache.size());
|
|
|
|
clear();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_info("enable gop cache");
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2014-04-29 06:44:07 +00:00
|
|
|
int SrsGopCache::cache(SrsSharedPtrMessage* msg)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
if (!enable_gop_cache) {
|
|
|
|
srs_verbose("gop cache is disabled.");
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// got video, update the video count if acceptable
|
|
|
|
if (msg->header.is_video()) {
|
|
|
|
cached_video_count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// no acceptable video or pure audio, disable the cache.
|
|
|
|
if (cached_video_count == 0) {
|
|
|
|
srs_verbose("ignore any frame util got a h264 video frame.");
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// clear gop cache when got key frame
|
2014-06-08 14:36:17 +00:00
|
|
|
if (msg->header.is_video() && SrsFlvCodec::video_is_keyframe(msg->payload, msg->size)) {
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_info("clear gop cache when got keyframe. vcount=%d, count=%d",
|
|
|
|
cached_video_count, (int)gop_cache.size());
|
|
|
|
|
|
|
|
clear();
|
|
|
|
|
|
|
|
// curent msg is video frame, so we set to 1.
|
|
|
|
cached_video_count = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// cache the frame.
|
|
|
|
gop_cache.push_back(msg->copy());
|
|
|
|
|
|
|
|
return ret;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SrsGopCache::clear()
|
|
|
|
{
|
2014-04-29 06:44:07 +00:00
|
|
|
std::vector<SrsSharedPtrMessage*>::iterator it;
|
2014-03-18 03:32:58 +00:00
|
|
|
for (it = gop_cache.begin(); it != gop_cache.end(); ++it) {
|
2014-04-29 06:44:07 +00:00
|
|
|
SrsSharedPtrMessage* msg = *it;
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_freep(msg);
|
|
|
|
}
|
|
|
|
gop_cache.clear();
|
2013-12-14 06:06:32 +00:00
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
cached_video_count = 0;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2014-06-25 09:14:11 +00:00
|
|
|
int SrsGopCache::dump(SrsConsumer* consumer, bool atc, int tba, int tbv, SrsRtmpJitterAlgorithm jitter_algorithm)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-04-29 06:44:07 +00:00
|
|
|
std::vector<SrsSharedPtrMessage*>::iterator it;
|
2014-03-18 03:32:58 +00:00
|
|
|
for (it = gop_cache.begin(); it != gop_cache.end(); ++it) {
|
2014-04-29 06:44:07 +00:00
|
|
|
SrsSharedPtrMessage* msg = *it;
|
2014-06-22 12:01:25 +00:00
|
|
|
SrsSharedPtrMessage* copy = msg->copy();
|
2014-06-25 09:14:11 +00:00
|
|
|
if ((ret = consumer->enqueue(copy, atc, tba, tbv, jitter_algorithm)) != ERROR_SUCCESS) {
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_error("dispatch cached gop failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
srs_trace("dispatch cached gop success. count=%d, duration=%d", (int)gop_cache.size(), consumer->get_time());
|
|
|
|
|
|
|
|
return ret;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2014-03-26 08:25:02 +00:00
|
|
|
bool SrsGopCache::empty()
|
|
|
|
{
|
|
|
|
return gop_cache.empty();
|
|
|
|
}
|
|
|
|
|
|
|
|
int64_t SrsGopCache::get_start_time()
|
|
|
|
{
|
|
|
|
if (empty()) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-04-29 06:44:07 +00:00
|
|
|
SrsSharedPtrMessage* msg = gop_cache[0];
|
2014-03-26 08:25:02 +00:00
|
|
|
srs_assert(msg);
|
|
|
|
|
|
|
|
return msg->header.timestamp;
|
|
|
|
}
|
|
|
|
|
2013-12-14 06:06:32 +00:00
|
|
|
std::map<std::string, SrsSource*> SrsSource::pool;
|
|
|
|
|
2014-04-17 08:57:04 +00:00
|
|
|
int SrsSource::find(SrsRequest* req, SrsSource** ppsource)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-04-17 08:57:04 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
string stream_url = req->get_stream_url();
|
|
|
|
string vhost = req->vhost;
|
|
|
|
|
|
|
|
if (pool.find(stream_url) == pool.end()) {
|
2014-04-17 08:57:04 +00:00
|
|
|
SrsSource* source = new SrsSource(req);
|
|
|
|
if ((ret = source->initialize()) != ERROR_SUCCESS) {
|
|
|
|
srs_freep(source);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
pool[stream_url] = source;
|
2014-04-11 06:13:14 +00:00
|
|
|
srs_info("create new source for url=%s, vhost=%s", stream_url.c_str(), vhost.c_str());
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
|
2014-06-23 03:18:55 +00:00
|
|
|
// we always update the request of resource,
|
|
|
|
// for origin auth is on, the token in request maybe invalid,
|
|
|
|
// and we only need to update the token of request, it's simple.
|
|
|
|
if (true) {
|
|
|
|
SrsSource* source = pool[stream_url];
|
|
|
|
source->_req->update_auth(req);
|
|
|
|
*ppsource = source;
|
|
|
|
}
|
2014-04-17 08:57:04 +00:00
|
|
|
|
|
|
|
return ret;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2014-05-03 14:59:21 +00:00
|
|
|
void SrsSource::destroy()
|
|
|
|
{
|
|
|
|
std::map<std::string, SrsSource*>::iterator it;
|
|
|
|
for (it = pool.begin(); it != pool.end(); ++it) {
|
|
|
|
SrsSource* source = it->second;
|
|
|
|
srs_freep(source);
|
|
|
|
}
|
|
|
|
pool.clear();
|
|
|
|
}
|
|
|
|
|
2014-04-26 09:16:18 +00:00
|
|
|
SrsSource::SrsSource(SrsRequest* req)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-04-26 09:16:18 +00:00
|
|
|
_req = req->copy();
|
2014-06-25 09:14:11 +00:00
|
|
|
jitter_algorithm = SrsRtmpJitterAlgorithmOFF;
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2014-04-15 06:01:57 +00:00
|
|
|
#ifdef SRS_AUTO_HLS
|
2014-03-18 03:32:58 +00:00
|
|
|
hls = new SrsHls(this);
|
2013-12-14 06:06:32 +00:00
|
|
|
#endif
|
2014-04-16 01:28:02 +00:00
|
|
|
#ifdef SRS_AUTO_DVR
|
|
|
|
dvr = new SrsDvr(this);
|
|
|
|
#endif
|
2014-04-15 06:01:57 +00:00
|
|
|
#ifdef SRS_AUTO_TRANSCODE
|
2014-03-18 03:32:58 +00:00
|
|
|
encoder = new SrsEncoder();
|
2013-12-14 06:06:32 +00:00
|
|
|
#endif
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
cache_metadata = cache_sh_video = cache_sh_audio = NULL;
|
|
|
|
|
|
|
|
frame_rate = sample_rate = 0;
|
|
|
|
_can_publish = true;
|
2014-05-27 09:59:59 +00:00
|
|
|
_source_id = -1;
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2014-04-27 01:29:37 +00:00
|
|
|
play_edge = new SrsPlayEdge();
|
|
|
|
publish_edge = new SrsPublishEdge();
|
2014-03-18 03:32:58 +00:00
|
|
|
gop_cache = new SrsGopCache();
|
2014-05-08 06:33:25 +00:00
|
|
|
aggregate_stream = new SrsStream();
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
_srs_config->subscribe(this);
|
2014-04-26 09:16:18 +00:00
|
|
|
atc = _srs_config->get_atc(_req->vhost);
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SrsSource::~SrsSource()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
_srs_config->unsubscribe(this);
|
|
|
|
|
2014-05-03 14:59:21 +00:00
|
|
|
// never free the consumers,
|
|
|
|
// for all consumers are auto free.
|
|
|
|
consumers.clear();
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
if (true) {
|
|
|
|
std::vector<SrsForwarder*>::iterator it;
|
|
|
|
for (it = forwarders.begin(); it != forwarders.end(); ++it) {
|
|
|
|
SrsForwarder* forwarder = *it;
|
|
|
|
srs_freep(forwarder);
|
|
|
|
}
|
|
|
|
forwarders.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_freep(cache_metadata);
|
|
|
|
srs_freep(cache_sh_video);
|
|
|
|
srs_freep(cache_sh_audio);
|
|
|
|
|
2014-04-27 01:29:37 +00:00
|
|
|
srs_freep(play_edge);
|
|
|
|
srs_freep(publish_edge);
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_freep(gop_cache);
|
2014-05-08 06:33:25 +00:00
|
|
|
srs_freep(aggregate_stream);
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2014-04-15 06:01:57 +00:00
|
|
|
#ifdef SRS_AUTO_HLS
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_freep(hls);
|
2013-12-14 06:06:32 +00:00
|
|
|
#endif
|
2014-04-16 01:28:02 +00:00
|
|
|
#ifdef SRS_AUTO_DVR
|
|
|
|
srs_freep(dvr);
|
|
|
|
#endif
|
2014-04-15 06:01:57 +00:00
|
|
|
#ifdef SRS_AUTO_TRANSCODE
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_freep(encoder);
|
2013-12-14 06:06:32 +00:00
|
|
|
#endif
|
2013-12-15 04:34:22 +00:00
|
|
|
|
2014-04-26 09:16:18 +00:00
|
|
|
srs_freep(_req);
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2014-04-17 08:57:04 +00:00
|
|
|
int SrsSource::initialize()
|
|
|
|
{
|
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
#ifdef SRS_AUTO_DVR
|
2014-04-26 09:16:18 +00:00
|
|
|
if ((ret = dvr->initialize(_req)) != ERROR_SUCCESS) {
|
2014-04-17 08:57:04 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#endif
|
2014-04-26 09:16:18 +00:00
|
|
|
|
2014-04-27 01:29:37 +00:00
|
|
|
if ((ret = play_edge->initialize(this, _req)) != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
if ((ret = publish_edge->initialize(this, _req)) != ERROR_SUCCESS) {
|
2014-04-26 09:16:18 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2014-04-17 08:57:04 +00:00
|
|
|
|
2014-04-28 09:20:35 +00:00
|
|
|
double queue_size = _srs_config->get_queue_length(_req->vhost);
|
|
|
|
publish_edge->set_queue_size(queue_size);
|
|
|
|
|
2014-06-25 09:14:11 +00:00
|
|
|
jitter_algorithm = (SrsRtmpJitterAlgorithm)_srs_config->get_time_jitter(_req->vhost);
|
|
|
|
|
2014-04-17 08:57:04 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-04-13 05:31:59 +00:00
|
|
|
int SrsSource::on_reload_vhost_atc(string vhost)
|
2014-04-12 14:00:27 +00:00
|
|
|
{
|
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-04-26 09:16:18 +00:00
|
|
|
if (_req->vhost != vhost) {
|
2014-04-12 14:00:27 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// atc changed.
|
|
|
|
bool enabled_atc = _srs_config->get_atc(vhost);
|
|
|
|
|
|
|
|
srs_warn("vhost %s atc changed to %d, connected client may corrupt.",
|
|
|
|
vhost.c_str(), enabled_atc);
|
|
|
|
|
|
|
|
gop_cache->clear();
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-04-13 05:31:59 +00:00
|
|
|
int SrsSource::on_reload_vhost_gop_cache(string vhost)
|
2013-12-15 04:04:28 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-04-26 09:16:18 +00:00
|
|
|
if (_req->vhost != vhost) {
|
2014-03-18 03:32:58 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// gop cache changed.
|
|
|
|
bool enabled_cache = _srs_config->get_gop_cache(vhost);
|
|
|
|
|
|
|
|
srs_trace("vhost %s gop_cache changed to %d, source url=%s",
|
2014-04-26 09:16:18 +00:00
|
|
|
vhost.c_str(), enabled_cache, _req->get_stream_url().c_str());
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
set_cache(enabled_cache);
|
|
|
|
|
|
|
|
return ret;
|
2013-12-15 04:04:28 +00:00
|
|
|
}
|
|
|
|
|
2014-04-13 05:31:59 +00:00
|
|
|
int SrsSource::on_reload_vhost_queue_length(string vhost)
|
2013-12-15 10:25:55 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-04-26 09:16:18 +00:00
|
|
|
if (_req->vhost != vhost) {
|
2014-03-18 03:32:58 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-04-26 09:16:18 +00:00
|
|
|
double queue_size = _srs_config->get_queue_length(_req->vhost);
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
if (true) {
|
|
|
|
std::vector<SrsConsumer*>::iterator it;
|
|
|
|
|
|
|
|
for (it = consumers.begin(); it != consumers.end(); ++it) {
|
|
|
|
SrsConsumer* consumer = *it;
|
|
|
|
consumer->set_queue_size(queue_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_trace("consumers reload queue size success.");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (true) {
|
|
|
|
std::vector<SrsForwarder*>::iterator it;
|
|
|
|
|
|
|
|
for (it = forwarders.begin(); it != forwarders.end(); ++it) {
|
|
|
|
SrsForwarder* forwarder = *it;
|
|
|
|
forwarder->set_queue_size(queue_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_trace("forwarders reload queue size success.");
|
|
|
|
}
|
|
|
|
|
2014-04-28 09:20:35 +00:00
|
|
|
if (true) {
|
|
|
|
publish_edge->set_queue_size(queue_size);
|
|
|
|
srs_trace("publish_edge reload queue size success.");
|
|
|
|
}
|
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
return ret;
|
2013-12-15 10:25:55 +00:00
|
|
|
}
|
|
|
|
|
2014-06-25 09:14:11 +00:00
|
|
|
int SrsSource::on_reload_vhost_time_jitter(string vhost)
|
|
|
|
{
|
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
if (_req->vhost != vhost) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
jitter_algorithm = (SrsRtmpJitterAlgorithm)_srs_config->get_time_jitter(_req->vhost);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-04-13 05:31:59 +00:00
|
|
|
int SrsSource::on_reload_vhost_forward(string vhost)
|
2013-12-15 04:34:22 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-04-26 09:16:18 +00:00
|
|
|
if (_req->vhost != vhost) {
|
2014-03-18 03:32:58 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2013-12-15 04:34:22 +00:00
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
// forwarders
|
|
|
|
destroy_forwarders();
|
|
|
|
if ((ret = create_forwarders()) != ERROR_SUCCESS) {
|
|
|
|
srs_error("create forwarders failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
2013-12-15 09:09:25 +00:00
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_trace("vhost %s forwarders reload success", vhost.c_str());
|
|
|
|
|
|
|
|
return ret;
|
2013-12-15 04:34:22 +00:00
|
|
|
}
|
|
|
|
|
2014-04-13 05:31:59 +00:00
|
|
|
int SrsSource::on_reload_vhost_hls(string vhost)
|
2013-12-15 05:07:39 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-04-26 09:16:18 +00:00
|
|
|
if (_req->vhost != vhost) {
|
2014-03-18 03:32:58 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-04-15 06:01:57 +00:00
|
|
|
#ifdef SRS_AUTO_HLS
|
2014-03-18 03:32:58 +00:00
|
|
|
hls->on_unpublish();
|
2014-04-26 09:16:18 +00:00
|
|
|
if ((ret = hls->on_publish(_req)) != ERROR_SUCCESS) {
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_error("hls publish failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_trace("vhost %s hls reload success", vhost.c_str());
|
2013-12-15 05:07:39 +00:00
|
|
|
#endif
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
return ret;
|
2013-12-15 05:07:39 +00:00
|
|
|
}
|
|
|
|
|
2014-04-17 08:22:21 +00:00
|
|
|
int SrsSource::on_reload_vhost_dvr(string vhost)
|
|
|
|
{
|
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-04-26 09:16:18 +00:00
|
|
|
if (_req->vhost != vhost) {
|
2014-04-17 08:22:21 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef SRS_AUTO_DVR
|
2014-04-17 08:57:04 +00:00
|
|
|
// cleanup dvr
|
2014-04-17 08:22:21 +00:00
|
|
|
dvr->on_unpublish();
|
2014-04-17 08:57:04 +00:00
|
|
|
|
|
|
|
// reinitialize the dvr, update plan.
|
2014-04-26 09:16:18 +00:00
|
|
|
if ((ret = dvr->initialize(_req)) != ERROR_SUCCESS) {
|
2014-04-17 08:57:04 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// start to publish by new plan.
|
2014-04-26 09:16:18 +00:00
|
|
|
if ((ret = dvr->on_publish(_req)) != ERROR_SUCCESS) {
|
2014-04-17 08:22:21 +00:00
|
|
|
srs_error("dvr publish failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
2014-04-17 08:57:04 +00:00
|
|
|
|
2014-04-17 08:22:21 +00:00
|
|
|
srs_trace("vhost %s dvr reload success", vhost.c_str());
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-04-13 05:31:59 +00:00
|
|
|
int SrsSource::on_reload_vhost_transcode(string vhost)
|
2013-12-15 05:07:39 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-04-26 09:16:18 +00:00
|
|
|
if (_req->vhost != vhost) {
|
2014-03-18 03:32:58 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-04-15 06:01:57 +00:00
|
|
|
#ifdef SRS_AUTO_TRANSCODE
|
2014-03-18 03:32:58 +00:00
|
|
|
encoder->on_unpublish();
|
2014-04-26 09:16:18 +00:00
|
|
|
if ((ret = encoder->on_publish(_req)) != ERROR_SUCCESS) {
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_error("start encoder failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_trace("vhost %s transcode reload success", vhost.c_str());
|
2013-12-15 05:07:39 +00:00
|
|
|
#endif
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
return ret;
|
2013-12-15 05:07:39 +00:00
|
|
|
}
|
|
|
|
|
2013-12-15 09:09:25 +00:00
|
|
|
int SrsSource::on_forwarder_start(SrsForwarder* forwarder)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
// feed the forwarder the metadata/sequence header,
|
|
|
|
// when reload to enable the forwarder.
|
|
|
|
if (cache_metadata && (ret = forwarder->on_meta_data(cache_metadata->copy())) != ERROR_SUCCESS) {
|
|
|
|
srs_error("forwarder process onMetaData message failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
if (cache_sh_video && (ret = forwarder->on_video(cache_sh_video->copy())) != ERROR_SUCCESS) {
|
|
|
|
srs_error("forwarder process video sequence header message failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
if (cache_sh_audio && (ret = forwarder->on_audio(cache_sh_audio->copy())) != ERROR_SUCCESS) {
|
|
|
|
srs_error("forwarder process audio sequence header message failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2013-12-15 09:09:25 +00:00
|
|
|
}
|
|
|
|
|
2013-12-15 12:29:18 +00:00
|
|
|
int SrsSource::on_hls_start()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-04-15 06:01:57 +00:00
|
|
|
#ifdef SRS_AUTO_HLS
|
2014-03-18 03:32:58 +00:00
|
|
|
// feed the hls the metadata/sequence header,
|
2014-04-16 03:11:53 +00:00
|
|
|
// when reload to start hls, hls will never get the sequence header in stream,
|
|
|
|
// use the SrsSource.on_hls_start to push the sequence header to HLS.
|
2014-03-18 03:32:58 +00:00
|
|
|
// TODO: maybe need to decode the metadata?
|
|
|
|
if (cache_sh_video && (ret = hls->on_video(cache_sh_video->copy())) != ERROR_SUCCESS) {
|
|
|
|
srs_error("hls process video sequence header message failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
if (cache_sh_audio && (ret = hls->on_audio(cache_sh_audio->copy())) != ERROR_SUCCESS) {
|
|
|
|
srs_error("hls process audio sequence header message failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
2014-04-17 08:06:49 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-04-24 08:32:19 +00:00
|
|
|
int SrsSource::on_dvr_request_sh()
|
2014-04-17 08:06:49 +00:00
|
|
|
{
|
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
#ifdef SRS_AUTO_DVR
|
|
|
|
// feed the dvr the metadata/sequence header,
|
|
|
|
// when reload to start dvr, dvr will never get the sequence header in stream,
|
2014-04-24 08:32:19 +00:00
|
|
|
// use the SrsSource.on_dvr_request_sh to push the sequence header to DVR.
|
2014-04-17 08:06:49 +00:00
|
|
|
if (cache_metadata) {
|
|
|
|
char* payload = (char*)cache_metadata->payload;
|
|
|
|
int size = (int)cache_metadata->size;
|
|
|
|
|
|
|
|
SrsStream stream;
|
|
|
|
if ((ret = stream.initialize(payload, size)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("dvr decode metadata stream failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
SrsOnMetaDataPacket pkt;
|
|
|
|
if ((ret = pkt.decode(&stream)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("dvr decode metadata packet failed.");
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ret = dvr->on_meta_data(&pkt)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("dvr process onMetaData message failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2014-04-17 08:06:49 +00:00
|
|
|
if (cache_sh_video && (ret = dvr->on_video(cache_sh_video->copy())) != ERROR_SUCCESS) {
|
|
|
|
srs_error("dvr process video sequence header message failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
if (cache_sh_audio && (ret = dvr->on_audio(cache_sh_audio->copy())) != ERROR_SUCCESS) {
|
|
|
|
srs_error("dvr process audio sequence header message failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
2013-12-15 12:29:18 +00:00
|
|
|
#endif
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
return ret;
|
2013-12-15 12:29:18 +00:00
|
|
|
}
|
|
|
|
|
2014-05-27 09:59:59 +00:00
|
|
|
int SrsSource::on_source_id_changed(int id)
|
|
|
|
{
|
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
if (_source_id == id) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
_source_id = id;
|
|
|
|
|
2014-05-27 11:18:31 +00:00
|
|
|
// notice all consumer
|
|
|
|
std::vector<SrsConsumer*>::iterator it;
|
|
|
|
for (it = consumers.begin(); it != consumers.end(); ++it) {
|
|
|
|
SrsConsumer* consumer = *it;
|
|
|
|
consumer->update_source_id();
|
|
|
|
}
|
|
|
|
|
2014-05-27 09:59:59 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int SrsSource::source_id()
|
|
|
|
{
|
|
|
|
return _source_id;
|
|
|
|
}
|
|
|
|
|
2013-12-14 06:06:32 +00:00
|
|
|
bool SrsSource::can_publish()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return _can_publish;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2014-04-29 06:44:07 +00:00
|
|
|
int SrsSource::on_meta_data(SrsMessage* msg, SrsOnMetaDataPacket* metadata)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-04-15 06:01:57 +00:00
|
|
|
#ifdef SRS_AUTO_HLS
|
2014-03-18 03:32:58 +00:00
|
|
|
if (metadata && (ret = hls->on_meta_data(metadata->metadata)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("hls process onMetaData message failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
2013-12-14 06:06:32 +00:00
|
|
|
#endif
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2014-04-16 01:28:02 +00:00
|
|
|
#ifdef SRS_AUTO_DVR
|
2014-04-17 08:06:49 +00:00
|
|
|
if (metadata && (ret = dvr->on_meta_data(metadata)) != ERROR_SUCCESS) {
|
2014-04-16 01:28:02 +00:00
|
|
|
srs_error("dvr process onMetaData message failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#endif
|
2014-05-29 06:16:34 +00:00
|
|
|
|
|
|
|
SrsAmf0Any* prop = NULL;
|
|
|
|
|
|
|
|
// generate metadata info to print
|
|
|
|
std::stringstream ss;
|
|
|
|
if ((prop = metadata->metadata->ensure_property_number("width")) != NULL) {
|
|
|
|
ss << ", width=" << (int)prop->to_number();
|
|
|
|
}
|
|
|
|
if ((prop = metadata->metadata->ensure_property_number("height")) != NULL) {
|
|
|
|
ss << ", height=" << (int)prop->to_number();
|
|
|
|
}
|
|
|
|
if ((prop = metadata->metadata->ensure_property_number("videocodecid")) != NULL) {
|
|
|
|
ss << ", vcodec=" << (int)prop->to_number();
|
|
|
|
}
|
|
|
|
if ((prop = metadata->metadata->ensure_property_number("audiocodecid")) != NULL) {
|
|
|
|
ss << ", acodec=" << (int)prop->to_number();
|
|
|
|
}
|
2014-04-16 01:28:02 +00:00
|
|
|
|
2014-05-29 06:16:34 +00:00
|
|
|
// add server info to metadata
|
2014-03-18 03:32:58 +00:00
|
|
|
metadata->metadata->set("server", SrsAmf0Any::str(RTMP_SIG_SRS_KEY" "RTMP_SIG_SRS_VERSION" ("RTMP_SIG_SRS_URL_SHORT")"));
|
2014-05-14 03:46:17 +00:00
|
|
|
metadata->metadata->set("authors", SrsAmf0Any::str(RTMP_SIG_SRS_PRIMARY_AUTHROS));
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2014-06-28 08:43:57 +00:00
|
|
|
// version, for example, 1.0.0
|
|
|
|
// add version to metadata, please donot remove it, for debug.
|
|
|
|
metadata->metadata->set("server_version", SrsAmf0Any::str(RTMP_SIG_SRS_VERSION));
|
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
if ((prop = metadata->metadata->get_property("audiosamplerate")) != NULL) {
|
|
|
|
if (prop->is_number()) {
|
|
|
|
sample_rate = (int)prop->to_number();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((prop = metadata->metadata->get_property("framerate")) != NULL) {
|
|
|
|
if (prop->is_number()) {
|
|
|
|
frame_rate = (int)prop->to_number();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-30 04:08:11 +00:00
|
|
|
// if allow atc_auto and bravo-atc detected, open atc for vhost.
|
2014-04-30 02:31:05 +00:00
|
|
|
atc = _srs_config->get_atc(_req->vhost);
|
2014-04-30 04:08:11 +00:00
|
|
|
if (_srs_config->get_atc_auto(_req->vhost)) {
|
|
|
|
if ((prop = metadata->metadata->get_property("bravo_atc")) != NULL) {
|
|
|
|
if (prop->is_string() && prop->to_str() == "true") {
|
|
|
|
atc = true;
|
|
|
|
}
|
2014-04-29 10:27:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
// encode the metadata to payload
|
2014-04-29 06:44:07 +00:00
|
|
|
int size = 0;
|
2014-03-18 03:32:58 +00:00
|
|
|
char* payload = NULL;
|
|
|
|
if ((ret = metadata->encode(size, payload)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("encode metadata error. ret=%d", ret);
|
2014-05-13 06:24:39 +00:00
|
|
|
srs_freep(payload);
|
2014-03-18 03:32:58 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_verbose("encode metadata success.");
|
|
|
|
|
2014-04-29 06:44:07 +00:00
|
|
|
if (size <= 0) {
|
|
|
|
srs_warn("ignore the invalid metadata. size=%d", size);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
// create a shared ptr message.
|
|
|
|
srs_freep(cache_metadata);
|
2014-04-29 06:44:07 +00:00
|
|
|
cache_metadata = new SrsSharedPtrMessage();
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
// dump message to shared ptr message.
|
2014-07-06 10:23:14 +00:00
|
|
|
// the payload/size managed by cache_metadata, user should not free it.
|
|
|
|
if ((ret = cache_metadata->create(&msg->header, payload, size)) != ERROR_SUCCESS) {
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_error("initialize the cache metadata failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_verbose("initialize shared ptr metadata success.");
|
|
|
|
|
|
|
|
// copy to all consumer
|
|
|
|
if (true) {
|
|
|
|
std::vector<SrsConsumer*>::iterator it;
|
|
|
|
for (it = consumers.begin(); it != consumers.end(); ++it) {
|
|
|
|
SrsConsumer* consumer = *it;
|
2014-06-22 12:01:25 +00:00
|
|
|
SrsSharedPtrMessage* copy = cache_metadata->copy();
|
2014-06-25 09:14:11 +00:00
|
|
|
if ((ret = consumer->enqueue(copy, atc, sample_rate, frame_rate, jitter_algorithm)) != ERROR_SUCCESS) {
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_error("dispatch the metadata failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
2014-05-29 06:16:34 +00:00
|
|
|
srs_trace("got metadata%s", ss.str().c_str());
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// copy to all forwarders
|
|
|
|
if (true) {
|
|
|
|
std::vector<SrsForwarder*>::iterator it;
|
|
|
|
for (it = forwarders.begin(); it != forwarders.end(); ++it) {
|
|
|
|
SrsForwarder* forwarder = *it;
|
|
|
|
if ((ret = forwarder->on_meta_data(cache_metadata->copy())) != ERROR_SUCCESS) {
|
|
|
|
srs_error("forwarder process onMetaData message failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2014-07-06 10:23:14 +00:00
|
|
|
int SrsSource::on_audio(SrsMessage* __audio)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-07-06 10:23:14 +00:00
|
|
|
// convert __audio to msg, user should not use __audio again.
|
|
|
|
// the payload is transfer to msg, and set to NULL in __audio.
|
|
|
|
SrsSharedPtrMessage msg;
|
|
|
|
if ((ret = msg.create(__audio)) != ERROR_SUCCESS) {
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_error("initialize the audio failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_verbose("initialize shared ptr audio success.");
|
|
|
|
|
2014-04-15 06:01:57 +00:00
|
|
|
#ifdef SRS_AUTO_HLS
|
2014-07-06 10:23:14 +00:00
|
|
|
if ((ret = hls->on_audio(msg.copy())) != ERROR_SUCCESS) {
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_warn("hls process audio message failed, ignore and disable hls. ret=%d", ret);
|
|
|
|
|
|
|
|
// unpublish, ignore ret.
|
|
|
|
hls->on_unpublish();
|
|
|
|
|
|
|
|
// ignore.
|
|
|
|
ret = ERROR_SUCCESS;
|
|
|
|
}
|
2013-12-14 06:06:32 +00:00
|
|
|
#endif
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2014-04-16 01:28:02 +00:00
|
|
|
#ifdef SRS_AUTO_DVR
|
2014-07-06 10:23:14 +00:00
|
|
|
if ((ret = dvr->on_audio(msg.copy())) != ERROR_SUCCESS) {
|
2014-04-16 01:28:02 +00:00
|
|
|
srs_warn("dvr process audio message failed, ignore and disable dvr. ret=%d", ret);
|
|
|
|
|
|
|
|
// unpublish, ignore ret.
|
|
|
|
dvr->on_unpublish();
|
|
|
|
|
|
|
|
// ignore.
|
|
|
|
ret = ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
// copy to all consumer
|
|
|
|
if (true) {
|
2014-06-22 12:01:25 +00:00
|
|
|
for (int i = 0; i < (int)consumers.size(); i++) {
|
|
|
|
SrsConsumer* consumer = consumers.at(i);
|
2014-07-06 10:23:14 +00:00
|
|
|
SrsSharedPtrMessage* copy = msg.copy();
|
2014-06-25 09:14:11 +00:00
|
|
|
if ((ret = consumer->enqueue(copy, atc, sample_rate, frame_rate, jitter_algorithm)) != ERROR_SUCCESS) {
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_error("dispatch the audio failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
srs_info("dispatch audio success.");
|
|
|
|
}
|
2014-06-22 12:01:25 +00:00
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
// copy to all forwarders.
|
|
|
|
if (true) {
|
|
|
|
std::vector<SrsForwarder*>::iterator it;
|
|
|
|
for (it = forwarders.begin(); it != forwarders.end(); ++it) {
|
|
|
|
SrsForwarder* forwarder = *it;
|
2014-07-06 10:23:14 +00:00
|
|
|
if ((ret = forwarder->on_audio(msg.copy())) != ERROR_SUCCESS) {
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_error("forwarder process audio message failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// cache the sequence header if h264
|
2014-05-13 07:15:25 +00:00
|
|
|
// donot cache the sequence header to gop_cache, return here.
|
2014-07-06 10:23:14 +00:00
|
|
|
if (SrsFlvCodec::audio_is_sequence_header(msg.payload, msg.size)) {
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_freep(cache_sh_audio);
|
2014-07-06 10:23:14 +00:00
|
|
|
cache_sh_audio = msg.copy();
|
2014-07-06 01:59:41 +00:00
|
|
|
|
|
|
|
// parse detail audio codec
|
|
|
|
SrsAvcAacCodec codec;
|
|
|
|
SrsCodecSample sample;
|
2014-07-06 10:23:14 +00:00
|
|
|
if ((ret = codec.audio_aac_demux(msg.payload, msg.size, &sample)) != ERROR_SUCCESS) {
|
2014-07-06 01:59:41 +00:00
|
|
|
srs_error("codec demux audio failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int flv_sample_sizes[] = {8, 16, 0};
|
|
|
|
static int flv_sound_types[] = {1, 2, 0};
|
|
|
|
srs_trace("%dB audio sh, "
|
|
|
|
"codec(%d, profile=%d, %dchannels, %dkbps, %dHZ), "
|
|
|
|
"flv(%dbits, %dchannels, %dHZ)",
|
2014-07-06 10:23:14 +00:00
|
|
|
msg.header.payload_length, codec.audio_codec_id,
|
2014-07-06 01:59:41 +00:00
|
|
|
codec.aac_profile, codec.aac_channels,
|
|
|
|
codec.audio_data_rate / 1000, aac_sample_rates[codec.aac_sample_rate],
|
|
|
|
flv_sample_sizes[sample.sound_size], flv_sound_types[sample.sound_type],
|
|
|
|
flv_sample_rates[sample.sound_rate]);
|
2014-03-18 03:32:58 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// cache the last gop packets
|
2014-07-06 10:23:14 +00:00
|
|
|
if ((ret = gop_cache->cache(&msg)) != ERROR_SUCCESS) {
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_error("shrink gop cache failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_verbose("cache gop success.");
|
|
|
|
|
2014-03-26 08:25:02 +00:00
|
|
|
// if atc, update the sequence header to abs time.
|
|
|
|
if (atc) {
|
|
|
|
if (cache_sh_audio) {
|
2014-07-06 10:23:14 +00:00
|
|
|
cache_sh_audio->header.timestamp = msg.header.timestamp;
|
2014-03-26 08:25:02 +00:00
|
|
|
}
|
|
|
|
if (cache_metadata) {
|
2014-07-06 10:23:14 +00:00
|
|
|
cache_metadata->header.timestamp = msg.header.timestamp;
|
2014-03-26 08:25:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
return ret;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2014-07-06 10:23:14 +00:00
|
|
|
int SrsSource::on_video(SrsMessage* __video)
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-07-06 10:23:14 +00:00
|
|
|
// convert __video to msg, user should not use __video again.
|
|
|
|
// the payload is transfer to msg, and set to NULL in __video.
|
|
|
|
SrsSharedPtrMessage msg;
|
|
|
|
if ((ret = msg.create(__video)) != ERROR_SUCCESS) {
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_error("initialize the video failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_verbose("initialize shared ptr video success.");
|
|
|
|
|
2014-04-15 06:01:57 +00:00
|
|
|
#ifdef SRS_AUTO_HLS
|
2014-07-06 10:23:14 +00:00
|
|
|
if ((ret = hls->on_video(msg.copy())) != ERROR_SUCCESS) {
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_warn("hls process video message failed, ignore and disable hls. ret=%d", ret);
|
|
|
|
|
|
|
|
// unpublish, ignore ret.
|
|
|
|
hls->on_unpublish();
|
|
|
|
|
|
|
|
// ignore.
|
|
|
|
ret = ERROR_SUCCESS;
|
|
|
|
}
|
2013-12-14 06:06:32 +00:00
|
|
|
#endif
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2014-04-16 01:28:02 +00:00
|
|
|
#ifdef SRS_AUTO_DVR
|
2014-07-06 10:23:14 +00:00
|
|
|
if ((ret = dvr->on_video(msg.copy())) != ERROR_SUCCESS) {
|
2014-04-16 01:28:02 +00:00
|
|
|
srs_warn("dvr process video message failed, ignore and disable dvr. ret=%d", ret);
|
|
|
|
|
|
|
|
// unpublish, ignore ret.
|
|
|
|
dvr->on_unpublish();
|
|
|
|
|
|
|
|
// ignore.
|
|
|
|
ret = ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
// copy to all consumer
|
|
|
|
if (true) {
|
2014-06-22 12:01:25 +00:00
|
|
|
for (int i = 0; i < (int)consumers.size(); i++) {
|
|
|
|
SrsConsumer* consumer = consumers.at(i);
|
2014-07-06 10:23:14 +00:00
|
|
|
SrsSharedPtrMessage* copy = msg.copy();
|
2014-06-25 09:14:11 +00:00
|
|
|
if ((ret = consumer->enqueue(copy, atc, sample_rate, frame_rate, jitter_algorithm)) != ERROR_SUCCESS) {
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_error("dispatch the video failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
srs_info("dispatch video success.");
|
|
|
|
}
|
|
|
|
|
|
|
|
// copy to all forwarders.
|
|
|
|
if (true) {
|
|
|
|
std::vector<SrsForwarder*>::iterator it;
|
|
|
|
for (it = forwarders.begin(); it != forwarders.end(); ++it) {
|
|
|
|
SrsForwarder* forwarder = *it;
|
2014-07-06 10:23:14 +00:00
|
|
|
if ((ret = forwarder->on_video(msg.copy())) != ERROR_SUCCESS) {
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_error("forwarder process video message failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// cache the sequence header if h264
|
2014-05-13 07:15:25 +00:00
|
|
|
// donot cache the sequence header to gop_cache, return here.
|
2014-07-06 10:23:14 +00:00
|
|
|
if (SrsFlvCodec::video_is_sequence_header(msg.payload, msg.size)) {
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_freep(cache_sh_video);
|
2014-07-06 10:23:14 +00:00
|
|
|
cache_sh_video = msg.copy();
|
2014-07-06 01:59:41 +00:00
|
|
|
|
|
|
|
// parse detail audio codec
|
|
|
|
SrsAvcAacCodec codec;
|
|
|
|
SrsCodecSample sample;
|
2014-07-06 10:23:14 +00:00
|
|
|
if ((ret = codec.video_avc_demux(msg.payload, msg.size, &sample)) != ERROR_SUCCESS) {
|
2014-07-06 01:59:41 +00:00
|
|
|
srs_error("codec demux video failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_trace("%dB video sh, "
|
|
|
|
"codec(%d, profile=%d, level=%d, %dx%d, %dkbps, %dfps, %ds)",
|
2014-07-06 10:23:14 +00:00
|
|
|
msg.header.payload_length, codec.video_codec_id,
|
2014-07-06 01:59:41 +00:00
|
|
|
codec.avc_profile, codec.avc_level, codec.width, codec.height,
|
|
|
|
codec.video_data_rate / 1000, codec.frame_rate, codec.duration);
|
2014-03-18 03:32:58 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// cache the last gop packets
|
2014-07-06 10:23:14 +00:00
|
|
|
if ((ret = gop_cache->cache(&msg)) != ERROR_SUCCESS) {
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_error("gop cache msg failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_verbose("cache gop success.");
|
|
|
|
|
2014-03-26 08:25:02 +00:00
|
|
|
// if atc, update the sequence header to abs time.
|
|
|
|
if (atc) {
|
|
|
|
if (cache_sh_video) {
|
2014-07-06 10:23:14 +00:00
|
|
|
cache_sh_video->header.timestamp = msg.header.timestamp;
|
2014-03-26 08:25:02 +00:00
|
|
|
}
|
|
|
|
if (cache_metadata) {
|
2014-07-06 10:23:14 +00:00
|
|
|
cache_metadata->header.timestamp = msg.header.timestamp;
|
2014-03-26 08:25:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
return ret;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2014-05-08 06:33:25 +00:00
|
|
|
int SrsSource::on_aggregate(SrsMessage* msg)
|
|
|
|
{
|
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
SrsStream* stream = aggregate_stream;
|
|
|
|
if ((ret = stream->initialize((char*)msg->payload, msg->size)) != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (!stream->empty()) {
|
|
|
|
if (!stream->require(1)) {
|
|
|
|
ret = ERROR_RTMP_AGGREGATE;
|
|
|
|
srs_error("invalid aggregate message type. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
int8_t type = stream->read_1bytes();
|
|
|
|
|
|
|
|
if (!stream->require(3)) {
|
|
|
|
ret = ERROR_RTMP_AGGREGATE;
|
|
|
|
srs_error("invalid aggregate message size. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
int32_t data_size = stream->read_3bytes();
|
|
|
|
|
|
|
|
if (data_size < 0) {
|
|
|
|
ret = ERROR_RTMP_AGGREGATE;
|
|
|
|
srs_error("invalid aggregate message size(negative). ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!stream->require(3)) {
|
|
|
|
ret = ERROR_RTMP_AGGREGATE;
|
|
|
|
srs_error("invalid aggregate message time. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
int32_t timestamp = stream->read_3bytes();
|
|
|
|
|
|
|
|
if (!stream->require(1)) {
|
|
|
|
ret = ERROR_RTMP_AGGREGATE;
|
|
|
|
srs_error("invalid aggregate message time(high). ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
int32_t time_h = stream->read_1bytes();
|
|
|
|
|
|
|
|
timestamp |= time_h<<24;
|
|
|
|
timestamp &= 0x7FFFFFFF;
|
|
|
|
|
|
|
|
if (!stream->require(3)) {
|
|
|
|
ret = ERROR_RTMP_AGGREGATE;
|
|
|
|
srs_error("invalid aggregate message stream_id. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
int32_t stream_id = stream->read_3bytes();
|
|
|
|
|
|
|
|
if (data_size > 0 && !stream->require(data_size)) {
|
|
|
|
ret = ERROR_RTMP_AGGREGATE;
|
|
|
|
srs_error("invalid aggregate message data. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// to common message.
|
|
|
|
SrsCommonMessage __o;
|
|
|
|
SrsMessage& o = __o;
|
|
|
|
|
|
|
|
o.header.message_type = type;
|
|
|
|
o.header.payload_length = data_size;
|
|
|
|
o.header.timestamp_delta = timestamp;
|
|
|
|
o.header.timestamp = timestamp;
|
|
|
|
o.header.stream_id = stream_id;
|
|
|
|
o.header.perfer_cid = msg->header.perfer_cid;
|
|
|
|
|
|
|
|
if (data_size > 0) {
|
|
|
|
o.size = data_size;
|
|
|
|
o.payload = new int8_t[o.size];
|
|
|
|
stream->read_bytes((char*)o.payload, o.size);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!stream->require(4)) {
|
|
|
|
ret = ERROR_RTMP_AGGREGATE;
|
|
|
|
srs_error("invalid aggregate message previous tag size. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
stream->read_4bytes();
|
|
|
|
|
|
|
|
// process parsed message
|
|
|
|
if (o.header.is_audio()) {
|
|
|
|
if ((ret = on_audio(&o)) != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
} else if (o.header.is_video()) {
|
|
|
|
if ((ret = on_video(&o)) != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-04-26 09:16:18 +00:00
|
|
|
int SrsSource::on_publish()
|
2013-12-14 06:06:32 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
// update the request object.
|
2014-04-26 09:16:18 +00:00
|
|
|
srs_assert(_req);
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
_can_publish = false;
|
|
|
|
|
2014-05-27 09:59:59 +00:00
|
|
|
// whatever, the publish thread is the source or edge source,
|
|
|
|
// save its id to srouce id.
|
|
|
|
on_source_id_changed(_srs_context->get_id());
|
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
// create forwarders
|
|
|
|
if ((ret = create_forwarders()) != ERROR_SUCCESS) {
|
|
|
|
srs_error("create forwarders failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-04-15 06:01:57 +00:00
|
|
|
#ifdef SRS_AUTO_TRANSCODE
|
2014-04-26 09:16:18 +00:00
|
|
|
if ((ret = encoder->on_publish(_req)) != ERROR_SUCCESS) {
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_error("start encoder failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
2013-12-14 06:06:32 +00:00
|
|
|
#endif
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2014-04-15 06:01:57 +00:00
|
|
|
#ifdef SRS_AUTO_HLS
|
2014-04-26 09:16:18 +00:00
|
|
|
if ((ret = hls->on_publish(_req)) != ERROR_SUCCESS) {
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_error("start hls failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
2013-12-14 06:06:32 +00:00
|
|
|
#endif
|
2014-04-16 01:28:02 +00:00
|
|
|
|
|
|
|
#ifdef SRS_AUTO_DVR
|
2014-04-26 09:16:18 +00:00
|
|
|
if ((ret = dvr->on_publish(_req)) != ERROR_SUCCESS) {
|
2014-04-16 01:28:02 +00:00
|
|
|
srs_error("start dvr failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#endif
|
2013-12-14 06:06:32 +00:00
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
return ret;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SrsSource::on_unpublish()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
// destroy all forwarders
|
|
|
|
destroy_forwarders();
|
2013-12-14 06:06:32 +00:00
|
|
|
|
2014-04-15 06:01:57 +00:00
|
|
|
#ifdef SRS_AUTO_TRANSCODE
|
2014-03-18 03:32:58 +00:00
|
|
|
encoder->on_unpublish();
|
2013-12-14 06:06:32 +00:00
|
|
|
#endif
|
|
|
|
|
2014-04-15 06:01:57 +00:00
|
|
|
#ifdef SRS_AUTO_HLS
|
2014-03-18 03:32:58 +00:00
|
|
|
hls->on_unpublish();
|
2013-12-14 06:06:32 +00:00
|
|
|
#endif
|
2014-04-16 01:28:02 +00:00
|
|
|
|
|
|
|
#ifdef SRS_AUTO_DVR
|
|
|
|
dvr->on_unpublish();
|
|
|
|
#endif
|
2013-12-14 06:06:32 +00:00
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
gop_cache->clear();
|
2013-12-14 06:06:32 +00:00
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_freep(cache_metadata);
|
|
|
|
frame_rate = sample_rate = 0;
|
|
|
|
|
|
|
|
srs_freep(cache_sh_video);
|
|
|
|
srs_freep(cache_sh_audio);
|
|
|
|
|
2014-05-29 06:16:34 +00:00
|
|
|
srs_info("clear cache/metadata/sequence-headers when unpublish.");
|
|
|
|
srs_trace("cleanup when unpublish");
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
_can_publish = true;
|
2014-05-27 09:59:59 +00:00
|
|
|
_source_id = -1;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int SrsSource::create_consumer(SrsConsumer*& consumer)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
consumer = new SrsConsumer(this);
|
|
|
|
consumers.push_back(consumer);
|
|
|
|
|
2014-04-26 09:16:18 +00:00
|
|
|
double queue_size = _srs_config->get_queue_length(_req->vhost);
|
2014-03-18 03:32:58 +00:00
|
|
|
consumer->set_queue_size(queue_size);
|
|
|
|
|
2014-03-26 08:25:02 +00:00
|
|
|
// if atc, update the sequence header to gop cache time.
|
|
|
|
if (atc && !gop_cache->empty()) {
|
2014-05-13 07:30:20 +00:00
|
|
|
if (cache_metadata) {
|
|
|
|
cache_metadata->header.timestamp = gop_cache->get_start_time();
|
|
|
|
}
|
2014-03-26 08:25:02 +00:00
|
|
|
if (cache_sh_video) {
|
|
|
|
cache_sh_video->header.timestamp = gop_cache->get_start_time();
|
|
|
|
}
|
|
|
|
if (cache_sh_audio) {
|
|
|
|
cache_sh_audio->header.timestamp = gop_cache->get_start_time();
|
|
|
|
}
|
|
|
|
}
|
2014-05-13 07:30:20 +00:00
|
|
|
|
2014-06-25 09:14:11 +00:00
|
|
|
int tba = sample_rate;
|
|
|
|
int tbv = frame_rate;
|
|
|
|
SrsRtmpJitterAlgorithm ag = jitter_algorithm;
|
|
|
|
|
2014-05-13 07:30:20 +00:00
|
|
|
// copy metadata.
|
2014-06-25 09:14:11 +00:00
|
|
|
if (cache_metadata && (ret = consumer->enqueue(cache_metadata->copy(), atc, tba, tbv, ag)) != ERROR_SUCCESS) {
|
2014-05-13 07:30:20 +00:00
|
|
|
srs_error("dispatch metadata failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_info("dispatch metadata success");
|
2014-03-26 08:25:02 +00:00
|
|
|
|
|
|
|
// copy sequence header
|
2014-06-25 09:14:11 +00:00
|
|
|
if (cache_sh_video && (ret = consumer->enqueue(cache_sh_video->copy(), atc, tba, tbv, ag)) != ERROR_SUCCESS) {
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_error("dispatch video sequence header failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_info("dispatch video sequence header success");
|
|
|
|
|
2014-06-25 09:14:11 +00:00
|
|
|
if (cache_sh_audio && (ret = consumer->enqueue(cache_sh_audio->copy(), atc, tba, tbv, ag)) != ERROR_SUCCESS) {
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_error("dispatch audio sequence header failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_info("dispatch audio sequence header success");
|
|
|
|
|
2014-03-26 08:25:02 +00:00
|
|
|
// copy gop cache to client.
|
2014-06-25 09:14:11 +00:00
|
|
|
if ((ret = gop_cache->dump(consumer, atc, tba, tbv, ag)) != ERROR_SUCCESS) {
|
2014-03-18 03:32:58 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_trace("create consumer, queue_size=%.2f, tba=%d, tbv=%d", queue_size, sample_rate, frame_rate);
|
|
|
|
|
|
|
|
return ret;
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SrsSource::on_consumer_destroy(SrsConsumer* consumer)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
std::vector<SrsConsumer*>::iterator it;
|
|
|
|
it = std::find(consumers.begin(), consumers.end(), consumer);
|
|
|
|
if (it != consumers.end()) {
|
|
|
|
consumers.erase(it);
|
|
|
|
}
|
|
|
|
srs_info("handle consumer destroy success.");
|
2014-04-26 13:41:18 +00:00
|
|
|
|
|
|
|
if (consumers.empty()) {
|
2014-04-27 01:29:37 +00:00
|
|
|
play_edge->on_all_client_stop();
|
2014-04-26 13:41:18 +00:00
|
|
|
}
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SrsSource::set_cache(bool enabled)
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
gop_cache->set(enabled);
|
2013-12-14 06:06:32 +00:00
|
|
|
}
|
|
|
|
|
2014-04-26 13:41:18 +00:00
|
|
|
int SrsSource::on_edge_start_play()
|
2014-04-25 08:35:03 +00:00
|
|
|
{
|
2014-04-27 01:29:37 +00:00
|
|
|
return play_edge->on_client_play();
|
|
|
|
}
|
|
|
|
|
|
|
|
int SrsSource::on_edge_start_publish()
|
|
|
|
{
|
|
|
|
return publish_edge->on_client_publish();
|
2014-04-25 08:35:03 +00:00
|
|
|
}
|
|
|
|
|
2014-04-29 06:44:07 +00:00
|
|
|
int SrsSource::on_edge_proxy_publish(SrsMessage* msg)
|
2014-04-27 03:11:15 +00:00
|
|
|
{
|
2014-04-27 06:57:28 +00:00
|
|
|
return publish_edge->on_proxy_publish(msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SrsSource::on_edge_proxy_unpublish()
|
|
|
|
{
|
|
|
|
publish_edge->on_proxy_unpublish();
|
2014-04-27 03:11:15 +00:00
|
|
|
}
|
|
|
|
|
2013-12-15 04:34:22 +00:00
|
|
|
int SrsSource::create_forwarders()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-04-26 09:16:18 +00:00
|
|
|
SrsConfDirective* conf = _srs_config->get_forward(_req->vhost);
|
2014-03-18 03:32:58 +00:00
|
|
|
for (int i = 0; conf && i < (int)conf->args.size(); i++) {
|
|
|
|
std::string forward_server = conf->args.at(i);
|
|
|
|
|
|
|
|
SrsForwarder* forwarder = new SrsForwarder(this);
|
|
|
|
forwarders.push_back(forwarder);
|
|
|
|
|
2014-04-26 09:16:18 +00:00
|
|
|
double queue_size = _srs_config->get_queue_length(_req->vhost);
|
2014-03-18 03:32:58 +00:00
|
|
|
forwarder->set_queue_size(queue_size);
|
|
|
|
|
2014-04-26 09:16:18 +00:00
|
|
|
if ((ret = forwarder->on_publish(_req, forward_server)) != ERROR_SUCCESS) {
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_error("start forwarder failed. "
|
|
|
|
"vhost=%s, app=%s, stream=%s, forward-to=%s",
|
2014-04-26 09:16:18 +00:00
|
|
|
_req->vhost.c_str(), _req->app.c_str(), _req->stream.c_str(),
|
2014-03-18 03:32:58 +00:00
|
|
|
forward_server.c_str());
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2013-12-15 04:34:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SrsSource::destroy_forwarders()
|
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
std::vector<SrsForwarder*>::iterator it;
|
|
|
|
for (it = forwarders.begin(); it != forwarders.end(); ++it) {
|
|
|
|
SrsForwarder* forwarder = *it;
|
|
|
|
forwarder->on_unpublish();
|
|
|
|
srs_freep(forwarder);
|
|
|
|
}
|
|
|
|
forwarders.clear();
|
2013-12-15 04:34:22 +00:00
|
|
|
}
|
|
|
|
|