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

« back to all changes in this revision

Viewing changes to src/mcs/mir/sourcemediamanager.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 "mcs/logger.h"
 
19
 
 
20
#include "mcs/common/threadedexecutor.h"
 
21
 
 
22
#include "mcs/video/statistics.h"
 
23
#include "mcs/video/videoformat.h"
 
24
 
 
25
#include "mcs/streaming/mpegtspacketizer.h"
 
26
#include "mcs/streaming/rtpsender.h"
 
27
 
 
28
#include "mcs/mir/sourcemediamanager.h"
 
29
 
 
30
#include "mcs/android/h264encoder.h"
 
31
 
 
32
namespace mcs {
 
33
namespace mir {
 
34
 
 
35
SourceMediaManager::Ptr SourceMediaManager::Create(const std::string &remote_address) {
 
36
    return std::shared_ptr<SourceMediaManager>(new SourceMediaManager(remote_address));
 
37
}
 
38
 
 
39
SourceMediaManager::SourceMediaManager(const std::string &remote_address) :
 
40
    remote_address_(remote_address),
 
41
    state_(State::Stopped) {
 
42
}
 
43
 
 
44
SourceMediaManager::~SourceMediaManager() {
 
45
    if (state_ != State::Stopped)
 
46
        StopPipeline();
 
47
 
 
48
    mcs::video::Statistics::Instance()->Dump();
 
49
}
 
50
 
 
51
bool SourceMediaManager::Configure() {
 
52
    auto rr = mcs::video::ExtractRateAndResolution(format_);
 
53
 
 
54
    MCS_DEBUG("dimensions: %dx%d@%d", rr.width, rr.height, rr.framerate);
 
55
 
 
56
    // FIXME we don't support any other mode than extend for now as that means some
 
57
    // additional work from mir to still give us properly sized frames we can hand
 
58
    // to the encoder.
 
59
    Screencast::DisplayOutput output{Screencast::DisplayMode::kExtend, rr.width, rr.height};
 
60
 
 
61
    connector_ = std::make_shared<mcs::mir::Screencast>(output);
 
62
    if (!connector_->IsValid())
 
63
        return false;
 
64
 
 
65
    encoder_ = mcs::android::H264Encoder::Create();
 
66
 
 
67
    int profile = 0, level = 0, constraint = 0;
 
68
    mcs::video::ExtractProfileLevel(format_, &profile, &level, &constraint);
 
69
 
 
70
    auto config = mcs::android::H264Encoder::DefaultConfiguration();
 
71
    config.width = rr.width;
 
72
    config.height = rr.height;
 
73
    config.framerate = rr.framerate;
 
74
    config.profile_idc = profile;
 
75
    config.level_idc = level;
 
76
    config.constraint_set = constraint;
 
77
 
 
78
    if (!encoder_->Configure(config)) {
 
79
        MCS_ERROR("Failed to configure encoder");
 
80
        return false;
 
81
    }
 
82
 
 
83
    encoder_executor_ = mcs::common::ThreadedExecutor::Create(encoder_, "Encoder");
 
84
 
 
85
    renderer_ = mcs::mir::StreamRenderer::Create(connector_, encoder_);
 
86
    renderer_->SetDimensions(rr.width, rr.height);
 
87
 
 
88
    auto rtp_sender = mcs::streaming::RTPSender::Create(remote_address_, sink_port1_);
 
89
    auto mpegts_packetizer = mcs::streaming::MPEGTSPacketizer::Create();
 
90
 
 
91
    sender_ = mcs::streaming::MediaSender::Create(mpegts_packetizer, rtp_sender, config);
 
92
    encoder_->SetDelegate(sender_);
 
93
 
 
94
    return true;
 
95
}
 
96
 
 
97
void SourceMediaManager::StartPipeline() {
 
98
    sender_->Start();
 
99
    encoder_executor_->Start();
 
100
    renderer_->StartThreaded();
 
101
}
 
102
 
 
103
void SourceMediaManager::StopPipeline() {
 
104
    renderer_->Stop();
 
105
    encoder_executor_->Stop();
 
106
    sender_->Stop();
 
107
}
 
108
 
 
109
void SourceMediaManager::Play() {
 
110
    if (!IsPaused() || !renderer_)
 
111
        return;
 
112
 
 
113
    MCS_DEBUG("");
 
114
 
 
115
    StartPipeline();
 
116
 
 
117
    state_ = State::Playing;
 
118
}
 
119
 
 
120
void SourceMediaManager::Pause() {
 
121
    if (IsPaused()|| !renderer_)
 
122
        return;
 
123
 
 
124
    MCS_DEBUG("");
 
125
 
 
126
    StopPipeline();
 
127
 
 
128
    state_ = State::Paused;
 
129
}
 
130
 
 
131
void SourceMediaManager::Teardown() {
 
132
    if (state_ == State::Stopped || !renderer_)
 
133
        return;
 
134
 
 
135
    MCS_DEBUG("");
 
136
 
 
137
    StopPipeline();
 
138
 
 
139
    state_ = State::Stopped;
 
140
}
 
141
 
 
142
bool SourceMediaManager::IsPaused() const {
 
143
    return state_ == State::Paused ||
 
144
           state_ == State::Stopped;
 
145
}
 
146
 
 
147
void SourceMediaManager::SendIDRPicture() {
 
148
    if (!encoder_)
 
149
        return;
 
150
 
 
151
    encoder_->SendIDRFrame();
 
152
}
 
153
 
 
154
int SourceMediaManager::GetLocalRtpPort() const {
 
155
    MCS_DEBUG("local port %d", sender_->LocalRTPPort());
 
156
    return sender_->LocalRTPPort();
 
157
}
 
158
 
 
159
} // namespace mir
 
160
} // namespace mcs