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