Line data Source code
1 : /* 2 : * Copyright (C) 2004-2025 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 "video_mixer.h" 20 : #include "socket_pair.h" 21 : #include "client/videomanager.h" 22 : #include "logger.h" 23 : #include "manager.h" 24 : #include "media_device.h" 25 : #include "sip/sipcall.h" 26 : #ifdef ENABLE_HWACCEL 27 : #include "accel.h" 28 : #endif 29 : 30 : #include <map> 31 : #include <unistd.h> 32 : 33 : namespace jami { 34 : namespace video { 35 : 36 : using std::string; 37 : 38 147 : VideoSender::VideoSender(const std::string& dest, 39 : const MediaStream& opts, 40 : const MediaDescription& args, 41 : SocketPair& socketPair, 42 : const uint16_t seqVal, 43 : uint16_t mtu, 44 147 : bool enableHwAccel) 45 147 : : muxContext_(socketPair.createIOContext(mtu)) 46 294 : , videoEncoder_(new MediaEncoder) 47 : { 48 147 : keyFrameFreq_ = opts.frameRate.numerator() * KEY_FRAME_PERIOD; 49 147 : videoEncoder_->openOutput(dest, "rtp"); 50 147 : videoEncoder_->setOptions(opts); 51 147 : videoEncoder_->setOptions(args); 52 : #ifdef ENABLE_HWACCEL 53 147 : videoEncoder_->enableAccel(enableHwAccel and Manager::instance().videoPreferences.getEncodingAccelerated()); 54 : #endif 55 147 : videoEncoder_->addStream(*args.codec); 56 147 : videoEncoder_->setInitSeqVal(seqVal); 57 147 : videoEncoder_->setIOContext(muxContext_->getContext()); 58 147 : } 59 : 60 : void 61 5751 : VideoSender::encodeAndSendVideo(const std::shared_ptr<VideoFrame>& input_frame) 62 : { 63 5751 : int angle = input_frame->getOrientation(); 64 5751 : if (rotation_ != angle) { 65 49 : rotation_ = angle; 66 49 : if (changeOrientationCallback_) 67 49 : changeOrientationCallback_(rotation_); 68 : } 69 : 70 5751 : if (auto packet = input_frame->packet()) { 71 0 : videoEncoder_->send(*packet); 72 : } else { 73 5751 : bool is_keyframe = forceKeyFrame_ > 0 or (keyFrameFreq_ > 0 and (frameNumber_ % keyFrameFreq_) == 0); 74 : 75 5751 : if (is_keyframe) 76 76 : --forceKeyFrame_; 77 : 78 5751 : if (videoEncoder_->encode(input_frame, is_keyframe, frameNumber_++) < 0) 79 0 : JAMI_ERR("encoding failed"); 80 : } 81 : #ifdef DEBUG_SDP 82 : if (frameNumber_ == 1) // video stream is lazy initialized, wait for first frame 83 : videoEncoder_->print_sdp(); 84 : #endif 85 5751 : } 86 : 87 : void 88 5751 : VideoSender::update(Observable<std::shared_ptr<MediaFrame>>* /*obs*/, const std::shared_ptr<MediaFrame>& frame_p) 89 : { 90 5751 : encodeAndSendVideo(std::dynamic_pointer_cast<VideoFrame>(frame_p)); 91 5751 : } 92 : 93 : void 94 121 : VideoSender::forceKeyFrame() 95 : { 96 121 : JAMI_DBG("Key frame requested"); 97 121 : ++forceKeyFrame_; 98 121 : } 99 : 100 : uint16_t 101 0 : VideoSender::getLastSeqValue() 102 : { 103 0 : return videoEncoder_->getLastSeqValue(); 104 : } 105 : 106 : void 107 157 : VideoSender::setChangeOrientationCallback(std::function<void(int)> cb) 108 : { 109 157 : changeOrientationCallback_ = std::move(cb); 110 157 : } 111 : 112 : int 113 37 : VideoSender::setBitrate(uint64_t br) 114 : { 115 : // The encoder may be destroy during a bitrate change 116 : // when a codec parameter like auto quality change 117 37 : if (!videoEncoder_) 118 0 : return -1; // NOK 119 : 120 37 : return videoEncoder_->setBitrate(br); 121 : } 122 : 123 : } // namespace video 124 : } // namespace jami