Line data Source code
1 : /* 2 : * Copyright (C) 2004-2024 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 "noncopyable.h" 20 : #include "threadloop.h" 21 : #include "media/media_stream.h" 22 : #include "media/media_device.h" // DeviceParams 23 : #include "media/video/video_base.h" 24 : #include "media/media_codec.h" 25 : 26 : #include <map> 27 : #include <atomic> 28 : #include <future> 29 : #include <string> 30 : #include <mutex> 31 : #include <condition_variable> 32 : #include <array> 33 : 34 : #if __APPLE__ 35 : #import "TargetConditionals.h" 36 : #endif 37 : 38 : namespace jami { 39 : class MediaDecoder; 40 : class MediaDemuxer; 41 : } // namespace jami 42 : 43 : namespace jami { 44 : namespace video { 45 : 46 : class SinkClient; 47 : 48 : enum class VideoInputMode { ManagedByClient, ManagedByDaemon, Undefined }; 49 : 50 : class VideoInput : public VideoGenerator 51 : { 52 : public: 53 : VideoInput(VideoInputMode inputMode = VideoInputMode::Undefined, 54 : const std::string& resource = "local", 55 : const std::string& sink = ""); 56 : ~VideoInput(); 57 : 58 : // as VideoGenerator 59 : const std::string& getName() const { return resource_; } 60 : int getWidth() const; 61 : int getHeight() const; 62 : AVPixelFormat getPixelFormat() const; 63 : 64 : const DeviceParams& getConfig() const { 65 : return decOpts_; 66 : } 67 113 : std::shared_future<DeviceParams> getParams() const { 68 113 : return futureDecOpts_; 69 : } 70 : 71 : MediaStream getInfo() const; 72 : 73 : void setSink(const std::string& sinkId); 74 : void updateStartTime(int64_t startTime); 75 : void configureFilePlayback(const std::string& path, 76 : std::shared_ptr<MediaDemuxer>& demuxer, 77 : int index); 78 : void flushBuffers(); 79 20 : void setPaused(bool paused) { paused_ = paused; } 80 : void setSeekTime(int64_t time); 81 : void setupSink(const int width, const int height); 82 : void stopSink(); 83 : 84 : void setRecorderCallback(const std::function<void(const MediaStream& ms)>& cb); 85 : 86 : #if VIDEO_CLIENT_INPUT 87 : /* 88 : * these functions are used to pass buffer from/to the daemon 89 : * on the Android and UWP builds 90 : */ 91 : void* obtainFrame(int length); 92 : void releaseFrame(void* frame); 93 : #else 94 : void stopInput(); 95 : #endif 96 : 97 : void setSuccessfulSetupCb(const std::function<void(MediaType, bool)>& cb) 98 : { 99 : onSuccessfulSetup_ = cb; 100 : } 101 : 102 : /** 103 : * Restart stopped video input 104 : * @note if a media is removed, then re-added in a conference, the loop will be stopped 105 : * and this input must be restarted 106 : */ 107 : void restart(); 108 : 109 : private: 110 : NON_COPYABLE(VideoInput); 111 : 112 : std::shared_future<DeviceParams> switchInput(const std::string& resource); 113 : 114 : std::string resource_; 115 : std::atomic<bool> switchPending_ = {false}; 116 : std::atomic_bool isStopped_ = {false}; 117 : 118 : DeviceParams decOpts_; 119 : std::promise<DeviceParams> foundDecOpts_; 120 : std::shared_future<DeviceParams> futureDecOpts_; 121 : bool emulateRate_ = false; 122 : 123 : std::atomic_bool decOptsFound_ {false}; 124 : void foundDecOpts(const DeviceParams& params); 125 : 126 : void clearOptions(); 127 : 128 : // true if decOpts_ is ready to use, false if using promise/future 129 : bool initCamera(const std::string& device); 130 : bool initFile(std::string path); 131 : 132 : #ifdef __APPLE__ 133 : bool initAVFoundation(const std::string& display); 134 : #elif defined(WIN32) 135 : bool initWindowsGrab(const std::string& display); 136 : #else 137 : bool initLinuxGrab(const std::string& display); 138 : #endif 139 : 140 : bool isCapturing() const noexcept; 141 : void startLoop(); 142 : 143 : void switchDevice(); 144 : bool capturing_ {false}; 145 : void createDecoder(); 146 : void deleteDecoder(); 147 : std::unique_ptr<MediaDecoder> decoder_; 148 : std::shared_ptr<SinkClient> sink_; 149 : ThreadLoop loop_; 150 : 151 : // for ThreadLoop 152 : bool setup(); 153 : void process(); 154 : void cleanup(); 155 : 156 : bool captureFrame(); 157 : 158 : int rotation_ {0}; 159 : std::shared_ptr<AVBufferRef> displayMatrix_; 160 : void setRotation(int angle); 161 : VideoInputMode inputMode_; 162 410 : inline bool videoManagedByClient() const 163 : { 164 410 : return inputMode_ == VideoInputMode::ManagedByClient; 165 : } 166 : bool playingFile_ = false; 167 : std::atomic_bool paused_ {true}; 168 : 169 : std::function<void(MediaType, bool)> onSuccessfulSetup_; 170 : std::function<void(const MediaStream& ms)> recorderCallback_; 171 : }; 172 : 173 : } // namespace video 174 : } // namespace jami