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 : #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 <memory>
34 : #include <optional>
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 319 : 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 5586 : int getWidth() const { return videoOpts_.width; };
98 5586 : int getHeight() const { return videoOpts_.height; };
99 :
100 : void setInitSeqVal(uint16_t seqVal);
101 : uint16_t getLastSeqValue();
102 :
103 : int setBitrate(uint64_t br);
104 : int setPacketLoss(uint64_t pl);
105 :
106 : #ifdef ENABLE_HWACCEL
107 : void enableAccel(bool enableAccel);
108 : #endif
109 :
110 : static std::string testH265Accel();
111 :
112 : unsigned getStreamCount() const;
113 : MediaStream getStream(const std::string& name, int streamIdx = -1) const;
114 :
115 : int getCurrentAudioAVCtxFrameSize();
116 :
117 : private:
118 : NON_COPYABLE(MediaEncoder);
119 : AVCodecContext* prepareEncoderContext(const AVCodec* outputCodec, bool is_video);
120 : void forcePresetX2645(AVCodecContext* encoderCtx);
121 : void extractProfileLevelID(const std::string& parameters, AVCodecContext* ctx);
122 : int initVideoStream(AVBufferRef* framesCtx = {});
123 : int initStream(const SystemCodecInfo& systemCodecInfo, AVBufferRef* framesCtx = {});
124 : void openIOContext();
125 : void startIO();
126 : AVCodecContext* getCurrentVideoAVCtx();
127 : AVCodecContext* getCurrentAudioAVCtx();
128 : void stopEncoder();
129 : AVCodecContext* initCodec(AVMediaType mediaType, AVCodecID avcodecId, uint64_t br);
130 : void initH264(AVCodecContext* encoderCtx, uint64_t br);
131 : void initH265(AVCodecContext* encoderCtx, uint64_t br);
132 : void initVP8(AVCodecContext* encoderCtx, uint64_t br);
133 : void initMPEG4(AVCodecContext* encoderCtx, uint64_t br);
134 : void initH263(AVCodecContext* encoderCtx, uint64_t br);
135 : void initOpus(AVCodecContext* encoderCtx);
136 : bool isDynBitrateSupported(AVCodecID codecid);
137 : bool isDynPacketLossSupported(AVCodecID codecid);
138 : void initAccel(AVCodecContext* encoderCtx, uint64_t br);
139 : #ifdef ENABLE_VIDEO
140 : int getHWFrame(const std::shared_ptr<VideoFrame>& input, std::shared_ptr<VideoFrame>& output);
141 : std::shared_ptr<VideoFrame> getUnlinkedHWFrame(const VideoFrame& input);
142 : std::shared_ptr<VideoFrame> getHWFrameFromSWFrame(const VideoFrame& input);
143 : std::shared_ptr<VideoFrame> getScaledSWFrame(const VideoFrame& input);
144 : #endif
145 :
146 : std::vector<AVCodecContext*> encoders_;
147 : AVFormatContext* outputCtx_ = nullptr;
148 : AVIOContext* ioCtx_ = nullptr;
149 : int currentStreamIdx_ = -1;
150 : unsigned sent_samples = 0;
151 : bool initialized_ {false};
152 : bool fileIO_ {false};
153 : const AVCodec* outputCodec_ = nullptr;
154 : std::mutex encMutex_;
155 : bool linkableHW_ {false};
156 : RateMode mode_ {RateMode::CRF_CONSTRAINED};
157 : bool fecEnabled_ {false};
158 :
159 : #ifdef ENABLE_VIDEO
160 : video::VideoScaler scaler_;
161 : std::shared_ptr<VideoFrame> scaledFrame_;
162 : #endif // ENABLE_VIDEO
163 :
164 : std::vector<uint8_t> scaledFrameBuffer_;
165 : int scaledFrameBufferSize_ = 0;
166 :
167 : #ifdef ENABLE_HWACCEL
168 : bool enableAccel_ {false};
169 : std::unique_ptr<video::HardwareAccel> accel_;
170 : #endif
171 :
172 : protected:
173 : void readConfig(AVCodecContext* encoderCtx);
174 : AVDictionary* options_ = nullptr;
175 : MediaStream videoOpts_;
176 : MediaStream audioOpts_;
177 : std::optional<SystemCodecInfo> videoCodecInfo_ {};
178 : };
179 :
180 : } // namespace jami
|