@0biwank/screen-capture 1.0.1 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of @0biwank/screen-capture might be problematic. Click here for more details.
- package/LICENSE +339 -21
- package/LICENSES/CPP-HTTPLIB-MIT.txt +21 -0
- package/LICENSES/FFMPEG-GPLv2.txt +340 -0
- package/LICENSES/PROJECT-MIT.txt +21 -0
- package/LICENSES/X264-COPYING.txt +341 -0
- package/README.md +53 -64
- package/SOURCE.md +35 -0
- package/THIRD_PARTY_NOTICES.md +28 -0
- package/binding.gyp +58 -0
- package/include/CameraCapturer.h +54 -0
- package/include/DesktopCapturer.h +83 -0
- package/include/HLSMuxer/AudioEncoder.h +75 -0
- package/include/HLSMuxer/FileHLSMuxer.h +63 -0
- package/include/HLSMuxer/HLSMuxer.h +13 -0
- package/include/HLSMuxer/VideoEncoder.h +90 -0
- package/include/MediaPipeline.h +39 -0
- package/include/SourceHelper.h +41 -0
- package/include/SourceHelperWrapper.h +29 -0
- package/include/Types.h +58 -0
- package/include/UploadManager.h +9 -0
- package/include/httplib.h +12065 -0
- package/index.d.ts +99 -0
- package/index.js +105 -14
- package/package.json +31 -17
- package/prebuilds/SHA256SUMS +2 -0
- package/prebuilds/darwin-arm64/native_capture.node +0 -0
- package/prebuilds/darwin-x64/native_capture.node +0 -0
- package/scripts/build-ffmpeg-vendor.mjs +178 -0
- package/scripts/build.mjs +53 -0
- package/scripts/stage-prebuild.mjs +28 -0
- package/scripts/verify-package.mjs +39 -0
- package/scripts/verify-packlist.mjs +40 -0
- package/scripts/verify-runtime.cjs +28 -0
- package/src/CameraCapturer.mm +154 -0
- package/src/DesktopCapturer.mm +995 -0
- package/src/HLSMuxer/AudioEncoder.cpp +484 -0
- package/src/HLSMuxer/FileHLSMuxer.cpp +345 -0
- package/src/HLSMuxer/HLSMuxer.cpp +0 -0
- package/src/HLSMuxer/VideoEncoder.cpp +462 -0
- package/src/MediaPipeline.cpp +375 -0
- package/src/MediaProcessor.cpp +0 -0
- package/src/SourceHelper.mm +184 -0
- package/src/SourceHelperWrapper.mm +63 -0
- package/src/UploadManager.h +7 -0
- package/src/addon.cpp +347 -0
- package/vendor/ffmpeg/README.md +40 -0
- package/build/Release/media_processor.node +0 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "Types.h"
|
|
4
|
+
#include <atomic>
|
|
5
|
+
#include <functional>
|
|
6
|
+
#include <memory>
|
|
7
|
+
#include <string>
|
|
8
|
+
|
|
9
|
+
using SegmentReadyCallback = std::function<void(const std::string&)>;
|
|
10
|
+
|
|
11
|
+
struct CaptureOptions
|
|
12
|
+
{
|
|
13
|
+
CGDirectDisplayID display_id = 0;
|
|
14
|
+
bool capture_window = false;
|
|
15
|
+
CGWindowID window_id = 0;
|
|
16
|
+
bool no_screen = false;
|
|
17
|
+
|
|
18
|
+
bool camera = false;
|
|
19
|
+
std::string camera_device_uid;
|
|
20
|
+
|
|
21
|
+
uint32_t width = 1920;
|
|
22
|
+
uint32_t height = 1080;
|
|
23
|
+
uint32_t fps = 30;
|
|
24
|
+
uint32_t gop_size = 30;
|
|
25
|
+
uint32_t video_bitrate = 9'000'000;
|
|
26
|
+
bool crop_enabled = false;
|
|
27
|
+
uint32_t crop_x = 0;
|
|
28
|
+
uint32_t crop_y = 0;
|
|
29
|
+
uint32_t crop_width = 0;
|
|
30
|
+
uint32_t crop_height = 0;
|
|
31
|
+
|
|
32
|
+
bool system_audio = true;
|
|
33
|
+
bool microphone = false;
|
|
34
|
+
std::string mic_device_uid;
|
|
35
|
+
uint32_t sample_rate = 48000;
|
|
36
|
+
uint32_t audio_bitrate = 128'000;
|
|
37
|
+
uint32_t channels = 2;
|
|
38
|
+
bool exclude_app_audio = false;
|
|
39
|
+
|
|
40
|
+
std::string output_dir;
|
|
41
|
+
std::string recording_id;
|
|
42
|
+
uint32_t segment_time_sec = 4;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
class DesktopCapturer
|
|
46
|
+
{
|
|
47
|
+
public:
|
|
48
|
+
DesktopCapturer();
|
|
49
|
+
~DesktopCapturer();
|
|
50
|
+
|
|
51
|
+
bool selectSource(CaptureSource source);
|
|
52
|
+
bool startCapture(const CaptureOptions &options, SegmentReadyCallback segment_ready_callback = nullptr);
|
|
53
|
+
bool stopCapture();
|
|
54
|
+
bool pauseCapture();
|
|
55
|
+
bool resumeCapture();
|
|
56
|
+
const std::string &lastError() const { return m_last_error; }
|
|
57
|
+
|
|
58
|
+
void on_video_sample(void *cm_sample_buffer_ref);
|
|
59
|
+
void on_camera_sample(void *cm_sample_buffer_ref);
|
|
60
|
+
void on_audio_sample(void *cm_sample_buffer_ref);
|
|
61
|
+
void on_mic_pcm(const float *data, uint32_t frames, uint32_t sample_rate, uint32_t channels,
|
|
62
|
+
double host_time_sec);
|
|
63
|
+
|
|
64
|
+
private:
|
|
65
|
+
void *m_stream = nullptr;
|
|
66
|
+
void *m_config = nullptr;
|
|
67
|
+
void *m_filter = nullptr;
|
|
68
|
+
void *m_delegate = nullptr;
|
|
69
|
+
void *m_audio_engine = nullptr;
|
|
70
|
+
void *m_camera_capturer = nullptr;
|
|
71
|
+
|
|
72
|
+
CaptureSource m_source;
|
|
73
|
+
CaptureOptions m_options;
|
|
74
|
+
std::string m_last_error;
|
|
75
|
+
|
|
76
|
+
bool m_capturing = false;
|
|
77
|
+
|
|
78
|
+
struct Impl;
|
|
79
|
+
std::unique_ptr<Impl> m_impl;
|
|
80
|
+
|
|
81
|
+
bool setup_mic_capture();
|
|
82
|
+
void stop_mic_capture();
|
|
83
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <iostream>
|
|
4
|
+
#include <queue>
|
|
5
|
+
#include <string>
|
|
6
|
+
#include "Types.h"
|
|
7
|
+
#include <vector>
|
|
8
|
+
#include <cstdint>
|
|
9
|
+
|
|
10
|
+
extern "C"
|
|
11
|
+
{
|
|
12
|
+
struct AVCodec;
|
|
13
|
+
struct AVStream;
|
|
14
|
+
struct AVFormatContext;
|
|
15
|
+
struct AVCodecContext;
|
|
16
|
+
struct SwrContext;
|
|
17
|
+
struct AVAudioFifo;
|
|
18
|
+
struct AVFrame;
|
|
19
|
+
struct AVPacket;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
class AudioEncoder
|
|
23
|
+
{
|
|
24
|
+
private:
|
|
25
|
+
// state variables
|
|
26
|
+
bool m_initialized;
|
|
27
|
+
|
|
28
|
+
// conversion essentials
|
|
29
|
+
int m_sampleRate;
|
|
30
|
+
int m_channels;
|
|
31
|
+
int m_bitrate;
|
|
32
|
+
int64_t m_pts;
|
|
33
|
+
int64_t m_sampleCount;
|
|
34
|
+
int64_t m_nextInputPts;
|
|
35
|
+
std::queue<AVPacket *> m_packetQueue;
|
|
36
|
+
std::vector<std::string> m_chunkFileNames;
|
|
37
|
+
|
|
38
|
+
// FFMpeg
|
|
39
|
+
const AVCodec *m_codec;
|
|
40
|
+
OutputMode mode;
|
|
41
|
+
AVCodecContext *m_codecContext;
|
|
42
|
+
SwrContext *m_swrContext;
|
|
43
|
+
AVAudioFifo *m_audioFifo;
|
|
44
|
+
AVFrame *m_frame;
|
|
45
|
+
|
|
46
|
+
// standalone
|
|
47
|
+
AVStream *m_stream;
|
|
48
|
+
AVFormatContext *m_formatContext;
|
|
49
|
+
int currentChunkIndex;
|
|
50
|
+
double targetChunkDuration;
|
|
51
|
+
int64_t currentSegmentStartPts;
|
|
52
|
+
double currentSegmentDuration;
|
|
53
|
+
|
|
54
|
+
private:
|
|
55
|
+
bool shouldStartNewChunk() const;
|
|
56
|
+
void forceNewChunk();
|
|
57
|
+
// Drain encoder and handle remaining packets based on mode
|
|
58
|
+
void flushEncoder();
|
|
59
|
+
|
|
60
|
+
public:
|
|
61
|
+
AudioEncoder();
|
|
62
|
+
~AudioEncoder();
|
|
63
|
+
bool initialize(int sampleRate, int channels, int bitrate, OutputMode mode);
|
|
64
|
+
bool encodeSamples(const uint8_t *samples, int numSamples, int64_t pts = -1);
|
|
65
|
+
AVPacket *getNextPacket();
|
|
66
|
+
bool hasPackets() const;
|
|
67
|
+
std::string generatePlaylist() const;
|
|
68
|
+
void cleanup();
|
|
69
|
+
|
|
70
|
+
bool isInitialized() { return m_initialized; }
|
|
71
|
+
int getSampleRate() { return m_sampleRate; }
|
|
72
|
+
int getChannels() { return m_channels; }
|
|
73
|
+
const AVCodecContext *getCodecContext() const { return m_codecContext; }
|
|
74
|
+
OutputMode getMode() const { return mode; }
|
|
75
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <cstdint>
|
|
4
|
+
#include <functional>
|
|
5
|
+
#include <set>
|
|
6
|
+
#include <string>
|
|
7
|
+
|
|
8
|
+
extern "C" {
|
|
9
|
+
struct AVBSFContext;
|
|
10
|
+
struct AVCodecContext;
|
|
11
|
+
struct AVFormatContext;
|
|
12
|
+
struct AVPacket;
|
|
13
|
+
struct AVStream;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
class FileHLSMuxer {
|
|
17
|
+
public:
|
|
18
|
+
FileHLSMuxer();
|
|
19
|
+
~FileHLSMuxer();
|
|
20
|
+
|
|
21
|
+
bool init(const std::string& output_dir,
|
|
22
|
+
const std::string& recording_id,
|
|
23
|
+
int segment_time_sec,
|
|
24
|
+
const AVCodecContext* video_codec_ctx,
|
|
25
|
+
const AVCodecContext* audio_codec_ctx);
|
|
26
|
+
|
|
27
|
+
void set_expected_segment_duration_ms(double duration_ms);
|
|
28
|
+
void set_segment_ready_callback(std::function<void(const std::string&)> callback);
|
|
29
|
+
|
|
30
|
+
void push_video(AVPacket* pkt);
|
|
31
|
+
void push_audio(AVPacket* pkt);
|
|
32
|
+
|
|
33
|
+
void shutdown();
|
|
34
|
+
bool is_initialized() const { return m_initialized; }
|
|
35
|
+
|
|
36
|
+
private:
|
|
37
|
+
int write_packet(AVPacket* pkt, bool is_video);
|
|
38
|
+
bool init_h264_bsf_if_needed();
|
|
39
|
+
void log_overlong_segment_if_needed(AVPacket* pkt);
|
|
40
|
+
void notify_ready_segments();
|
|
41
|
+
|
|
42
|
+
AVFormatContext* m_fmt_ctx = nullptr;
|
|
43
|
+
AVStream* m_video_stream = nullptr;
|
|
44
|
+
AVStream* m_audio_stream = nullptr;
|
|
45
|
+
AVBSFContext* m_h264_bsf_ctx = nullptr;
|
|
46
|
+
|
|
47
|
+
std::string m_output_dir;
|
|
48
|
+
std::string m_recording_id;
|
|
49
|
+
std::string m_playlist_path;
|
|
50
|
+
std::set<std::string> m_notified_segments;
|
|
51
|
+
std::function<void(const std::string&)> m_segment_ready_callback;
|
|
52
|
+
bool m_initialized = false;
|
|
53
|
+
|
|
54
|
+
int m_fps = 30;
|
|
55
|
+
int m_sample_rate = 48000;
|
|
56
|
+
int m_audio_frame_samples = 1024;
|
|
57
|
+
int m_video_tb_num = 1;
|
|
58
|
+
int m_video_tb_den = 30;
|
|
59
|
+
int m_audio_tb_num = 1;
|
|
60
|
+
int m_audio_tb_den = 48000;
|
|
61
|
+
double m_expected_segment_duration_ms = 0.0;
|
|
62
|
+
int64_t m_last_segment_key_pts = -1;
|
|
63
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
/*
|
|
3
|
+
This Encoder in the default format needs to produce H264 packets
|
|
4
|
+
and when in the seperate stream mode it needs to produces TS chunks.
|
|
5
|
+
|
|
6
|
+
- Input: CVPixelBufferRef, BGRA
|
|
7
|
+
- Output:
|
|
8
|
+
- Default: H264 packets for the TS Muxer to process
|
|
9
|
+
- Seperate Stream: TS chunks with playlist.
|
|
10
|
+
|
|
11
|
+
I need to track frame count, timestamps, keyframes
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
#include "Types.h"
|
|
15
|
+
#include <cstdint>
|
|
16
|
+
#include <iostream>
|
|
17
|
+
#include <queue>
|
|
18
|
+
#include <vector>
|
|
19
|
+
|
|
20
|
+
extern "C"
|
|
21
|
+
{
|
|
22
|
+
struct AVCodecContext;
|
|
23
|
+
struct AVPacket;
|
|
24
|
+
struct AVCodec;
|
|
25
|
+
struct AVFrame;
|
|
26
|
+
struct SwsContext;
|
|
27
|
+
struct AVStream;
|
|
28
|
+
struct AVFormatContext;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
class VideoEncoder
|
|
32
|
+
{
|
|
33
|
+
// all variables
|
|
34
|
+
private:
|
|
35
|
+
int frameHeight;
|
|
36
|
+
int frameWidth;
|
|
37
|
+
int frameRate;
|
|
38
|
+
bool isPaused;
|
|
39
|
+
bool m_initialized;
|
|
40
|
+
|
|
41
|
+
// FFMPEG
|
|
42
|
+
AVCodecContext *m_codecContext;
|
|
43
|
+
const AVCodec *m_codec;
|
|
44
|
+
AVStream *m_stream;
|
|
45
|
+
AVFormatContext *m_formatContext;
|
|
46
|
+
AVFrame *m_frame;
|
|
47
|
+
SwsContext *m_swsContext;
|
|
48
|
+
|
|
49
|
+
// Timing & state
|
|
50
|
+
int64_t m_frameCount;
|
|
51
|
+
int64_t m_pts;
|
|
52
|
+
int64_t m_dts;
|
|
53
|
+
int64_t m_lastInputPts;
|
|
54
|
+
int64_t currentSegmentStartPts;
|
|
55
|
+
double currentSegmentDuration;
|
|
56
|
+
|
|
57
|
+
// Chunking
|
|
58
|
+
int currentChunkIndex;
|
|
59
|
+
double targetChunkDuration;
|
|
60
|
+
OutputMode mode;
|
|
61
|
+
std::vector<std::string> m_chunkFileNames;
|
|
62
|
+
|
|
63
|
+
// output buffer
|
|
64
|
+
std::queue<AVPacket *> m_packetQueue;
|
|
65
|
+
|
|
66
|
+
// all functions
|
|
67
|
+
public:
|
|
68
|
+
VideoEncoder();
|
|
69
|
+
~VideoEncoder();
|
|
70
|
+
bool initialize(int width, int height, int fps, int bitrate, OutputMode mode, int gopSize = 0);
|
|
71
|
+
bool encodeFrame(uint8_t *pixelData, int stride, int64_t pts = -1);
|
|
72
|
+
void cleanup();
|
|
73
|
+
|
|
74
|
+
// Chunk control
|
|
75
|
+
void forceKeyFrame();
|
|
76
|
+
bool shouldStartNewChunk() const;
|
|
77
|
+
|
|
78
|
+
// Muxed mode when we want just single stream
|
|
79
|
+
AVPacket *getNextPacket();
|
|
80
|
+
bool hasPackets() const;
|
|
81
|
+
std::string generatePlaylist() const;
|
|
82
|
+
|
|
83
|
+
// getters to get the state of the VideoEncoder
|
|
84
|
+
bool isInitialized() const { return m_initialized; }
|
|
85
|
+
int getWidth() const { return frameWidth; }
|
|
86
|
+
int getHeigth() const { return frameHeight; }
|
|
87
|
+
int getFPS() const { return frameRate; }
|
|
88
|
+
int64_t getFrameCount() const { return m_frameCount; }
|
|
89
|
+
const AVCodecContext *getCodecContext() const { return m_codecContext; }
|
|
90
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#include <cstdint>
|
|
3
|
+
#include <functional>
|
|
4
|
+
#include <memory>
|
|
5
|
+
#include <string>
|
|
6
|
+
|
|
7
|
+
struct PipelineConfig {
|
|
8
|
+
int width = 1920;
|
|
9
|
+
int height = 1080;
|
|
10
|
+
int fps = 30;
|
|
11
|
+
int gop_size = 30;
|
|
12
|
+
int video_bitrate = 9'000'000;
|
|
13
|
+
int sample_rate = 48000;
|
|
14
|
+
int channels = 2;
|
|
15
|
+
int audio_bitrate = 128'000;
|
|
16
|
+
std::string output_dir;
|
|
17
|
+
std::string recording_id;
|
|
18
|
+
int segment_time_sec = 4;
|
|
19
|
+
std::function<void(const std::string&)> segment_ready_callback;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
class MediaPipeline {
|
|
23
|
+
public:
|
|
24
|
+
MediaPipeline();
|
|
25
|
+
~MediaPipeline();
|
|
26
|
+
|
|
27
|
+
bool init(const PipelineConfig& cfg);
|
|
28
|
+
|
|
29
|
+
void push_video_frame(const uint8_t* data, int stride, int64_t pts_ticks,
|
|
30
|
+
bool is_keyframe_hint = false);
|
|
31
|
+
|
|
32
|
+
void push_audio_s16(const int16_t* data, int num_frames, int64_t pts_samples);
|
|
33
|
+
|
|
34
|
+
void flush_and_shutdown();
|
|
35
|
+
|
|
36
|
+
private:
|
|
37
|
+
struct Impl;
|
|
38
|
+
std::unique_ptr<Impl> m_impl;
|
|
39
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <Foundation/Foundation.h>
|
|
4
|
+
#include <ScreenCaptureKit/ScreenCaptureKit.h>
|
|
5
|
+
#include <cstdint>
|
|
6
|
+
#include <iostream>
|
|
7
|
+
#include <vector>
|
|
8
|
+
#include <ApplicationServices/ApplicationServices.h>
|
|
9
|
+
/*
|
|
10
|
+
food for thought: should I keep a shared
|
|
11
|
+
list of sources that get refreshed every
|
|
12
|
+
time, or should I just provide the functions
|
|
13
|
+
to get the list?
|
|
14
|
+
|
|
15
|
+
Both should be easy to do but ig we should
|
|
16
|
+
go with the idea where I just return the list
|
|
17
|
+
right!? Shouldn't complicate it too much
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
namespace SourceHelper
|
|
21
|
+
{
|
|
22
|
+
struct Displays
|
|
23
|
+
{
|
|
24
|
+
CGDirectDisplayID id;
|
|
25
|
+
uint32_t width;
|
|
26
|
+
uint32_t height;
|
|
27
|
+
std::string title;
|
|
28
|
+
bool isMain;
|
|
29
|
+
};
|
|
30
|
+
struct Windows
|
|
31
|
+
{
|
|
32
|
+
CGWindowID id;
|
|
33
|
+
uint32_t width;
|
|
34
|
+
uint32_t height;
|
|
35
|
+
std::string title;
|
|
36
|
+
// CGWindow
|
|
37
|
+
};
|
|
38
|
+
std::vector<Displays> getDisplaySources();
|
|
39
|
+
std::vector<Windows> getWindowSources();
|
|
40
|
+
bool isCaptureableWindow(const NSDictionary* windowInfo);
|
|
41
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <vector>
|
|
4
|
+
#include <cstdint>
|
|
5
|
+
#include <string>
|
|
6
|
+
|
|
7
|
+
namespace SourceHelperWrapper
|
|
8
|
+
{
|
|
9
|
+
struct Display
|
|
10
|
+
{
|
|
11
|
+
uint32_t id;
|
|
12
|
+
uint32_t width;
|
|
13
|
+
uint32_t height;
|
|
14
|
+
std::string title;
|
|
15
|
+
bool isMain;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
struct Window
|
|
19
|
+
{
|
|
20
|
+
uint32_t id;
|
|
21
|
+
uint32_t width;
|
|
22
|
+
uint32_t height;
|
|
23
|
+
std::string title;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
std::vector<Display> getDisplaySources();
|
|
27
|
+
std::vector<Window> getWindowSources();
|
|
28
|
+
bool isCaptureableWindow(uint32_t windowID);
|
|
29
|
+
}
|
package/include/Types.h
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
// only use for universal type definitions
|
|
4
|
+
#include <ApplicationServices/ApplicationServices.h>
|
|
5
|
+
#include <CoreFoundation/CFCGTypes.h>
|
|
6
|
+
#include <CoreGraphics/CGDirectDisplay.h>
|
|
7
|
+
#include <CoreGraphics/CGGeometry.h>
|
|
8
|
+
#include <CoreGraphics/CGWindow.h>
|
|
9
|
+
#include <cstdint>
|
|
10
|
+
#include <string>
|
|
11
|
+
|
|
12
|
+
/*
|
|
13
|
+
I think I wrote this very good ;)
|
|
14
|
+
PS Claude helped too! Constructor was it's idea
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
EDIT: modified to store the scContent
|
|
18
|
+
*/
|
|
19
|
+
struct CaptureSource {
|
|
20
|
+
bool isWindow;
|
|
21
|
+
union {
|
|
22
|
+
CGWindowID windowID;
|
|
23
|
+
CGDirectDisplayID displayID;
|
|
24
|
+
};
|
|
25
|
+
void *scContent;
|
|
26
|
+
uint32_t width;
|
|
27
|
+
uint32_t height;
|
|
28
|
+
std::string title;
|
|
29
|
+
CGRect captureRect;
|
|
30
|
+
|
|
31
|
+
static CaptureSource createWindow(CGWindowID id, uint32_t w, uint32_t h,
|
|
32
|
+
std::string t) {
|
|
33
|
+
CaptureSource s;
|
|
34
|
+
s.isWindow = true;
|
|
35
|
+
s.windowID = id;
|
|
36
|
+
s.width = w;
|
|
37
|
+
s.height = h;
|
|
38
|
+
s.title = t;
|
|
39
|
+
s.captureRect = CGRectMake(0, 0, w, h);
|
|
40
|
+
s.scContent = nullptr;
|
|
41
|
+
return s;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
static CaptureSource createDisplay(CGDirectDisplayID id, uint32_t w,
|
|
45
|
+
uint32_t h, std::string t) {
|
|
46
|
+
CaptureSource s;
|
|
47
|
+
s.isWindow = false;
|
|
48
|
+
s.displayID = id;
|
|
49
|
+
s.width = w;
|
|
50
|
+
s.height = h;
|
|
51
|
+
s.title = t;
|
|
52
|
+
s.captureRect = CGRectMake(0, 0, w, h);
|
|
53
|
+
s.scContent = nullptr;
|
|
54
|
+
return s;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
enum class OutputMode { STANDALONE, MUXED };
|