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 "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 <atomic> 27 : #include <future> 28 : #include <string> 29 : 30 : #if __APPLE__ 31 : #import "TargetConditionals.h" 32 : #endif 33 : 34 : namespace jami { 35 : class MediaDecoder; 36 : class MediaDemuxer; 37 : } // namespace jami 38 : 39 : namespace jami { 40 : namespace video { 41 : 42 : class SinkClient; 43 : 44 : enum class VideoInputMode : uint8_t { ManagedByClient, ManagedByDaemon, Undefined }; 45 : 46 : class VideoInput : public VideoGenerator 47 : { 48 : public: 49 : VideoInput(VideoInputMode inputMode = VideoInputMode::Undefined, 50 : const std::string& resource = "local", 51 : const std::string& sink = ""); 52 : ~VideoInput(); 53 : 54 : // as VideoGenerator 55 : const std::string& getName() const { return resource_; } 56 : int getWidth() const; 57 : int getHeight() const; 58 : AVPixelFormat getPixelFormat() const; 59 : 60 : const DeviceParams& getConfig() const { return decOpts_; } 61 99 : std::shared_future<DeviceParams> getParams() const { return futureDecOpts_; } 62 : 63 : MediaStream getInfo() const; 64 : 65 : void setSink(const std::string& sinkId); 66 : void updateStartTime(int64_t startTime); 67 : void configureFilePlayback(const std::string& path, std::shared_ptr<MediaDemuxer>& demuxer, int index); 68 : void flushBuffers(); 69 10 : void setPaused(bool paused) { paused_ = paused; } 70 : void setSeekTime(int64_t time); 71 : void setupSink(const int width, const int height); 72 : void stopSink(); 73 : 74 : void setRecorderCallback(const std::function<void(const MediaStream& ms)>& cb); 75 : 76 : void setSuccessfulSetupCb(const std::function<void(MediaType, bool)>& cb) { onSuccessfulSetup_ = cb; } 77 : 78 : /** 79 : * Restart stopped video input 80 : * @note if a media is removed, then re-added in a conference, the loop will be stopped 81 : * and this input must be restarted 82 : */ 83 : void restart(); 84 : 85 : private: 86 : NON_COPYABLE(VideoInput); 87 : 88 : std::shared_future<DeviceParams> switchInput(const std::string& resource); 89 : 90 : std::string resource_; 91 : std::atomic<bool> switchPending_ = {false}; 92 : std::atomic_bool isStopped_ = {false}; 93 : 94 : DeviceParams decOpts_; 95 : std::promise<DeviceParams> foundDecOpts_; 96 : std::shared_future<DeviceParams> futureDecOpts_; 97 : bool emulateRate_ = false; 98 : 99 : std::atomic_bool decOptsFound_ {false}; 100 : void foundDecOpts(const DeviceParams& params); 101 : 102 : void clearOptions(); 103 : 104 : // true if decOpts_ is ready to use, false if using promise/future 105 : bool initCamera(const std::string& device); 106 : bool initFile(const std::string& path); 107 : 108 : #ifdef __APPLE__ 109 : bool initAVFoundation(const std::string& display); 110 : #elif defined(WIN32) 111 : bool initWindowsGrab(const std::string& display); 112 : #else 113 : bool initLinuxGrab(const std::string& display); 114 : #endif 115 : 116 : bool isCapturing() const noexcept; 117 : void startLoop(); 118 : 119 : void switchDevice(); 120 : bool capturing_ {false}; 121 : void createDecoder(); 122 : void deleteDecoder(); 123 : std::unique_ptr<MediaDecoder> decoder_; 124 : std::shared_ptr<SinkClient> sink_; 125 : ThreadLoop loop_; 126 : 127 : // for ThreadLoop 128 : bool setup(); 129 : void process(); 130 : void cleanup(); 131 : 132 : bool captureFrame(); 133 : 134 : int rotation_ {0}; 135 : std::shared_ptr<AVBufferRef> displayMatrix_; 136 : void setRotation(int angle); 137 : VideoInputMode inputMode_; 138 446 : inline bool videoManagedByClient() const { return inputMode_ == VideoInputMode::ManagedByClient; } 139 : bool playingFile_ = false; 140 : std::atomic_bool paused_ {true}; 141 : 142 : std::function<void(MediaType, bool)> onSuccessfulSetup_; 143 : std::function<void(const MediaStream& ms)> recorderCallback_; 144 : }; 145 : 146 : } // namespace video 147 : } // namespace jami