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 101 : 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 18 : 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 447 : 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
|