@byteplus/react-native-live-push 1.1.3-rc.4 → 1.3.0-rc.0

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.
Files changed (68) hide show
  1. package/android/build.gradle +2 -2
  2. package/android/src/main/java/com/volcengine/velive/rn/push/ClassHelper.java +9 -0
  3. package/android/src/main/java/com/volcengine/velive/rn/push/NativeVariableManager.java +5 -8
  4. package/android/src/main/java/com/volcengine/velive/rn/push/VeLivePushModule.java +1 -0
  5. package/android/src/main/java/com/volcengine/velive/rn/push/mixer/MixerManager.java +2 -4
  6. package/android/src/main/java/com/volcengine/velive/rn/push/mixer/MixerView.java +50 -145
  7. package/android/src/main/java/com/volcengine/velive/rn/push/mixer/MixerViewManager.java +1 -37
  8. package/ios/VeLiveMixerHelper.h +16 -11
  9. package/ios/VeLiveMixerHelper.m +39 -13
  10. package/ios/VeLiveMixerView.h +1 -8
  11. package/ios/VeLiveMixerView.m +178 -231
  12. package/ios/VeLiveMixerViewManager.m +2 -38
  13. package/lib/commonjs/index.js +23205 -20306
  14. package/lib/commonjs/typescript/android/index.d.ts +0 -3
  15. package/lib/commonjs/typescript/codegen/android/api.d.ts +190 -644
  16. package/lib/commonjs/typescript/codegen/android/callback.d.ts +234 -2
  17. package/lib/commonjs/typescript/codegen/android/errorcode.d.ts +66 -0
  18. package/lib/commonjs/typescript/codegen/android/keytype.d.ts +1014 -181
  19. package/lib/commonjs/typescript/codegen/ios/api.d.ts +890 -0
  20. package/lib/commonjs/typescript/codegen/ios/callback.d.ts +162 -0
  21. package/lib/commonjs/typescript/codegen/ios/errorcode.d.ts +101 -1
  22. package/lib/commonjs/typescript/codegen/ios/keytype.d.ts +694 -0
  23. package/lib/commonjs/typescript/codegen/pack/api.d.ts +303 -686
  24. package/lib/commonjs/typescript/codegen/pack/callback.d.ts +37 -38
  25. package/lib/commonjs/typescript/codegen/pack/errorcode.d.ts +75 -5
  26. package/lib/commonjs/typescript/codegen/pack/keytype.d.ts +1002 -298
  27. package/lib/commonjs/typescript/core/api.d.ts +2 -1
  28. package/lib/commonjs/typescript/core/keytype.d.ts +2 -3
  29. package/lib/commonjs/typescript/core/pusher.d.ts +0 -3
  30. package/lib/commonjs/typescript/view/MixView.d.ts +1 -9
  31. package/lib/module/index.js +23206 -20306
  32. package/lib/module/typescript/android/index.d.ts +0 -3
  33. package/lib/module/typescript/codegen/android/api.d.ts +190 -644
  34. package/lib/module/typescript/codegen/android/callback.d.ts +234 -2
  35. package/lib/module/typescript/codegen/android/errorcode.d.ts +66 -0
  36. package/lib/module/typescript/codegen/android/keytype.d.ts +1014 -181
  37. package/lib/module/typescript/codegen/ios/api.d.ts +890 -0
  38. package/lib/module/typescript/codegen/ios/callback.d.ts +162 -0
  39. package/lib/module/typescript/codegen/ios/errorcode.d.ts +101 -1
  40. package/lib/module/typescript/codegen/ios/keytype.d.ts +694 -0
  41. package/lib/module/typescript/codegen/pack/api.d.ts +303 -686
  42. package/lib/module/typescript/codegen/pack/callback.d.ts +37 -38
  43. package/lib/module/typescript/codegen/pack/errorcode.d.ts +75 -5
  44. package/lib/module/typescript/codegen/pack/keytype.d.ts +1002 -298
  45. package/lib/module/typescript/core/api.d.ts +2 -1
  46. package/lib/module/typescript/core/keytype.d.ts +2 -3
  47. package/lib/module/typescript/core/pusher.d.ts +0 -3
  48. package/lib/module/typescript/view/MixView.d.ts +1 -9
  49. package/lib/typescript/android/index.d.ts +0 -3
  50. package/lib/typescript/codegen/android/api.d.ts +190 -644
  51. package/lib/typescript/codegen/android/callback.d.ts +234 -2
  52. package/lib/typescript/codegen/android/errorcode.d.ts +66 -0
  53. package/lib/typescript/codegen/android/keytype.d.ts +1014 -181
  54. package/lib/typescript/codegen/ios/api.d.ts +890 -0
  55. package/lib/typescript/codegen/ios/callback.d.ts +162 -0
  56. package/lib/typescript/codegen/ios/errorcode.d.ts +101 -1
  57. package/lib/typescript/codegen/ios/keytype.d.ts +694 -0
  58. package/lib/typescript/codegen/pack/api.d.ts +303 -686
  59. package/lib/typescript/codegen/pack/callback.d.ts +37 -38
  60. package/lib/typescript/codegen/pack/errorcode.d.ts +75 -5
  61. package/lib/typescript/codegen/pack/keytype.d.ts +1002 -298
  62. package/lib/typescript/core/api.d.ts +2 -1
  63. package/lib/typescript/core/keytype.d.ts +2 -3
  64. package/lib/typescript/core/pusher.d.ts +0 -3
  65. package/lib/typescript/view/MixView.d.ts +1 -9
  66. package/package.json +1 -1
  67. package/react-native-velive-push.podspec +3 -3
  68. package/android/src/main/java/com/volcengine/velive/rn/push/ScreenCaptureHelper.java +0 -73
@@ -8,24 +8,16 @@
8
8
  #import "VeLiveMixerView.h"
9
9
  #import "VeLiveMixerHelper.h"
10
10
  #import <AVFoundation/AVFoundation.h>
11
+ #import <CoreImage/CoreImage.h>
11
12
  #import <CoreMedia/CoreMedia.h>
12
13
  #import <CoreVideo/CoreVideo.h>
13
14
  #import <UIKit/UIKit.h>
14
15
 
15
16
  @interface VeLiveMixerUIView ()
16
17
 
17
- // Mix configuration - Align with Android
18
- @property(nonatomic, assign) float mixX;
19
- @property(nonatomic, assign) float mixY;
20
- @property(nonatomic, assign) float mixWidth;
21
- @property(nonatomic, assign) float mixHeight;
22
- @property(nonatomic, assign) int mixZOrder;
23
- @property(nonatomic, assign) int mixRenderMode;
24
-
25
18
  // Capture configuration - Internal properties
26
19
  @property(nonatomic, strong) NSString *internalCaptureMode;
27
20
  @property(nonatomic, assign) float internalCaptureFramerate;
28
- @property(nonatomic, assign) float internalAutoSensitivity;
29
21
 
30
22
  // Capture state - Align with Android
31
23
  @property(nonatomic, strong) NSTimer *captureTimer;
@@ -34,21 +26,12 @@
34
26
  @property(nonatomic, assign) CFTimeInterval lastCaptureTime;
35
27
 
36
28
  // Performance optimization - Align with Android
37
- @property(nonatomic, strong) UIImage *lastBitmap;
38
-
39
- // Auto mode state - Align with Android
40
- @property(nonatomic, assign) int changeCount;
41
- @property(nonatomic, assign) CFTimeInterval windowStartTime;
42
- @property(nonatomic, assign) BOOL isInRealtimeMode;
29
+ @property(nonatomic) CVPixelBufferRef lastPixelBuffer;
43
30
 
44
31
  @end
45
32
 
46
33
  @implementation VeLiveMixerUIView
47
34
 
48
- static const CFTimeInterval AUTO_WINDOW_SECONDS = 2.0; // 2 second window
49
- static const int HIGH_CHANGE_THRESHOLD = 10;
50
- static const int LOW_CHANGE_THRESHOLD = 2;
51
-
52
35
  - (instancetype)initWithFrame:(CGRect)frame {
53
36
  self = [super initWithFrame:frame];
54
37
  if (self) {
@@ -69,25 +52,13 @@ static const int LOW_CHANGE_THRESHOLD = 2;
69
52
 
70
53
  - (void)initializeCapture {
71
54
  // Initialize defaults - Completely align with Android
72
- _mixX = 0.0f;
73
- _mixY = 0.0f;
74
- _mixWidth = 0.0f;
75
- _mixHeight = 0.0f;
76
- _mixZOrder = 0;
77
- _mixRenderMode = 0;
78
-
79
55
  _internalCaptureMode = @"onchange";
80
- _internalCaptureFramerate = 30.0f;
81
- _internalAutoSensitivity = 5.0f;
56
+ _internalCaptureFramerate = 5.0f; // realTime mode default 5 fps
82
57
 
83
58
  _isCapturing = NO;
84
59
  _isDestroyed = NO;
85
60
  _lastCaptureTime = 0;
86
-
87
- // Auto mode state
88
- _changeCount = 0;
89
- _windowStartTime = 0;
90
- _isInRealtimeMode = NO;
61
+ _lastPixelBuffer = NULL;
91
62
  }
92
63
 
93
64
  #pragma mark - Property Getters/Setters - Align with React Native props
@@ -116,14 +87,6 @@ static const int LOW_CHANGE_THRESHOLD = 2;
116
87
  }
117
88
  }
118
89
 
119
- - (NSNumber *)autoSensitivity {
120
- return @(self.internalAutoSensitivity);
121
- }
122
-
123
- - (void)setAutoSensitivity:(NSNumber *)sensitivity {
124
- _internalAutoSensitivity = MAX(1.0f, MIN(10.0f, [sensitivity floatValue]));
125
- }
126
-
127
90
  - (void)setViewId:(NSString *)viewId {
128
91
  if (!viewId) {
129
92
  return;
@@ -142,61 +105,6 @@ static const int LOW_CHANGE_THRESHOLD = 2;
142
105
  }
143
106
  }
144
107
 
145
- #pragma mark - Property setters for React Native props - Align with Android
146
-
147
- // React Native property setter - Corresponds to VeLiveMixerViewManager.m
148
- // properties
149
- - (void)setX:(NSNumber *)x {
150
- _x = x;
151
- _mixX = [x floatValue];
152
- }
153
-
154
- - (void)setY:(NSNumber *)y {
155
- _y = y;
156
- _mixY = [y floatValue];
157
- }
158
-
159
- - (void)setWidth:(NSNumber *)width {
160
- _width = width;
161
- _mixWidth = [width floatValue];
162
- }
163
-
164
- - (void)setHeight:(NSNumber *)height {
165
- _height = height;
166
- _mixHeight = [height floatValue];
167
- }
168
-
169
- - (void)setZOrder:(NSNumber *)zOrder {
170
- _zOrder = zOrder;
171
- _mixZOrder = [zOrder intValue];
172
- }
173
-
174
- - (void)setRenderMode:(NSNumber *)renderMode {
175
- _renderMode = renderMode;
176
- _mixRenderMode = [renderMode intValue];
177
- }
178
-
179
- #pragma mark - Internal setters for mix configuration - Internal use
180
-
181
- - (void)setMixX:(float)x {
182
- _mixX = x;
183
- }
184
- - (void)setMixY:(float)y {
185
- _mixY = y;
186
- }
187
- - (void)setMixWidth:(float)width {
188
- _mixWidth = width;
189
- }
190
- - (void)setMixHeight:(float)height {
191
- _mixHeight = height;
192
- }
193
- - (void)setMixZOrder:(int)zOrder {
194
- _mixZOrder = zOrder;
195
- }
196
- - (void)setMixRenderMode:(int)renderMode {
197
- _mixRenderMode = renderMode;
198
- }
199
-
200
108
  #pragma mark - Capture Methods - Completely align with Android
201
109
 
202
110
  - (void)startCapture {
@@ -207,8 +115,6 @@ static const int LOW_CHANGE_THRESHOLD = 2;
207
115
  [self startOnChangeCapture];
208
116
  } else if ([self.internalCaptureMode isEqualToString:@"realtime"]) {
209
117
  [self startRealtimeCapture];
210
- } else if ([self.internalCaptureMode isEqualToString:@"auto"]) {
211
- [self startAutoCapture];
212
118
  }
213
119
  // manual mode doesn't auto-start
214
120
  }
@@ -220,7 +126,22 @@ static const int LOW_CHANGE_THRESHOLD = 2;
220
126
  }
221
127
 
222
128
  - (void)startOnChangeCapture {
223
- // onchange mode triggers in layoutSubviews
129
+ // onchange mode triggers every 2 seconds
130
+ self.captureTimer =
131
+ [NSTimer scheduledTimerWithTimeInterval:2.0
132
+ target:self
133
+ selector:@selector(onChangeCapture)
134
+ userInfo:nil
135
+ repeats:YES];
136
+ }
137
+
138
+ - (void)onChangeCapture {
139
+ if (!self.isDestroyed &&
140
+ [self.internalCaptureMode isEqualToString:@"onchange"]) {
141
+ @autoreleasepool {
142
+ [self performCapture:@"onchange"];
143
+ }
144
+ }
224
145
  }
225
146
 
226
147
  - (void)startRealtimeCapture {
@@ -262,59 +183,6 @@ static const int LOW_CHANGE_THRESHOLD = 2;
262
183
  }
263
184
  }
264
185
 
265
- - (void)startAutoCapture {
266
- // Start with onchange mode
267
- self.isInRealtimeMode = NO;
268
- self.windowStartTime = CACurrentMediaTime();
269
- self.changeCount = 0;
270
- [self startOnChangeCapture];
271
- }
272
-
273
- #pragma mark - Layout Change Detection - Align with Android's onViewChanged
274
-
275
- - (void)handleAutoModeChange {
276
- if (!self.isInRealtimeMode) {
277
- [self performCapture:@"auto_onchange"];
278
- }
279
-
280
- // Count changes for auto mode
281
- self.changeCount++;
282
-
283
- CFTimeInterval currentTime = CACurrentMediaTime();
284
- if (currentTime - self.windowStartTime >= AUTO_WINDOW_SECONDS) {
285
- [self evaluateAutoMode];
286
- // Reset window
287
- self.windowStartTime = currentTime;
288
- self.changeCount = 0;
289
- }
290
- }
291
-
292
- - (void)evaluateAutoMode {
293
- float changesPerSecond = self.changeCount / AUTO_WINDOW_SECONDS;
294
- float threshold = self.internalAutoSensitivity;
295
-
296
- BOOL shouldBeRealtime =
297
- changesPerSecond > (HIGH_CHANGE_THRESHOLD / threshold);
298
- BOOL shouldBeOnChange = changesPerSecond < (LOW_CHANGE_THRESHOLD / threshold);
299
-
300
- if (shouldBeRealtime && !self.isInRealtimeMode) {
301
- [self switchToRealtimeMode];
302
- } else if (shouldBeOnChange && self.isInRealtimeMode) {
303
- [self switchToOnChangeMode];
304
- }
305
- }
306
-
307
- - (void)switchToRealtimeMode {
308
- self.isInRealtimeMode = YES;
309
- [self startRealtimeCapture];
310
- }
311
-
312
- - (void)switchToOnChangeMode {
313
- self.isInRealtimeMode = NO;
314
- [self.captureTimer invalidate];
315
- self.captureTimer = nil;
316
- }
317
-
318
186
  #pragma mark - Core Capture Logic - Align with Android's performCapture
319
187
 
320
188
  - (void)performCapture:(NSString *)trigger {
@@ -323,7 +191,7 @@ static const int LOW_CHANGE_THRESHOLD = 2;
323
191
 
324
192
  // Throttle captures to prevent excessive calls
325
193
  CFTimeInterval currentTime = CACurrentMediaTime();
326
- if (currentTime - self.lastCaptureTime < 1.0 / 60.0) { // Max 60fps
194
+ if (currentTime - self.lastCaptureTime < 1.0 / 30.0) { // Max 30fps
327
195
  return;
328
196
  }
329
197
  self.lastCaptureTime = currentTime;
@@ -331,9 +199,10 @@ static const int LOW_CHANGE_THRESHOLD = 2;
331
199
  self.isCapturing = YES;
332
200
 
333
201
  @try {
334
- UIImage *bitmap = [self createBitmap];
335
- if (bitmap) {
336
- [self processBitmap:bitmap trigger:trigger];
202
+ CVPixelBufferRef pixelBuffer = [self createPixelBuffer];
203
+ if (pixelBuffer) {
204
+ [self processPixelBuffer:pixelBuffer trigger:trigger];
205
+ CVPixelBufferRelease(pixelBuffer);
337
206
  }
338
207
  } @finally {
339
208
  self.isCapturing = NO;
@@ -385,75 +254,6 @@ static const int LOW_CHANGE_THRESHOLD = 2;
385
254
  }
386
255
  }
387
256
 
388
- - (void)processBitmap:(UIImage *)bitmap trigger:(NSString *)trigger {
389
- @autoreleasepool {
390
- if (!bitmap || bitmap.size.width <= 0 || bitmap.size.height <= 0) {
391
- return;
392
- }
393
-
394
- // Check bitmap memory size and skip if too large
395
- CGFloat bitmapMemoryMB =
396
- (bitmap.size.width * bitmap.size.height * 4.0) / (1024.0 * 1024.0);
397
- if (bitmapMemoryMB > 50.0) { // Skip bitmaps larger than 50MB
398
- return;
399
- }
400
-
401
- if (self.bitmapCaptureCallback) {
402
- @try {
403
- [self.bitmapCaptureCallback onBitmapCaptured:bitmap];
404
- } @catch (NSException *exception) {
405
- if (self.bitmapCaptureCallback) {
406
- [self.bitmapCaptureCallback
407
- onCaptureError:[NSString stringWithFormat:@"Callback error: %@",
408
- exception.reason]];
409
- }
410
- }
411
- }
412
-
413
- if (self.onBitmapCapture) {
414
- @autoreleasepool {
415
- NSDictionary *event = @{
416
- @"trigger" : trigger ?: @"unknown",
417
- @"success" : @(YES),
418
- @"x" : @(self.mixX),
419
- @"y" : @(self.mixY),
420
- @"width" : @(self.mixWidth),
421
- @"height" : @(self.mixHeight),
422
- @"zOrder" : @(self.mixZOrder),
423
- @"renderMode" : @(self.mixRenderMode),
424
- @"bitmapWidth" : @(bitmap.size.width),
425
- @"bitmapHeight" : @(bitmap.size.height)
426
- };
427
- self.onBitmapCapture(event);
428
- }
429
- }
430
-
431
- // Clean up old bitmap immediately
432
- if (self.lastBitmap) {
433
- self.lastBitmap = nil;
434
- }
435
-
436
- // For realtime mode, don't keep bitmap reference to reduce memory usage
437
- if ([trigger isEqualToString:@"realtime"]) {
438
- // Bitmap will be auto-released at autoreleasepool end
439
-
440
- // Force memory cleanup every 10 realtime captures
441
- static int realtimeCount = 0;
442
- realtimeCount++;
443
- if (realtimeCount % 10 == 0) {
444
- dispatch_async(
445
- dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
446
- @autoreleasepool {
447
- [[NSURLCache sharedURLCache] removeAllCachedResponses];
448
- }
449
- });
450
- }
451
- } else {
452
- self.lastBitmap = bitmap;
453
- }
454
- }
455
- }
456
-
457
257
  #pragma mark - Public Methods - Align with Android interface
458
258
 
459
259
  // Align with Android's performManualCapture
@@ -472,8 +272,11 @@ static const int LOW_CHANGE_THRESHOLD = 2;
472
272
  self.isDestroyed = YES;
473
273
  [self stopCapture];
474
274
 
475
- // Clean up bitmap cache
476
- self.lastBitmap = nil;
275
+ // Clean up pixelBuffer cache
276
+ if (self.lastPixelBuffer) {
277
+ CVPixelBufferRelease(self.lastPixelBuffer);
278
+ self.lastPixelBuffer = NULL;
279
+ }
477
280
 
478
281
  // Clean up callback references, avoid circular references
479
282
  self.bitmapCaptureCallback = nil;
@@ -537,8 +340,12 @@ static const int LOW_CHANGE_THRESHOLD = 2;
537
340
  }
538
341
 
539
342
  - (CVPixelBufferRef)createPixelBuffer {
540
- // Implement pixel buffer creation (corresponds to Android's ByteBuffer)
541
- return NULL; // Temporary return NULL, implementation based on needs
343
+ UIImage *bitmap = [self createBitmap];
344
+ if (!bitmap) {
345
+ return NULL;
346
+ }
347
+
348
+ return [self pixelBufferFromUIImage:bitmap];
542
349
  }
543
350
 
544
351
  - (CMSampleBufferRef)createSampleBuffer {
@@ -587,8 +394,6 @@ static const int LOW_CHANGE_THRESHOLD = 2;
587
394
  // Original capture logic
588
395
  if ([self.internalCaptureMode isEqualToString:@"onchange"]) {
589
396
  [self performCapture:@"onchange"];
590
- } else if ([self.internalCaptureMode isEqualToString:@"auto"]) {
591
- [self handleAutoModeChange];
592
397
  }
593
398
  }
594
399
 
@@ -597,4 +402,146 @@ static const int LOW_CHANGE_THRESHOLD = 2;
597
402
  [super setBackgroundColor:backgroundColor];
598
403
  }
599
404
 
405
+ #pragma mark - Helper Methods
406
+
407
+ - (CVPixelBufferRef)pixelBufferFromUIImage:(UIImage *)image {
408
+ if (!image) {
409
+ return NULL;
410
+ }
411
+
412
+ CGImageRef cgImage = image.CGImage;
413
+ if (!cgImage) {
414
+ return NULL;
415
+ }
416
+
417
+ CGFloat width = CGImageGetWidth(cgImage);
418
+ CGFloat height = CGImageGetHeight(cgImage);
419
+
420
+ NSDictionary *options = @{
421
+ (NSString *)kCVPixelBufferCGImageCompatibilityKey : @YES,
422
+ (NSString *)kCVPixelBufferCGBitmapContextCompatibilityKey : @YES,
423
+ (NSString *)kCVPixelBufferIOSurfacePropertiesKey : @{}
424
+ };
425
+
426
+ CVPixelBufferRef pixelBuffer = NULL;
427
+ CVReturn status = CVPixelBufferCreate(
428
+ kCFAllocatorDefault, width, height, kCVPixelFormatType_32BGRA,
429
+ (__bridge CFDictionaryRef)options, &pixelBuffer);
430
+
431
+ if (status != kCVReturnSuccess || !pixelBuffer) {
432
+ return NULL;
433
+ }
434
+
435
+ CVPixelBufferLockBaseAddress(pixelBuffer, 0);
436
+
437
+ void *pixelData = CVPixelBufferGetBaseAddress(pixelBuffer);
438
+ size_t bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer);
439
+
440
+ CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
441
+ CGContextRef context = CGBitmapContextCreate(
442
+ pixelData, width, height, 8, bytesPerRow, colorSpace,
443
+ kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host);
444
+
445
+ if (!context) {
446
+ CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
447
+ CVPixelBufferRelease(pixelBuffer);
448
+ CGColorSpaceRelease(colorSpace);
449
+ return NULL;
450
+ }
451
+
452
+ CGContextDrawImage(context, CGRectMake(0, 0, width, height), cgImage);
453
+
454
+ CGContextRelease(context);
455
+ CGColorSpaceRelease(colorSpace);
456
+ CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
457
+
458
+ return pixelBuffer;
459
+ }
460
+
461
+ - (void)processPixelBuffer:(CVPixelBufferRef)pixelBuffer
462
+ trigger:(NSString *)trigger {
463
+ @autoreleasepool {
464
+ if (!pixelBuffer) {
465
+ return;
466
+ }
467
+
468
+ // Clean up old pixelBuffer cache
469
+ if (self.lastPixelBuffer) {
470
+ CVPixelBufferRelease(self.lastPixelBuffer);
471
+ self.lastPixelBuffer = NULL;
472
+ }
473
+
474
+ // Cache pixelBuffer for non-realtime modes
475
+ if (![trigger isEqualToString:@"realtime"]) {
476
+ // Retain current pixelBuffer as cache
477
+ CVPixelBufferRetain(pixelBuffer);
478
+ self.lastPixelBuffer = pixelBuffer;
479
+ }
480
+
481
+ // If callback is needed, create temporary UIImage
482
+ if (self.bitmapCaptureCallback || self.onBitmapCapture) {
483
+ UIImage *bitmap = [self UIImageFromPixelBuffer:pixelBuffer];
484
+ if (bitmap) {
485
+ if (self.bitmapCaptureCallback) {
486
+ @try {
487
+ [self.bitmapCaptureCallback onBitmapCaptured:bitmap];
488
+ } @catch (NSException *exception) {
489
+ if (self.bitmapCaptureCallback) {
490
+ [self.bitmapCaptureCallback
491
+ onCaptureError:[NSString
492
+ stringWithFormat:@"Callback error: %@",
493
+ exception.reason]];
494
+ }
495
+ }
496
+ }
497
+
498
+ if (self.onBitmapCapture) {
499
+ @autoreleasepool {
500
+ NSDictionary *event = @{
501
+ @"trigger" : trigger ?: @"unknown",
502
+ @"success" : @(YES),
503
+ @"bitmapWidth" : @(bitmap.size.width),
504
+ @"bitmapHeight" : @(bitmap.size.height)
505
+ };
506
+ self.onBitmapCapture(event);
507
+ }
508
+ }
509
+ }
510
+ }
511
+
512
+ // Memory cleanup for realtime mode
513
+ if ([trigger isEqualToString:@"realtime"]) {
514
+ static int realtimeCount = 0;
515
+ realtimeCount++;
516
+ if (realtimeCount % 10 == 0) {
517
+ dispatch_async(
518
+ dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
519
+ @autoreleasepool {
520
+ [[NSURLCache sharedURLCache] removeAllCachedResponses];
521
+ }
522
+ });
523
+ }
524
+ }
525
+ }
526
+ }
527
+
528
+ - (UIImage *)UIImageFromPixelBuffer:(CVPixelBufferRef)pixelBuffer {
529
+ if (!pixelBuffer) {
530
+ return nil;
531
+ }
532
+
533
+ CIImage *ciImage = [CIImage imageWithCVPixelBuffer:pixelBuffer];
534
+ CIContext *context = [CIContext contextWithOptions:nil];
535
+ CGImageRef cgImage = [context createCGImage:ciImage fromRect:ciImage.extent];
536
+
537
+ if (!cgImage) {
538
+ return nil;
539
+ }
540
+
541
+ UIImage *image = [UIImage imageWithCGImage:cgImage];
542
+ CGImageRelease(cgImage);
543
+
544
+ return image;
545
+ }
546
+
600
547
  @end
@@ -33,42 +33,11 @@ RCT_CUSTOM_VIEW_PROPERTY(viewId, NSString, VeLiveMixerUIView) {
33
33
  if (json == nil) {
34
34
  return;
35
35
  }
36
-
36
+
37
37
  NSString *viewId = [RCTConvert NSString:json];
38
38
  [view setViewId:viewId];
39
39
  }
40
40
 
41
- // 导出混合配置属性 - 与Android保持一致的属性名
42
- RCT_CUSTOM_VIEW_PROPERTY(x, NSNumber, VeLiveMixerUIView) {
43
- NSNumber *x = [RCTConvert NSNumber:json];
44
- [view setX:x];
45
- }
46
-
47
- RCT_CUSTOM_VIEW_PROPERTY(y, NSNumber, VeLiveMixerUIView) {
48
- NSNumber *y = [RCTConvert NSNumber:json];
49
- [view setY:y];
50
- }
51
-
52
- RCT_CUSTOM_VIEW_PROPERTY(width, NSNumber, VeLiveMixerUIView) {
53
- NSNumber *width = [RCTConvert NSNumber:json];
54
- [view setWidth:width];
55
- }
56
-
57
- RCT_CUSTOM_VIEW_PROPERTY(height, NSNumber, VeLiveMixerUIView) {
58
- NSNumber *height = [RCTConvert NSNumber:json];
59
- [view setHeight:height];
60
- }
61
-
62
- RCT_CUSTOM_VIEW_PROPERTY(zOrder, NSNumber, VeLiveMixerUIView) {
63
- NSNumber *zOrder = [RCTConvert NSNumber:json];
64
- [view setZOrder:zOrder];
65
- }
66
-
67
- RCT_CUSTOM_VIEW_PROPERTY(renderMode, NSNumber, VeLiveMixerUIView) {
68
- NSNumber *renderMode = [RCTConvert NSNumber:json];
69
- [view setRenderMode:renderMode];
70
- }
71
-
72
41
  // 导出捕获配置属性
73
42
  RCT_CUSTOM_VIEW_PROPERTY(captureMode, NSString, VeLiveMixerUIView) {
74
43
  NSString *captureMode = [RCTConvert NSString:json];
@@ -84,9 +53,4 @@ RCT_CUSTOM_VIEW_PROPERTY(captureFramerate, NSNumber, VeLiveMixerUIView) {
84
53
  [view setCaptureFramerate:framerate];
85
54
  }
86
55
 
87
- RCT_CUSTOM_VIEW_PROPERTY(autoSensitivity, NSNumber, VeLiveMixerUIView) {
88
- NSNumber *sensitivity = [RCTConvert NSNumber:json];
89
- [view setAutoSensitivity:sensitivity];
90
- }
91
-
92
- @end
56
+ @end