2020-04-23 09:08:21 +00:00
|
|
|
/**
|
|
|
|
* The MIT License (MIT)
|
|
|
|
*
|
|
|
|
* Copyright (c) 2013-2020 John
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <srs_app_rtp_queue.hpp>
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sstream>
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
#include <srs_kernel_error.hpp>
|
|
|
|
#include <srs_kernel_rtp.hpp>
|
|
|
|
#include <srs_kernel_utility.hpp>
|
|
|
|
#include <srs_app_utility.hpp>
|
|
|
|
|
|
|
|
SrsRtpNackInfo::SrsRtpNackInfo()
|
|
|
|
{
|
|
|
|
generate_time_ = srs_update_system_time();
|
|
|
|
pre_req_nack_time_ = 0;
|
|
|
|
req_nack_count_ = 0;
|
|
|
|
}
|
|
|
|
|
2020-04-30 00:24:15 +00:00
|
|
|
SrsRtpNackForReceiver::SrsRtpNackForReceiver(SrsRtpQueue* rtp_queue, size_t queue_size)
|
2020-04-23 09:08:21 +00:00
|
|
|
{
|
2020-04-24 08:19:08 +00:00
|
|
|
max_queue_size_ = queue_size;
|
2020-04-23 09:08:21 +00:00
|
|
|
rtp_queue_ = rtp_queue;
|
|
|
|
pre_check_time_ = 0;
|
|
|
|
|
2020-04-24 08:19:08 +00:00
|
|
|
srs_info("max_queue_size=%u, nack opt: max_count=%d, max_alive_time=%us, first_nack_interval=%ld, nack_interval=%ld"
|
|
|
|
max_queue_size_, opts_.max_count, opts_.max_alive_time, opts.first_nack_interval, opts_.nack_interval);
|
2020-04-23 09:08:21 +00:00
|
|
|
}
|
|
|
|
|
2020-04-30 00:24:15 +00:00
|
|
|
SrsRtpNackForReceiver::~SrsRtpNackForReceiver()
|
2020-04-23 09:08:21 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2020-04-30 00:24:15 +00:00
|
|
|
void SrsRtpNackForReceiver::insert(uint16_t seq)
|
2020-04-23 09:08:21 +00:00
|
|
|
{
|
|
|
|
// FIXME: full, drop packet, and request key frame.
|
2020-05-04 12:42:30 +00:00
|
|
|
queue_[seq] = SrsRtpNackInfo();
|
2020-04-23 09:08:21 +00:00
|
|
|
}
|
|
|
|
|
2020-04-30 00:24:15 +00:00
|
|
|
void SrsRtpNackForReceiver::remove(uint16_t seq)
|
2020-04-23 09:08:21 +00:00
|
|
|
{
|
|
|
|
queue_.erase(seq);
|
|
|
|
}
|
|
|
|
|
2020-04-30 00:24:15 +00:00
|
|
|
SrsRtpNackInfo* SrsRtpNackForReceiver::find(uint16_t seq)
|
2020-04-23 09:08:21 +00:00
|
|
|
{
|
|
|
|
std::map<uint16_t, SrsRtpNackInfo>::iterator iter = queue_.find(seq);
|
|
|
|
|
|
|
|
if (iter == queue_.end()) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return &(iter->second);
|
|
|
|
}
|
|
|
|
|
2020-04-30 00:24:15 +00:00
|
|
|
void SrsRtpNackForReceiver::check_queue_size()
|
2020-04-23 09:08:21 +00:00
|
|
|
{
|
2020-04-24 08:19:08 +00:00
|
|
|
if (queue_.size() >= max_queue_size_) {
|
|
|
|
rtp_queue_->notify_nack_list_full();
|
2020-04-23 09:08:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-30 00:24:15 +00:00
|
|
|
void SrsRtpNackForReceiver::get_nack_seqs(vector<uint16_t>& seqs)
|
2020-04-23 09:08:21 +00:00
|
|
|
{
|
|
|
|
srs_utime_t now = srs_update_system_time();
|
2020-05-04 12:42:30 +00:00
|
|
|
srs_utime_t interval = now - pre_check_time_;
|
2020-04-23 09:08:21 +00:00
|
|
|
if (interval < opts_.nack_interval / 2) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
pre_check_time_ = now;
|
2020-05-04 12:42:30 +00:00
|
|
|
|
2020-04-23 09:08:21 +00:00
|
|
|
std::map<uint16_t, SrsRtpNackInfo>::iterator iter = queue_.begin();
|
|
|
|
while (iter != queue_.end()) {
|
|
|
|
const uint16_t& seq = iter->first;
|
|
|
|
SrsRtpNackInfo& nack_info = iter->second;
|
|
|
|
|
|
|
|
int alive_time = now - nack_info.generate_time_;
|
|
|
|
if (alive_time > opts_.max_alive_time || nack_info.req_nack_count_ > opts_.max_count) {
|
|
|
|
rtp_queue_->notify_drop_seq(seq);
|
|
|
|
queue_.erase(iter++);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO:Statistics unorder packet.
|
|
|
|
if (now - nack_info.generate_time_ < opts_.first_nack_interval) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (now - nack_info.pre_req_nack_time_ >= opts_.nack_interval && nack_info.req_nack_count_ <= opts_.max_count) {
|
|
|
|
++nack_info.req_nack_count_;
|
|
|
|
nack_info.pre_req_nack_time_ = now;
|
|
|
|
seqs.push_back(seq);
|
|
|
|
}
|
|
|
|
|
|
|
|
++iter;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-30 00:24:15 +00:00
|
|
|
void SrsRtpNackForReceiver::update_rtt(int rtt)
|
2020-04-23 09:08:21 +00:00
|
|
|
{
|
2020-04-23 16:06:59 +00:00
|
|
|
rtt_ = rtt * SRS_UTIME_MILLISECONDS;
|
2020-04-23 09:08:21 +00:00
|
|
|
// FIXME: limit min and max value.
|
|
|
|
opts_.nack_interval = rtt_;
|
|
|
|
}
|
|
|
|
|
2020-05-05 00:08:03 +00:00
|
|
|
SrsRtpQueue::SrsRtpQueue()
|
2020-04-29 11:07:44 +00:00
|
|
|
{
|
2020-04-23 09:08:21 +00:00
|
|
|
jitter_ = 0;
|
2020-04-29 11:07:44 +00:00
|
|
|
last_trans_time_ = -1;
|
2020-04-23 09:08:21 +00:00
|
|
|
|
|
|
|
pre_number_of_packet_received_ = 0;
|
|
|
|
pre_number_of_packet_lossed_ = 0;
|
|
|
|
|
|
|
|
num_of_packet_received_ = 0;
|
|
|
|
number_of_packet_lossed_ = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
SrsRtpQueue::~SrsRtpQueue()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2020-05-05 00:08:03 +00:00
|
|
|
uint8_t SrsRtpQueue::get_fraction_lost()
|
|
|
|
{
|
|
|
|
int64_t total = (number_of_packet_lossed_ - pre_number_of_packet_lossed_ + num_of_packet_received_ - pre_number_of_packet_received_);
|
|
|
|
uint8_t loss = 0;
|
|
|
|
if (total > 0) {
|
|
|
|
loss = (number_of_packet_lossed_ - pre_number_of_packet_lossed_) * 256 / total;
|
|
|
|
}
|
|
|
|
|
|
|
|
pre_number_of_packet_lossed_ = number_of_packet_lossed_;
|
|
|
|
pre_number_of_packet_received_ = num_of_packet_received_;
|
|
|
|
|
|
|
|
return loss;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t SrsRtpQueue::get_cumulative_number_of_packets_lost()
|
|
|
|
{
|
|
|
|
return number_of_packet_lossed_;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t SrsRtpQueue::get_interarrival_jitter()
|
|
|
|
{
|
|
|
|
return static_cast<uint32_t>(jitter_);
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_error_t SrsRtpQueue::on_consume(SrsRtpNackForReceiver* nack, SrsRtpPacket2* pkt)
|
2020-04-23 09:08:21 +00:00
|
|
|
{
|
|
|
|
srs_error_t err = srs_success;
|
|
|
|
|
2020-04-27 05:45:50 +00:00
|
|
|
// TODO: FIXME: Update time for each packet, may hurt performance.
|
2020-04-23 09:08:21 +00:00
|
|
|
srs_utime_t now = srs_update_system_time();
|
|
|
|
|
2020-04-30 01:33:21 +00:00
|
|
|
uint16_t seq = pkt->rtp_header.get_sequence();
|
2020-05-04 12:42:30 +00:00
|
|
|
|
|
|
|
SrsRtpNackInfo* nack_info = NULL;
|
|
|
|
if (nack) {
|
|
|
|
nack_info = nack->find(seq);
|
|
|
|
}
|
|
|
|
|
2020-04-29 11:07:44 +00:00
|
|
|
if (nack_info) {
|
|
|
|
int nack_rtt = nack_info->req_nack_count_ ? ((now - nack_info->pre_req_nack_time_) / SRS_UTIME_MILLISECONDS) : 0;
|
|
|
|
(void)nack_rtt;
|
2020-05-02 02:07:55 +00:00
|
|
|
nack->remove(seq);
|
2020-04-29 11:07:44 +00:00
|
|
|
}
|
2020-04-23 09:08:21 +00:00
|
|
|
|
2020-04-29 11:07:44 +00:00
|
|
|
// Calc jitter time, ignore nack packets.
|
|
|
|
// TODO: FIXME: Covert time to srs_utime_t.
|
|
|
|
if (last_trans_time_ == -1) {
|
2020-04-30 01:33:21 +00:00
|
|
|
last_trans_time_ = now / 1000 - pkt->rtp_header.get_timestamp() / 90;
|
2020-04-29 11:07:44 +00:00
|
|
|
} else if (!nack_info) {
|
2020-04-30 01:33:21 +00:00
|
|
|
int trans_time = now / 1000 - pkt->rtp_header.get_timestamp() / 90;
|
2020-04-23 09:08:21 +00:00
|
|
|
|
2020-04-29 11:07:44 +00:00
|
|
|
int cur_jitter = trans_time - last_trans_time_;
|
|
|
|
if (cur_jitter < 0) {
|
|
|
|
cur_jitter = -cur_jitter;
|
2020-04-23 09:08:21 +00:00
|
|
|
}
|
2020-04-29 11:07:44 +00:00
|
|
|
|
|
|
|
last_trans_time_ = trans_time;
|
|
|
|
|
|
|
|
jitter_ = (jitter_ * 15.0 / 16.0) + (static_cast<double>(cur_jitter) / 16.0);
|
2020-04-23 09:08:21 +00:00
|
|
|
}
|
|
|
|
|
2020-05-05 00:08:03 +00:00
|
|
|
// OK, got new RTP packet.
|
2020-04-29 11:07:44 +00:00
|
|
|
if (!nack_info) {
|
|
|
|
++num_of_packet_received_;
|
|
|
|
}
|
|
|
|
|
2020-04-23 09:08:21 +00:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2020-05-03 11:09:48 +00:00
|
|
|
void SrsRtpQueue::insert_into_nack_list(SrsRtpNackForReceiver* nack, uint16_t first, uint16_t last)
|
2020-04-23 09:08:21 +00:00
|
|
|
{
|
2020-05-04 12:42:30 +00:00
|
|
|
if (!nack) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-05-03 11:09:48 +00:00
|
|
|
for (uint16_t s = first; s != last; ++s) {
|
2020-05-02 02:07:55 +00:00
|
|
|
nack->insert(s);
|
2020-04-23 09:08:21 +00:00
|
|
|
++number_of_packet_lossed_;
|
|
|
|
}
|
|
|
|
|
2020-05-02 02:07:55 +00:00
|
|
|
nack->check_queue_size();
|
2020-04-23 09:08:21 +00:00
|
|
|
}
|
|
|
|
|
2020-05-05 00:08:03 +00:00
|
|
|
SrsRtpAudioQueue::SrsRtpAudioQueue(int capacity)
|
2020-05-02 12:57:36 +00:00
|
|
|
{
|
2020-05-05 00:08:03 +00:00
|
|
|
queue_ = new SrsRtpRingBuffer<SrsRtpPacket2*>(capacity);
|
2020-05-02 12:57:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SrsRtpAudioQueue::~SrsRtpAudioQueue()
|
|
|
|
{
|
2020-05-05 00:08:03 +00:00
|
|
|
srs_freep(queue_);
|
2020-05-02 12:57:36 +00:00
|
|
|
}
|
|
|
|
|
2020-05-03 09:57:07 +00:00
|
|
|
void SrsRtpAudioQueue::notify_drop_seq(uint16_t seq)
|
|
|
|
{
|
2020-05-03 11:09:48 +00:00
|
|
|
uint16_t next = seq + 1;
|
|
|
|
if (srs_rtp_seq_distance(queue_->end, seq) > 0) {
|
|
|
|
seq = queue_->end;
|
|
|
|
}
|
|
|
|
srs_trace("nack drop seq=%u, drop range [%u, %u, %u]", seq, queue_->begin, next, queue_->end);
|
|
|
|
|
|
|
|
queue_->advance_to(next);
|
2020-05-03 09:57:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SrsRtpAudioQueue::notify_nack_list_full()
|
|
|
|
{
|
|
|
|
// TODO: FIXME: Maybe we should not drop all packets.
|
2020-05-03 11:09:48 +00:00
|
|
|
queue_->advance_to(queue_->end);
|
2020-05-03 09:57:07 +00:00
|
|
|
}
|
|
|
|
|
2020-05-05 00:08:03 +00:00
|
|
|
uint32_t SrsRtpAudioQueue::get_extended_highest_sequence()
|
|
|
|
{
|
|
|
|
return queue_->get_extended_highest_sequence();
|
|
|
|
}
|
|
|
|
|
2020-05-04 12:42:30 +00:00
|
|
|
srs_error_t SrsRtpAudioQueue::consume(SrsRtpNackForReceiver* nack, SrsRtpPacket2* pkt)
|
|
|
|
{
|
2020-05-05 00:08:03 +00:00
|
|
|
srs_error_t err = srs_success;
|
|
|
|
|
|
|
|
uint16_t seq = pkt->rtp_header.get_sequence();
|
|
|
|
|
|
|
|
SrsRtpNackInfo* nack_info = NULL;
|
|
|
|
if (nack) {
|
|
|
|
nack_info = nack->find(seq);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((err = SrsRtpQueue::on_consume(nack, pkt)) != srs_success) {
|
2020-05-05 00:24:49 +00:00
|
|
|
return srs_error_wrap(err, "consume audio");
|
2020-05-05 00:08:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// OK, we got one new RTP packet, which is not in NACK.
|
|
|
|
if (!nack_info) {
|
|
|
|
uint16_t nack_first = 0, nack_last = 0;
|
|
|
|
if (!queue_->update(seq, nack_first, nack_last)) {
|
|
|
|
srs_warn("too old seq %u, range [%u, %u]", seq, queue_->begin, queue_->end);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nack && srs_rtp_seq_distance(nack_first, nack_last) > 0) {
|
|
|
|
srs_trace("update seq=%u, nack range [%u, %u]", seq, nack_first, nack_last);
|
|
|
|
insert_into_nack_list(nack, nack_first, nack_last);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Save packet at the position seq.
|
|
|
|
queue_->set(seq, pkt);
|
|
|
|
|
|
|
|
return err;
|
2020-05-04 12:42:30 +00:00
|
|
|
}
|
|
|
|
|
2020-05-03 06:28:51 +00:00
|
|
|
void SrsRtpAudioQueue::collect_frames(SrsRtpNackForReceiver* nack, vector<SrsRtpPacket2*>& frames)
|
2020-05-02 12:57:36 +00:00
|
|
|
{
|
2020-05-03 11:09:48 +00:00
|
|
|
// When done, next point to the next available packet.
|
|
|
|
uint16_t next = queue_->begin;
|
2020-05-02 12:57:36 +00:00
|
|
|
|
2020-05-04 22:41:19 +00:00
|
|
|
// If nack disabled, we ignore any empty packet.
|
|
|
|
if (!nack) {
|
|
|
|
for (; next != queue_->end; ++next) {
|
|
|
|
SrsRtpPacket2* pkt = queue_->at(next);
|
|
|
|
if (pkt) {
|
|
|
|
frames.push_back(pkt);
|
2020-05-04 12:42:30 +00:00
|
|
|
}
|
|
|
|
}
|
2020-05-04 22:41:19 +00:00
|
|
|
} else {
|
|
|
|
for (; next != queue_->end; ++next) {
|
|
|
|
SrsRtpPacket2* pkt = queue_->at(next);
|
2020-05-04 12:42:30 +00:00
|
|
|
|
2020-05-04 22:41:19 +00:00
|
|
|
// TODO: FIXME: Should not wait for NACK packets.
|
|
|
|
// Not found or in NACK, stop collecting frame.
|
|
|
|
if (!pkt || nack->find(next) != NULL) {
|
|
|
|
srs_trace("wait for nack seq=%u", next);
|
|
|
|
break;
|
|
|
|
}
|
2020-05-02 12:57:36 +00:00
|
|
|
|
2020-05-04 22:41:19 +00:00
|
|
|
frames.push_back(pkt);
|
|
|
|
}
|
2020-05-02 12:57:36 +00:00
|
|
|
}
|
|
|
|
|
2020-05-04 22:41:19 +00:00
|
|
|
// Reap packets from begin to next.
|
2020-05-03 11:09:48 +00:00
|
|
|
if (next != queue_->begin) {
|
2020-05-02 12:57:36 +00:00
|
|
|
// Reset the range of packets to NULL in buffer.
|
2020-05-03 11:09:48 +00:00
|
|
|
queue_->reset(queue_->begin, next);
|
2020-05-02 12:57:36 +00:00
|
|
|
|
2020-05-03 11:09:48 +00:00
|
|
|
srs_verbose("RTC collect audio [%u, %u, %u]", queue_->begin, next, queue_->end);
|
2020-05-02 12:57:36 +00:00
|
|
|
queue_->advance_to(next);
|
|
|
|
}
|
2020-05-03 06:28:51 +00:00
|
|
|
|
|
|
|
// For audio, if overflow, clear all packets.
|
2020-05-04 12:42:30 +00:00
|
|
|
// TODO: FIXME: Should notify nack?
|
2020-05-03 06:28:51 +00:00
|
|
|
if (queue_->overflow()) {
|
2020-05-03 11:09:48 +00:00
|
|
|
queue_->advance_to(queue_->end);
|
2020-05-03 06:28:51 +00:00
|
|
|
}
|
2020-05-02 12:57:36 +00:00
|
|
|
}
|
|
|
|
|
2020-05-05 00:24:49 +00:00
|
|
|
SrsRtpVideoPacket::SrsRtpVideoPacket()
|
|
|
|
{
|
|
|
|
video_is_first_packet = false;
|
|
|
|
video_is_last_packet = false;
|
|
|
|
video_is_idr = false;
|
|
|
|
|
|
|
|
pkt = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
SrsRtpVideoPacket::~SrsRtpVideoPacket()
|
|
|
|
{
|
|
|
|
srs_freep(pkt);
|
|
|
|
}
|
|
|
|
|
|
|
|
SrsRtpPacket2* SrsRtpVideoPacket::detach()
|
|
|
|
{
|
|
|
|
SrsRtpPacket2* p = pkt;
|
|
|
|
pkt = NULL;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2020-05-05 00:08:03 +00:00
|
|
|
SrsRtpVideoQueue::SrsRtpVideoQueue(int capacity)
|
2020-05-02 12:57:36 +00:00
|
|
|
{
|
2020-05-03 02:15:54 +00:00
|
|
|
request_key_frame_ = false;
|
2020-05-05 00:24:49 +00:00
|
|
|
queue_ = new SrsRtpRingBuffer<SrsRtpVideoPacket*>(capacity);
|
2020-05-02 12:57:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SrsRtpVideoQueue::~SrsRtpVideoQueue()
|
|
|
|
{
|
2020-05-05 00:08:03 +00:00
|
|
|
srs_freep(queue_);
|
2020-05-02 12:57:36 +00:00
|
|
|
}
|
|
|
|
|
2020-05-03 09:57:07 +00:00
|
|
|
void SrsRtpVideoQueue::notify_drop_seq(uint16_t seq)
|
|
|
|
{
|
2020-05-03 11:09:48 +00:00
|
|
|
// If not found start frame, return the end, and we will clear queue.
|
|
|
|
uint16_t next = next_start_of_frame(seq);
|
|
|
|
srs_trace("nack drop seq=%u, drop range [%u, %u, %u]", seq, queue_->begin, next, queue_->end);
|
2020-05-03 09:57:07 +00:00
|
|
|
|
2020-05-03 11:09:48 +00:00
|
|
|
queue_->advance_to(next);
|
2020-05-03 09:57:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SrsRtpVideoQueue::notify_nack_list_full()
|
|
|
|
{
|
2020-05-03 11:09:48 +00:00
|
|
|
// If not found start frame, return the end, and we will clear queue.
|
2020-05-03 09:57:07 +00:00
|
|
|
uint16_t next = next_keyframe();
|
2020-05-03 11:09:48 +00:00
|
|
|
srs_trace("nack overflow, drop range [%u, %u, %u]", queue_->begin, next, queue_->end);
|
2020-05-03 09:57:07 +00:00
|
|
|
|
2020-05-03 11:09:48 +00:00
|
|
|
queue_->advance_to(next);
|
2020-05-03 09:57:07 +00:00
|
|
|
}
|
|
|
|
|
2020-05-05 00:08:03 +00:00
|
|
|
uint32_t SrsRtpVideoQueue::get_extended_highest_sequence()
|
|
|
|
{
|
|
|
|
return queue_->get_extended_highest_sequence();
|
|
|
|
}
|
|
|
|
|
2020-05-03 09:41:00 +00:00
|
|
|
srs_error_t SrsRtpVideoQueue::consume(SrsRtpNackForReceiver* nack, SrsRtpPacket2* pkt)
|
2020-05-02 12:57:36 +00:00
|
|
|
{
|
2020-05-03 09:41:00 +00:00
|
|
|
srs_error_t err = srs_success;
|
|
|
|
|
2020-05-05 00:24:49 +00:00
|
|
|
SrsRtpVideoPacket* vpkt = new SrsRtpVideoPacket();
|
|
|
|
vpkt->pkt = pkt;
|
|
|
|
|
2020-05-03 09:41:00 +00:00
|
|
|
uint8_t v = (uint8_t)pkt->nalu_type;
|
|
|
|
if (v == kFuA) {
|
|
|
|
SrsRtpFUAPayload2* payload = dynamic_cast<SrsRtpFUAPayload2*>(pkt->payload);
|
|
|
|
if (!payload) {
|
2020-05-05 00:24:49 +00:00
|
|
|
srs_freep(pkt); srs_freep(vpkt);
|
2020-05-03 09:41:00 +00:00
|
|
|
return srs_error_new(ERROR_RTC_RTP_MUXER, "FU-A payload");
|
|
|
|
}
|
|
|
|
|
2020-05-05 00:24:49 +00:00
|
|
|
vpkt->video_is_first_packet = payload->start;
|
|
|
|
vpkt->video_is_last_packet = payload->end;
|
|
|
|
vpkt->video_is_idr = (payload->nalu_type == SrsAvcNaluTypeIDR);
|
2020-05-03 09:41:00 +00:00
|
|
|
} else {
|
2020-05-05 00:24:49 +00:00
|
|
|
vpkt->video_is_first_packet = true;
|
|
|
|
vpkt->video_is_last_packet = true;
|
2020-05-03 09:41:00 +00:00
|
|
|
|
|
|
|
if (v == kStapA) {
|
2020-05-05 00:24:49 +00:00
|
|
|
vpkt->video_is_idr = true;
|
2020-05-03 09:41:00 +00:00
|
|
|
} else {
|
2020-05-05 00:24:49 +00:00
|
|
|
vpkt->video_is_idr = (pkt->nalu_type == SrsAvcNaluTypeIDR);
|
2020-05-03 09:41:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-05 00:08:03 +00:00
|
|
|
uint16_t seq = pkt->rtp_header.get_sequence();
|
|
|
|
|
|
|
|
SrsRtpNackInfo* nack_info = NULL;
|
|
|
|
if (nack) {
|
|
|
|
nack_info = nack->find(seq);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((err = SrsRtpQueue::on_consume(nack, pkt)) != srs_success) {
|
2020-05-05 00:24:49 +00:00
|
|
|
srs_freep(pkt); srs_freep(vpkt);
|
|
|
|
return srs_error_wrap(err, "consume video");
|
2020-05-03 09:41:00 +00:00
|
|
|
}
|
|
|
|
|
2020-05-05 00:08:03 +00:00
|
|
|
// OK, we got one new RTP packet, which is not in NACK.
|
|
|
|
if (!nack_info) {
|
|
|
|
uint16_t nack_first = 0, nack_last = 0;
|
|
|
|
if (!queue_->update(seq, nack_first, nack_last)) {
|
|
|
|
srs_warn("too old seq %u, range [%u, %u]", seq, queue_->begin, queue_->end);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nack && srs_rtp_seq_distance(nack_first, nack_last) > 0) {
|
|
|
|
srs_trace("update seq=%u, nack range [%u, %u]", seq, nack_first, nack_last);
|
|
|
|
insert_into_nack_list(nack, nack_first, nack_last);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Save packet at the position seq.
|
2020-05-05 00:24:49 +00:00
|
|
|
queue_->set(seq, vpkt);
|
2020-05-05 00:08:03 +00:00
|
|
|
|
2020-05-03 09:41:00 +00:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SrsRtpVideoQueue::collect_frames(SrsRtpNackForReceiver* nack, std::vector<SrsRtpPacket2*>& frames)
|
|
|
|
{
|
2020-05-03 11:09:48 +00:00
|
|
|
while (true) {
|
2020-05-03 09:41:00 +00:00
|
|
|
SrsRtpPacket2* pkt = NULL;
|
2020-05-03 11:09:48 +00:00
|
|
|
collect_frame(nack, &pkt);
|
2020-05-03 09:41:00 +00:00
|
|
|
if (!pkt) {
|
2020-05-03 11:09:48 +00:00
|
|
|
break;
|
2020-05-03 09:41:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
frames.push_back(pkt);
|
|
|
|
}
|
2020-05-02 12:57:36 +00:00
|
|
|
|
2020-05-03 05:37:04 +00:00
|
|
|
if (queue_->overflow()) {
|
|
|
|
on_overflow(nack);
|
2020-05-02 12:57:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-03 02:15:54 +00:00
|
|
|
bool SrsRtpVideoQueue::should_request_key_frame()
|
|
|
|
{
|
|
|
|
if (request_key_frame_) {
|
|
|
|
request_key_frame_ = false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return request_key_frame_;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SrsRtpVideoQueue::request_keyframe()
|
|
|
|
{
|
|
|
|
request_key_frame_ = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SrsRtpVideoQueue::on_overflow(SrsRtpNackForReceiver* nack)
|
|
|
|
{
|
2020-05-03 11:09:48 +00:00
|
|
|
// If not found start frame, return the end, and we will clear queue.
|
|
|
|
uint16_t next = next_start_of_frame(queue_->begin);
|
|
|
|
srs_trace("on overflow, remove range [%u, %u, %u]", queue_->begin, next, queue_->end);
|
2020-05-03 02:15:54 +00:00
|
|
|
|
2020-05-03 11:09:48 +00:00
|
|
|
for (uint16_t s = queue_->begin; s != next; ++s) {
|
2020-05-04 12:42:30 +00:00
|
|
|
if (nack) {
|
|
|
|
nack->remove(s);
|
|
|
|
}
|
2020-05-03 02:15:54 +00:00
|
|
|
queue_->remove(s);
|
|
|
|
}
|
|
|
|
|
2020-05-03 11:09:48 +00:00
|
|
|
queue_->advance_to(next);
|
2020-05-03 02:15:54 +00:00
|
|
|
}
|
|
|
|
|
2020-05-02 12:57:36 +00:00
|
|
|
// TODO: FIXME: Should refer to the FU-A original video frame, to avoid finding for each packet.
|
2020-05-03 11:09:48 +00:00
|
|
|
void SrsRtpVideoQueue::collect_frame(SrsRtpNackForReceiver* nack, SrsRtpPacket2** ppkt)
|
2020-05-02 12:57:36 +00:00
|
|
|
{
|
|
|
|
bool found = false;
|
2020-05-05 00:24:49 +00:00
|
|
|
vector<SrsRtpVideoPacket*> frame;
|
2020-05-03 09:41:00 +00:00
|
|
|
|
2020-05-03 11:09:48 +00:00
|
|
|
// When done, next point to the next available packet.
|
|
|
|
uint16_t next = queue_->begin;
|
2020-05-02 01:15:49 +00:00
|
|
|
|
2020-05-04 22:41:19 +00:00
|
|
|
// If nack disabled, we ignore any empty packet.
|
|
|
|
if (!nack) {
|
|
|
|
for (; next != queue_->end; ++next) {
|
2020-05-05 00:24:49 +00:00
|
|
|
SrsRtpVideoPacket* vpkt = queue_->at(next);
|
|
|
|
if (!vpkt) {
|
2020-05-04 12:42:30 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-05-05 00:24:49 +00:00
|
|
|
if (frame.empty() && !vpkt->video_is_first_packet) {
|
2020-05-04 12:42:30 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-05-05 00:24:49 +00:00
|
|
|
frame.push_back(vpkt);
|
2020-05-04 12:42:30 +00:00
|
|
|
|
2020-05-05 00:24:49 +00:00
|
|
|
if (vpkt->pkt->rtp_header.get_marker() || vpkt->video_is_last_packet) {
|
2020-05-04 12:42:30 +00:00
|
|
|
found = true;
|
|
|
|
next++;
|
|
|
|
break;
|
|
|
|
}
|
2020-05-02 01:48:04 +00:00
|
|
|
}
|
2020-05-04 22:41:19 +00:00
|
|
|
} else {
|
|
|
|
for (; next != queue_->end; ++next) {
|
2020-05-05 00:24:49 +00:00
|
|
|
SrsRtpVideoPacket* vpkt = queue_->at(next);
|
2020-05-04 22:41:19 +00:00
|
|
|
|
|
|
|
// TODO: FIXME: Should not wait for NACK packets.
|
|
|
|
// Not found or in NACK, stop collecting frame.
|
2020-05-05 00:24:49 +00:00
|
|
|
if (!vpkt || nack->find(next) != NULL) {
|
2020-05-04 22:41:19 +00:00
|
|
|
srs_trace("wait for nack seq=%u", next);
|
|
|
|
return;
|
|
|
|
}
|
2020-05-02 01:15:49 +00:00
|
|
|
|
2020-05-04 22:41:19 +00:00
|
|
|
// Ignore when the first packet not the start.
|
2020-05-05 00:24:49 +00:00
|
|
|
if (frame.empty() && !vpkt->video_is_first_packet) {
|
2020-05-04 22:41:19 +00:00
|
|
|
return;
|
|
|
|
}
|
2020-04-23 09:08:21 +00:00
|
|
|
|
2020-05-04 22:41:19 +00:00
|
|
|
// OK, collect packet to frame.
|
2020-05-05 00:24:49 +00:00
|
|
|
frame.push_back(vpkt);
|
2020-05-02 12:57:36 +00:00
|
|
|
|
2020-05-04 22:41:19 +00:00
|
|
|
// Done, we got the last packet of frame.
|
|
|
|
// @remark Note that the STAP-A is marker false and it's the last packet.
|
2020-05-05 00:24:49 +00:00
|
|
|
if (vpkt->pkt->rtp_header.get_marker() || vpkt->video_is_last_packet) {
|
2020-05-04 22:41:19 +00:00
|
|
|
found = true;
|
|
|
|
next++;
|
|
|
|
break;
|
|
|
|
}
|
2020-04-23 09:08:21 +00:00
|
|
|
}
|
|
|
|
}
|
2020-05-02 12:57:36 +00:00
|
|
|
|
2020-05-03 09:41:00 +00:00
|
|
|
if (!found || frame.empty()) {
|
|
|
|
return;
|
2020-05-02 12:57:36 +00:00
|
|
|
}
|
|
|
|
|
2020-05-03 11:09:48 +00:00
|
|
|
if (next != queue_->begin) {
|
2020-05-02 12:57:36 +00:00
|
|
|
// Reset the range of packets to NULL in buffer.
|
2020-05-03 11:09:48 +00:00
|
|
|
queue_->reset(queue_->begin, next);
|
2020-05-02 12:57:36 +00:00
|
|
|
|
2020-05-03 11:09:48 +00:00
|
|
|
srs_verbose("RTC collect video [%u, %u, %u]", queue_->begin, next, queue_->end);
|
2020-05-02 12:57:36 +00:00
|
|
|
queue_->advance_to(next);
|
|
|
|
}
|
2020-05-03 09:41:00 +00:00
|
|
|
|
|
|
|
// Merge packets to one packet.
|
2020-05-03 11:09:48 +00:00
|
|
|
covert_frame(frame, ppkt);
|
2020-05-05 00:24:49 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < (int)frame.size(); i++) {
|
|
|
|
SrsRtpVideoPacket* pkt = frame[i];
|
|
|
|
srs_freep(pkt);
|
|
|
|
}
|
2020-05-03 09:41:00 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-05-05 00:24:49 +00:00
|
|
|
void SrsRtpVideoQueue::covert_frame(std::vector<SrsRtpVideoPacket*>& frame, SrsRtpPacket2** ppkt)
|
2020-05-03 09:41:00 +00:00
|
|
|
{
|
|
|
|
if (frame.size() == 1) {
|
2020-05-05 00:24:49 +00:00
|
|
|
*ppkt = frame[0]->detach();
|
2020-05-03 09:41:00 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If more than one packet in a frame, it must be FU-A.
|
2020-05-05 00:24:49 +00:00
|
|
|
SrsRtpPacket2* head = frame.at(0)->pkt;
|
2020-05-03 09:41:00 +00:00
|
|
|
SrsAvcNaluType nalu_type = head->nalu_type;
|
|
|
|
|
|
|
|
// Covert FU-A to one RAW RTP packet.
|
|
|
|
int nn_nalus = 0;
|
|
|
|
for (size_t i = 0; i < frame.size(); ++i) {
|
2020-05-05 00:24:49 +00:00
|
|
|
SrsRtpVideoPacket* vpkt = frame[i];
|
|
|
|
SrsRtpFUAPayload2* payload = dynamic_cast<SrsRtpFUAPayload2*>(vpkt->pkt->payload);
|
2020-05-03 09:41:00 +00:00
|
|
|
if (!payload) {
|
2020-05-05 00:24:49 +00:00
|
|
|
nn_nalus = 0; break;
|
2020-05-03 09:41:00 +00:00
|
|
|
}
|
2020-05-05 00:24:49 +00:00
|
|
|
|
2020-05-03 09:41:00 +00:00
|
|
|
nn_nalus += payload->size;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Invalid packets, ignore.
|
|
|
|
if (nalu_type != (SrsAvcNaluType)kFuA || !nn_nalus) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Merge to one RAW RTP packet.
|
|
|
|
// TODO: FIXME: Should covert to multiple NALU RTP packet to avoid copying.
|
|
|
|
SrsRtpPacket2* pkt = new SrsRtpPacket2();
|
|
|
|
pkt->rtp_header = head->rtp_header;
|
2020-05-04 06:47:58 +00:00
|
|
|
pkt->padding = head->padding;
|
2020-05-03 09:41:00 +00:00
|
|
|
|
|
|
|
SrsRtpFUAPayload2* head_payload = dynamic_cast<SrsRtpFUAPayload2*>(head->payload);
|
|
|
|
pkt->nalu_type = head_payload->nalu_type;
|
|
|
|
|
|
|
|
SrsRtpRawPayload* payload = pkt->reuse_raw();
|
|
|
|
payload->nn_payload = nn_nalus + 1;
|
|
|
|
payload->payload = new char[payload->nn_payload];
|
|
|
|
|
|
|
|
SrsBuffer buf(payload->payload, payload->nn_payload);
|
|
|
|
|
|
|
|
buf.write_1bytes(head_payload->nri | head_payload->nalu_type); // NALU header.
|
|
|
|
|
|
|
|
for (size_t i = 0; i < frame.size(); ++i) {
|
2020-05-05 00:24:49 +00:00
|
|
|
SrsRtpVideoPacket* vpkt = frame[i];
|
|
|
|
SrsRtpFUAPayload2* payload = dynamic_cast<SrsRtpFUAPayload2*>(vpkt->pkt->payload);
|
2020-05-03 09:41:00 +00:00
|
|
|
buf.write_bytes(payload->payload, payload->size);
|
|
|
|
}
|
|
|
|
|
|
|
|
*ppkt = pkt;
|
2020-04-23 09:08:21 +00:00
|
|
|
}
|
2020-05-02 12:57:36 +00:00
|
|
|
|
2020-05-03 11:09:48 +00:00
|
|
|
uint16_t SrsRtpVideoQueue::next_start_of_frame(uint16_t seq)
|
2020-05-03 09:57:07 +00:00
|
|
|
{
|
2020-05-03 11:09:48 +00:00
|
|
|
uint16_t s = seq;
|
|
|
|
if (srs_rtp_seq_distance(seq, queue_->begin) >= 0) {
|
|
|
|
s = queue_->begin + 1;
|
2020-05-03 09:57:07 +00:00
|
|
|
}
|
|
|
|
|
2020-05-03 11:09:48 +00:00
|
|
|
for (; s != queue_->end; ++s) {
|
2020-05-05 00:24:49 +00:00
|
|
|
SrsRtpVideoPacket* vpkt = queue_->at(s);
|
|
|
|
if (vpkt && vpkt->video_is_first_packet) {
|
2020-05-03 09:57:07 +00:00
|
|
|
return s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-03 11:09:48 +00:00
|
|
|
return queue_->end;
|
2020-05-03 09:57:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t SrsRtpVideoQueue::next_keyframe()
|
|
|
|
{
|
2020-05-03 11:09:48 +00:00
|
|
|
uint16_t s = queue_->begin + 1;
|
2020-05-03 09:57:07 +00:00
|
|
|
|
2020-05-03 11:09:48 +00:00
|
|
|
for (; s != queue_->end; ++s) {
|
2020-05-05 00:24:49 +00:00
|
|
|
SrsRtpVideoPacket* vpkt = queue_->at(s);
|
|
|
|
if (vpkt && vpkt->video_is_idr && vpkt->video_is_first_packet) {
|
2020-05-03 09:57:07 +00:00
|
|
|
return s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-03 11:09:48 +00:00
|
|
|
return queue_->end;
|
2020-05-03 09:57:07 +00:00
|
|
|
}
|
|
|
|
|