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 48 : 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 48 : bool enableHwAccel)
41 48 : : muxContext_(socketPair.createIOContext(mtu))
42 96 : , videoEncoder_(new MediaEncoder)
43 : {
44 48 : keyFrameFreq_ = static_cast<int>(opts.frameRate.numerator() * KEY_FRAME_PERIOD);
45 96 : videoEncoder_->openOutput(dest, "rtp");
46 48 : videoEncoder_->setOptions(opts);
47 48 : videoEncoder_->setOptions(args);
48 : #ifdef ENABLE_HWACCEL
49 48 : videoEncoder_->enableAccel(enableHwAccel and Manager::instance().videoPreferences.getEncodingAccelerated());
50 : #endif
51 48 : videoEncoder_->addStream(*args.codec);
52 48 : videoEncoder_->setInitSeqVal(seqVal);
53 48 : videoEncoder_->setIOContext(muxContext_->getContext());
54 48 : }
55 :
56 : void
57 4 : VideoSender::encodeAndSendVideo(const std::shared_ptr<VideoFrame>& input_frame)
58 : {
59 4 : int angle = input_frame->getOrientation();
60 4 : if (rotation_ != angle) {
61 1 : rotation_ = angle;
62 1 : if (changeOrientationCallback_)
63 1 : changeOrientationCallback_(rotation_);
64 : }
65 :
66 4 : if (auto* packet = input_frame->packet()) {
67 0 : videoEncoder_->send(*packet);
68 : } else {
69 4 : bool is_keyframe = forceKeyFrame_ > 0 or (keyFrameFreq_ > 0 and (frameNumber_ % keyFrameFreq_) == 0);
70 :
71 4 : if (is_keyframe)
72 2 : --forceKeyFrame_;
73 :
74 4 : 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 4 : }
82 :
83 : void
84 4 : VideoSender::update(Observable<std::shared_ptr<MediaFrame>>* /*obs*/, const std::shared_ptr<MediaFrame>& frame_p)
85 : {
86 4 : encodeAndSendVideo(std::dynamic_pointer_cast<VideoFrame>(frame_p));
87 4 : }
88 :
89 : void
90 74 : VideoSender::forceKeyFrame()
91 : {
92 74 : JAMI_LOG("Key frame requested");
93 74 : ++forceKeyFrame_;
94 74 : }
95 :
96 : uint16_t
97 0 : VideoSender::getLastSeqValue()
98 : {
99 0 : return videoEncoder_->getLastSeqValue();
100 : }
101 :
102 : void
103 57 : VideoSender::setChangeOrientationCallback(std::function<void(int)> cb)
104 : {
105 57 : changeOrientationCallback_ = std::move(cb);
106 57 : }
107 :
108 : int
109 0 : 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 0 : if (!videoEncoder_)
114 0 : return -1; // NOK
115 :
116 0 : return videoEncoder_->setBitrate(br);
117 : }
118 :
119 : } // namespace video
120 : } // namespace jami
|