Line data Source code
1 : /* 2 : * Copyright (C) 2004-2024 Savoir-faire Linux Inc. 3 : * 4 : * Author: Philippe Gorley <philippe.gorley@savoirfairelinux.com> 5 : * Author: Pierre Lespagnol <pierre.lespagnol@savoirfairelinux.com> 6 : * 7 : * This program is free software; you can redistribute it and/or modify 8 : * it under the terms of the GNU General Public License as published by 9 : * the Free Software Foundation; either version 3 of the License, or 10 : * (at your option) any later version. 11 : * 12 : * This program is distributed in the hope that it will be useful, 13 : * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 : * GNU General Public License for more details. 16 : * 17 : * You should have received a copy of the GNU General Public License 18 : * along with this program; if not, write to the Free Software 19 : * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 : */ 21 : 22 : #pragma once 23 : 24 : #include "libav_deps.h" 25 : #include "media_codec.h" 26 : 27 : #include <memory> 28 : #include <string> 29 : #include <vector> 30 : #include <list> 31 : 32 : extern "C" { 33 : #include <libavutil/hwcontext.h> 34 : } 35 : 36 : namespace jami { 37 : namespace video { 38 : 39 : 40 : enum class DeviceState { 41 : NOT_TESTED, 42 : USABLE, 43 : NOT_USABLE 44 : }; 45 : 46 : /** 47 : * @brief Provides an abstraction layer to the hardware acceleration APIs in FFmpeg. 48 : */ 49 : class HardwareAccel 50 : { 51 : public: 52 : /** 53 : * @brief Transfers hardware frame to main memory. 54 : * 55 : * Transfers a hardware decoded frame back to main memory. Should be called after 56 : * the frame is decoded using avcodec_send_packet/avcodec_receive_frame. 57 : * 58 : * If @frame is software, this is a no-op. 59 : * 60 : * @param frame Refrerence to the decoded hardware frame. 61 : * @param desiredFormat Software pixel format that the hardware outputs. 62 : * @returns Software frame. 63 : */ 64 : static std::unique_ptr<VideoFrame> transferToMainMemory(const VideoFrame& frame, 65 : AVPixelFormat desiredFormat); 66 : 67 : /** 68 : * @brief Constructs a HardwareAccel object 69 : * 70 : * Made public so std::unique_ptr can access it. Should not be called. 71 : */ 72 : HardwareAccel(AVCodecID id, 73 : const std::string& name, 74 : AVHWDeviceType hwType, 75 : AVPixelFormat format, 76 : AVPixelFormat swFormat, 77 : CodecType type, 78 : bool dynBitrate); 79 : 80 : /** 81 : * @brief Dereferences hardware contexts. 82 : */ 83 : ~HardwareAccel(); 84 : 85 : /** 86 : * @brief Codec that is being accelerated. 87 : */ 88 0 : AVCodecID getCodecId() const { return id_; }; 89 : 90 : /** 91 : * @brief Name of the hardware layer/API being used. 92 : */ 93 0 : const std::string& getName() const { return name_; }; 94 : 95 : /** 96 : * @brief Hardware format. 97 : */ 98 0 : AVPixelFormat getFormat() const { return format_; }; 99 : 100 : /** 101 : * @brief Software format. 102 : * 103 : * For encoding it is the format expected by the hardware. For decoding 104 : * it is the format output by the hardware. 105 : */ 106 0 : AVPixelFormat getSoftwareFormat() const { return swFormat_; } 107 : 108 : /** 109 : * @brief Gets the name of the codec. 110 : * 111 : * Decoding: avcodec_get_name(id_) 112 : * Encoding: avcodec_get_name(id_) + '_' + name_ 113 : */ 114 : std::string getCodecName() const; 115 : 116 : /** 117 : * @brief If hardware decoder can feed hardware encoder directly. 118 : * 119 : * Returns whether or not the decoder is linked to an encoder or vice-versa. Being linked 120 : * means an encoder can directly use the decoder's hardware frame, without first 121 : * transferring it to main memory. 122 : */ 123 0 : bool isLinked() const { return linked_; } 124 : 125 : /** 126 : * @brief Set some extra details in the codec context. 127 : * 128 : * Should be called after a successful 129 : * setup (setupDecoder or setupEncoder). 130 : * For decoding, sets the hw_device_ctx and get_format callback. If the decoder has 131 : * a frames context, mark as linked. 132 : * For encoding, sets hw_device_ctx and hw_frames_ctx, and may set some hardware 133 : * codec options. 134 : */ 135 : void setDetails(AVCodecContext* codecCtx); 136 : 137 : /** 138 : * @brief Transfers a frame to/from the GPU memory. 139 : * 140 : * Transfers a hardware decoded frame back to main memory. Should be called after 141 : * the frame is decoded using avcodec_send_packet/avcodec_receive_frame or before 142 : * the frame is encoded using avcodec_send_frame/avcodec_receive_packet. 143 : * 144 : * @param frame Hardware frame when decoding, software frame when encoding. 145 : * @returns Software frame when decoding, hardware frame when encoding. 146 : */ 147 : std::unique_ptr<VideoFrame> transfer(const VideoFrame& frame); 148 : 149 : /** 150 : * @brief Links this HardwareAccel's frames context with the passed in context. 151 : * 152 : * This serves to skip transferring a decoded frame back to main memory before encoding. 153 : */ 154 : bool linkHardware(AVBufferRef* framesCtx); 155 : 156 : static std::list<HardwareAccel> getCompatibleAccel(AVCodecID id, 157 : int width, 158 : int height, 159 : CodecType type); 160 : int initAPI(bool linkable, AVBufferRef* framesCtx); 161 0 : bool dynBitrate() { return dynBitrate_; } 162 : 163 : private: 164 : bool initDevice(const std::string& device); 165 : bool initFrame(); 166 : 167 : AVCodecID id_ {AV_CODEC_ID_NONE}; 168 : std::string name_; 169 : AVHWDeviceType hwType_ {AV_HWDEVICE_TYPE_NONE}; 170 : AVPixelFormat format_ {AV_PIX_FMT_NONE}; 171 : AVPixelFormat swFormat_ {AV_PIX_FMT_NONE}; 172 : CodecType type_ {CODEC_NONE}; 173 : bool linked_ {false}; 174 : int width_ {0}; 175 : int height_ {0}; 176 : bool dynBitrate_ {false}; 177 : 178 : AVBufferRef* deviceCtx_ {nullptr}; 179 : AVBufferRef* framesCtx_ {nullptr}; 180 : 181 : int init_device(const char* name, const char* device, int flags); 182 : int init_device_type(std::string& dev); 183 : 184 : std::list<std::pair<std::string, DeviceState>>* possible_devices_; 185 : }; 186 : 187 : } // namespace video 188 : } // namespace jami