noobs 0.0.131 → 0.0.142

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/README.md CHANGED
@@ -11,6 +11,8 @@ Uses a [custom](https://github.com/aza547/warcraft-recorder-obs-studio) fork of
11
11
  - Enable "replay_buffer to recording".
12
12
  - Allow libobs to be used as a library easier.
13
13
 
14
+ Windows is the only supported platform.
15
+
14
16
  ## Installation
15
17
 
16
18
  ```bash
@@ -25,10 +27,9 @@ import noobs from 'noobs';
25
27
 
26
28
  const distPath = ...;
27
29
  const logPath = ...;
28
- const recordingPath = ...;
29
30
  const cb = (signal) => console.log(signal);
30
31
 
31
- noobs.Init(distPath, logPath, recordingPath, cb);
32
+ noobs.Init(distPath, logPath, cb);
32
33
  ...
33
34
  noobs.Shutdown();
34
35
  ```
package/dist/noobs.node CHANGED
Binary file
package/index.d.ts CHANGED
@@ -147,6 +147,10 @@ export type SceneItemPosition = {
147
147
  y: number; // Y position in pixels
148
148
  scaleX: number; // X scaling factor
149
149
  scaleY: number; // Y scaling factor
150
+ cropLeft: number; // Pixels to crop from the left
151
+ cropRight: number; // Pixels to crop from the right
152
+ cropTop: number; // Pixels to crop from the top
153
+ cropBottom: number; // Pixels to crop from the bottom
150
154
  };
151
155
 
152
156
  export type SourceDimensions = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "noobs",
3
- "version": "0.0.131",
3
+ "version": "0.0.142",
4
4
  "description": "A native Node.js addon with libobs bindings for Warcraft Recorder.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -9,6 +9,8 @@
9
9
  },
10
10
  "scripts": {
11
11
  "build": "node-gyp rebuild && node dist.js",
12
+ "test-errors": "ts-node --project test/tsconfig.json test/errors.ts",
13
+ "test-preview": "ts-node --project test/tsconfig.json test/preview.ts",
12
14
  "configure-cursor-anysphere": "node-gyp configure -- -f compile_commands_json && copy build\\Release\\compile_commands.json src\\compile_commands.json"
13
15
  },
14
16
  "files": [
@@ -24,7 +26,8 @@
24
26
  "license": "LGPL-2.0",
25
27
  "devDependencies": {
26
28
  "@types/node": "^24.1.0",
27
- "node-gyp": "^11.2.0"
29
+ "node-gyp": "^11.2.0",
30
+ "ts-node": "^10.9.2"
28
31
  },
29
32
  "dependencies": {
30
33
  "node-addon-api": "^8.4.0"
package/src/main.cpp CHANGED
@@ -37,7 +37,8 @@ Napi::Value ObsShutdown(const Napi::CallbackInfo& info) {
37
37
  Napi::Value ObsSetRecordingDir(const Napi::CallbackInfo& info) {
38
38
  if (!obs) {
39
39
  blog(LOG_ERROR, "ObsSetRecordingDir called but obs is not initialized");
40
- throw std::runtime_error("Obs not initialized");
40
+ Napi::Error::New(info.Env(), "Obs not initialized").ThrowAsJavaScriptException();
41
+ return info.Env().Undefined();
41
42
  }
42
43
 
43
44
  bool valid = info.Length() == 1 && info[0].IsString();
@@ -55,7 +56,8 @@ Napi::Value ObsSetRecordingDir(const Napi::CallbackInfo& info) {
55
56
  Napi::Value ObsResetVideoContext(const Napi::CallbackInfo& info) {
56
57
  if (!obs) {
57
58
  blog(LOG_ERROR, "ObsResetVideoContext called but obs is not initialized");
58
- throw std::runtime_error("Obs not initialized");
59
+ Napi::Error::New(info.Env(), "Obs not initialized").ThrowAsJavaScriptException();
60
+ return info.Env().Undefined();
59
61
  }
60
62
 
61
63
  bool valid = info.Length() == 3 && info[0].IsNumber() && info[1].IsNumber() && info[2].IsNumber();
@@ -76,7 +78,8 @@ Napi::Value ObsResetVideoContext(const Napi::CallbackInfo& info) {
76
78
  Napi::Value ObsListVideoEncoders(const Napi::CallbackInfo& info) {
77
79
  if (!obs) {
78
80
  blog(LOG_ERROR, "ObsListVideoEncoders called but obs is not initialized");
79
- throw std::runtime_error("Obs not initialized");
81
+ Napi::Error::New(info.Env(), "Obs not initialized").ThrowAsJavaScriptException();
82
+ return info.Env().Undefined();
80
83
  }
81
84
 
82
85
  bool valid = info.Length() == 0;
@@ -99,7 +102,8 @@ Napi::Value ObsListVideoEncoders(const Napi::CallbackInfo& info) {
99
102
  Napi::Value ObsSetVideoEncoder(const Napi::CallbackInfo& info) {
100
103
  if (!obs) {
101
104
  blog(LOG_ERROR, "ObsSetVideoEncoder called but obs is not initialized");
102
- throw std::runtime_error("Obs not initialized");
105
+ Napi::Error::New(info.Env(), "Obs not initialized").ThrowAsJavaScriptException();
106
+ return info.Env().Undefined();
103
107
  }
104
108
 
105
109
  bool valid = info.Length() == 2 &&
@@ -125,7 +129,8 @@ Napi::Value ObsSetBuffering(const Napi::CallbackInfo& info) {
125
129
 
126
130
  if (!obs) {
127
131
  blog(LOG_ERROR, "ObsSetBuffering called but obs is not initialized");
128
- throw std::runtime_error("Obs not initialized");
132
+ Napi::Error::New(info.Env(), "Obs not initialized").ThrowAsJavaScriptException();
133
+ return info.Env().Undefined();
129
134
  }
130
135
 
131
136
  bool valid = info.Length() == 1 && info[0].IsBoolean();
@@ -146,7 +151,8 @@ Napi::Value ObsStartBuffer(const Napi::CallbackInfo& info) {
146
151
 
147
152
  if (!obs) {
148
153
  blog(LOG_ERROR, "ObsStartBuffer called but obs is not initialized");
149
- throw std::runtime_error("Obs not initialized");
154
+ Napi::Error::New(info.Env(), "Obs not initialized").ThrowAsJavaScriptException();
155
+ return info.Env().Undefined();
150
156
  }
151
157
 
152
158
  obs->startBuffering();
@@ -156,7 +162,8 @@ Napi::Value ObsStartBuffer(const Napi::CallbackInfo& info) {
156
162
  Napi::Value ObsStartRecording(const Napi::CallbackInfo& info) {
157
163
  if (!obs) {
158
164
  blog(LOG_ERROR, "ObsStartRecording called but obs is not initialized");
159
- throw std::runtime_error("Obs not initialized");
165
+ Napi::Error::New(info.Env(), "Obs not initialized").ThrowAsJavaScriptException();
166
+ return info.Env().Undefined();
160
167
  }
161
168
 
162
169
  int offset = 0;
@@ -172,7 +179,8 @@ Napi::Value ObsStartRecording(const Napi::CallbackInfo& info) {
172
179
  Napi::Value ObsStopRecording(const Napi::CallbackInfo& info) {
173
180
  if (!obs) {
174
181
  blog(LOG_ERROR, "ObsStopRecording called but obs is not initialized");
175
- throw std::runtime_error("Obs not initialized");
182
+ Napi::Error::New(info.Env(), "Obs not initialized").ThrowAsJavaScriptException();
183
+ return info.Env().Undefined();
176
184
  }
177
185
 
178
186
  obs->stopRecording();
@@ -182,7 +190,8 @@ Napi::Value ObsStopRecording(const Napi::CallbackInfo& info) {
182
190
  Napi::Value ObsForceStopRecording(const Napi::CallbackInfo& info) {
183
191
  if (!obs) {
184
192
  blog(LOG_ERROR, "ObsForceStopRecording called but obs is not initialized");
185
- throw std::runtime_error("Obs not initialized");
193
+ Napi::Error::New(info.Env(), "Obs not initialized").ThrowAsJavaScriptException();
194
+ return info.Env().Undefined();
186
195
  }
187
196
 
188
197
  obs->forceStopRecording();
@@ -192,7 +201,8 @@ Napi::Value ObsForceStopRecording(const Napi::CallbackInfo& info) {
192
201
  Napi::Value ObsGetLastRecording(const Napi::CallbackInfo& info) {
193
202
  if (!obs) {
194
203
  blog(LOG_ERROR, "ObsGetLastRecording called but obs is not initialized");
195
- throw std::runtime_error("Obs not initialized");
204
+ Napi::Error::New(info.Env(), "Obs not initialized").ThrowAsJavaScriptException();
205
+ return info.Env().Undefined();
196
206
  }
197
207
 
198
208
  std::string lastRecording = obs->getLastRecording();
@@ -204,7 +214,8 @@ Napi::Value ObsInitPreview(const Napi::CallbackInfo& info) {
204
214
 
205
215
  if (!obs) {
206
216
  blog(LOG_ERROR, "ObsInitPreview called but obs is not initialized");
207
- throw std::runtime_error("Obs not initialized");
217
+ Napi::Error::New(info.Env(), "Obs not initialized").ThrowAsJavaScriptException();
218
+ return info.Env().Undefined();
208
219
  }
209
220
 
210
221
  bool valid = info.Length() == 1 && info[0].IsBuffer();
@@ -231,7 +242,8 @@ Napi::Value ObsConfigurePreview(const Napi::CallbackInfo& info) {
231
242
 
232
243
  if (!obs) {
233
244
  blog(LOG_ERROR, "ObsConfigurePreview called but obs is not initialized");
234
- throw std::runtime_error("Obs not initialized");
245
+ Napi::Error::New(info.Env(), "Obs not initialized").ThrowAsJavaScriptException();
246
+ return info.Env().Undefined();
235
247
  }
236
248
 
237
249
  bool valid = info.Length() == 4 &&
@@ -259,7 +271,8 @@ Napi::Value ObsShowPreview(const Napi::CallbackInfo& info) {
259
271
 
260
272
  if (!obs) {
261
273
  blog(LOG_ERROR, "ObsShowPreview called but obs is not initialized");
262
- throw std::runtime_error("Obs not initialized");
274
+ Napi::Error::New(info.Env(), "Obs not initialized").ThrowAsJavaScriptException();
275
+ return info.Env().Undefined();
263
276
  }
264
277
 
265
278
  obs->showPreview();
@@ -269,7 +282,8 @@ Napi::Value ObsShowPreview(const Napi::CallbackInfo& info) {
269
282
  Napi::Value ObsHidePreview(const Napi::CallbackInfo& info) {
270
283
  if (!obs) {
271
284
  blog(LOG_ERROR, "ObsHidePreview called but obs is not initialized");
272
- throw std::runtime_error("Obs not initialized");
285
+ Napi::Error::New(info.Env(), "Obs not initialized").ThrowAsJavaScriptException();
286
+ return info.Env().Undefined();
273
287
  }
274
288
 
275
289
  obs->hidePreview();
@@ -279,7 +293,8 @@ Napi::Value ObsHidePreview(const Napi::CallbackInfo& info) {
279
293
  Napi::Value ObsDisablePreview(const Napi::CallbackInfo& info) {
280
294
  if (!obs) {
281
295
  blog(LOG_ERROR, "ObsDisablePreview called but obs is not initialized");
282
- throw std::runtime_error("Obs not initialized");
296
+ Napi::Error::New(info.Env(), "Obs not initialized").ThrowAsJavaScriptException();
297
+ return info.Env().Undefined();
283
298
  }
284
299
 
285
300
  obs->disablePreview();
@@ -289,7 +304,8 @@ Napi::Value ObsDisablePreview(const Napi::CallbackInfo& info) {
289
304
  Napi::Value ObsGetPreviewInfo(const Napi::CallbackInfo& info) {
290
305
  if (!obs) {
291
306
  blog(LOG_ERROR, "ObsGetPreviewInfo called but obs is not initialized");
292
- throw std::runtime_error("Obs not initialized");
307
+ Napi::Error::New(info.Env(), "Obs not initialized").ThrowAsJavaScriptException();
308
+ return info.Env().Undefined();
293
309
  }
294
310
 
295
311
  PreviewInfo previewInfo = obs->getPreviewInfo();
@@ -306,7 +322,8 @@ Napi::Value ObsGetPreviewInfo(const Napi::CallbackInfo& info) {
306
322
  Napi::Value ObsCreateSource(const Napi::CallbackInfo& info) {
307
323
  if (!obs) {
308
324
  blog(LOG_ERROR, "ObsCreateSource called but obs is not initialized");
309
- throw std::runtime_error("Obs not initialized");
325
+ Napi::Error::New(info.Env(), "Obs not initialized").ThrowAsJavaScriptException();
326
+ return info.Env().Undefined();
310
327
  }
311
328
 
312
329
  bool valid = info.Length() == 2 &&
@@ -328,7 +345,8 @@ Napi::Value ObsCreateSource(const Napi::CallbackInfo& info) {
328
345
  Napi::Value ObsDeleteSource(const Napi::CallbackInfo& info) {
329
346
  if (!obs) {
330
347
  blog(LOG_ERROR, "ObsDeleteSource called but obs is not initialized");
331
- throw std::runtime_error("Obs not initialized");
348
+ Napi::Error::New(info.Env(), "Obs not initialized").ThrowAsJavaScriptException();
349
+ return info.Env().Undefined();
332
350
  }
333
351
 
334
352
  bool valid = info.Length() == 1 && info[0].IsString();
@@ -346,7 +364,9 @@ Napi::Value ObsDeleteSource(const Napi::CallbackInfo& info) {
346
364
  Napi::Value ObsGetSourceSettings(const Napi::CallbackInfo& info) {
347
365
  if (!obs) {
348
366
  blog(LOG_ERROR, "ObsGetSourceSettings called but obs is not initialized");
349
- throw std::runtime_error("Obs not initialized");
367
+ Napi::Env env = info.Env();
368
+ Napi::Error::New(env, "Obs not initialized").ThrowAsJavaScriptException();
369
+ return env.Undefined();
350
370
  }
351
371
 
352
372
  bool valid = info.Length() == 1 && info[0].IsString();
@@ -368,7 +388,8 @@ Napi::Value ObsGetSourceSettings(const Napi::CallbackInfo& info) {
368
388
  Napi::Value ObsSetSourceSettings(const Napi::CallbackInfo& info) {
369
389
  if (!obs) {
370
390
  blog(LOG_ERROR, "ObsSetSourceSettings called but obs is not initialized");
371
- throw std::runtime_error("Obs not initialized");
391
+ Napi::Error::New(info.Env(), "Obs not initialized").ThrowAsJavaScriptException();
392
+ return info.Env().Undefined();
372
393
  }
373
394
 
374
395
  bool valid = info.Length() == 2 && info[0].IsString() && info[1].IsObject();
@@ -391,7 +412,8 @@ Napi::Value ObsSetSourceSettings(const Napi::CallbackInfo& info) {
391
412
  Napi::Value ObsGetSourceProperties(const Napi::CallbackInfo& info) {
392
413
  if (!obs) {
393
414
  blog(LOG_ERROR, "ObsGetSourceProperties called but obs is not initialized");
394
- throw std::runtime_error("Obs not initialized");
415
+ Napi::Error::New(info.Env(), "Obs not initialized").ThrowAsJavaScriptException();
416
+ return info.Env().Undefined();
395
417
  }
396
418
 
397
419
  bool valid = info.Length() == 1 && info[0].IsString();
@@ -413,7 +435,8 @@ Napi::Value ObsGetSourceProperties(const Napi::CallbackInfo& info) {
413
435
  Napi::Value ObsSetMuteAudioInputs(const Napi::CallbackInfo& info) {
414
436
  if (!obs) {
415
437
  blog(LOG_ERROR, "ObsSetMuteAudioInputs called but obs is not initialized");
416
- throw std::runtime_error("Obs not initialized");
438
+ Napi::Error::New(info.Env(), "Obs not initialized").ThrowAsJavaScriptException();
439
+ return info.Env().Undefined();
417
440
  }
418
441
 
419
442
  bool valid = info.Length() == 1 && info[0].IsBoolean();
@@ -431,7 +454,8 @@ Napi::Value ObsSetMuteAudioInputs(const Napi::CallbackInfo& info) {
431
454
  Napi::Value ObsSetSourceVolume(const Napi::CallbackInfo& info) {
432
455
  if (!obs) {
433
456
  blog(LOG_ERROR, "ObsSetSourceVolume called but obs is not initialized");
434
- throw std::runtime_error("Obs not initialized");
457
+ Napi::Error::New(info.Env(), "Obs not initialized").ThrowAsJavaScriptException();
458
+ return info.Env().Undefined();
435
459
  }
436
460
 
437
461
  bool valid = info.Length() == 2 && info[0].IsString() && info[1].IsNumber();
@@ -450,7 +474,8 @@ Napi::Value ObsSetSourceVolume(const Napi::CallbackInfo& info) {
450
474
  Napi::Value ObsSetVolmeterEnabled(const Napi::CallbackInfo& info) {
451
475
  if (!obs) {
452
476
  blog(LOG_ERROR, "ObsSetVolmeterEnabled called but obs is not initialized");
453
- throw std::runtime_error("Obs not initialized");
477
+ Napi::Error::New(info.Env(), "Obs not initialized").ThrowAsJavaScriptException();
478
+ return info.Env().Undefined();
454
479
  }
455
480
 
456
481
  bool valid = info.Length() == 1 && info[0].IsBoolean();
@@ -469,7 +494,8 @@ Napi::Value ObsSetVolmeterEnabled(const Napi::CallbackInfo& info) {
469
494
  Napi::Value ObsSetAudioSuppression(const Napi::CallbackInfo& info) {
470
495
  if (!obs) {
471
496
  blog(LOG_ERROR, "ObsSetAudioSuppression called but obs is not initialized");
472
- throw std::runtime_error("Obs not initialized");
497
+ Napi::Error::New(info.Env(), "Obs not initialized").ThrowAsJavaScriptException();
498
+ return info.Env().Undefined();
473
499
  }
474
500
 
475
501
  bool valid = info.Length() == 1 && info[0].IsBoolean();
@@ -487,7 +513,8 @@ Napi::Value ObsSetAudioSuppression(const Napi::CallbackInfo& info) {
487
513
  Napi::Value ObsSetForceMono(const Napi::CallbackInfo& info) {
488
514
  if (!obs) {
489
515
  blog(LOG_ERROR, "ObsSetForceMono called but obs is not initialized");
490
- throw std::runtime_error("Obs not initialized");
516
+ Napi::Error::New(info.Env(), "Obs not initialized").ThrowAsJavaScriptException();
517
+ return info.Env().Undefined();
491
518
  }
492
519
 
493
520
  bool valid = info.Length() == 1 && info[0].IsBoolean();
@@ -505,7 +532,8 @@ Napi::Value ObsSetForceMono(const Napi::CallbackInfo& info) {
505
532
  Napi::Value ObsAddSourceToScene(const Napi::CallbackInfo& info) {
506
533
  if (!obs) {
507
534
  blog(LOG_ERROR, "ObsAddSourceToScene called but obs is not initialized");
508
- throw std::runtime_error("Obs not initialized");
535
+ Napi::Error::New(info.Env(), "Obs not initialized").ThrowAsJavaScriptException();
536
+ return info.Env().Undefined();
509
537
  }
510
538
 
511
539
  bool valid = info.Length() == 1 && info[0].IsString();
@@ -524,7 +552,8 @@ Napi::Value ObsAddSourceToScene(const Napi::CallbackInfo& info) {
524
552
  Napi::Value ObsRemoveSourceFromScene(const Napi::CallbackInfo& info) {
525
553
  if (!obs) {
526
554
  blog(LOG_ERROR, "ObsRemoveSourceFromScene called but obs is not initialized");
527
- throw std::runtime_error("Obs not initialized");
555
+ Napi::Error::New(info.Env(), "Obs not initialized").ThrowAsJavaScriptException();
556
+ return info.Env().Undefined();
528
557
  }
529
558
 
530
559
  bool valid = info.Length() == 1 && info[0].IsString();
@@ -542,7 +571,8 @@ Napi::Value ObsRemoveSourceFromScene(const Napi::CallbackInfo& info) {
542
571
  Napi::Value ObsGetSourcePos(const Napi::CallbackInfo& info) {
543
572
  if (!obs) {
544
573
  blog(LOG_ERROR, "ObsGetSourcePos called but obs is not initialized");
545
- throw std::runtime_error("Obs not initialized");
574
+ Napi::Error::New(info.Env(), "Obs not initialized").ThrowAsJavaScriptException();
575
+ return info.Env().Undefined();
546
576
  }
547
577
 
548
578
  bool valid = info.Length() == 1 && info[0].IsString();
@@ -554,23 +584,32 @@ Napi::Value ObsGetSourcePos(const Napi::CallbackInfo& info) {
554
584
 
555
585
  std::string name = info[0].As<Napi::String>().Utf8Value();
556
586
 
557
- vec2 pos; vec2 size; vec2 scale;
558
- obs->getSourcePos(name, &pos, &size, &scale);
587
+ vec2 pos; vec2 size; vec2 scale; obs_sceneitem_crop crop;
588
+ obs->getSourcePos(name, &pos, &size, &scale, &crop);
559
589
 
560
590
  Napi::Object result = Napi::Object::New(info.Env());
591
+
561
592
  result.Set("x", Napi::Number::New(info.Env(), pos.x));
562
593
  result.Set("y", Napi::Number::New(info.Env(), pos.y));
594
+
563
595
  result.Set("width", Napi::Number::New(info.Env(), size.x));
564
596
  result.Set("height", Napi::Number::New(info.Env(), size.y));
565
597
  result.Set("scaleX", Napi::Number::New(info.Env(), scale.x));
566
598
  result.Set("scaleY", Napi::Number::New(info.Env(), scale.y));
599
+
600
+ result.Set("cropLeft", Napi::Number::New(info.Env(), crop.left));
601
+ result.Set("cropRight", Napi::Number::New(info.Env(), crop.right));
602
+ result.Set("cropTop", Napi::Number::New(info.Env(), crop.top));
603
+ result.Set("cropBottom", Napi::Number::New(info.Env(), crop.bottom));
604
+
567
605
  return result;
568
606
  }
569
607
 
570
608
  Napi::Value ObsSetSourcePos(const Napi::CallbackInfo& info) {
571
609
  if (!obs) {
572
610
  blog(LOG_ERROR, "ObsSetSourcePos called but obs is not initialized");
573
- throw std::runtime_error("Obs not initialized");
611
+ Napi::Error::New(info.Env(), "Obs not initialized").ThrowAsJavaScriptException();
612
+ return info.Env().Undefined();
574
613
  }
575
614
 
576
615
  bool valid = info.Length() == 2 &&
@@ -593,7 +632,13 @@ Napi::Value ObsSetSourcePos(const Napi::CallbackInfo& info) {
593
632
  float scaleY = position.Get("scaleY").As<Napi::Number>().FloatValue();
594
633
  vec2 scale = { scaleX, scaleY };
595
634
 
596
- obs->setSourcePos(name, &pos, &scale);
635
+ int cropLeft = position.Get("cropLeft").As<Napi::Number>().Int32Value();
636
+ int cropRight = position.Get("cropRight").As<Napi::Number>().Int32Value();
637
+ int cropTop = position.Get("cropTop").As<Napi::Number>().Int32Value();
638
+ int cropBottom = position.Get("cropBottom").As<Napi::Number>().Int32Value();
639
+ obs_sceneitem_crop crop = { cropLeft, cropTop, cropRight, cropBottom }; // Careful with ordering.
640
+
641
+ obs->setSourcePos(name, &pos, &scale, &crop);
597
642
  return info.Env().Undefined();
598
643
  }
599
644
 
@@ -597,14 +597,15 @@ void ObsInterface::disconnect_signal_handlers(obs_output_t *output) {
597
597
 
598
598
  bool draw_source_outline(obs_scene_t *scene, obs_sceneitem_t *item, void *p) {
599
599
  // Get the item position and size
600
- vec2 pos; vec2 scale;
600
+ vec2 pos; vec2 scale; obs_sceneitem_crop crop;
601
601
  obs_sceneitem_get_pos(item, &pos);
602
602
  obs_sceneitem_get_scale(item, &scale);
603
+ obs_sceneitem_get_crop(item, &crop);
603
604
 
604
- // Calculate actual size with scaling
605
+ // Calculate actual size, accounting for scaling and cropping.
605
606
  obs_source_t *src = obs_sceneitem_get_source(item);
606
- float width = obs_source_get_width(src) * scale.x;
607
- float height = obs_source_get_height(src) * scale.y;
607
+ float width = (obs_source_get_width(src) - crop.left - crop.right) * scale.x;
608
+ float height = (obs_source_get_height(src) - crop.top - crop.bottom) * scale.y;
608
609
 
609
610
  if (width <= 0 || height <= 0) {
610
611
  // Don't want to call gs_draw_sprite with zero width or height.
@@ -634,7 +635,7 @@ bool draw_source_outline(obs_scene_t *scene, obs_sceneitem_t *item, void *p) {
634
635
 
635
636
  // Bottom border
636
637
  gs_matrix_push();
637
- gs_matrix_translate3f(pos.x, pos.y + height - 4.0f, 0.0f);
638
+ gs_matrix_translate3f(pos.x, pos.y + height - 4.0f, 0.0f);
638
639
  gs_draw_sprite(nullptr, 0, width, 4.0f);
639
640
  gs_matrix_pop();
640
641
 
@@ -652,7 +653,7 @@ bool draw_source_outline(obs_scene_t *scene, obs_sceneitem_t *item, void *p) {
652
653
 
653
654
  // Dragging point box (25x25 pixels in bottom-right corner)
654
655
  gs_matrix_push();
655
- gs_matrix_translate3f(pos.x + width - 25.0f, pos.y + height - 25.0f, 0.0f);
656
+ gs_matrix_translate3f(pos.x + width - 25.0f, pos.y + height - 25.0f, 0.0f);
656
657
  gs_draw_sprite(nullptr, 0, 25.0f, 25.0f);
657
658
  gs_matrix_pop();
658
659
 
@@ -1164,7 +1165,7 @@ void ObsInterface::removeSourceFromScene(std::string name) {
1164
1165
  blog(LOG_INFO, "ObsInterface::removeSourceFromScene exited");
1165
1166
  }
1166
1167
 
1167
- void ObsInterface::getSourcePos(std::string name, vec2* pos, vec2* size, vec2* scale)
1168
+ void ObsInterface::getSourcePos(std::string name, vec2* pos, vec2* size, vec2* scale, obs_sceneitem_crop* crop)
1168
1169
  {
1169
1170
  auto it = sources.find(name);
1170
1171
 
@@ -1189,13 +1190,14 @@ void ObsInterface::getSourcePos(std::string name, vec2* pos, vec2* size, vec2* s
1189
1190
 
1190
1191
  obs_sceneitem_get_pos(item, pos);
1191
1192
  obs_sceneitem_get_scale(item, scale);
1193
+ obs_sceneitem_get_crop(item, crop);
1192
1194
 
1193
1195
  // Pre-scaled sizes.
1194
1196
  size->x = obs_source_get_width(source);
1195
1197
  size->y = obs_source_get_height(source);
1196
1198
  }
1197
1199
 
1198
- void ObsInterface::setSourcePos(std::string name, vec2* pos, vec2* scale) {
1200
+ void ObsInterface::setSourcePos(std::string name, vec2* pos, vec2* scale, obs_sceneitem_crop* crop) {
1199
1201
  obs_sceneitem_t *item = obs_scene_find_source(scene, name.c_str());
1200
1202
 
1201
1203
  if (!item) {
@@ -1205,6 +1207,7 @@ void ObsInterface::setSourcePos(std::string name, vec2* pos, vec2* scale) {
1205
1207
 
1206
1208
  obs_sceneitem_set_pos(item, pos);
1207
1209
  obs_sceneitem_set_scale(item, scale);
1210
+ obs_sceneitem_set_crop(item, crop);
1208
1211
  }
1209
1212
 
1210
1213
  std::vector<std::string> ObsInterface::listAvailableVideoEncoders()
@@ -67,8 +67,8 @@ class ObsInterface {
67
67
 
68
68
  void addSourceToScene(std::string name); // Add source to scene.
69
69
  void removeSourceFromScene(std::string name); // Remove source from scene.
70
- void getSourcePos(std::string name, vec2* pos, vec2* size, vec2* scale); // Size is returned to allow clients to calculate scale.
71
- void setSourcePos(std::string name, vec2* pos, vec2* scale); // Size does not get set here because it's set by the source itself.
70
+ void getSourcePos(std::string name, vec2* pos, vec2* size, vec2* scale, obs_sceneitem_crop* crop); // Size is returned to allow clients to calculate scale.
71
+ void setSourcePos(std::string name, vec2* pos, vec2* scale, obs_sceneitem_crop* crop); // Size does not get set here because it's set by the source itself.
72
72
 
73
73
  void initPreview(HWND parent); // Must call this before showPreview to setup resources.
74
74
  void configurePreview(int x, int y, int width, int height); // Move and resize the preview display.