2
* Copyright (C) 2015 Canonical, Ltd.
4
* This program is free software: you can redistribute it and/or modify it
5
* under the terms of the GNU General Public License version 3, as published
6
* by the Free Software Foundation.
8
* This program is distributed in the hope that it will be useful, but
9
* WITHOUT ANY WARRANTY; without even the implied warranties of
10
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11
* PURPOSE. See the GNU General Public License for more details.
13
* You should have received a copy of the GNU General Public License along
14
* with this program. If not, see <http://www.gnu.org/licenses/>.
20
#include "mcs/logger.h"
22
#include "mcs/video/statistics.h"
24
#include "mcs/streaming/mediasender.h"
25
#include "mcs/streaming/mpegtspacketizer.h"
26
#include "mcs/streaming/rtpsender.h"
29
static constexpr const char *kMediaSenderThreadName{"MediaSender"};
35
MediaSender::Ptr MediaSender::Create(const Packetizer::Ptr &packetizer, const TransportSender::Ptr &sender, const mcs::video::BaseEncoder::Config &config) {
36
return std::shared_ptr<MediaSender>(new MediaSender(packetizer, sender, config));
39
MediaSender::MediaSender(const Packetizer::Ptr &packetizer, const TransportSender::Ptr &sender, const mcs::video::BaseEncoder::Config &config) :
40
packetizer_(packetizer),
43
queue_(video::BufferQueue::Create()),
46
if (!packetizer_ || !sender_) {
47
MCS_WARNING("Sender not correct initialized. Missing packetizer or sender.");
51
// FIXME once we add support for audio this can be only used for video
52
// and we need to differentiate here per track.
53
Packetizer::TrackFormat format;
54
format.profile_idc = config.profile_idc;
55
format.level_idc = config.level_idc;
56
format.constraint_set = config.constraint_set;
57
format.mime = "video/avc";
59
video_track_ = packetizer_->AddTrack(format);
62
MediaSender::~MediaSender() {
66
void MediaSender::Start() {
70
if (!sender_ || !packetizer_)
74
worker_thread_ = std::thread(&MediaSender::WorkerThread, this);
75
pthread_setname_np(worker_thread_.native_handle(), kMediaSenderThreadName);
78
void MediaSender::Stop() {
83
worker_thread_.join();
86
void MediaSender::ProcessBuffer(const mcs::video::Buffer::Ptr &buffer) {
87
mcs::video::Buffer::Ptr packets;
89
static int64_t start_time_us = mcs::Utils::GetNowUs();
90
static unsigned int buffer_count = 0;
93
int64_t time_now_us = mcs::Utils::GetNowUs();
94
if (start_time_us + 1000000ll <= time_now_us) {
95
video::Statistics::Instance()->RecordSenderBufferPerSecond(buffer_count);
97
start_time_us = time_now_us;
100
// FIXME: By default we're expecting the encoder to insert SPS and PPS
101
// with each IDR frame but we need to handle also the case where the
102
// encoder is not capable of doing this. For that we simply have to set
103
// flags to Packetizer::kPrependSPSandPPStoIDRFrames.
106
// Per spec we need to emit PAT/PMT and PCR updates atleast every 100ms
107
int64_t time_us = mcs::Utils::GetNowUs();
108
if (prev_time_us_ < 0ll || prev_time_us_ + 100000ll <= time_us) {
109
flags |= Packetizer::kEmitPATandPMT;
110
flags |= Packetizer::kEmitPCR;
111
prev_time_us_ = time_us;
114
if (!packetizer_->Packetize(video_track_, buffer, &packets, flags)) {
115
MCS_ERROR("MPEGTS packetizing failed");
119
packets->SetTimestamp(buffer->Timestamp());
120
sender_->Queue(packets);
123
void MediaSender::WorkerThread() {
125
// This will wait for a short time and then return back
126
// so we can loop again and check if we have to exit or
128
if (!queue_->WaitToBeFilled())
131
auto buffer = queue_->Pop();
132
ProcessBuffer(buffer);
136
void MediaSender::OnBufferAvailable(const video::Buffer::Ptr &buffer) {
137
queue_->Push(buffer);
140
void MediaSender::OnBufferWithCodecConfig(const video::Buffer::Ptr &buffer) {
144
packetizer_->SubmitCSD(video_track_, buffer);
147
uint16_t MediaSender::LocalRTPPort() const {
151
return sender_->LocalPort();
154
} // namespace streaming