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 : #pragma once 18 : 19 : #ifdef HAVE_CONFIG_H 20 : #include "config.h" 21 : #endif 22 : 23 : #ifdef ENABLE_VIDEO 24 : #include "video/video_base.h" 25 : #include "video/video_scaler.h" 26 : #endif 27 : 28 : #include "noncopyable.h" 29 : #include "media_buffer.h" 30 : #include "media_codec.h" 31 : #include "media_stream.h" 32 : 33 : #include <map> 34 : #include <memory> 35 : #include <string> 36 : #include <vector> 37 : 38 : extern "C" { 39 : struct AVCodecContext; 40 : struct AVFormatContext; 41 : struct AVDictionary; 42 : struct AVCodec; 43 : } 44 : 45 : namespace jami { 46 : 47 : struct MediaDescription; 48 : 49 : #ifdef ENABLE_HWACCEL 50 : namespace video { 51 : class HardwareAccel; 52 : } 53 : #endif 54 : 55 : class MediaEncoderException : public std::runtime_error 56 : { 57 : public: 58 0 : MediaEncoderException(const char* msg) 59 0 : : std::runtime_error(msg) 60 0 : {} 61 0 : MediaEncoderException(const std::string& msg) 62 0 : : std::runtime_error(msg) 63 0 : {} 64 : }; 65 : 66 : class MediaEncoder 67 : { 68 : public: 69 : MediaEncoder(); 70 : ~MediaEncoder(); 71 : 72 : void openOutput(const std::string& filename, const std::string& format = ""); 73 : void setMetadata(const std::string& title, const std::string& description); 74 : void setOptions(const MediaStream& opts); 75 : void setOptions(const MediaDescription& args); 76 : int addStream(const SystemCodecInfo& codec); 77 330 : void setIOContext(AVIOContext* ioctx) { ioCtx_ = ioctx; } 78 : void resetStreams(int width, int height); 79 : 80 : bool send(AVPacket& packet, int streamIdx = -1); 81 : 82 : #ifdef ENABLE_VIDEO 83 : int encode(const std::shared_ptr<VideoFrame>& input, bool is_keyframe, int64_t frame_number); 84 : #endif // ENABLE_VIDEO 85 : 86 : int encodeAudio(AudioFrame& frame); 87 : 88 : // frame should be ready to be sent to the encoder at this point 89 : int encode(AVFrame* frame, int streamIdx); 90 : 91 : int flush(); 92 : std::string print_sdp(); 93 : 94 : /* getWidth and getHeight return size of the encoded frame. 95 : * Values have meaning only after openLiveOutput call. 96 : */ 97 5702 : int getWidth() const { return videoOpts_.width; }; 98 5702 : int getHeight() const { return videoOpts_.height; }; 99 : 100 : void setInitSeqVal(uint16_t seqVal); 101 : uint16_t getLastSeqValue(); 102 : 103 : const std::string& getAudioCodec() const { return audioCodec_; } 104 : const std::string& getVideoCodec() const { return videoCodec_; } 105 : 106 : int setBitrate(uint64_t br); 107 : int setPacketLoss(uint64_t pl); 108 : 109 : #ifdef ENABLE_HWACCEL 110 : void enableAccel(bool enableAccel); 111 : #endif 112 : 113 : static std::string testH265Accel(); 114 : 115 : unsigned getStreamCount() const; 116 : MediaStream getStream(const std::string& name, int streamIdx = -1) const; 117 : 118 : int getCurrentAudioAVCtxFrameSize(); 119 : 120 : private: 121 : NON_COPYABLE(MediaEncoder); 122 : AVCodecContext* prepareEncoderContext(const AVCodec* outputCodec, bool is_video); 123 : void forcePresetX2645(AVCodecContext* encoderCtx); 124 : void extractProfileLevelID(const std::string& parameters, AVCodecContext* ctx); 125 : int initStream(const std::string& codecName, AVBufferRef* framesCtx = {}); 126 : int initStream(const SystemCodecInfo& systemCodecInfo, AVBufferRef* framesCtx = {}); 127 : void openIOContext(); 128 : void startIO(); 129 : AVCodecContext* getCurrentVideoAVCtx(); 130 : AVCodecContext* getCurrentAudioAVCtx(); 131 : void stopEncoder(); 132 : AVCodecContext* initCodec(AVMediaType mediaType, AVCodecID avcodecId, uint64_t br); 133 : void initH264(AVCodecContext* encoderCtx, uint64_t br); 134 : void initH265(AVCodecContext* encoderCtx, uint64_t br); 135 : void initVP8(AVCodecContext* encoderCtx, uint64_t br); 136 : void initMPEG4(AVCodecContext* encoderCtx, uint64_t br); 137 : void initH263(AVCodecContext* encoderCtx, uint64_t br); 138 : void initOpus(AVCodecContext* encoderCtx); 139 : bool isDynBitrateSupported(AVCodecID codecid); 140 : bool isDynPacketLossSupported(AVCodecID codecid); 141 : void initAccel(AVCodecContext* encoderCtx, uint64_t br); 142 : #ifdef ENABLE_VIDEO 143 : int getHWFrame(const std::shared_ptr<VideoFrame>& input, std::shared_ptr<VideoFrame>& output); 144 : std::shared_ptr<VideoFrame> getUnlinkedHWFrame(const VideoFrame& input); 145 : std::shared_ptr<VideoFrame> getHWFrameFromSWFrame(const VideoFrame& input); 146 : std::shared_ptr<VideoFrame> getScaledSWFrame(const VideoFrame& input); 147 : #endif 148 : 149 : std::vector<AVCodecContext*> encoders_; 150 : AVFormatContext* outputCtx_ = nullptr; 151 : AVIOContext* ioCtx_ = nullptr; 152 : int currentStreamIdx_ = -1; 153 : unsigned sent_samples = 0; 154 : bool initialized_ {false}; 155 : bool fileIO_ {false}; 156 : const AVCodec* outputCodec_ = nullptr; 157 : std::mutex encMutex_; 158 : bool linkableHW_ {false}; 159 : RateMode mode_ {RateMode::CRF_CONSTRAINED}; 160 : bool fecEnabled_ {false}; 161 : 162 : #ifdef ENABLE_VIDEO 163 : video::VideoScaler scaler_; 164 : std::shared_ptr<VideoFrame> scaledFrame_; 165 : #endif // ENABLE_VIDEO 166 : 167 : std::vector<uint8_t> scaledFrameBuffer_; 168 : int scaledFrameBufferSize_ = 0; 169 : 170 : #ifdef ENABLE_HWACCEL 171 : bool enableAccel_ {false}; 172 : std::unique_ptr<video::HardwareAccel> accel_; 173 : #endif 174 : 175 : protected: 176 : void readConfig(AVCodecContext* encoderCtx); 177 : AVDictionary* options_ = nullptr; 178 : MediaStream videoOpts_; 179 : MediaStream audioOpts_; 180 : std::string videoCodec_; 181 : std::string audioCodec_; 182 : }; 183 : 184 : } // namespace jami