@byteplus/react-native-live-push 1.2.0-rc.0 → 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.
- package/android/src/main/java/com/volcengine/velive/rn/push/mixer/MixerManager.java +1 -1
- package/android/src/main/java/com/volcengine/velive/rn/push/mixer/MixerView.java +19 -125
- package/android/src/main/java/com/volcengine/velive/rn/push/mixer/MixerViewManager.java +1 -37
- package/ios/VeLiveMixerHelper.h +9 -6
- package/ios/VeLiveMixerHelper.m +38 -12
- package/ios/VeLiveMixerView.h +1 -8
- package/ios/VeLiveMixerView.m +178 -231
- package/ios/VeLiveMixerViewManager.m +0 -36
- package/lib/commonjs/index.js +3 -4
- package/lib/commonjs/typescript/core/keytype.d.ts +2 -3
- package/lib/commonjs/typescript/view/MixView.d.ts +1 -9
- package/lib/module/index.js +3 -4
- package/lib/module/typescript/core/keytype.d.ts +2 -3
- package/lib/module/typescript/view/MixView.d.ts +1 -9
- package/lib/typescript/core/keytype.d.ts +2 -3
- package/lib/typescript/view/MixView.d.ts +1 -9
- package/package.json +1 -1
- package/react-native-velive-push.podspec +2 -2
|
@@ -20,24 +20,14 @@ public class MixerView extends FrameLayout {
|
|
|
20
20
|
private ThemedReactContext context;
|
|
21
21
|
private String viewId;
|
|
22
22
|
|
|
23
|
-
// Mix configuration
|
|
24
|
-
private float mixX = 0f;
|
|
25
|
-
private float mixY = 0f;
|
|
26
|
-
private float mixWidth = 0f;
|
|
27
|
-
private float mixHeight = 0f;
|
|
28
|
-
private int mixZOrder = 0;
|
|
29
|
-
private int mixRenderMode = 0;
|
|
30
|
-
|
|
31
23
|
// Capture configuration
|
|
32
24
|
private String captureMode = "onchange";
|
|
33
|
-
private float captureFramerate =
|
|
34
|
-
private float autoSensitivity = 5f;
|
|
25
|
+
private float captureFramerate = 5f; // realTime mode default 5 fps
|
|
35
26
|
|
|
36
27
|
// Capture state
|
|
37
28
|
private Handler captureHandler;
|
|
38
29
|
private Runnable captureRunnable;
|
|
39
30
|
private ViewTreeObserver.OnGlobalLayoutListener layoutListener;
|
|
40
|
-
private ViewTreeObserver.OnDrawListener drawListener;
|
|
41
31
|
private AtomicBoolean isCapturing = new AtomicBoolean(false);
|
|
42
32
|
private AtomicBoolean isDestroyed = new AtomicBoolean(false);
|
|
43
33
|
|
|
@@ -46,14 +36,6 @@ public class MixerView extends FrameLayout {
|
|
|
46
36
|
private long lastCaptureTime = 0;
|
|
47
37
|
private final Object captureLock = new Object();
|
|
48
38
|
|
|
49
|
-
// Auto mode state
|
|
50
|
-
private int changeCount = 0;
|
|
51
|
-
private long windowStartTime = 0;
|
|
52
|
-
private boolean isInRealtimeMode = false;
|
|
53
|
-
private static final long AUTO_WINDOW_MS = 2000; // 2 second window
|
|
54
|
-
private static final int HIGH_CHANGE_THRESHOLD = 10;
|
|
55
|
-
private static final int LOW_CHANGE_THRESHOLD = 2;
|
|
56
|
-
|
|
57
39
|
// Add callback support for MixerManager integration
|
|
58
40
|
private MixerManager.BitmapCaptureCallback bitmapCaptureCallback;
|
|
59
41
|
|
|
@@ -67,19 +49,6 @@ public class MixerView extends FrameLayout {
|
|
|
67
49
|
private void initializeCapture() {
|
|
68
50
|
// Initialize layout change listener
|
|
69
51
|
layoutListener = this::onViewChanged;
|
|
70
|
-
|
|
71
|
-
// Initialize draw listener for auto mode
|
|
72
|
-
drawListener = this::onViewDraw;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Setters for mix configuration
|
|
76
|
-
public void setMixX(float x) { this.mixX = x; }
|
|
77
|
-
public void setMixY(float y) { this.mixY = y; }
|
|
78
|
-
public void setMixWidth(float width) { this.mixWidth = width; }
|
|
79
|
-
public void setMixHeight(float height) { this.mixHeight = height; }
|
|
80
|
-
public void setMixZOrder(int zOrder) { this.mixZOrder = zOrder; }
|
|
81
|
-
public void setMixRenderMode(int renderMode) {
|
|
82
|
-
this.mixRenderMode = renderMode;
|
|
83
52
|
}
|
|
84
53
|
|
|
85
54
|
public void setCaptureMode(String mode) {
|
|
@@ -98,10 +67,6 @@ public class MixerView extends FrameLayout {
|
|
|
98
67
|
}
|
|
99
68
|
}
|
|
100
69
|
|
|
101
|
-
public void setAutoSensitivity(float sensitivity) {
|
|
102
|
-
this.autoSensitivity = Math.max(1f, Math.min(10f, sensitivity));
|
|
103
|
-
}
|
|
104
|
-
|
|
105
70
|
private void startCapture() {
|
|
106
71
|
if (isDestroyed.get())
|
|
107
72
|
return;
|
|
@@ -113,9 +78,6 @@ public class MixerView extends FrameLayout {
|
|
|
113
78
|
case "realtime":
|
|
114
79
|
startRealtimeCapture();
|
|
115
80
|
break;
|
|
116
|
-
case "auto":
|
|
117
|
-
startAutoCapture();
|
|
118
|
-
break;
|
|
119
81
|
case "manual":
|
|
120
82
|
// Manual mode doesn't auto-start
|
|
121
83
|
break;
|
|
@@ -128,9 +90,6 @@ public class MixerView extends FrameLayout {
|
|
|
128
90
|
if (layoutListener != null) {
|
|
129
91
|
getViewTreeObserver().removeOnGlobalLayoutListener(layoutListener);
|
|
130
92
|
}
|
|
131
|
-
if (drawListener != null) {
|
|
132
|
-
getViewTreeObserver().removeOnDrawListener(drawListener);
|
|
133
|
-
}
|
|
134
93
|
}
|
|
135
94
|
|
|
136
95
|
// Stop realtime capture
|
|
@@ -143,9 +102,19 @@ public class MixerView extends FrameLayout {
|
|
|
143
102
|
}
|
|
144
103
|
|
|
145
104
|
private void startOnChangeCapture() {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
105
|
+
// onChange mode triggers every 2 seconds
|
|
106
|
+
long interval = 2000; // 2 seconds
|
|
107
|
+
|
|
108
|
+
captureRunnable = new Runnable() {
|
|
109
|
+
@Override
|
|
110
|
+
public void run() {
|
|
111
|
+
if (!isDestroyed.get() && "onchange".equals(captureMode)) {
|
|
112
|
+
performCapture("onchange");
|
|
113
|
+
captureHandler.postDelayed(this, interval);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
captureHandler.postDelayed(captureRunnable, interval);
|
|
149
118
|
}
|
|
150
119
|
|
|
151
120
|
private void startRealtimeCapture() {
|
|
@@ -170,82 +139,13 @@ public class MixerView extends FrameLayout {
|
|
|
170
139
|
}
|
|
171
140
|
}
|
|
172
141
|
|
|
173
|
-
private void startAutoCapture() {
|
|
174
|
-
// Start with onchange mode
|
|
175
|
-
isInRealtimeMode = false;
|
|
176
|
-
windowStartTime = System.currentTimeMillis();
|
|
177
|
-
changeCount = 0;
|
|
178
|
-
|
|
179
|
-
if (getViewTreeObserver().isAlive()) {
|
|
180
|
-
getViewTreeObserver().addOnGlobalLayoutListener(layoutListener);
|
|
181
|
-
getViewTreeObserver().addOnDrawListener(drawListener);
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
142
|
private void onViewChanged() {
|
|
186
143
|
if (isDestroyed.get()) {
|
|
187
144
|
return;
|
|
188
145
|
}
|
|
189
146
|
|
|
190
|
-
|
|
191
|
-
case "onchange":
|
|
147
|
+
if ("onchange".equals(captureMode)) {
|
|
192
148
|
performCapture("onchange");
|
|
193
|
-
break;
|
|
194
|
-
case "auto":
|
|
195
|
-
handleAutoModeChange();
|
|
196
|
-
break;
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
private void onViewDraw() {
|
|
201
|
-
if (isDestroyed.get() || !"auto".equals(captureMode))
|
|
202
|
-
return;
|
|
203
|
-
|
|
204
|
-
// Count draws for auto mode sensitivity
|
|
205
|
-
changeCount++;
|
|
206
|
-
|
|
207
|
-
long currentTime = System.currentTimeMillis();
|
|
208
|
-
if (currentTime - windowStartTime >= AUTO_WINDOW_MS) {
|
|
209
|
-
evaluateAutoMode();
|
|
210
|
-
// Reset window
|
|
211
|
-
windowStartTime = currentTime;
|
|
212
|
-
changeCount = 0;
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
private void handleAutoModeChange() {
|
|
217
|
-
if (!isInRealtimeMode) {
|
|
218
|
-
performCapture("auto_onchange");
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
private void evaluateAutoMode() {
|
|
223
|
-
float changesPerSecond = changeCount * 1000f / AUTO_WINDOW_MS;
|
|
224
|
-
float threshold = autoSensitivity;
|
|
225
|
-
|
|
226
|
-
boolean shouldBeRealtime =
|
|
227
|
-
changesPerSecond > (HIGH_CHANGE_THRESHOLD / threshold);
|
|
228
|
-
boolean shouldBeOnChange =
|
|
229
|
-
changesPerSecond < (LOW_CHANGE_THRESHOLD / threshold);
|
|
230
|
-
|
|
231
|
-
if (shouldBeRealtime && !isInRealtimeMode) {
|
|
232
|
-
switchToRealtimeMode();
|
|
233
|
-
} else if (shouldBeOnChange && isInRealtimeMode) {
|
|
234
|
-
switchToOnChangeMode();
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
private void switchToRealtimeMode() {
|
|
239
|
-
isInRealtimeMode = true;
|
|
240
|
-
startRealtimeCapture();
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
private void switchToOnChangeMode() {
|
|
244
|
-
isInRealtimeMode = false;
|
|
245
|
-
// Stop realtime capture but keep layout listener
|
|
246
|
-
if (captureRunnable != null) {
|
|
247
|
-
captureHandler.removeCallbacks(captureRunnable);
|
|
248
|
-
captureRunnable = null;
|
|
249
149
|
}
|
|
250
150
|
}
|
|
251
151
|
|
|
@@ -338,12 +238,6 @@ public class MixerView extends FrameLayout {
|
|
|
338
238
|
WritableMap event = Arguments.createMap();
|
|
339
239
|
event.putString("trigger", trigger);
|
|
340
240
|
event.putBoolean("success", true);
|
|
341
|
-
event.putDouble("x", mixX);
|
|
342
|
-
event.putDouble("y", mixY);
|
|
343
|
-
event.putDouble("width", mixWidth);
|
|
344
|
-
event.putDouble("height", mixHeight);
|
|
345
|
-
event.putInt("zOrder", mixZOrder);
|
|
346
|
-
event.putInt("renderMode", mixRenderMode);
|
|
347
241
|
event.putInt("bitmapWidth", bitmap.getWidth());
|
|
348
242
|
event.putInt("bitmapHeight", bitmap.getHeight());
|
|
349
243
|
} catch (IllegalStateException e) {
|
|
@@ -356,8 +250,8 @@ public class MixerView extends FrameLayout {
|
|
|
356
250
|
lastBitmap.recycle();
|
|
357
251
|
}
|
|
358
252
|
|
|
359
|
-
//
|
|
360
|
-
//
|
|
253
|
+
// If no callback is set, immediately release current bitmap to avoid memory accumulation
|
|
254
|
+
// If callback is set, bitmap will be managed by the callback receiver
|
|
361
255
|
if (bitmapCaptureCallback == null) {
|
|
362
256
|
if (bitmap != null && !bitmap.isRecycled()) {
|
|
363
257
|
bitmap.recycle();
|
|
@@ -392,7 +286,7 @@ public class MixerView extends FrameLayout {
|
|
|
392
286
|
super.onAttachedToWindow();
|
|
393
287
|
if (viewId != null) {
|
|
394
288
|
MixerManager.cachedMixedViews.put(viewId, this);
|
|
395
|
-
//
|
|
289
|
+
// Notify MixerManager that view is ready, check for pending callbacks
|
|
396
290
|
MixerManager.onViewReady(viewId, this);
|
|
397
291
|
}
|
|
398
292
|
}
|
|
@@ -409,7 +303,7 @@ public class MixerView extends FrameLayout {
|
|
|
409
303
|
public void setViewId(String viewId) {
|
|
410
304
|
this.viewId = viewId;
|
|
411
305
|
MixerManager.cachedMixedViews.put(viewId, this);
|
|
412
|
-
//
|
|
306
|
+
// Notify MixerManager that view is ready, check for pending callbacks
|
|
413
307
|
MixerManager.onViewReady(viewId, this);
|
|
414
308
|
}
|
|
415
309
|
|
|
@@ -22,52 +22,16 @@ public class MixerViewManager extends ViewGroupManager<MixerView> {
|
|
|
22
22
|
return new MixerView(reactContext);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
// Props for mixing configuration
|
|
26
|
-
@ReactProp(name = "x", defaultFloat = 0f)
|
|
27
|
-
public void setX(MixerView view, float x) {
|
|
28
|
-
view.setMixX(x);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
@ReactProp(name = "y", defaultFloat = 0f)
|
|
32
|
-
public void setY(MixerView view, float y) {
|
|
33
|
-
view.setMixY(y);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
@ReactProp(name = "width", defaultFloat = 0f)
|
|
37
|
-
public void setWidth(MixerView view, float width) {
|
|
38
|
-
view.setMixWidth(width);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
@ReactProp(name = "height", defaultFloat = 0f)
|
|
42
|
-
public void setHeight(MixerView view, float height) {
|
|
43
|
-
view.setMixHeight(height);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
@ReactProp(name = "zOrder", defaultInt = 0)
|
|
47
|
-
public void setZOrder(MixerView view, int zOrder) {
|
|
48
|
-
view.setMixZOrder(zOrder);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
@ReactProp(name = "renderMode", defaultInt = 0)
|
|
52
|
-
public void setRenderMode(MixerView view, int renderMode) {
|
|
53
|
-
view.setMixRenderMode(renderMode);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
25
|
@ReactProp(name = "captureMode")
|
|
57
26
|
public void setCaptureMode(MixerView view, @Nullable String captureMode) {
|
|
58
27
|
view.setCaptureMode(captureMode != null ? captureMode : "onchange");
|
|
59
28
|
}
|
|
60
29
|
|
|
61
|
-
@ReactProp(name = "captureFramerate", defaultFloat =
|
|
30
|
+
@ReactProp(name = "captureFramerate", defaultFloat = 5f)
|
|
62
31
|
public void setCaptureFramerate(MixerView view, float framerate) {
|
|
63
32
|
view.setCaptureFramerate(framerate);
|
|
64
33
|
}
|
|
65
34
|
|
|
66
|
-
@ReactProp(name = "autoSensitivity", defaultFloat = 5f)
|
|
67
|
-
public void setAutoSensitivity(MixerView view, float sensitivity) {
|
|
68
|
-
view.setAutoSensitivity(sensitivity);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
35
|
@ReactProp(name = "viewId")
|
|
72
36
|
public void setViewId(MixerView view, @Nullable String viewId) {
|
|
73
37
|
if (viewId != null) {
|
package/ios/VeLiveMixerHelper.h
CHANGED
|
@@ -6,17 +6,18 @@
|
|
|
6
6
|
//
|
|
7
7
|
|
|
8
8
|
#import "VeLiveMixerView.h"
|
|
9
|
+
#import <CoreVideo/CoreVideo.h>
|
|
9
10
|
#import <Foundation/Foundation.h>
|
|
10
11
|
|
|
11
12
|
NS_ASSUME_NONNULL_BEGIN
|
|
12
13
|
|
|
13
|
-
//
|
|
14
|
+
// Forward declaration
|
|
14
15
|
@class VeLivePusher;
|
|
15
16
|
|
|
16
|
-
//
|
|
17
|
+
// Mixer helper class - fully aligned with Android MixerManager.java
|
|
17
18
|
@interface VeLiveMixerHelper : NSObject <VeLiveBitmapCaptureCallback>
|
|
18
19
|
|
|
19
|
-
//
|
|
20
|
+
// Aligned with Android's static cachedMixedViews
|
|
20
21
|
@property(class, nonatomic, strong)
|
|
21
22
|
NSMutableDictionary<NSString *, VeLiveMixerUIView *> *cachedMixedViews;
|
|
22
23
|
|
|
@@ -24,21 +25,23 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
24
25
|
|
|
25
26
|
- (instancetype)initWithPusher:(VeLivePusher *)pusher;
|
|
26
27
|
|
|
27
|
-
// Public
|
|
28
|
+
// Public methods - fully aligned with Android MixerManager's public interface
|
|
28
29
|
- (void)setPusher:(VeLivePusher *)pusher;
|
|
29
30
|
- (int)addView:(NSString *)viewId config:(NSDictionary *)viewInfo;
|
|
30
31
|
- (BOOL)updateView:(NSString *)viewId config:(NSDictionary *)viewInfo;
|
|
31
32
|
- (BOOL)removeView:(NSString *)viewId;
|
|
32
33
|
- (void)captureView:(NSString *)viewId;
|
|
33
34
|
|
|
34
|
-
// Static
|
|
35
|
+
// Static methods - for sending captured content to mixer
|
|
35
36
|
+ (void)setupCallbackForMixerView:(VeLiveMixerUIView *)mixerView
|
|
36
37
|
streamId:(int)streamId;
|
|
37
38
|
+ (void)sendBitmapToMixerStatic:(int)streamId bitmap:(UIImage *)bitmap;
|
|
39
|
+
+ (void)sendPixelBufferToMixerStatic:(int)streamId
|
|
40
|
+
pixelBuffer:(CVPixelBufferRef)pixelBuffer;
|
|
38
41
|
+ (VeLiveMixerHelper *)findActiveMixerManager;
|
|
39
42
|
+ (void)onViewReady:(NSString *)viewId mixerView:(VeLiveMixerUIView *)mixerView;
|
|
40
43
|
|
|
41
|
-
//
|
|
44
|
+
// Resource cleanup
|
|
42
45
|
- (void)cleanup;
|
|
43
46
|
|
|
44
47
|
@end
|
package/ios/VeLiveMixerHelper.m
CHANGED
|
@@ -43,10 +43,11 @@ static NSString *TAG = @"VeLiveMixerHelper";
|
|
|
43
43
|
|
|
44
44
|
@implementation VeLiveMixerHelper
|
|
45
45
|
|
|
46
|
-
//
|
|
46
|
+
// Aligned with Android's static cachedMixedViews
|
|
47
47
|
static NSMutableDictionary<NSString *, VeLiveMixerUIView *> *_cachedMixedViews =
|
|
48
48
|
nil;
|
|
49
|
-
static VeLiveMixerHelper *currentInstance =
|
|
49
|
+
static VeLiveMixerHelper *currentInstance =
|
|
50
|
+
nil; // Strong reference to prevent ARC deallocation
|
|
50
51
|
|
|
51
52
|
+ (NSMutableDictionary<NSString *, VeLiveMixerUIView *> *)cachedMixedViews {
|
|
52
53
|
if (!_cachedMixedViews) {
|
|
@@ -176,7 +177,7 @@ static VeLiveMixerHelper *currentInstance = nil; // 强引用,防止被ARC释
|
|
|
176
177
|
if ([view isKindOfClass:[VeLiveMixerUIView class]]) {
|
|
177
178
|
[VeLiveMixerHelper setupCallbackForMixerView:view streamId:videoStreamId];
|
|
178
179
|
|
|
179
|
-
//
|
|
180
|
+
// Delayed capture execution to ensure view layout completion
|
|
180
181
|
dispatch_after(
|
|
181
182
|
dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)),
|
|
182
183
|
dispatch_get_main_queue(), ^{
|
|
@@ -238,7 +239,7 @@ static VeLiveMixerHelper *currentInstance = nil; // 强引用,防止被ARC释
|
|
|
238
239
|
|
|
239
240
|
[self.mixedViewLayout setObject:updatedLayout forKey:viewId];
|
|
240
241
|
|
|
241
|
-
//
|
|
242
|
+
// Delayed capture execution to ensure property updates completion
|
|
242
243
|
VeLiveMixerUIView *mixerView =
|
|
243
244
|
[[VeLiveMixerHelper cachedMixedViews] objectForKey:viewId];
|
|
244
245
|
if ([mixerView isKindOfClass:[VeLiveMixerUIView class]]) {
|
|
@@ -344,6 +345,7 @@ static VeLiveMixerHelper *currentInstance = nil; // 强引用,防止被ARC释
|
|
|
344
345
|
videoLayout.width = [layout[@"width"] floatValue];
|
|
345
346
|
videoLayout.height = [layout[@"height"] floatValue];
|
|
346
347
|
videoLayout.zOrder = [layout[@"zOrder"] intValue];
|
|
348
|
+
videoLayout.alpha = [layout[@"alpha"] floatValue];
|
|
347
349
|
videoLayout.renderMode = [layout[@"renderMode"] intValue];
|
|
348
350
|
description.mixVideoStreams = @[ videoLayout ];
|
|
349
351
|
[instance.pusher.getMixerManager
|
|
@@ -369,6 +371,15 @@ static VeLiveMixerHelper *currentInstance = nil; // 强引用,防止被ARC释
|
|
|
369
371
|
}
|
|
370
372
|
}
|
|
371
373
|
|
|
374
|
+
// New: Send pixelBuffer directly to mixer, avoiding UIImage conversion overhead
|
|
375
|
+
+ (void)sendPixelBufferToMixerStatic:(int)streamId
|
|
376
|
+
pixelBuffer:(CVPixelBufferRef)pixelBuffer {
|
|
377
|
+
VeLiveMixerHelper *instance = [VeLiveMixerHelper findActiveMixerManager];
|
|
378
|
+
if (instance && instance.pusher) {
|
|
379
|
+
[instance sendPixelBufferToMixer:streamId pixelBuffer:pixelBuffer];
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
372
383
|
+ (VeLiveMixerHelper *)findActiveMixerManager {
|
|
373
384
|
return currentInstance;
|
|
374
385
|
}
|
|
@@ -503,6 +514,7 @@ static VeLiveMixerHelper *currentInstance = nil; // 强引用,防止被ARC释
|
|
|
503
514
|
|
|
504
515
|
#pragma mark - Private Methods
|
|
505
516
|
|
|
517
|
+
// Send UIImage to mixer (via pixelBuffer conversion)
|
|
506
518
|
- (void)sendBitmapToMixer:(int)streamId bitmap:(UIImage *)bitmap {
|
|
507
519
|
@autoreleasepool {
|
|
508
520
|
if (!self.pusher || !bitmap) {
|
|
@@ -517,6 +529,27 @@ static VeLiveMixerHelper *currentInstance = nil; // 强引用,防止被ARC释
|
|
|
517
529
|
return;
|
|
518
530
|
}
|
|
519
531
|
|
|
532
|
+
// Use new pixelBuffer method
|
|
533
|
+
[self sendPixelBufferToMixer:streamId pixelBuffer:pixelBuffer];
|
|
534
|
+
|
|
535
|
+
} @finally {
|
|
536
|
+
if (pixelBuffer) {
|
|
537
|
+
CVPixelBufferRelease(pixelBuffer);
|
|
538
|
+
pixelBuffer = NULL;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// Send pixelBuffer directly to mixer, better performance
|
|
545
|
+
- (void)sendPixelBufferToMixer:(int)streamId
|
|
546
|
+
pixelBuffer:(CVPixelBufferRef)pixelBuffer {
|
|
547
|
+
@autoreleasepool {
|
|
548
|
+
if (!self.pusher || !pixelBuffer) {
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
@try {
|
|
520
553
|
VeLiveVideoFrame *videoFrame = [[VeLiveVideoFrame alloc] init];
|
|
521
554
|
videoFrame.bufferType = VeLiveVideoBufferTypePixelBuffer;
|
|
522
555
|
videoFrame.pts = CMTimeMakeWithSeconds(CACurrentMediaTime(), 1000000000);
|
|
@@ -524,15 +557,8 @@ static VeLiveMixerHelper *currentInstance = nil; // 强引用,防止被ARC释
|
|
|
524
557
|
|
|
525
558
|
[[self.pusher getMixerManager] sendCustomVideoFrame:videoFrame
|
|
526
559
|
streamId:streamId];
|
|
527
|
-
CVPixelBufferRelease(pixelBuffer);
|
|
528
|
-
|
|
529
|
-
pixelBuffer = NULL;
|
|
530
|
-
|
|
531
560
|
} @catch (NSException *exception) {
|
|
532
|
-
|
|
533
|
-
CVPixelBufferRelease(pixelBuffer);
|
|
534
|
-
pixelBuffer = NULL;
|
|
535
|
-
}
|
|
561
|
+
// Handle exception silently
|
|
536
562
|
}
|
|
537
563
|
}
|
|
538
564
|
}
|
package/ios/VeLiveMixerView.h
CHANGED
|
@@ -30,16 +30,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
30
30
|
// 视图标识
|
|
31
31
|
@property (nonatomic, strong) NSString *viewId;
|
|
32
32
|
|
|
33
|
-
//
|
|
34
|
-
@property (nonatomic, strong) NSNumber *x;
|
|
35
|
-
@property (nonatomic, strong) NSNumber *y;
|
|
36
|
-
@property (nonatomic, strong) NSNumber *width;
|
|
37
|
-
@property (nonatomic, strong) NSNumber *height;
|
|
38
|
-
@property (nonatomic, strong) NSNumber *zOrder;
|
|
39
|
-
@property (nonatomic, strong) NSNumber *renderMode;
|
|
33
|
+
// 捕获配置属性
|
|
40
34
|
@property (nonatomic, strong) NSString *captureMode;
|
|
41
35
|
@property (nonatomic, strong) NSNumber *captureFramerate;
|
|
42
|
-
@property (nonatomic, strong) NSNumber *autoSensitivity;
|
|
43
36
|
|
|
44
37
|
// React Native 事件回调
|
|
45
38
|
@property (nonatomic, copy) RCTBubblingEventBlock onBitmapCapture;
|
package/ios/VeLiveMixerView.m
CHANGED
|
@@ -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
|
|
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 =
|
|
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
|
|
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 /
|
|
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
|
-
|
|
335
|
-
if (
|
|
336
|
-
[self
|
|
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
|
|
476
|
-
self.
|
|
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
|
-
|
|
541
|
-
|
|
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
|
|
@@ -38,37 +38,6 @@ RCT_CUSTOM_VIEW_PROPERTY(viewId, NSString, VeLiveMixerUIView) {
|
|
|
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
56
|
@end
|
package/lib/commonjs/index.js
CHANGED
|
@@ -26958,8 +26958,7 @@ var getId = function () {
|
|
|
26958
26958
|
};
|
|
26959
26959
|
var MixView = React.forwardRef(function (props, ref) {
|
|
26960
26960
|
var _a = props.captureMode, captureMode = _a === void 0 ? 'onchange' : _a, // Default to most performant mode
|
|
26961
|
-
captureFramerate = props.captureFramerate,
|
|
26962
|
-
onViewMount = props.onViewMount, onViewUnmount = props.onViewUnmount, restProps = __rest(props, ["captureMode", "captureFramerate", "autoSensitivity", "onViewMount", "onViewUnmount"]);
|
|
26961
|
+
captureFramerate = props.captureFramerate, onViewMount = props.onViewMount, onViewUnmount = props.onViewUnmount, restProps = __rest(props, ["captureMode", "captureFramerate", "onViewMount", "onViewUnmount"]);
|
|
26963
26962
|
var viewId = React.useMemo(function () {
|
|
26964
26963
|
return restProps.viewId || getId();
|
|
26965
26964
|
}, [restProps.viewId]);
|
|
@@ -26974,7 +26973,7 @@ var MixView = React.forwardRef(function (props, ref) {
|
|
|
26974
26973
|
};
|
|
26975
26974
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
26976
26975
|
}, [viewId]);
|
|
26977
|
-
return (jsxRuntime.jsx(NativeMixView, __assign({}, restProps, { viewId: viewId, captureMode: captureMode, captureFramerate: captureFramerate,
|
|
26976
|
+
return (jsxRuntime.jsx(NativeMixView, __assign({}, restProps, { viewId: viewId, captureMode: captureMode, captureFramerate: captureFramerate, ref: ref })));
|
|
26978
26977
|
});
|
|
26979
26978
|
|
|
26980
26979
|
var VeView = React.forwardRef(function (props, ref) {
|
|
@@ -27009,7 +27008,7 @@ var VeImageView = React.forwardRef(function (props, ref) {
|
|
|
27009
27008
|
});
|
|
27010
27009
|
|
|
27011
27010
|
var VeWebView = React.forwardRef(function (props, ref) {
|
|
27012
|
-
var renderMode = props.renderMode, _a = props.captureMode, captureMode = _a === void 0 ? '
|
|
27011
|
+
var renderMode = props.renderMode, _a = props.captureMode, captureMode = _a === void 0 ? 'realtime' : _a, onViewMount = props.onViewMount, onViewUnmount = props.onViewUnmount, viewId = props.viewId, viewProps = __rest(props, ["renderMode", "captureMode", "onViewMount", "onViewUnmount", "viewId"]);
|
|
27013
27012
|
return (jsxRuntime.jsx(MixView, { renderMode: renderMode, captureMode: captureMode, viewId: viewId, onViewMount: onViewMount, onViewUnmount: onViewUnmount, children: jsxRuntime.jsx(reactNative.View, __assign({}, viewProps, { ref: ref })) }));
|
|
27014
27013
|
});
|
|
27015
27014
|
|
|
@@ -7,12 +7,11 @@ export interface MixConfig {
|
|
|
7
7
|
alpha?: number;
|
|
8
8
|
zOrder?: number;
|
|
9
9
|
renderMode?: number;
|
|
10
|
-
captureMode?: 'onchange' | 'realtime' | '
|
|
10
|
+
captureMode?: 'onchange' | 'realtime' | 'manual';
|
|
11
11
|
}
|
|
12
12
|
export interface MixViewConfig {
|
|
13
13
|
renderMode?: number;
|
|
14
|
-
captureMode?: 'onchange' | 'realtime' | '
|
|
14
|
+
captureMode?: 'onchange' | 'realtime' | 'manual';
|
|
15
15
|
captureFramerate?: number;
|
|
16
|
-
autoSensitivity?: number;
|
|
17
16
|
}
|
|
18
17
|
export { VeLiveOrientation, VeLiveAudioBufferType, VeLiveAudioCaptureConfiguration, VeLiveAudioCaptureType, VeLiveAudioChannel, VeLiveAudioEncoderConfiguration, VeLiveAudioFrameSource, VeLiveAudioMixType, VeLiveAudioPowerLevel, VeLiveAudioProfile, VeLiveAudioSampleRate, VeLiveFileRecorderConfiguration, VeLiveFirstFrameType, VeLiveMixAudioLayout, VeLiveMixVideoLayout, VeLiveNetworkQuality, VeLivePixelFormat, VeLivePusherLogLevel, VeLivePusherRenderMode, VeLivePusherStatistics, VeLivePusherStatus, VeLiveStreamMixDescription, VeLiveVideoBufferType, VeLiveVideoCaptureConfiguration, VeLiveVideoCaptureType, VeLiveVideoCodec, VeLiveVideoEffectLicenseConfiguration, VeLiveVideoEffectLicenseType, VeLiveVideoEncoderConfiguration, VeLiveVideoFrameSource, VeLiveVideoMirrorType, VeLiveVideoResolution, VeLiveVideoRotation, };
|
|
@@ -17,20 +17,12 @@ export interface NativeMixViewProps extends ViewProps, Partial<MixViewConfig> {
|
|
|
17
17
|
* - 'manual': User controls capture timing via ref methods
|
|
18
18
|
* Best for: Custom scenarios where you want full control
|
|
19
19
|
* Performance: Depends on user implementation
|
|
20
|
-
*
|
|
21
|
-
* - 'auto': Automatically detect based on content behavior (experimental)
|
|
22
|
-
* Monitors view changes and switches between onchange/realtime
|
|
23
20
|
*/
|
|
24
|
-
captureMode?: 'onchange' | 'realtime' | 'manual'
|
|
21
|
+
captureMode?: 'onchange' | 'realtime' | 'manual';
|
|
25
22
|
/**
|
|
26
23
|
* For realtime mode: custom framerate (default uses stream framerate)
|
|
27
24
|
*/
|
|
28
25
|
captureFramerate?: number;
|
|
29
|
-
/**
|
|
30
|
-
* For auto mode: sensitivity threshold for switching to realtime
|
|
31
|
-
* Higher values = less sensitive to changes
|
|
32
|
-
*/
|
|
33
|
-
autoSensitivity?: number;
|
|
34
26
|
}
|
|
35
27
|
export interface MixViewEventProps {
|
|
36
28
|
/**
|
package/lib/module/index.js
CHANGED
|
@@ -26956,8 +26956,7 @@ var getId = function () {
|
|
|
26956
26956
|
};
|
|
26957
26957
|
var MixView = React.forwardRef(function (props, ref) {
|
|
26958
26958
|
var _a = props.captureMode, captureMode = _a === void 0 ? 'onchange' : _a, // Default to most performant mode
|
|
26959
|
-
captureFramerate = props.captureFramerate,
|
|
26960
|
-
onViewMount = props.onViewMount, onViewUnmount = props.onViewUnmount, restProps = __rest(props, ["captureMode", "captureFramerate", "autoSensitivity", "onViewMount", "onViewUnmount"]);
|
|
26959
|
+
captureFramerate = props.captureFramerate, onViewMount = props.onViewMount, onViewUnmount = props.onViewUnmount, restProps = __rest(props, ["captureMode", "captureFramerate", "onViewMount", "onViewUnmount"]);
|
|
26961
26960
|
var viewId = useMemo(function () {
|
|
26962
26961
|
return restProps.viewId || getId();
|
|
26963
26962
|
}, [restProps.viewId]);
|
|
@@ -26972,7 +26971,7 @@ var MixView = React.forwardRef(function (props, ref) {
|
|
|
26972
26971
|
};
|
|
26973
26972
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
26974
26973
|
}, [viewId]);
|
|
26975
|
-
return (jsx(NativeMixView, __assign({}, restProps, { viewId: viewId, captureMode: captureMode, captureFramerate: captureFramerate,
|
|
26974
|
+
return (jsx(NativeMixView, __assign({}, restProps, { viewId: viewId, captureMode: captureMode, captureFramerate: captureFramerate, ref: ref })));
|
|
26976
26975
|
});
|
|
26977
26976
|
|
|
26978
26977
|
var VeView = React.forwardRef(function (props, ref) {
|
|
@@ -27007,7 +27006,7 @@ var VeImageView = React.forwardRef(function (props, ref) {
|
|
|
27007
27006
|
});
|
|
27008
27007
|
|
|
27009
27008
|
var VeWebView = React.forwardRef(function (props, ref) {
|
|
27010
|
-
var renderMode = props.renderMode, _a = props.captureMode, captureMode = _a === void 0 ? '
|
|
27009
|
+
var renderMode = props.renderMode, _a = props.captureMode, captureMode = _a === void 0 ? 'realtime' : _a, onViewMount = props.onViewMount, onViewUnmount = props.onViewUnmount, viewId = props.viewId, viewProps = __rest(props, ["renderMode", "captureMode", "onViewMount", "onViewUnmount", "viewId"]);
|
|
27011
27010
|
return (jsx(MixView, { renderMode: renderMode, captureMode: captureMode, viewId: viewId, onViewMount: onViewMount, onViewUnmount: onViewUnmount, children: jsx(View, __assign({}, viewProps, { ref: ref })) }));
|
|
27012
27011
|
});
|
|
27013
27012
|
|
|
@@ -7,12 +7,11 @@ export interface MixConfig {
|
|
|
7
7
|
alpha?: number;
|
|
8
8
|
zOrder?: number;
|
|
9
9
|
renderMode?: number;
|
|
10
|
-
captureMode?: 'onchange' | 'realtime' | '
|
|
10
|
+
captureMode?: 'onchange' | 'realtime' | 'manual';
|
|
11
11
|
}
|
|
12
12
|
export interface MixViewConfig {
|
|
13
13
|
renderMode?: number;
|
|
14
|
-
captureMode?: 'onchange' | 'realtime' | '
|
|
14
|
+
captureMode?: 'onchange' | 'realtime' | 'manual';
|
|
15
15
|
captureFramerate?: number;
|
|
16
|
-
autoSensitivity?: number;
|
|
17
16
|
}
|
|
18
17
|
export { VeLiveOrientation, VeLiveAudioBufferType, VeLiveAudioCaptureConfiguration, VeLiveAudioCaptureType, VeLiveAudioChannel, VeLiveAudioEncoderConfiguration, VeLiveAudioFrameSource, VeLiveAudioMixType, VeLiveAudioPowerLevel, VeLiveAudioProfile, VeLiveAudioSampleRate, VeLiveFileRecorderConfiguration, VeLiveFirstFrameType, VeLiveMixAudioLayout, VeLiveMixVideoLayout, VeLiveNetworkQuality, VeLivePixelFormat, VeLivePusherLogLevel, VeLivePusherRenderMode, VeLivePusherStatistics, VeLivePusherStatus, VeLiveStreamMixDescription, VeLiveVideoBufferType, VeLiveVideoCaptureConfiguration, VeLiveVideoCaptureType, VeLiveVideoCodec, VeLiveVideoEffectLicenseConfiguration, VeLiveVideoEffectLicenseType, VeLiveVideoEncoderConfiguration, VeLiveVideoFrameSource, VeLiveVideoMirrorType, VeLiveVideoResolution, VeLiveVideoRotation, };
|
|
@@ -17,20 +17,12 @@ export interface NativeMixViewProps extends ViewProps, Partial<MixViewConfig> {
|
|
|
17
17
|
* - 'manual': User controls capture timing via ref methods
|
|
18
18
|
* Best for: Custom scenarios where you want full control
|
|
19
19
|
* Performance: Depends on user implementation
|
|
20
|
-
*
|
|
21
|
-
* - 'auto': Automatically detect based on content behavior (experimental)
|
|
22
|
-
* Monitors view changes and switches between onchange/realtime
|
|
23
20
|
*/
|
|
24
|
-
captureMode?: 'onchange' | 'realtime' | 'manual'
|
|
21
|
+
captureMode?: 'onchange' | 'realtime' | 'manual';
|
|
25
22
|
/**
|
|
26
23
|
* For realtime mode: custom framerate (default uses stream framerate)
|
|
27
24
|
*/
|
|
28
25
|
captureFramerate?: number;
|
|
29
|
-
/**
|
|
30
|
-
* For auto mode: sensitivity threshold for switching to realtime
|
|
31
|
-
* Higher values = less sensitive to changes
|
|
32
|
-
*/
|
|
33
|
-
autoSensitivity?: number;
|
|
34
26
|
}
|
|
35
27
|
export interface MixViewEventProps {
|
|
36
28
|
/**
|
|
@@ -7,12 +7,11 @@ export interface MixConfig {
|
|
|
7
7
|
alpha?: number;
|
|
8
8
|
zOrder?: number;
|
|
9
9
|
renderMode?: number;
|
|
10
|
-
captureMode?: 'onchange' | 'realtime' | '
|
|
10
|
+
captureMode?: 'onchange' | 'realtime' | 'manual';
|
|
11
11
|
}
|
|
12
12
|
export interface MixViewConfig {
|
|
13
13
|
renderMode?: number;
|
|
14
|
-
captureMode?: 'onchange' | 'realtime' | '
|
|
14
|
+
captureMode?: 'onchange' | 'realtime' | 'manual';
|
|
15
15
|
captureFramerate?: number;
|
|
16
|
-
autoSensitivity?: number;
|
|
17
16
|
}
|
|
18
17
|
export { VeLiveOrientation, VeLiveAudioBufferType, VeLiveAudioCaptureConfiguration, VeLiveAudioCaptureType, VeLiveAudioChannel, VeLiveAudioEncoderConfiguration, VeLiveAudioFrameSource, VeLiveAudioMixType, VeLiveAudioPowerLevel, VeLiveAudioProfile, VeLiveAudioSampleRate, VeLiveFileRecorderConfiguration, VeLiveFirstFrameType, VeLiveMixAudioLayout, VeLiveMixVideoLayout, VeLiveNetworkQuality, VeLivePixelFormat, VeLivePusherLogLevel, VeLivePusherRenderMode, VeLivePusherStatistics, VeLivePusherStatus, VeLiveStreamMixDescription, VeLiveVideoBufferType, VeLiveVideoCaptureConfiguration, VeLiveVideoCaptureType, VeLiveVideoCodec, VeLiveVideoEffectLicenseConfiguration, VeLiveVideoEffectLicenseType, VeLiveVideoEncoderConfiguration, VeLiveVideoFrameSource, VeLiveVideoMirrorType, VeLiveVideoResolution, VeLiveVideoRotation, };
|
|
@@ -17,20 +17,12 @@ export interface NativeMixViewProps extends ViewProps, Partial<MixViewConfig> {
|
|
|
17
17
|
* - 'manual': User controls capture timing via ref methods
|
|
18
18
|
* Best for: Custom scenarios where you want full control
|
|
19
19
|
* Performance: Depends on user implementation
|
|
20
|
-
*
|
|
21
|
-
* - 'auto': Automatically detect based on content behavior (experimental)
|
|
22
|
-
* Monitors view changes and switches between onchange/realtime
|
|
23
20
|
*/
|
|
24
|
-
captureMode?: 'onchange' | 'realtime' | 'manual'
|
|
21
|
+
captureMode?: 'onchange' | 'realtime' | 'manual';
|
|
25
22
|
/**
|
|
26
23
|
* For realtime mode: custom framerate (default uses stream framerate)
|
|
27
24
|
*/
|
|
28
25
|
captureFramerate?: number;
|
|
29
|
-
/**
|
|
30
|
-
* For auto mode: sensitivity threshold for switching to realtime
|
|
31
|
-
* Higher values = less sensitive to changes
|
|
32
|
-
*/
|
|
33
|
-
autoSensitivity?: number;
|
|
34
26
|
}
|
|
35
27
|
export interface MixViewEventProps {
|
|
36
28
|
/**
|
package/package.json
CHANGED
|
@@ -50,6 +50,6 @@ Pod::Spec.new do |s|
|
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
s.dependency 'VolcApiEngine', '1.6.2'
|
|
53
|
-
s.dependency 'TTSDKFramework/Core', '1.46.300.
|
|
54
|
-
s.dependency 'TTSDKFramework/LivePush-RTS', '1.46.300.
|
|
53
|
+
s.dependency 'TTSDKFramework/Core', '1.46.300.3-premium'
|
|
54
|
+
s.dependency 'TTSDKFramework/LivePush-RTS', '1.46.300.3-premium'
|
|
55
55
|
end
|