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