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 : #include "libav_deps.h"
20 : #include "media_codec.h"
21 : #include "video/video_base.h"
22 :
23 : #include <memory>
24 : #include <string>
25 : #include <list>
26 :
27 : extern "C" {
28 : #include <libavutil/hwcontext.h>
29 : }
30 :
31 : namespace jami {
32 : namespace video {
33 :
34 : enum class DeviceState : uint8_t { NOT_TESTED, USABLE, NOT_USABLE };
35 :
36 : /**
37 : * @brief Provides an abstraction layer to the hardware acceleration APIs in FFmpeg.
38 : */
39 : class HardwareAccel
40 : {
41 : public:
42 : /**
43 : * @brief Transfers hardware frame to main memory.
44 : *
45 : * Transfers a hardware decoded frame back to main memory. Should be called after
46 : * the frame is decoded using avcodec_send_packet/avcodec_receive_frame.
47 : *
48 : * If @frame is software, this is a no-op.
49 : *
50 : * @param frame Refrerence to the decoded hardware frame.
51 : * @param desiredFormat Software pixel format that the hardware outputs.
52 : * @returns Software frame.
53 : */
54 : static std::unique_ptr<VideoFrame> transferToMainMemory(const VideoFrame& frame, AVPixelFormat desiredFormat);
55 :
56 : /**
57 : * @brief Constructs a HardwareAccel object
58 : *
59 : * Made public so std::unique_ptr can access it. Should not be called.
60 : */
61 : HardwareAccel(AVCodecID id,
62 : const std::string& name,
63 : AVHWDeviceType hwType,
64 : AVPixelFormat format,
65 : AVPixelFormat swFormat,
66 : CodecType type,
67 : bool dynBitrate);
68 :
69 : /**
70 : * @brief Dereferences hardware contexts.
71 : */
72 : ~HardwareAccel();
73 :
74 : /**
75 : * @brief Codec that is being accelerated.
76 : */
77 0 : AVCodecID getCodecId() const { return id_; };
78 :
79 : /**
80 : * @brief Name of the hardware layer/API being used.
81 : */
82 0 : const std::string& getName() const { return name_; };
83 :
84 : /**
85 : * @brief Hardware format.
86 : */
87 0 : AVPixelFormat getFormat() const { return format_; };
88 :
89 : /**
90 : * @brief Software format.
91 : *
92 : * For encoding it is the format expected by the hardware. For decoding
93 : * it is the format output by the hardware.
94 : */
95 23 : AVPixelFormat getSoftwareFormat() const { return swFormat_; }
96 :
97 : /**
98 : * @brief Gets the name of the codec.
99 : *
100 : * Decoding: avcodec_get_name(id_)
101 : * Encoding: avcodec_get_name(id_) + '_' + name_
102 : */
103 : std::string getCodecName() const;
104 :
105 : /**
106 : * @brief If hardware decoder can feed hardware encoder directly.
107 : *
108 : * Returns whether or not the decoder is linked to an encoder or vice-versa. Being linked
109 : * means an encoder can directly use the decoder's hardware frame, without first
110 : * transferring it to main memory.
111 : */
112 0 : bool isLinked() const { return linked_; }
113 :
114 : /**
115 : * @brief Set some extra details in the codec context.
116 : *
117 : * Should be called after a successful
118 : * setup (setupDecoder or setupEncoder).
119 : * For decoding, sets the hw_device_ctx and get_format callback. If the decoder has
120 : * a frames context, mark as linked.
121 : * For encoding, sets hw_device_ctx and hw_frames_ctx, and may set some hardware
122 : * codec options.
123 : */
124 : void setDetails(AVCodecContext* codecCtx);
125 :
126 : /**
127 : * @brief Transfers a frame to/from the GPU memory.
128 : *
129 : * Transfers a hardware decoded frame back to main memory. Should be called after
130 : * the frame is decoded using avcodec_send_packet/avcodec_receive_frame or before
131 : * the frame is encoded using avcodec_send_frame/avcodec_receive_packet.
132 : *
133 : * @param frame Hardware frame when decoding, software frame when encoding.
134 : * @returns Software frame when decoding, hardware frame when encoding.
135 : */
136 : std::unique_ptr<VideoFrame> transfer(const VideoFrame& frame);
137 :
138 : /**
139 : * @brief Links this HardwareAccel's frames context with the passed in context.
140 : *
141 : * This serves to skip transferring a decoded frame back to main memory before encoding.
142 : */
143 : bool linkHardware(AVBufferRef* framesCtx);
144 :
145 : static std::list<HardwareAccel> getCompatibleAccel(AVCodecID id, int width, int height, CodecType type);
146 : int initAPI(bool linkable, AVBufferRef* framesCtx);
147 0 : bool dynBitrate() { return dynBitrate_; }
148 :
149 : private:
150 : bool initDevice(const std::string& device);
151 : bool initFrame();
152 :
153 : AVCodecID id_ {AV_CODEC_ID_NONE};
154 : std::string name_;
155 : AVHWDeviceType hwType_ {AV_HWDEVICE_TYPE_NONE};
156 : AVPixelFormat format_ {AV_PIX_FMT_NONE};
157 : AVPixelFormat swFormat_ {AV_PIX_FMT_NONE};
158 : CodecType type_ {CODEC_NONE};
159 : bool linked_ {false};
160 : int width_ {0};
161 : int height_ {0};
162 : bool dynBitrate_ {false};
163 :
164 : AVBufferRef* deviceCtx_ {nullptr};
165 : AVBufferRef* framesCtx_ {nullptr};
166 :
167 : int init_device(const char* name, const char* device, int flags);
168 : int init_device_type(std::string& dev);
169 :
170 : std::list<std::pair<std::string, DeviceState>>* possible_devices_;
171 : };
172 :
173 : } // namespace video
174 : } // namespace jami
|