Line data Source code
1 : /*
2 : * Copyright (C) 2004-2026 Savoir-faire Linux Inc.
3 : *
4 : * This program is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 3 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * This program is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 : */
17 :
18 : #include "video_sender.h"
19 : #include "socket_pair.h"
20 : #include "logger.h"
21 : #include "manager.h"
22 :
23 : #ifdef ENABLE_HWACCEL
24 : #include "accel.h"
25 : #endif
26 :
27 : #include <unistd.h>
28 :
29 : namespace jami {
30 : namespace video {
31 :
32 : using std::string;
33 :
34 140 : VideoSender::VideoSender(const std::string& dest,
35 : const MediaStream& opts,
36 : const MediaDescription& args,
37 : SocketPair& socketPair,
38 : const uint16_t seqVal,
39 : uint16_t mtu,
40 140 : bool enableHwAccel)
41 140 : : muxContext_(socketPair.createIOContext(mtu))
42 280 : , videoEncoder_(new MediaEncoder)
43 : {
44 140 : keyFrameFreq_ = static_cast<int>(opts.frameRate.numerator() * KEY_FRAME_PERIOD);
45 280 : videoEncoder_->openOutput(dest, "rtp");
46 140 : videoEncoder_->setOptions(opts);
47 140 : videoEncoder_->setOptions(args);
48 : #ifdef ENABLE_HWACCEL
49 140 : videoEncoder_->enableAccel(enableHwAccel and Manager::instance().videoPreferences.getEncodingAccelerated());
50 : #endif
51 140 : videoEncoder_->addStream(*args.codec);
52 140 : videoEncoder_->setInitSeqVal(seqVal);
53 140 : videoEncoder_->setIOContext(muxContext_->getContext());
54 140 : }
55 :
56 : void
57 5635 : VideoSender::encodeAndSendVideo(const std::shared_ptr<VideoFrame>& input_frame)
58 : {
59 5635 : int angle = input_frame->getOrientation();
60 5635 : if (rotation_ != angle) {
61 49 : rotation_ = angle;
62 49 : if (changeOrientationCallback_)
63 49 : changeOrientationCallback_(rotation_);
64 : }
65 :
66 5635 : if (auto* packet = input_frame->packet()) {
67 0 : videoEncoder_->send(*packet);
68 : } else {
69 5635 : bool is_keyframe = forceKeyFrame_ > 0 or (keyFrameFreq_ > 0 and (frameNumber_ % keyFrameFreq_) == 0);
70 :
71 5635 : if (is_keyframe)
72 60 : --forceKeyFrame_;
73 :
74 5635 : if (videoEncoder_->encode(input_frame, is_keyframe, frameNumber_++) < 0)
75 0 : JAMI_ERROR("encoding failed");
76 : }
77 : #ifdef DEBUG_SDP
78 : if (frameNumber_ == 1) // video stream is lazy initialized, wait for first frame
79 : videoEncoder_->print_sdp();
80 : #endif
81 5635 : }
82 :
83 : void
84 5635 : VideoSender::update(Observable<std::shared_ptr<MediaFrame>>* /*obs*/, const std::shared_ptr<MediaFrame>& frame_p)
85 : {
86 5635 : encodeAndSendVideo(std::dynamic_pointer_cast<VideoFrame>(frame_p));
87 5635 : }
88 :
89 : void
90 148 : VideoSender::forceKeyFrame()
91 : {
92 592 : JAMI_LOG("Key frame requested");
93 148 : ++forceKeyFrame_;
94 148 : }
95 :
96 : uint16_t
97 0 : VideoSender::getLastSeqValue()
98 : {
99 0 : return videoEncoder_->getLastSeqValue();
100 : }
101 :
102 : void
103 150 : VideoSender::setChangeOrientationCallback(std::function<void(int)> cb)
104 : {
105 150 : changeOrientationCallback_ = std::move(cb);
106 150 : }
107 :
108 : int
109 31 : VideoSender::setBitrate(uint64_t br)
110 : {
111 : // The encoder may be destroy during a bitrate change
112 : // when a codec parameter like auto quality change
113 31 : if (!videoEncoder_)
114 0 : return -1; // NOK
115 :
116 31 : return videoEncoder_->setBitrate(br);
117 : }
118 :
119 : } // namespace video
120 : } // namespace jami
|