noobs 0.0.33 → 0.0.63
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.
- package/dist/noobs.node +0 -0
- package/dist/plugins/image-source.dll +0 -0
- package/dist/plugins/win-wasapi.dll +0 -0
- package/index.d.ts +150 -3
- package/index.js +1 -1
- package/package.json +1 -1
- package/src/main.cpp +212 -25
- package/src/obs_interface.cpp +316 -60
- package/src/obs_interface.h +24 -13
- package/src/utils.cpp +317 -1
- package/src/utils.h +10 -1
package/src/obs_interface.cpp
CHANGED
|
@@ -6,6 +6,12 @@
|
|
|
6
6
|
#include "obs_interface.h"
|
|
7
7
|
#include <vector>
|
|
8
8
|
#include <thread>
|
|
9
|
+
#include <iostream>
|
|
10
|
+
#include <map>
|
|
11
|
+
#include <string>
|
|
12
|
+
#include <graphics/matrix4.h>
|
|
13
|
+
#include <graphics/vec4.h>
|
|
14
|
+
#include <util/platform.h>
|
|
9
15
|
|
|
10
16
|
std::vector<std::string> ObsInterface::get_available_video_encoders()
|
|
11
17
|
{
|
|
@@ -158,7 +164,14 @@ void ObsInterface::init_obs(const std::string& pluginPath, const std::string& da
|
|
|
158
164
|
}
|
|
159
165
|
|
|
160
166
|
obs_add_data_path(dp.c_str()); // This is deprecated in libobs but it works for now.
|
|
161
|
-
|
|
167
|
+
|
|
168
|
+
std::vector<std::string> modules = {
|
|
169
|
+
"obs-x264.dll",
|
|
170
|
+
"obs-ffmpeg.dll",
|
|
171
|
+
"win-capture.dll", // Required for basically all forms of capture on Windows.
|
|
172
|
+
"image-source.dll", // Required for image sources.
|
|
173
|
+
"win-wasapi.dll" // Required for WASAPI audio input.
|
|
174
|
+
};
|
|
162
175
|
|
|
163
176
|
for (const auto& module : modules) {
|
|
164
177
|
std::string path = pluginPath + "/" + module;
|
|
@@ -178,33 +191,46 @@ void ObsInterface::init_obs(const std::string& pluginPath, const std::string& da
|
|
|
178
191
|
blog(LOG_INFO, "Exit init_obs");
|
|
179
192
|
}
|
|
180
193
|
|
|
181
|
-
void ObsInterface::
|
|
194
|
+
void ObsInterface::create_output(const std::string& recordingPath, bool buffering) {
|
|
182
195
|
blog(LOG_INFO, "Create output");
|
|
183
196
|
|
|
184
|
-
if (output && obs_output_active(output)) {
|
|
185
|
-
blog(LOG_ERROR, "Tried to recreate active output");
|
|
186
|
-
throw std::runtime_error("Failed to create output!");
|
|
187
|
-
}
|
|
188
|
-
|
|
189
197
|
if (output) {
|
|
190
198
|
blog(LOG_DEBUG, "Releasing output");
|
|
191
199
|
obs_output_release(output);
|
|
192
200
|
}
|
|
193
201
|
|
|
194
|
-
|
|
202
|
+
if (buffering) {
|
|
203
|
+
blog(LOG_INFO, "Creating replay buffer output");
|
|
204
|
+
output = obs_output_create("replay_buffer", "recording_output", NULL, NULL);
|
|
205
|
+
} else {
|
|
206
|
+
blog(LOG_INFO, "Creating file output");
|
|
207
|
+
output = obs_output_create("ffmpeg_muxer", "recording_output", NULL, NULL);
|
|
208
|
+
}
|
|
195
209
|
|
|
196
210
|
if (!output) {
|
|
197
211
|
blog(LOG_ERROR, "Failed to create output!");
|
|
198
212
|
throw std::runtime_error("Failed to create output!");
|
|
199
213
|
}
|
|
200
|
-
|
|
201
|
-
blog(LOG_INFO, "Set output settings");
|
|
214
|
+
|
|
202
215
|
obs_data_t *settings = obs_data_create();
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
216
|
+
|
|
217
|
+
if (buffering) {
|
|
218
|
+
blog(LOG_INFO, "Set replay_buffer settings");
|
|
219
|
+
obs_data_set_int(settings, "max_time_sec", 60);
|
|
220
|
+
obs_data_set_int(settings, "max_size_mb", 1024);
|
|
221
|
+
obs_data_set_string(settings, "directory", recordingPath.c_str());
|
|
222
|
+
obs_data_set_string(settings, "format", "%CCYY-%MM-%DD %hh-%mm-%ss");
|
|
223
|
+
obs_data_set_string(settings, "extension", "mp4");
|
|
224
|
+
} else {
|
|
225
|
+
blog(LOG_INFO, "Set ffmpeg_muxer settings");
|
|
226
|
+
obs_data_set_string(settings, "extension", "mp4");
|
|
227
|
+
// Apparently need to specify the exact path for ffmpeg_muxer.
|
|
228
|
+
// TODO add something to auto generate this ?
|
|
229
|
+
obs_data_set_string(settings, "path", (recordingPath + "/noobs.mp4").c_str());
|
|
230
|
+
recording_path = recordingPath + "/noobs.mp4";
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Apply and release the settings.
|
|
208
234
|
obs_output_update(output, settings);
|
|
209
235
|
obs_data_release(settings);
|
|
210
236
|
|
|
@@ -212,6 +238,33 @@ void ObsInterface::configure_output(const std::string& recordingPath) {
|
|
|
212
238
|
create_signal_handlers(output);
|
|
213
239
|
}
|
|
214
240
|
|
|
241
|
+
void ObsInterface::setRecordingDir(const std::string& recordingPath) {
|
|
242
|
+
blog(LOG_INFO, "Set recording directory");
|
|
243
|
+
// TODO make this work for file output also.
|
|
244
|
+
|
|
245
|
+
if (!output) {
|
|
246
|
+
blog(LOG_ERROR, "No output to update recording directory");
|
|
247
|
+
throw std::runtime_error("Output not initialized");
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// check its not active
|
|
251
|
+
if (obs_output_active(output)) {
|
|
252
|
+
blog(LOG_ERROR, "Output is active, cannot update recording path");
|
|
253
|
+
throw std::runtime_error("Output is active, cannot update recording path");
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
obs_data_t *settings = obs_output_get_settings(output);
|
|
257
|
+
|
|
258
|
+
if (!settings) {
|
|
259
|
+
blog(LOG_ERROR, "Failed to get output settings");
|
|
260
|
+
throw std::runtime_error("Failed to get output settings");
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
obs_data_set_string(settings, "directory", recordingPath.c_str());
|
|
264
|
+
obs_output_update(output, settings);
|
|
265
|
+
obs_data_release(settings);
|
|
266
|
+
}
|
|
267
|
+
|
|
215
268
|
void ObsInterface::configure_video_encoder() {
|
|
216
269
|
blog(LOG_INFO, "Create video encoder");
|
|
217
270
|
|
|
@@ -278,15 +331,8 @@ void ObsInterface::configure_audio_encoder() {
|
|
|
278
331
|
obs_encoder_set_audio(audio_encoder, obs_get_audio());
|
|
279
332
|
}
|
|
280
333
|
|
|
281
|
-
void ObsInterface::
|
|
282
|
-
blog(LOG_INFO, "
|
|
283
|
-
|
|
284
|
-
if (scene) {
|
|
285
|
-
blog(LOG_DEBUG, "Releasing scene");
|
|
286
|
-
obs_scene_release(scene);
|
|
287
|
-
scene = nullptr;
|
|
288
|
-
}
|
|
289
|
-
|
|
334
|
+
void ObsInterface::create_scene() {
|
|
335
|
+
blog(LOG_INFO, "Create scene");
|
|
290
336
|
scene = obs_scene_create("WCR Scene");
|
|
291
337
|
|
|
292
338
|
if (!scene) {
|
|
@@ -302,24 +348,85 @@ void ObsInterface::configure_scene() {
|
|
|
302
348
|
}
|
|
303
349
|
|
|
304
350
|
obs_set_output_source(0, scene_source); // 0 = video track
|
|
305
|
-
obs_scene_add(scene, video_source);
|
|
306
351
|
}
|
|
307
352
|
|
|
308
|
-
void ObsInterface::
|
|
309
|
-
blog(LOG_INFO, "Create
|
|
353
|
+
void ObsInterface::createSource(std::string name, std::string type) {
|
|
354
|
+
blog(LOG_INFO, "Create source: %s of type %s", name.c_str(), type.c_str());
|
|
355
|
+
|
|
356
|
+
obs_source_t *source = obs_source_create(
|
|
357
|
+
type.c_str(),
|
|
358
|
+
name.c_str(),
|
|
359
|
+
NULL, // No settings.
|
|
360
|
+
NULL // No hotkey data.
|
|
361
|
+
);
|
|
362
|
+
|
|
363
|
+
if (!source) {
|
|
364
|
+
blog(LOG_ERROR, "Failed to create source: %s", name.c_str());
|
|
365
|
+
throw std::runtime_error("Failed to create source!");
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
void ObsInterface::deleteSource(std::string name) {
|
|
370
|
+
blog(LOG_INFO, "Delete source: %s", name.c_str());
|
|
371
|
+
obs_source_t *source = obs_get_source_by_name(name.c_str());
|
|
372
|
+
|
|
373
|
+
if (!source) {
|
|
374
|
+
blog(LOG_WARNING, "Source not found: %s", name.c_str());
|
|
375
|
+
return; // Source not found, nothing to delete.
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
obs_source_release(source);
|
|
379
|
+
blog(LOG_INFO, "Source deleted: %s", name.c_str());
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
obs_data_t* ObsInterface::getSourceSettings(std::string name) {
|
|
383
|
+
blog(LOG_INFO, "Get source settings for: %s", name.c_str());
|
|
384
|
+
obs_source_t *source = obs_get_source_by_name(name.c_str());
|
|
385
|
+
|
|
386
|
+
if (!source) {
|
|
387
|
+
blog(LOG_ERROR, "Source not found: %s", name.c_str());
|
|
388
|
+
throw std::runtime_error("Source not found!");
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
obs_data_t *settings = obs_source_get_settings(source);
|
|
392
|
+
|
|
393
|
+
if (!settings) {
|
|
394
|
+
blog(LOG_ERROR, "Failed to get settings for source: %s", name.c_str());
|
|
395
|
+
throw std::runtime_error("Failed to get source settings!");
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
return settings;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
void ObsInterface::setSourceSettings(std::string name, obs_data_t* settings) {
|
|
402
|
+
blog(LOG_INFO, "Set source settings for: %s", name.c_str());
|
|
403
|
+
obs_source_t *source = obs_get_source_by_name(name.c_str());
|
|
310
404
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
405
|
+
if (!source) {
|
|
406
|
+
blog(LOG_ERROR, "Source not found: %s", name.c_str());
|
|
407
|
+
throw std::runtime_error("Source not found!");
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
obs_source_update(source, settings);
|
|
411
|
+
}
|
|
315
412
|
|
|
316
|
-
|
|
317
|
-
|
|
413
|
+
obs_properties_t* ObsInterface::getSourceProperties(std::string name) {
|
|
414
|
+
blog(LOG_INFO, "Get source properties for: %s", name.c_str());
|
|
415
|
+
obs_source_t *source = obs_get_source_by_name(name.c_str());
|
|
318
416
|
|
|
319
|
-
if (!
|
|
320
|
-
blog(LOG_ERROR, "
|
|
321
|
-
throw std::runtime_error("
|
|
417
|
+
if (!source) {
|
|
418
|
+
blog(LOG_ERROR, "Source not found: %s", name.c_str());
|
|
419
|
+
throw std::runtime_error("Source not found!");
|
|
322
420
|
}
|
|
421
|
+
|
|
422
|
+
obs_properties_t *props = obs_source_properties(source);
|
|
423
|
+
|
|
424
|
+
if (!props) {
|
|
425
|
+
blog(LOG_ERROR, "Failed to get properties for source: %s", name.c_str());
|
|
426
|
+
throw std::runtime_error("Failed to get source properties!");
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
return props;
|
|
323
430
|
}
|
|
324
431
|
|
|
325
432
|
void call_jscb(Napi::Env env, Napi::Function cb, SignalData* sd) {
|
|
@@ -374,8 +481,76 @@ void ObsInterface::create_signal_handlers(obs_output_t *output) {
|
|
|
374
481
|
signal_handler_connect(sh, "saved", output_signal_handler_saved, this);
|
|
375
482
|
}
|
|
376
483
|
|
|
484
|
+
bool draw_box(obs_scene_t *scene, obs_sceneitem_t *item, void *p) {
|
|
485
|
+
// Get the item position and size
|
|
486
|
+
vec2 pos; vec2 scale;
|
|
487
|
+
obs_sceneitem_get_pos(item, &pos);
|
|
488
|
+
obs_sceneitem_get_scale(item, &scale);
|
|
489
|
+
|
|
490
|
+
// Calculate actual size with scaling
|
|
491
|
+
obs_source_t *src = obs_sceneitem_get_source(item);
|
|
492
|
+
float width = obs_source_get_width(src) * scale.x;
|
|
493
|
+
float height = obs_source_get_height(src) * scale.y;
|
|
494
|
+
|
|
495
|
+
// Draw rectangle around the source using the position and size
|
|
496
|
+
gs_effect_t *solid = obs_get_base_effect(OBS_EFFECT_SOLID);
|
|
497
|
+
gs_eparam_t *color = gs_effect_get_param_by_name(solid, "color");
|
|
498
|
+
gs_technique_t *tech = gs_effect_get_technique(solid, "Solid");
|
|
499
|
+
|
|
500
|
+
vec4 col = {0.733f, 0.267f, 0.125f, 1.0f}; // #BB4420
|
|
501
|
+
gs_effect_set_vec4(color, &col);
|
|
502
|
+
|
|
503
|
+
gs_technique_begin(tech);
|
|
504
|
+
gs_technique_begin_pass(tech, 0);
|
|
505
|
+
|
|
506
|
+
gs_matrix_push();
|
|
507
|
+
gs_matrix_identity();
|
|
508
|
+
|
|
509
|
+
// Top border
|
|
510
|
+
gs_matrix_push();
|
|
511
|
+
gs_matrix_translate3f(pos.x, pos.y, 0.0f);
|
|
512
|
+
gs_draw_sprite(nullptr, 0, width, 2.0f);
|
|
513
|
+
gs_matrix_pop();
|
|
514
|
+
|
|
515
|
+
// Bottom border
|
|
516
|
+
gs_matrix_push();
|
|
517
|
+
gs_matrix_translate3f(pos.x, pos.y + height - 2.0f, 0.0f);
|
|
518
|
+
gs_draw_sprite(nullptr, 0, width, 2.0f);
|
|
519
|
+
gs_matrix_pop();
|
|
520
|
+
|
|
521
|
+
// Left border
|
|
522
|
+
gs_matrix_push();
|
|
523
|
+
gs_matrix_translate3f(pos.x, pos.y, 0.0f);
|
|
524
|
+
gs_draw_sprite(nullptr, 0, 2.0f, height);
|
|
525
|
+
gs_matrix_pop();
|
|
526
|
+
|
|
527
|
+
// Right border
|
|
528
|
+
gs_matrix_push();
|
|
529
|
+
gs_matrix_translate3f(pos.x + width - 2.0f, pos.y, 0.0f);
|
|
530
|
+
gs_draw_sprite(nullptr, 0, 2.0f, height);
|
|
531
|
+
gs_matrix_pop();
|
|
532
|
+
|
|
533
|
+
gs_matrix_pop();
|
|
534
|
+
|
|
535
|
+
gs_technique_end_pass(tech);
|
|
536
|
+
gs_technique_end(tech);
|
|
537
|
+
|
|
538
|
+
return true;
|
|
539
|
+
}
|
|
540
|
+
|
|
377
541
|
void draw_callback(void* data, uint32_t cx, uint32_t cy) {
|
|
542
|
+
// Initially, draw the OBS scene texture
|
|
378
543
|
obs_render_main_texture();
|
|
544
|
+
|
|
545
|
+
// This is some AI code that would draw a rectangle (and works).
|
|
546
|
+
// Set projection and viewport
|
|
547
|
+
gs_ortho(0.0f, float(cx), 0.0f, float(cy), -100.0f, 100.0f);
|
|
548
|
+
gs_set_viewport(0, 0, cx, cy);
|
|
549
|
+
|
|
550
|
+
// This was me trying to understand what OSN does.
|
|
551
|
+
obs_scene_t* scene = obs_get_scene_by_name("WCR Scene");
|
|
552
|
+
obs_scene_enum_items(scene, draw_box, NULL);
|
|
553
|
+
obs_scene_release(scene);
|
|
379
554
|
}
|
|
380
555
|
|
|
381
556
|
void ObsInterface::initPreview(HWND parent) {
|
|
@@ -470,7 +645,8 @@ ObsInterface::ObsInterface(
|
|
|
470
645
|
const std::string& logPath,
|
|
471
646
|
const std::string& dataPath,
|
|
472
647
|
const std::string& recordingPath,
|
|
473
|
-
Napi::ThreadSafeFunction cb
|
|
648
|
+
Napi::ThreadSafeFunction cb,
|
|
649
|
+
bool buffering
|
|
474
650
|
) {
|
|
475
651
|
// Setup logs first so we have logs for the initialization.
|
|
476
652
|
base_set_log_handler(log_handler, (void*)logPath.c_str());
|
|
@@ -483,11 +659,11 @@ ObsInterface::ObsInterface(
|
|
|
483
659
|
jscb = cb;
|
|
484
660
|
|
|
485
661
|
// Create the resources we rely on.
|
|
486
|
-
|
|
662
|
+
create_output(recordingPath, buffering);
|
|
663
|
+
create_scene();
|
|
664
|
+
|
|
487
665
|
configure_video_encoder();
|
|
488
666
|
configure_audio_encoder();
|
|
489
|
-
configure_video_source();
|
|
490
|
-
configure_scene();
|
|
491
667
|
}
|
|
492
668
|
|
|
493
669
|
ObsInterface::~ObsInterface() {
|
|
@@ -557,26 +733,52 @@ void ObsInterface::startBuffering() {
|
|
|
557
733
|
|
|
558
734
|
void ObsInterface::startRecording(int offset) {
|
|
559
735
|
blog(LOG_INFO, "ObsInterface::startRecording enter");
|
|
560
|
-
bool is_active = obs_output_active(output);
|
|
561
736
|
|
|
562
|
-
|
|
563
|
-
blog(LOG_ERROR, "Buffer is not active");
|
|
564
|
-
throw std::runtime_error("Buffer is not active");
|
|
565
|
-
}
|
|
737
|
+
const char* type = obs_output_get_id(output);
|
|
566
738
|
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
calldata_init(&cd);
|
|
570
|
-
calldata_set_int(&cd, "offset_seconds", offset);
|
|
571
|
-
proc_handler_t *ph = obs_output_get_proc_handler(output);
|
|
572
|
-
bool success = proc_handler_call(ph, "convert", &cd);
|
|
573
|
-
calldata_free(&cd);
|
|
739
|
+
if (strcmp(type, "replay_buffer") == 0) {
|
|
740
|
+
bool is_active = obs_output_active(output);
|
|
574
741
|
|
|
575
|
-
|
|
576
|
-
|
|
742
|
+
if (!is_active) {
|
|
743
|
+
blog(LOG_WARNING, "Buffer is not active");
|
|
744
|
+
throw std::runtime_error("Buffer is not active");
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
blog(LOG_INFO, "calling save proc handler");
|
|
748
|
+
calldata cd;
|
|
749
|
+
calldata_init(&cd);
|
|
750
|
+
calldata_set_int(&cd, "offset_seconds", offset);
|
|
751
|
+
proc_handler_t *ph = obs_output_get_proc_handler(output);
|
|
752
|
+
bool success = proc_handler_call(ph, "convert", &cd);
|
|
753
|
+
calldata_free(&cd);
|
|
754
|
+
|
|
755
|
+
if (!success) {
|
|
756
|
+
throw std::runtime_error("Failed to call convert procedure handler");
|
|
757
|
+
}
|
|
758
|
+
} else if (strcmp(type, "ffmpeg_muxer") == 0) {
|
|
759
|
+
blog(LOG_INFO, "Starting ffmpeg_muxer output");
|
|
760
|
+
|
|
761
|
+
bool is_active = obs_output_active(output);
|
|
762
|
+
|
|
763
|
+
if (is_active) {
|
|
764
|
+
blog(LOG_WARNING, "Output already active");
|
|
765
|
+
return;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
blog(LOG_WARNING, "Call start");
|
|
769
|
+
bool success = obs_output_start(output);
|
|
770
|
+
|
|
771
|
+
if (!success) {
|
|
772
|
+
const char *err = obs_output_get_last_error(output);
|
|
773
|
+
blog(LOG_ERROR, "Failed to start recording: %s", err ? err : "Unknown error");
|
|
774
|
+
throw std::runtime_error("Failed to start recording");
|
|
775
|
+
}
|
|
776
|
+
} else {
|
|
777
|
+
blog(LOG_ERROR, "Unknown output type: %s", type);
|
|
778
|
+
throw std::runtime_error("Unknown output type!");
|
|
577
779
|
}
|
|
578
780
|
|
|
579
|
-
|
|
781
|
+
blog(LOG_INFO, "ObsInterface::startRecording exit");
|
|
580
782
|
}
|
|
581
783
|
|
|
582
784
|
void ObsInterface::stopRecording() {
|
|
@@ -597,10 +799,27 @@ std::string ObsInterface::getLastRecording() {
|
|
|
597
799
|
calldata cd;
|
|
598
800
|
calldata_init(&cd);
|
|
599
801
|
proc_handler_t *ph = obs_output_get_proc_handler(output);
|
|
600
|
-
|
|
802
|
+
|
|
803
|
+
const char* type = obs_output_get_id(output);
|
|
804
|
+
|
|
805
|
+
if (strcmp(type, "ffmpeg_muxer") == 0) {
|
|
806
|
+
blog(LOG_INFO, "Getting last recording path from ffmpeg_muxer");
|
|
807
|
+
return recording_path;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
bool success;
|
|
811
|
+
|
|
812
|
+
if (strcmp(type, "replay_buffer") != 0) {
|
|
813
|
+
blog(LOG_ERROR, "Unknown output type: %s", type);
|
|
814
|
+
throw std::runtime_error("Unknown output type!");
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
success = proc_handler_call(ph, "get_last_replay", &cd);
|
|
601
818
|
|
|
602
819
|
if (!success) {
|
|
603
|
-
blog(LOG_ERROR, "Failed to call
|
|
820
|
+
blog(LOG_ERROR, "Failed to call procedure handler");
|
|
821
|
+
const char *err = obs_output_get_last_error(output);
|
|
822
|
+
blog(LOG_ERROR, "%s", err ? err : "Unknown error");
|
|
604
823
|
calldata_free(&cd);
|
|
605
824
|
return "";
|
|
606
825
|
}
|
|
@@ -613,6 +832,43 @@ std::string ObsInterface::getLastRecording() {
|
|
|
613
832
|
return path;
|
|
614
833
|
}
|
|
615
834
|
|
|
835
|
+
void ObsInterface::addSourceToScene(std::string name) {
|
|
836
|
+
blog(LOG_INFO, "ObsInterface::addSourceToScene called for source: %s", name.c_str());
|
|
837
|
+
|
|
838
|
+
obs_source_t *src = obs_get_source_by_name(name.c_str());
|
|
839
|
+
|
|
840
|
+
if (!src) {
|
|
841
|
+
blog(LOG_WARNING, "Did not find source for video source: %s", name.c_str());
|
|
842
|
+
return;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
// TODO refuse to add twice?
|
|
846
|
+
|
|
847
|
+
obs_sceneitem_t *item = obs_scene_add(scene, src);
|
|
848
|
+
|
|
849
|
+
if (!item) {
|
|
850
|
+
blog(LOG_ERROR, "Failed to add source to scene: %s", name.c_str());
|
|
851
|
+
obs_source_release(src);
|
|
852
|
+
return;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
blog(LOG_INFO, "ObsInterface::addSourceToScene exited");
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
void ObsInterface::removeSourceFromScene(std::string name) {
|
|
859
|
+
blog(LOG_INFO, "ObsInterface::removeSourceFromScene called for source: %s", name.c_str());
|
|
860
|
+
|
|
861
|
+
obs_sceneitem_t *item = obs_scene_find_source(scene, name.c_str());
|
|
862
|
+
|
|
863
|
+
if (!item) {
|
|
864
|
+
blog(LOG_WARNING, "Did not find scene item for video source: %s", name.c_str());
|
|
865
|
+
return;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
obs_sceneitem_remove(item);
|
|
869
|
+
blog(LOG_INFO, "ObsInterface::removeSourceFromScene exited");
|
|
870
|
+
}
|
|
871
|
+
|
|
616
872
|
void ObsInterface::getSourcePos(std::string name, vec2* pos, vec2* size, vec2* scale)
|
|
617
873
|
{
|
|
618
874
|
blog(LOG_INFO, "ObsInterface::getSourcePos called");
|
|
@@ -621,12 +877,12 @@ void ObsInterface::getSourcePos(std::string name, vec2* pos, vec2* size, vec2* s
|
|
|
621
877
|
obs_sceneitem_t *item = obs_scene_find_source(scene, name.c_str());
|
|
622
878
|
|
|
623
879
|
if (!src) {
|
|
624
|
-
blog(
|
|
880
|
+
blog(LOG_WARNING, "Did not find source for video source: %s", name);
|
|
625
881
|
return;
|
|
626
882
|
}
|
|
627
883
|
|
|
628
884
|
if (!item) {
|
|
629
|
-
blog(
|
|
885
|
+
blog(LOG_WARNING, "Did not find scene item for video source: %s", name);
|
|
630
886
|
return;
|
|
631
887
|
}
|
|
632
888
|
|
|
@@ -645,7 +901,7 @@ void ObsInterface::setSourcePos(std::string name, vec2* pos, vec2* scale) {
|
|
|
645
901
|
obs_sceneitem_t *item = obs_scene_find_source(scene, name.c_str());
|
|
646
902
|
|
|
647
903
|
if (!item) {
|
|
648
|
-
blog(
|
|
904
|
+
blog(LOG_WARNING, "Did not find scene item for video source: %s", name);
|
|
649
905
|
return;
|
|
650
906
|
}
|
|
651
907
|
|
package/src/obs_interface.h
CHANGED
|
@@ -10,26 +10,36 @@ struct SignalData {
|
|
|
10
10
|
class ObsInterface {
|
|
11
11
|
public:
|
|
12
12
|
ObsInterface(
|
|
13
|
-
const std::string& pluginPath, //
|
|
14
|
-
const std::string& logPath, //
|
|
15
|
-
const std::string& dataPath, //
|
|
16
|
-
const std::string& recordingPath, //
|
|
17
|
-
Napi::ThreadSafeFunction cb
|
|
13
|
+
const std::string& pluginPath, // Where to look for plugins
|
|
14
|
+
const std::string& logPath, // Where to write logs to
|
|
15
|
+
const std::string& dataPath, // Where to look for effects
|
|
16
|
+
const std::string& recordingPath, // Where to save recordings
|
|
17
|
+
Napi::ThreadSafeFunction cb, // JavaScript callback
|
|
18
|
+
bool buffering // Whether to enable buffering the recording in memory
|
|
18
19
|
);
|
|
19
20
|
|
|
20
21
|
~ObsInterface();
|
|
21
22
|
|
|
22
|
-
void startBuffering();
|
|
23
|
-
void startRecording(int offset);
|
|
24
|
-
void stopRecording();
|
|
25
|
-
std::string getLastRecording();
|
|
23
|
+
void startBuffering(); // Start buffering to memory.
|
|
24
|
+
void startRecording(int offset); // Convert the active buffered recording to a real one.
|
|
25
|
+
void stopRecording(); // Stop the recording.
|
|
26
|
+
std::string getLastRecording(); // Get the last recorded file path.
|
|
27
|
+
void setRecordingDir(const std::string& recordingPath); // Output must not be active when calling this.
|
|
26
28
|
|
|
29
|
+
void createSource(std::string name, std::string type); // Create a new source
|
|
30
|
+
void deleteSource(std::string name); // Release a source.
|
|
31
|
+
obs_data_t* getSourceSettings(std::string name); // Get the current settings.
|
|
32
|
+
void setSourceSettings(std::string name, obs_data_t* settings); // Set settings.
|
|
33
|
+
obs_properties_t* getSourceProperties(std::string name); // Get the settings schema.
|
|
34
|
+
|
|
35
|
+
void addSourceToScene(std::string name); // Add source to scene.
|
|
36
|
+
void removeSourceFromScene(std::string name); // Remove source from scene.
|
|
27
37
|
void getSourcePos(std::string name, vec2* pos, vec2* size, vec2* scale); // Size is returned to allow clients to calculate scale.
|
|
28
38
|
void setSourcePos(std::string name, vec2* pos, vec2* scale); // Size does not get set here because it's set by the source itself.
|
|
29
39
|
|
|
30
40
|
void initPreview(HWND parent); // Must call this before showPreview to setup resources.
|
|
31
41
|
void showPreview(int x, int y, int width, int height); // Also used for moving and resizing.
|
|
32
|
-
void hidePreview();
|
|
42
|
+
void hidePreview(); // Hide the preview display.
|
|
33
43
|
|
|
34
44
|
std::vector<std::string> get_available_video_encoders();
|
|
35
45
|
|
|
@@ -50,6 +60,7 @@ class ObsInterface {
|
|
|
50
60
|
obs_display_t *display = nullptr;
|
|
51
61
|
HWND preview_hwnd = nullptr; // window handle for scene preview
|
|
52
62
|
Napi::ThreadSafeFunction jscb; // javascript callback
|
|
63
|
+
std::string recording_path = "";
|
|
53
64
|
|
|
54
65
|
void init_obs(const std::string& pluginPath, const std::string& dataPath);
|
|
55
66
|
void reset_video();
|
|
@@ -68,9 +79,9 @@ class ObsInterface {
|
|
|
68
79
|
void list_input_types();
|
|
69
80
|
void list_output_types();
|
|
70
81
|
|
|
71
|
-
void
|
|
82
|
+
void create_scene();
|
|
83
|
+
void create_output(const std::string& recordingPath, bool buffering);
|
|
84
|
+
|
|
72
85
|
void configure_video_encoder();
|
|
73
86
|
void configure_audio_encoder();
|
|
74
|
-
void configure_scene();
|
|
75
|
-
void configure_video_source();
|
|
76
87
|
};
|