@byteplus/react-native-live-push 1.1.3-rc.1 → 1.1.3-rc.2
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/VeLivePushModule.java +13 -2
- package/android/src/main/java/com/volcengine/velive/rn/push/VeLivePushPackage.java +16 -13
- package/android/src/main/java/com/volcengine/velive/rn/push/VeLivePushView.java +16 -0
- package/android/src/main/java/com/volcengine/velive/rn/push/VeLivePushViewManager.java +7 -2
- package/android/src/main/java/com/volcengine/velive/rn/push/mixer/MixerManager.java +392 -0
- package/android/src/main/java/com/volcengine/velive/rn/push/mixer/MixerView.java +415 -0
- package/android/src/main/java/com/volcengine/velive/rn/push/mixer/MixerViewManager.java +79 -0
- package/android/src/main/java/com/volcengine/velive/rn/push/mixer/TextureMgr.java +168 -0
- package/android/src/main/java/com/volcengine/velive/rn/push/mixer/YuvHelper.java +154 -0
- package/ios/VeLiveMixerHelper.h +44 -0
- package/ios/VeLiveMixerHelper.m +562 -0
- package/ios/VeLiveMixerView.h +69 -0
- package/ios/VeLiveMixerView.m +592 -0
- package/ios/VeLiveMixerViewManager.m +92 -0
- package/lib/commonjs/index.js +1779 -980
- package/lib/commonjs/typescript/android/index.d.ts +47 -0
- package/lib/commonjs/typescript/codegen/android/api.d.ts +1527 -0
- package/lib/commonjs/typescript/codegen/android/callback.d.ts +91 -0
- package/lib/commonjs/typescript/codegen/android/errorcode.d.ts +26 -0
- package/lib/commonjs/typescript/codegen/android/index.d.ts +5 -0
- package/lib/commonjs/typescript/codegen/android/keytype.d.ts +846 -0
- package/lib/commonjs/typescript/codegen/android/types.d.ts +33 -0
- package/lib/commonjs/typescript/codegen/ios/api.d.ts +222 -0
- package/lib/commonjs/typescript/codegen/ios/callback.d.ts +80 -0
- package/lib/commonjs/typescript/codegen/ios/errorcode.d.ts +54 -0
- package/lib/commonjs/typescript/codegen/ios/external.d.ts +1 -0
- package/lib/commonjs/typescript/codegen/ios/index.d.ts +6 -0
- package/lib/commonjs/typescript/codegen/ios/keytype.d.ts +460 -0
- package/lib/commonjs/typescript/codegen/ios/types.d.ts +46 -0
- package/lib/commonjs/typescript/codegen/pack/api.d.ts +1835 -0
- package/lib/commonjs/typescript/codegen/pack/callback.d.ts +400 -0
- package/lib/commonjs/typescript/codegen/pack/errorcode.d.ts +35 -0
- package/lib/commonjs/typescript/codegen/pack/index.d.ts +5 -0
- package/lib/commonjs/typescript/codegen/pack/keytype.d.ts +1392 -0
- package/lib/commonjs/typescript/codegen/pack/types.d.ts +68 -0
- package/lib/commonjs/typescript/codegen/type-shim.d.ts +6 -0
- package/lib/commonjs/typescript/component.d.ts +15 -0
- package/lib/commonjs/typescript/core/api.d.ts +17 -0
- package/lib/commonjs/typescript/core/callback.d.ts +2 -0
- package/lib/commonjs/typescript/core/env.d.ts +29 -0
- package/lib/commonjs/typescript/core/errorcode.d.ts +2 -0
- package/lib/commonjs/typescript/core/index.d.ts +6 -0
- package/lib/commonjs/typescript/core/keytype.d.ts +17 -0
- package/lib/commonjs/typescript/core/mixer.d.ts +26 -0
- package/lib/commonjs/typescript/core/pusher.d.ts +16 -0
- package/lib/commonjs/typescript/index.d.ts +3 -0
- package/lib/commonjs/typescript/ios/extends.d.ts +41 -0
- package/lib/commonjs/typescript/platforms/android/extends.d.ts +8 -0
- package/lib/commonjs/typescript/platforms/android/helper.d.ts +8 -0
- package/lib/commonjs/typescript/platforms/android/mixer.d.ts +8 -0
- package/lib/commonjs/typescript/platforms/ios/extends.d.ts +17 -0
- package/lib/commonjs/typescript/platforms/ios/helper.d.ts +8 -0
- package/lib/commonjs/typescript/platforms/ios/mixer.d.ts +9 -0
- package/lib/commonjs/typescript/runtime.d.ts +1 -0
- package/lib/commonjs/typescript/view/MixView.d.ts +52 -0
- package/lib/commonjs/typescript/view/VeImageView.d.ts +19 -0
- package/lib/commonjs/typescript/view/VeTextView.d.ts +7 -0
- package/lib/commonjs/typescript/view/VeView.d.ts +7 -0
- package/lib/commonjs/typescript/view/VeWebView.d.ts +7 -0
- package/lib/commonjs/typescript/view/index.d.ts +5 -0
- package/lib/module/index.js +1776 -982
- package/lib/module/typescript/android/index.d.ts +47 -0
- package/lib/module/typescript/codegen/android/api.d.ts +1527 -0
- package/lib/module/typescript/codegen/android/callback.d.ts +91 -0
- package/lib/module/typescript/codegen/android/errorcode.d.ts +26 -0
- package/lib/module/typescript/codegen/android/index.d.ts +5 -0
- package/lib/module/typescript/codegen/android/keytype.d.ts +846 -0
- package/lib/module/typescript/codegen/android/types.d.ts +33 -0
- package/lib/module/typescript/codegen/ios/api.d.ts +222 -0
- package/lib/module/typescript/codegen/ios/callback.d.ts +80 -0
- package/lib/module/typescript/codegen/ios/errorcode.d.ts +54 -0
- package/lib/module/typescript/codegen/ios/external.d.ts +1 -0
- package/lib/module/typescript/codegen/ios/index.d.ts +6 -0
- package/lib/module/typescript/codegen/ios/keytype.d.ts +460 -0
- package/lib/module/typescript/codegen/ios/types.d.ts +46 -0
- package/lib/module/typescript/codegen/pack/api.d.ts +1835 -0
- package/lib/module/typescript/codegen/pack/callback.d.ts +400 -0
- package/lib/module/typescript/codegen/pack/errorcode.d.ts +35 -0
- package/lib/module/typescript/codegen/pack/index.d.ts +5 -0
- package/lib/module/typescript/codegen/pack/keytype.d.ts +1392 -0
- package/lib/module/typescript/codegen/pack/types.d.ts +68 -0
- package/lib/module/typescript/codegen/type-shim.d.ts +6 -0
- package/lib/module/typescript/component.d.ts +15 -0
- package/lib/module/typescript/core/api.d.ts +17 -0
- package/lib/module/typescript/core/callback.d.ts +2 -0
- package/lib/module/typescript/core/env.d.ts +29 -0
- package/lib/module/typescript/core/errorcode.d.ts +2 -0
- package/lib/module/typescript/core/index.d.ts +6 -0
- package/lib/module/typescript/core/keytype.d.ts +17 -0
- package/lib/module/typescript/core/mixer.d.ts +26 -0
- package/lib/module/typescript/core/pusher.d.ts +16 -0
- package/lib/module/typescript/index.d.ts +3 -0
- package/lib/module/typescript/ios/extends.d.ts +41 -0
- package/lib/module/typescript/platforms/android/extends.d.ts +8 -0
- package/lib/module/typescript/platforms/android/helper.d.ts +8 -0
- package/lib/module/typescript/platforms/android/mixer.d.ts +8 -0
- package/lib/module/typescript/platforms/ios/extends.d.ts +17 -0
- package/lib/module/typescript/platforms/ios/helper.d.ts +8 -0
- package/lib/module/typescript/platforms/ios/mixer.d.ts +9 -0
- package/lib/module/typescript/runtime.d.ts +1 -0
- package/lib/module/typescript/view/MixView.d.ts +52 -0
- package/lib/module/typescript/view/VeImageView.d.ts +19 -0
- package/lib/module/typescript/view/VeTextView.d.ts +7 -0
- package/lib/module/typescript/view/VeView.d.ts +7 -0
- package/lib/module/typescript/view/VeWebView.d.ts +7 -0
- package/lib/module/typescript/view/index.d.ts +5 -0
- package/lib/typescript/codegen/android/api.d.ts +1 -121
- package/lib/typescript/codegen/ios/api.d.ts +1 -28
- package/lib/typescript/codegen/pack/api.d.ts +1 -133
- package/lib/typescript/core/api.d.ts +17 -2
- package/lib/typescript/core/keytype.d.ts +15 -0
- package/lib/typescript/core/mixer.d.ts +26 -0
- package/lib/typescript/index.d.ts +1 -0
- package/lib/typescript/platforms/android/extends.d.ts +8 -0
- package/lib/typescript/platforms/android/mixer.d.ts +8 -0
- package/lib/typescript/platforms/ios/mixer.d.ts +9 -0
- package/lib/typescript/view/MixView.d.ts +52 -0
- package/lib/typescript/view/VeImageView.d.ts +19 -0
- package/lib/typescript/view/VeTextView.d.ts +7 -0
- package/lib/typescript/view/VeView.d.ts +7 -0
- package/lib/typescript/view/VeWebView.d.ts +7 -0
- package/lib/typescript/view/index.d.ts +5 -0
- package/package.json +1 -1
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
package com.volcengine.velive.rn.push.mixer;
|
|
2
|
+
|
|
3
|
+
import android.graphics.Bitmap;
|
|
4
|
+
import android.graphics.Canvas;
|
|
5
|
+
import android.os.Handler;
|
|
6
|
+
import android.os.Looper;
|
|
7
|
+
import android.view.ViewTreeObserver;
|
|
8
|
+
import android.widget.FrameLayout;
|
|
9
|
+
import androidx.annotation.Nullable;
|
|
10
|
+
import com.facebook.react.bridge.Arguments;
|
|
11
|
+
import com.facebook.react.bridge.ReadableArray;
|
|
12
|
+
import com.facebook.react.bridge.WritableMap;
|
|
13
|
+
import com.facebook.react.uimanager.ThemedReactContext;
|
|
14
|
+
import java.util.concurrent.atomic.AtomicBoolean;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Custom MixerView that supports different capture modes
|
|
18
|
+
*/
|
|
19
|
+
public class MixerView extends FrameLayout {
|
|
20
|
+
private ThemedReactContext context;
|
|
21
|
+
private String viewId;
|
|
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
|
+
// Capture configuration
|
|
32
|
+
private String captureMode = "onchange";
|
|
33
|
+
private float captureFramerate = 30f;
|
|
34
|
+
private float autoSensitivity = 5f;
|
|
35
|
+
|
|
36
|
+
// Capture state
|
|
37
|
+
private Handler captureHandler;
|
|
38
|
+
private Runnable captureRunnable;
|
|
39
|
+
private ViewTreeObserver.OnGlobalLayoutListener layoutListener;
|
|
40
|
+
private ViewTreeObserver.OnDrawListener drawListener;
|
|
41
|
+
private AtomicBoolean isCapturing = new AtomicBoolean(false);
|
|
42
|
+
private AtomicBoolean isDestroyed = new AtomicBoolean(false);
|
|
43
|
+
|
|
44
|
+
// Performance optimization
|
|
45
|
+
private Bitmap lastBitmap;
|
|
46
|
+
private long lastCaptureTime = 0;
|
|
47
|
+
private final Object captureLock = new Object();
|
|
48
|
+
|
|
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
|
+
// Add callback support for MixerManager integration
|
|
58
|
+
private MixerManager.BitmapCaptureCallback bitmapCaptureCallback;
|
|
59
|
+
|
|
60
|
+
public MixerView(ThemedReactContext context) {
|
|
61
|
+
super(context);
|
|
62
|
+
this.context = context;
|
|
63
|
+
this.captureHandler = new Handler(Looper.getMainLooper());
|
|
64
|
+
initializeCapture();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private void initializeCapture() {
|
|
68
|
+
// Initialize layout change listener
|
|
69
|
+
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
|
+
}
|
|
84
|
+
|
|
85
|
+
public void setCaptureMode(String mode) {
|
|
86
|
+
if (mode.equals(this.captureMode))
|
|
87
|
+
return;
|
|
88
|
+
|
|
89
|
+
stopCapture();
|
|
90
|
+
this.captureMode = mode;
|
|
91
|
+
startCapture();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
public void setCaptureFramerate(float framerate) {
|
|
95
|
+
this.captureFramerate = Math.max(1f, Math.min(60f, framerate));
|
|
96
|
+
if ("realtime".equals(captureMode)) {
|
|
97
|
+
restartRealtimeCapture();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
public void setAutoSensitivity(float sensitivity) {
|
|
102
|
+
this.autoSensitivity = Math.max(1f, Math.min(10f, sensitivity));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
private void startCapture() {
|
|
106
|
+
if (isDestroyed.get())
|
|
107
|
+
return;
|
|
108
|
+
|
|
109
|
+
switch (captureMode) {
|
|
110
|
+
case "onchange":
|
|
111
|
+
startOnChangeCapture();
|
|
112
|
+
break;
|
|
113
|
+
case "realtime":
|
|
114
|
+
startRealtimeCapture();
|
|
115
|
+
break;
|
|
116
|
+
case "auto":
|
|
117
|
+
startAutoCapture();
|
|
118
|
+
break;
|
|
119
|
+
case "manual":
|
|
120
|
+
// Manual mode doesn't auto-start
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
private void stopCapture() {
|
|
126
|
+
// Remove listeners
|
|
127
|
+
if (getViewTreeObserver().isAlive()) {
|
|
128
|
+
if (layoutListener != null) {
|
|
129
|
+
getViewTreeObserver().removeOnGlobalLayoutListener(layoutListener);
|
|
130
|
+
}
|
|
131
|
+
if (drawListener != null) {
|
|
132
|
+
getViewTreeObserver().removeOnDrawListener(drawListener);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Stop realtime capture
|
|
137
|
+
if (captureRunnable != null) {
|
|
138
|
+
captureHandler.removeCallbacks(captureRunnable);
|
|
139
|
+
captureRunnable = null;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
isCapturing.set(false);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
private void startOnChangeCapture() {
|
|
146
|
+
if (getViewTreeObserver().isAlive()) {
|
|
147
|
+
getViewTreeObserver().addOnGlobalLayoutListener(layoutListener);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
private void startRealtimeCapture() {
|
|
152
|
+
long interval = (long)(1000f / captureFramerate);
|
|
153
|
+
|
|
154
|
+
captureRunnable = new Runnable() {
|
|
155
|
+
@Override
|
|
156
|
+
public void run() {
|
|
157
|
+
if (!isDestroyed.get() && "realtime".equals(captureMode)) {
|
|
158
|
+
performCapture("realtime");
|
|
159
|
+
captureHandler.postDelayed(this, interval);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
captureHandler.postDelayed(captureRunnable, interval);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
private void restartRealtimeCapture() {
|
|
167
|
+
if ("realtime".equals(captureMode)) {
|
|
168
|
+
stopCapture();
|
|
169
|
+
startRealtimeCapture();
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
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
|
+
private void onViewChanged() {
|
|
186
|
+
if (isDestroyed.get()) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
switch (captureMode) {
|
|
191
|
+
case "onchange":
|
|
192
|
+
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
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
private void performCapture(String trigger) {
|
|
253
|
+
if (isCapturing.get() || isDestroyed.get()) {
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
long currentTime = System.currentTimeMillis();
|
|
258
|
+
if (currentTime - lastCaptureTime < 16) {
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
lastCaptureTime = currentTime;
|
|
262
|
+
|
|
263
|
+
synchronized (captureLock) {
|
|
264
|
+
if (isCapturing.compareAndSet(false, true)) {
|
|
265
|
+
Bitmap bitmap = null;
|
|
266
|
+
try {
|
|
267
|
+
bitmap = createBitmap();
|
|
268
|
+
if (bitmap != null) {
|
|
269
|
+
processBitmap(bitmap, trigger);
|
|
270
|
+
}
|
|
271
|
+
} catch (OutOfMemoryError e) {
|
|
272
|
+
System.gc();
|
|
273
|
+
if (bitmap != null && !bitmap.isRecycled()) {
|
|
274
|
+
bitmap.recycle();
|
|
275
|
+
bitmap = null;
|
|
276
|
+
}
|
|
277
|
+
} finally {
|
|
278
|
+
isCapturing.set(false);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
private Bitmap createBitmap() {
|
|
285
|
+
if (getWidth() <= 0 || getHeight() <= 0)
|
|
286
|
+
return null;
|
|
287
|
+
|
|
288
|
+
try {
|
|
289
|
+
Bitmap bitmap =
|
|
290
|
+
Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
|
|
291
|
+
Canvas canvas = new Canvas(bitmap);
|
|
292
|
+
draw(canvas);
|
|
293
|
+
return bitmap;
|
|
294
|
+
} catch (OutOfMemoryError e) {
|
|
295
|
+
// Try with lower quality
|
|
296
|
+
try {
|
|
297
|
+
Bitmap bitmap =
|
|
298
|
+
Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.RGB_565);
|
|
299
|
+
Canvas canvas = new Canvas(bitmap);
|
|
300
|
+
draw(canvas);
|
|
301
|
+
return bitmap;
|
|
302
|
+
} catch (Exception ex) {
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
private void processBitmap(Bitmap bitmap, String trigger) {
|
|
309
|
+
if (bitmap == null || bitmap.isRecycled()) {
|
|
310
|
+
if (bitmapCaptureCallback != null) {
|
|
311
|
+
bitmapCaptureCallback.onCaptureError("Bitmap is null or recycled");
|
|
312
|
+
}
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Call callback first if set (for MixerManager)
|
|
317
|
+
if (bitmapCaptureCallback != null) {
|
|
318
|
+
try {
|
|
319
|
+
bitmapCaptureCallback.onBitmapCaptured(bitmap);
|
|
320
|
+
} catch (Exception e) {
|
|
321
|
+
if (bitmapCaptureCallback != null) {
|
|
322
|
+
bitmapCaptureCallback.onCaptureError("Callback error: " + e.getMessage());
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
} else {
|
|
326
|
+
// Send event to JS (existing functionality)
|
|
327
|
+
try {
|
|
328
|
+
WritableMap event = Arguments.createMap();
|
|
329
|
+
event.putString("trigger", trigger);
|
|
330
|
+
event.putBoolean("success", true);
|
|
331
|
+
event.putDouble("x", mixX);
|
|
332
|
+
event.putDouble("y", mixY);
|
|
333
|
+
event.putDouble("width", mixWidth);
|
|
334
|
+
event.putDouble("height", mixHeight);
|
|
335
|
+
event.putInt("zOrder", mixZOrder);
|
|
336
|
+
event.putInt("renderMode", mixRenderMode);
|
|
337
|
+
event.putInt("bitmapWidth", bitmap.getWidth());
|
|
338
|
+
event.putInt("bitmapHeight", bitmap.getHeight());
|
|
339
|
+
} catch (IllegalStateException e) {
|
|
340
|
+
// Ignore
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// Clean up old bitmap
|
|
345
|
+
if (lastBitmap != null && !lastBitmap.isRecycled()) {
|
|
346
|
+
lastBitmap.recycle();
|
|
347
|
+
}
|
|
348
|
+
lastBitmap = bitmap;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
public void handleCommand(String command, @Nullable ReadableArray args) {
|
|
352
|
+
switch (command) {
|
|
353
|
+
case "capture":
|
|
354
|
+
performCapture("manual");
|
|
355
|
+
break;
|
|
356
|
+
case "startCapture":
|
|
357
|
+
startCapture();
|
|
358
|
+
break;
|
|
359
|
+
case "stopCapture":
|
|
360
|
+
stopCapture();
|
|
361
|
+
break;
|
|
362
|
+
case "setCaptureMode":
|
|
363
|
+
if (args != null && args.size() > 0) {
|
|
364
|
+
setCaptureMode(args.getString(0));
|
|
365
|
+
}
|
|
366
|
+
break;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
@Override
|
|
371
|
+
protected void onAttachedToWindow() {
|
|
372
|
+
super.onAttachedToWindow();
|
|
373
|
+
if (viewId != null) {
|
|
374
|
+
MixerManager.cachedMixedViews.put(viewId, this);
|
|
375
|
+
// 通知MixerManager视图已准备好,检查是否有待处理的回调
|
|
376
|
+
MixerManager.onViewReady(viewId, this);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
@Override
|
|
381
|
+
protected void onDetachedFromWindow() {
|
|
382
|
+
super.onDetachedFromWindow();
|
|
383
|
+
if (viewId != null) {
|
|
384
|
+
MixerManager.cachedMixedViews.remove(viewId);
|
|
385
|
+
}
|
|
386
|
+
cleanup();
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
public void setViewId(String viewId) {
|
|
390
|
+
this.viewId = viewId;
|
|
391
|
+
MixerManager.cachedMixedViews.put(viewId, this);
|
|
392
|
+
// 通知MixerManager视图已准备好,检查是否有待处理的回调
|
|
393
|
+
MixerManager.onViewReady(viewId, this);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// Add callback support for MixerManager integration
|
|
397
|
+
public void setBitmapCaptureCallback(MixerManager.BitmapCaptureCallback callback) {
|
|
398
|
+
this.bitmapCaptureCallback = callback;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// Public method for manual capture (called by MixerManager)
|
|
402
|
+
public void performManualCapture() {
|
|
403
|
+
performCapture("manual");
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
private void cleanup() {
|
|
407
|
+
isDestroyed.set(true);
|
|
408
|
+
stopCapture();
|
|
409
|
+
|
|
410
|
+
if (lastBitmap != null && !lastBitmap.isRecycled()) {
|
|
411
|
+
lastBitmap.recycle();
|
|
412
|
+
lastBitmap = null;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
package com.volcengine.velive.rn.push.mixer;
|
|
2
|
+
|
|
3
|
+
import androidx.annotation.NonNull;
|
|
4
|
+
import androidx.annotation.Nullable;
|
|
5
|
+
import com.facebook.react.uimanager.ViewGroupManager;
|
|
6
|
+
import com.facebook.react.uimanager.ThemedReactContext;
|
|
7
|
+
import com.facebook.react.uimanager.annotations.ReactProp;
|
|
8
|
+
|
|
9
|
+
public class MixerViewManager extends ViewGroupManager<MixerView> {
|
|
10
|
+
public static final String NAME = "VeLiveMixView";
|
|
11
|
+
|
|
12
|
+
@NonNull
|
|
13
|
+
@Override
|
|
14
|
+
public String getName() {
|
|
15
|
+
return NAME;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
@NonNull
|
|
19
|
+
@Override
|
|
20
|
+
protected MixerView
|
|
21
|
+
createViewInstance(@NonNull ThemedReactContext reactContext) {
|
|
22
|
+
return new MixerView(reactContext);
|
|
23
|
+
}
|
|
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
|
+
@ReactProp(name = "captureMode")
|
|
57
|
+
public void setCaptureMode(MixerView view, @Nullable String captureMode) {
|
|
58
|
+
view.setCaptureMode(captureMode != null ? captureMode : "onchange");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@ReactProp(name = "captureFramerate", defaultFloat = 30f)
|
|
62
|
+
public void setCaptureFramerate(MixerView view, float framerate) {
|
|
63
|
+
view.setCaptureFramerate(framerate);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@ReactProp(name = "autoSensitivity", defaultFloat = 5f)
|
|
67
|
+
public void setAutoSensitivity(MixerView view, float sensitivity) {
|
|
68
|
+
view.setAutoSensitivity(sensitivity);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@ReactProp(name = "viewId")
|
|
72
|
+
public void setViewId(MixerView view, @Nullable String viewId) {
|
|
73
|
+
if (viewId != null) {
|
|
74
|
+
view.setViewId(viewId);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
package com.volcengine.velive.rn.push.mixer;
|
|
2
|
+
|
|
3
|
+
import android.graphics.Bitmap;
|
|
4
|
+
import android.opengl.GLES20;
|
|
5
|
+
import android.opengl.GLUtils;
|
|
6
|
+
|
|
7
|
+
import com.pandora.common.env.Env;
|
|
8
|
+
import com.ss.avframework.opengl.GLThreadManager;
|
|
9
|
+
import com.ss.avframework.opengl.GlUtil;
|
|
10
|
+
|
|
11
|
+
import java.nio.ByteBuffer;
|
|
12
|
+
|
|
13
|
+
public class TextureMgr {
|
|
14
|
+
private int texture;
|
|
15
|
+
private int width;
|
|
16
|
+
private int height;
|
|
17
|
+
public TextureMgr(int width, int height) {
|
|
18
|
+
this.width = width;
|
|
19
|
+
this.height = height;
|
|
20
|
+
GLThreadManager.getMainGlHandle().post(() -> {
|
|
21
|
+
if (texture <= 0) {
|
|
22
|
+
texture = GlUtil.generateTexture(GLES20.GL_TEXTURE_2D);
|
|
23
|
+
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
|
|
24
|
+
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
|
|
25
|
+
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
|
|
26
|
+
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
|
|
27
|
+
GLES20.glFinish();
|
|
28
|
+
GlUtil.checkNoGLES2Error("clearBackgroundTex");
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public void cleanup() {
|
|
34
|
+
GLThreadManager.getMainGlHandle().post(() -> {
|
|
35
|
+
if (texture > 0) {
|
|
36
|
+
GLES20.glDeleteTextures(1, new int[]{texture}, 0);
|
|
37
|
+
texture = 0;
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public interface RenderListener {
|
|
43
|
+
void doBusiness(int texture);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public void dealWithTexture(ByteBuffer byteBuffer, RenderListener listener) {
|
|
47
|
+
GLThreadManager.getMainGlHandle().post(new Runnable() {
|
|
48
|
+
@Override
|
|
49
|
+
public void run() {
|
|
50
|
+
if (texture > 0) {
|
|
51
|
+
YuvHelper.NV21ToBitmap bm = null;
|
|
52
|
+
Bitmap bmp = null;
|
|
53
|
+
Bitmap rotatedBmp = null;
|
|
54
|
+
try {
|
|
55
|
+
bm = new YuvHelper.NV21ToBitmap(Env.getApplicationContext());
|
|
56
|
+
bmp = bm.nv21ToBitmap(byteBuffer.array(), width, height);
|
|
57
|
+
|
|
58
|
+
if (bmp == null || bmp.isRecycled()) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
|
|
63
|
+
rotatedBmp = YuvHelper.rotateBitmap(bmp, 0, false, true);
|
|
64
|
+
|
|
65
|
+
if (rotatedBmp != null && !rotatedBmp.isRecycled()) {
|
|
66
|
+
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, rotatedBmp, 0);
|
|
67
|
+
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
|
|
68
|
+
GLES20.glFlush();
|
|
69
|
+
listener.doBusiness(texture);
|
|
70
|
+
} else {
|
|
71
|
+
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
|
|
72
|
+
}
|
|
73
|
+
} catch (OutOfMemoryError e) {
|
|
74
|
+
System.gc();
|
|
75
|
+
} catch (Exception e) {
|
|
76
|
+
// Ignore
|
|
77
|
+
} finally {
|
|
78
|
+
if (bmp != null && !bmp.isRecycled()) {
|
|
79
|
+
bmp.recycle();
|
|
80
|
+
}
|
|
81
|
+
if (rotatedBmp != null && rotatedBmp != bmp && !rotatedBmp.isRecycled()) {
|
|
82
|
+
rotatedBmp.recycle();
|
|
83
|
+
}
|
|
84
|
+
if (bm != null) {
|
|
85
|
+
bm.cleanup();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
public void dealI420WithTexture(ByteBuffer byteBuffer, RenderListener listener) {
|
|
94
|
+
GLThreadManager.getMainGlHandle().post(new Runnable() {
|
|
95
|
+
@Override
|
|
96
|
+
public void run() {
|
|
97
|
+
if (texture > 0) {
|
|
98
|
+
Bitmap bm = null;
|
|
99
|
+
Bitmap rotatedBm = null;
|
|
100
|
+
try {
|
|
101
|
+
bm = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
|
102
|
+
bm.copyPixelsFromBuffer(byteBuffer);
|
|
103
|
+
|
|
104
|
+
if (bm.isRecycled()) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
|
|
109
|
+
rotatedBm = YuvHelper.rotateBitmap(bm, 0, false, true);
|
|
110
|
+
|
|
111
|
+
if (rotatedBm != null && !rotatedBm.isRecycled()) {
|
|
112
|
+
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, rotatedBm, 0);
|
|
113
|
+
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
|
|
114
|
+
GLES20.glFlush();
|
|
115
|
+
listener.doBusiness(texture);
|
|
116
|
+
} else {
|
|
117
|
+
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
|
|
118
|
+
}
|
|
119
|
+
} catch (OutOfMemoryError e) {
|
|
120
|
+
System.gc();
|
|
121
|
+
} catch (Exception e) {
|
|
122
|
+
// Ignore
|
|
123
|
+
} finally {
|
|
124
|
+
if (bm != null && !bm.isRecycled()) {
|
|
125
|
+
bm.recycle();
|
|
126
|
+
}
|
|
127
|
+
if (rotatedBm != null && rotatedBm != bm && !rotatedBm.isRecycled()) {
|
|
128
|
+
rotatedBm.recycle();
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
public void dealWithTexture(Bitmap bitmap, RenderListener listener) {
|
|
137
|
+
GLThreadManager.getMainGlHandle().post(() -> {
|
|
138
|
+
if (texture > 0) {
|
|
139
|
+
Bitmap processedBitmap = null;
|
|
140
|
+
try {
|
|
141
|
+
if (bitmap == null || bitmap.isRecycled()) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
|
|
146
|
+
processedBitmap = YuvHelper.rotateBitmap(bitmap, 0, false, true);
|
|
147
|
+
|
|
148
|
+
if (processedBitmap != null && !processedBitmap.isRecycled()) {
|
|
149
|
+
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, processedBitmap, 0);
|
|
150
|
+
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
|
|
151
|
+
GLES20.glFlush();
|
|
152
|
+
listener.doBusiness(texture);
|
|
153
|
+
} else {
|
|
154
|
+
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
|
|
155
|
+
}
|
|
156
|
+
} catch (OutOfMemoryError e) {
|
|
157
|
+
System.gc();
|
|
158
|
+
} catch (Exception e) {
|
|
159
|
+
// Ignore
|
|
160
|
+
} finally {
|
|
161
|
+
if (processedBitmap != null && processedBitmap != bitmap && !processedBitmap.isRecycled()) {
|
|
162
|
+
processedBitmap.recycle();
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}
|