~phablet-team/aethercast/fix-for-microsoft-dongle

« back to all changes in this revision

Viewing changes to src/mcs/streaming/mediasender.cpp

Add hardware encoding and video streaming support.

The hardware encoding is currently only for Android 5.x based devices. On all others encoding will simply not work. The streaming part of aethercast (MPEGTS packetizing, RTP sending) as based on some code from Android.

Approved by PS Jenkins bot, Thomas Voß, Jim Hodapp.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2015 Canonical, Ltd.
 
3
 *
 
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.
 
7
 *
 
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.
 
12
 *
 
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/>.
 
15
 *
 
16
 */
 
17
 
 
18
#include <stdio.h>
 
19
 
 
20
#include "mcs/logger.h"
 
21
 
 
22
#include "mcs/video/statistics.h"
 
23
 
 
24
#include "mcs/streaming/mediasender.h"
 
25
#include "mcs/streaming/mpegtspacketizer.h"
 
26
#include "mcs/streaming/rtpsender.h"
 
27
 
 
28
namespace {
 
29
static constexpr const char *kMediaSenderThreadName{"MediaSender"};
 
30
}
 
31
 
 
32
namespace mcs {
 
33
namespace streaming {
 
34
 
 
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));
 
37
}
 
38
 
 
39
MediaSender::MediaSender(const Packetizer::Ptr &packetizer, const TransportSender::Ptr &sender, const mcs::video::BaseEncoder::Config &config) :
 
40
    packetizer_(packetizer),
 
41
    sender_(sender),
 
42
    prev_time_us_(-1ll),
 
43
    queue_(video::BufferQueue::Create()),
 
44
    running_(false) {
 
45
 
 
46
    if (!packetizer_ || !sender_) {
 
47
        MCS_WARNING("Sender not correct initialized. Missing packetizer or sender.");
 
48
        return;
 
49
    }
 
50
 
 
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";
 
58
 
 
59
    video_track_ = packetizer_->AddTrack(format);
 
60
}
 
61
 
 
62
MediaSender::~MediaSender() {
 
63
    Stop();
 
64
}
 
65
 
 
66
void MediaSender::Start() {
 
67
    if (running_)
 
68
        return;
 
69
 
 
70
    if (!sender_ || !packetizer_)
 
71
        return;
 
72
 
 
73
    running_ = true;
 
74
    worker_thread_ = std::thread(&MediaSender::WorkerThread, this);
 
75
    pthread_setname_np(worker_thread_.native_handle(), kMediaSenderThreadName);
 
76
}
 
77
 
 
78
void MediaSender::Stop() {
 
79
    if (!running_)
 
80
        return;
 
81
 
 
82
    running_ = false;
 
83
    worker_thread_.join();
 
84
}
 
85
 
 
86
void MediaSender::ProcessBuffer(const mcs::video::Buffer::Ptr &buffer) {
 
87
    mcs::video::Buffer::Ptr packets;
 
88
 
 
89
    static int64_t start_time_us = mcs::Utils::GetNowUs();
 
90
    static unsigned int buffer_count = 0;
 
91
 
 
92
    buffer_count++;
 
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);
 
96
        buffer_count = 0;
 
97
        start_time_us = time_now_us;
 
98
    }
 
99
 
 
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.
 
104
    int flags = 0;
 
105
 
 
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;
 
112
    }
 
113
 
 
114
    if (!packetizer_->Packetize(video_track_, buffer, &packets, flags)) {
 
115
        MCS_ERROR("MPEGTS packetizing failed");
 
116
        return;
 
117
    }
 
118
 
 
119
    packets->SetTimestamp(buffer->Timestamp());
 
120
    sender_->Queue(packets);
 
121
}
 
122
 
 
123
void MediaSender::WorkerThread() {
 
124
    while (running_) {
 
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
 
127
        // not.
 
128
        if (!queue_->WaitToBeFilled())
 
129
            continue;
 
130
 
 
131
        auto buffer = queue_->Pop();
 
132
        ProcessBuffer(buffer);
 
133
    }
 
134
}
 
135
 
 
136
void MediaSender::OnBufferAvailable(const video::Buffer::Ptr &buffer) {
 
137
    queue_->Push(buffer);
 
138
}
 
139
 
 
140
void MediaSender::OnBufferWithCodecConfig(const video::Buffer::Ptr &buffer) {
 
141
    if (!packetizer_)
 
142
        return;
 
143
 
 
144
    packetizer_->SubmitCSD(video_track_, buffer);
 
145
}
 
146
 
 
147
uint16_t MediaSender::LocalRTPPort() const {
 
148
    if (!sender_)
 
149
        return 0;
 
150
 
 
151
    return sender_->LocalPort();
 
152
}
 
153
 
 
154
} // namespace streaming
 
155
} // namespace mcs