@volcengine/react-native-live-push 1.1.3-rc.1 → 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 (139) 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 +14 -2
  5. package/android/src/main/java/com/volcengine/velive/rn/push/VeLivePushPackage.java +16 -13
  6. package/android/src/main/java/com/volcengine/velive/rn/push/VeLivePushView.java +16 -0
  7. package/android/src/main/java/com/volcengine/velive/rn/push/VeLivePushViewManager.java +7 -2
  8. package/android/src/main/java/com/volcengine/velive/rn/push/mixer/MixerManager.java +410 -0
  9. package/android/src/main/java/com/volcengine/velive/rn/push/mixer/MixerView.java +328 -0
  10. package/android/src/main/java/com/volcengine/velive/rn/push/mixer/MixerViewManager.java +43 -0
  11. package/android/src/main/java/com/volcengine/velive/rn/push/mixer/TextureMgr.java +168 -0
  12. package/android/src/main/java/com/volcengine/velive/rn/push/mixer/YuvHelper.java +165 -0
  13. package/ios/VeLiveMixerHelper.h +49 -0
  14. package/ios/VeLiveMixerHelper.m +646 -0
  15. package/ios/VeLiveMixerView.h +62 -0
  16. package/ios/VeLiveMixerView.m +547 -0
  17. package/ios/VeLiveMixerViewManager.m +56 -0
  18. package/lib/commonjs/index.js +22697 -20359
  19. package/lib/commonjs/typescript/android/index.d.ts +44 -0
  20. package/lib/commonjs/typescript/codegen/android/api.d.ts +1068 -0
  21. package/lib/commonjs/typescript/codegen/android/callback.d.ts +333 -0
  22. package/lib/commonjs/typescript/codegen/android/errorcode.d.ts +92 -0
  23. package/lib/commonjs/typescript/codegen/android/index.d.ts +5 -0
  24. package/lib/commonjs/typescript/codegen/android/keytype.d.ts +1693 -0
  25. package/lib/commonjs/typescript/codegen/android/types.d.ts +33 -0
  26. package/lib/commonjs/typescript/codegen/ios/api.d.ts +1125 -0
  27. package/lib/commonjs/typescript/codegen/ios/callback.d.ts +242 -0
  28. package/lib/commonjs/typescript/codegen/ios/errorcode.d.ts +154 -0
  29. package/lib/commonjs/typescript/codegen/ios/external.d.ts +1 -0
  30. package/lib/commonjs/typescript/codegen/ios/index.d.ts +6 -0
  31. package/lib/commonjs/typescript/codegen/ios/keytype.d.ts +1154 -0
  32. package/lib/commonjs/typescript/codegen/ios/types.d.ts +46 -0
  33. package/lib/commonjs/typescript/codegen/pack/api.d.ts +1470 -0
  34. package/lib/commonjs/typescript/codegen/pack/callback.d.ts +446 -0
  35. package/lib/commonjs/typescript/codegen/pack/errorcode.d.ts +109 -0
  36. package/lib/commonjs/typescript/codegen/pack/index.d.ts +5 -0
  37. package/lib/commonjs/typescript/codegen/pack/keytype.d.ts +2248 -0
  38. package/lib/commonjs/typescript/codegen/pack/types.d.ts +68 -0
  39. package/lib/commonjs/typescript/codegen/type-shim.d.ts +6 -0
  40. package/lib/commonjs/typescript/component.d.ts +15 -0
  41. package/lib/commonjs/typescript/core/api.d.ts +18 -0
  42. package/lib/commonjs/typescript/core/callback.d.ts +2 -0
  43. package/lib/commonjs/typescript/core/env.d.ts +29 -0
  44. package/lib/commonjs/typescript/core/errorcode.d.ts +2 -0
  45. package/lib/commonjs/typescript/core/index.d.ts +6 -0
  46. package/lib/commonjs/typescript/core/keytype.d.ts +17 -0
  47. package/lib/commonjs/typescript/core/mixer.d.ts +26 -0
  48. package/lib/commonjs/typescript/core/pusher.d.ts +13 -0
  49. package/lib/commonjs/typescript/index.d.ts +3 -0
  50. package/lib/commonjs/typescript/ios/extends.d.ts +41 -0
  51. package/lib/commonjs/typescript/platforms/android/extends.d.ts +8 -0
  52. package/lib/commonjs/typescript/platforms/android/helper.d.ts +8 -0
  53. package/lib/commonjs/typescript/platforms/android/mixer.d.ts +8 -0
  54. package/lib/commonjs/typescript/platforms/ios/extends.d.ts +17 -0
  55. package/lib/commonjs/typescript/platforms/ios/helper.d.ts +8 -0
  56. package/lib/commonjs/typescript/platforms/ios/mixer.d.ts +9 -0
  57. package/lib/commonjs/typescript/runtime.d.ts +1 -0
  58. package/lib/commonjs/typescript/view/MixView.d.ts +44 -0
  59. package/lib/commonjs/typescript/view/VeImageView.d.ts +19 -0
  60. package/lib/commonjs/typescript/view/VeTextView.d.ts +7 -0
  61. package/lib/commonjs/typescript/view/VeView.d.ts +7 -0
  62. package/lib/commonjs/typescript/view/VeWebView.d.ts +7 -0
  63. package/lib/commonjs/typescript/view/index.d.ts +5 -0
  64. package/lib/module/index.js +22694 -20360
  65. package/lib/module/typescript/android/index.d.ts +44 -0
  66. package/lib/module/typescript/codegen/android/api.d.ts +1068 -0
  67. package/lib/module/typescript/codegen/android/callback.d.ts +333 -0
  68. package/lib/module/typescript/codegen/android/errorcode.d.ts +92 -0
  69. package/lib/module/typescript/codegen/android/index.d.ts +5 -0
  70. package/lib/module/typescript/codegen/android/keytype.d.ts +1693 -0
  71. package/lib/module/typescript/codegen/android/types.d.ts +33 -0
  72. package/lib/module/typescript/codegen/ios/api.d.ts +1125 -0
  73. package/lib/module/typescript/codegen/ios/callback.d.ts +242 -0
  74. package/lib/module/typescript/codegen/ios/errorcode.d.ts +154 -0
  75. package/lib/module/typescript/codegen/ios/external.d.ts +1 -0
  76. package/lib/module/typescript/codegen/ios/index.d.ts +6 -0
  77. package/lib/module/typescript/codegen/ios/keytype.d.ts +1154 -0
  78. package/lib/module/typescript/codegen/ios/types.d.ts +46 -0
  79. package/lib/module/typescript/codegen/pack/api.d.ts +1470 -0
  80. package/lib/module/typescript/codegen/pack/callback.d.ts +446 -0
  81. package/lib/module/typescript/codegen/pack/errorcode.d.ts +109 -0
  82. package/lib/module/typescript/codegen/pack/index.d.ts +5 -0
  83. package/lib/module/typescript/codegen/pack/keytype.d.ts +2248 -0
  84. package/lib/module/typescript/codegen/pack/types.d.ts +68 -0
  85. package/lib/module/typescript/codegen/type-shim.d.ts +6 -0
  86. package/lib/module/typescript/component.d.ts +15 -0
  87. package/lib/module/typescript/core/api.d.ts +18 -0
  88. package/lib/module/typescript/core/callback.d.ts +2 -0
  89. package/lib/module/typescript/core/env.d.ts +29 -0
  90. package/lib/module/typescript/core/errorcode.d.ts +2 -0
  91. package/lib/module/typescript/core/index.d.ts +6 -0
  92. package/lib/module/typescript/core/keytype.d.ts +17 -0
  93. package/lib/module/typescript/core/mixer.d.ts +26 -0
  94. package/lib/module/typescript/core/pusher.d.ts +13 -0
  95. package/lib/module/typescript/index.d.ts +3 -0
  96. package/lib/module/typescript/ios/extends.d.ts +41 -0
  97. package/lib/module/typescript/platforms/android/extends.d.ts +8 -0
  98. package/lib/module/typescript/platforms/android/helper.d.ts +8 -0
  99. package/lib/module/typescript/platforms/android/mixer.d.ts +8 -0
  100. package/lib/module/typescript/platforms/ios/extends.d.ts +17 -0
  101. package/lib/module/typescript/platforms/ios/helper.d.ts +8 -0
  102. package/lib/module/typescript/platforms/ios/mixer.d.ts +9 -0
  103. package/lib/module/typescript/runtime.d.ts +1 -0
  104. package/lib/module/typescript/view/MixView.d.ts +44 -0
  105. package/lib/module/typescript/view/VeImageView.d.ts +19 -0
  106. package/lib/module/typescript/view/VeTextView.d.ts +7 -0
  107. package/lib/module/typescript/view/VeView.d.ts +7 -0
  108. package/lib/module/typescript/view/VeWebView.d.ts +7 -0
  109. package/lib/module/typescript/view/index.d.ts +5 -0
  110. package/lib/typescript/android/index.d.ts +0 -3
  111. package/lib/typescript/codegen/android/api.d.ts +194 -762
  112. package/lib/typescript/codegen/android/callback.d.ts +85 -48
  113. package/lib/typescript/codegen/android/errorcode.d.ts +30 -0
  114. package/lib/typescript/codegen/android/keytype.d.ts +514 -122
  115. package/lib/typescript/codegen/ios/api.d.ts +380 -351
  116. package/lib/typescript/codegen/ios/callback.d.ts +33 -6
  117. package/lib/typescript/codegen/ios/errorcode.d.ts +52 -2
  118. package/lib/typescript/codegen/ios/keytype.d.ts +313 -35
  119. package/lib/typescript/codegen/pack/api.d.ts +302 -821
  120. package/lib/typescript/codegen/pack/callback.d.ts +54 -49
  121. package/lib/typescript/codegen/pack/errorcode.d.ts +38 -5
  122. package/lib/typescript/codegen/pack/keytype.d.ts +672 -228
  123. package/lib/typescript/core/api.d.ts +18 -2
  124. package/lib/typescript/core/keytype.d.ts +15 -0
  125. package/lib/typescript/core/mixer.d.ts +26 -0
  126. package/lib/typescript/core/pusher.d.ts +0 -3
  127. package/lib/typescript/index.d.ts +1 -0
  128. package/lib/typescript/platforms/android/extends.d.ts +8 -0
  129. package/lib/typescript/platforms/android/mixer.d.ts +8 -0
  130. package/lib/typescript/platforms/ios/mixer.d.ts +9 -0
  131. package/lib/typescript/view/MixView.d.ts +44 -0
  132. package/lib/typescript/view/VeImageView.d.ts +19 -0
  133. package/lib/typescript/view/VeTextView.d.ts +7 -0
  134. package/lib/typescript/view/VeView.d.ts +7 -0
  135. package/lib/typescript/view/VeWebView.d.ts +7 -0
  136. package/lib/typescript/view/index.d.ts +5 -0
  137. package/package.json +1 -1
  138. package/react-native-velive-push.podspec +3 -3
  139. package/android/src/main/java/com/volcengine/velive/rn/push/ScreenCaptureHelper.java +0 -73
@@ -0,0 +1,328 @@
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
+ // Capture configuration
24
+ private String captureMode = "onchange";
25
+ private float captureFramerate = 5f; // realTime mode default 5 fps
26
+
27
+ // Capture state
28
+ private Handler captureHandler;
29
+ private Runnable captureRunnable;
30
+ private ViewTreeObserver.OnGlobalLayoutListener layoutListener;
31
+ private AtomicBoolean isCapturing = new AtomicBoolean(false);
32
+ private AtomicBoolean isDestroyed = new AtomicBoolean(false);
33
+
34
+ // Performance optimization
35
+ private Bitmap lastBitmap;
36
+ private long lastCaptureTime = 0;
37
+ private final Object captureLock = new Object();
38
+
39
+ // Add callback support for MixerManager integration
40
+ private MixerManager.BitmapCaptureCallback bitmapCaptureCallback;
41
+
42
+ public MixerView(ThemedReactContext context) {
43
+ super(context);
44
+ this.context = context;
45
+ this.captureHandler = new Handler(Looper.getMainLooper());
46
+ initializeCapture();
47
+ }
48
+
49
+ private void initializeCapture() {
50
+ // Initialize layout change listener
51
+ layoutListener = this::onViewChanged;
52
+ }
53
+
54
+ public void setCaptureMode(String mode) {
55
+ if (mode.equals(this.captureMode))
56
+ return;
57
+
58
+ stopCapture();
59
+ this.captureMode = mode;
60
+ startCapture();
61
+ }
62
+
63
+ public void setCaptureFramerate(float framerate) {
64
+ this.captureFramerate = Math.max(1f, Math.min(60f, framerate));
65
+ if ("realtime".equals(captureMode)) {
66
+ restartRealtimeCapture();
67
+ }
68
+ }
69
+
70
+ private void startCapture() {
71
+ if (isDestroyed.get())
72
+ return;
73
+
74
+ switch (captureMode) {
75
+ case "onchange":
76
+ startOnChangeCapture();
77
+ break;
78
+ case "realtime":
79
+ startRealtimeCapture();
80
+ break;
81
+ case "manual":
82
+ // Manual mode doesn't auto-start
83
+ break;
84
+ }
85
+ }
86
+
87
+ private void stopCapture() {
88
+ // Remove listeners
89
+ if (getViewTreeObserver().isAlive()) {
90
+ if (layoutListener != null) {
91
+ getViewTreeObserver().removeOnGlobalLayoutListener(layoutListener);
92
+ }
93
+ }
94
+
95
+ // Stop realtime capture
96
+ if (captureRunnable != null) {
97
+ captureHandler.removeCallbacks(captureRunnable);
98
+ captureRunnable = null;
99
+ }
100
+
101
+ isCapturing.set(false);
102
+ }
103
+
104
+ private void startOnChangeCapture() {
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);
118
+ }
119
+
120
+ private void startRealtimeCapture() {
121
+ long interval = (long)(1000f / captureFramerate);
122
+
123
+ captureRunnable = new Runnable() {
124
+ @Override
125
+ public void run() {
126
+ if (!isDestroyed.get() && "realtime".equals(captureMode)) {
127
+ performCapture("realtime");
128
+ captureHandler.postDelayed(this, interval);
129
+ }
130
+ }
131
+ };
132
+ captureHandler.postDelayed(captureRunnable, interval);
133
+ }
134
+
135
+ private void restartRealtimeCapture() {
136
+ if ("realtime".equals(captureMode)) {
137
+ stopCapture();
138
+ startRealtimeCapture();
139
+ }
140
+ }
141
+
142
+ private void onViewChanged() {
143
+ if (isDestroyed.get()) {
144
+ return;
145
+ }
146
+
147
+ if ("onchange".equals(captureMode)) {
148
+ performCapture("onchange");
149
+ }
150
+ }
151
+
152
+ private void performCapture(String trigger) {
153
+ if (isCapturing.get() || isDestroyed.get()) {
154
+ return;
155
+ }
156
+
157
+ long currentTime = System.currentTimeMillis();
158
+ long minInterval = 33; // 30 FPS ~ 33ms per frame
159
+ if (currentTime - lastCaptureTime < minInterval) {
160
+ return;
161
+ }
162
+ lastCaptureTime = currentTime;
163
+
164
+ synchronized (captureLock) {
165
+ if (isCapturing.compareAndSet(false, true)) {
166
+ Bitmap bitmap = null;
167
+ try {
168
+ bitmap = createBitmap();
169
+ if (bitmap != null) {
170
+ processBitmap(bitmap, trigger);
171
+ }
172
+ } catch (OutOfMemoryError e) {
173
+ System.gc();
174
+ // If an OOM occurs and the bitmap has not been passed to
175
+ // processBitmap, recycle it
176
+ if (bitmap != null && !bitmap.isRecycled()) {
177
+ bitmap.recycle();
178
+ }
179
+ } catch (Exception e) {
180
+ // If any other exception occurs and the bitmap has not been passed to
181
+ // processBitmap, recycle it
182
+ if (bitmap != null && !bitmap.isRecycled()) {
183
+ bitmap.recycle();
184
+ }
185
+ } finally {
186
+ isCapturing.set(false);
187
+ }
188
+ }
189
+ }
190
+ }
191
+
192
+ private Bitmap createBitmap() {
193
+ if (getWidth() <= 0 || getHeight() <= 0)
194
+ return null;
195
+
196
+ try {
197
+ Bitmap bitmap =
198
+ Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
199
+ Canvas canvas = new Canvas(bitmap);
200
+ draw(canvas);
201
+ return bitmap;
202
+ } catch (OutOfMemoryError e) {
203
+ // Try with lower quality
204
+ try {
205
+ Bitmap bitmap =
206
+ Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.RGB_565);
207
+ Canvas canvas = new Canvas(bitmap);
208
+ draw(canvas);
209
+ return bitmap;
210
+ } catch (Exception ex) {
211
+ return null;
212
+ }
213
+ }
214
+ }
215
+
216
+ private void processBitmap(Bitmap bitmap, String trigger) {
217
+ if (bitmap == null || bitmap.isRecycled()) {
218
+ if (bitmapCaptureCallback != null) {
219
+ bitmapCaptureCallback.onCaptureError("Bitmap is null or recycled");
220
+ }
221
+ return;
222
+ }
223
+
224
+ // Call callback first if set (for MixerManager)
225
+ if (bitmapCaptureCallback != null) {
226
+ try {
227
+ // only capture if the callback is set
228
+ bitmapCaptureCallback.onBitmapCaptured(bitmap);
229
+ } catch (Exception e) {
230
+ if (bitmapCaptureCallback != null) {
231
+ bitmapCaptureCallback.onCaptureError("Callback error: " +
232
+ e.getMessage());
233
+ }
234
+ }
235
+ } else {
236
+ // Send event to JS (existing functionality)
237
+ try {
238
+ WritableMap event = Arguments.createMap();
239
+ event.putString("trigger", trigger);
240
+ event.putBoolean("success", true);
241
+ event.putInt("bitmapWidth", bitmap.getWidth());
242
+ event.putInt("bitmapHeight", bitmap.getHeight());
243
+ } catch (IllegalStateException e) {
244
+ // Ignore
245
+ }
246
+ }
247
+
248
+ // Clean up old bitmap
249
+ if (lastBitmap != null && !lastBitmap.isRecycled()) {
250
+ lastBitmap.recycle();
251
+ }
252
+
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
255
+ if (bitmapCaptureCallback == null) {
256
+ if (bitmap != null && !bitmap.isRecycled()) {
257
+ bitmap.recycle();
258
+ }
259
+ lastBitmap = null;
260
+ } else {
261
+ lastBitmap = bitmap;
262
+ }
263
+ }
264
+
265
+ public void handleCommand(String command, @Nullable ReadableArray args) {
266
+ switch (command) {
267
+ case "capture":
268
+ performCapture("manual");
269
+ break;
270
+ case "startCapture":
271
+ startCapture();
272
+ break;
273
+ case "stopCapture":
274
+ stopCapture();
275
+ break;
276
+ case "setCaptureMode":
277
+ if (args != null && args.size() > 0) {
278
+ setCaptureMode(args.getString(0));
279
+ }
280
+ break;
281
+ }
282
+ }
283
+
284
+ @Override
285
+ protected void onAttachedToWindow() {
286
+ super.onAttachedToWindow();
287
+ if (viewId != null) {
288
+ MixerManager.cachedMixedViews.put(viewId, this);
289
+ // Notify MixerManager that view is ready, check for pending callbacks
290
+ MixerManager.onViewReady(viewId, this);
291
+ }
292
+ }
293
+
294
+ @Override
295
+ protected void onDetachedFromWindow() {
296
+ super.onDetachedFromWindow();
297
+ if (viewId != null) {
298
+ MixerManager.cachedMixedViews.remove(viewId);
299
+ }
300
+ cleanup();
301
+ }
302
+
303
+ public void setViewId(String viewId) {
304
+ this.viewId = viewId;
305
+ MixerManager.cachedMixedViews.put(viewId, this);
306
+ // Notify MixerManager that view is ready, check for pending callbacks
307
+ MixerManager.onViewReady(viewId, this);
308
+ }
309
+
310
+ // Add callback support for MixerManager integration
311
+ public void
312
+ setBitmapCaptureCallback(MixerManager.BitmapCaptureCallback callback) {
313
+ this.bitmapCaptureCallback = callback;
314
+ }
315
+
316
+ // Public method for manual capture (called by MixerManager)
317
+ public void performManualCapture() { performCapture("manual"); }
318
+
319
+ private void cleanup() {
320
+ isDestroyed.set(true);
321
+ stopCapture();
322
+
323
+ if (lastBitmap != null && !lastBitmap.isRecycled()) {
324
+ lastBitmap.recycle();
325
+ lastBitmap = null;
326
+ }
327
+ }
328
+ }
@@ -0,0 +1,43 @@
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
+ @ReactProp(name = "captureMode")
26
+ public void setCaptureMode(MixerView view, @Nullable String captureMode) {
27
+ view.setCaptureMode(captureMode != null ? captureMode : "onchange");
28
+ }
29
+
30
+ @ReactProp(name = "captureFramerate", defaultFloat = 5f)
31
+ public void setCaptureFramerate(MixerView view, float framerate) {
32
+ view.setCaptureFramerate(framerate);
33
+ }
34
+
35
+ @ReactProp(name = "viewId")
36
+ public void setViewId(MixerView view, @Nullable String viewId) {
37
+ if (viewId != null) {
38
+ view.setViewId(viewId);
39
+ }
40
+ }
41
+ }
42
+
43
+
@@ -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
+ boolean needRecycle = false;
141
+ try {
142
+ if (bitmap == null || bitmap.isRecycled()) {
143
+ return;
144
+ }
145
+ GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
146
+ processedBitmap = YuvHelper.rotateBitmap(bitmap, 0, false, true);
147
+ needRecycle = (processedBitmap != null && processedBitmap != bitmap);
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 (needRecycle && processedBitmap != null && !processedBitmap.isRecycled()) {
162
+ processedBitmap.recycle();
163
+ }
164
+ }
165
+ }
166
+ });
167
+ }
168
+ }
@@ -0,0 +1,165 @@
1
+ package com.volcengine.velive.rn.push.mixer;
2
+
3
+ import android.content.Context;
4
+ import android.graphics.Bitmap;
5
+ import android.graphics.Matrix;
6
+ import android.renderscript.Allocation;
7
+ import android.renderscript.Element;
8
+ import android.renderscript.RenderScript;
9
+ import android.renderscript.ScriptIntrinsicYuvToRGB;
10
+ import android.renderscript.Type;
11
+
12
+ import java.nio.ByteBuffer;
13
+
14
+ public class YuvHelper {
15
+ private static RenderScript globalRS = null;
16
+ public static synchronized RenderScript getGlobalRS(Context context) {
17
+ if (globalRS == null) {
18
+ globalRS = RenderScript.create(context.getApplicationContext());
19
+ }
20
+ return globalRS;
21
+ }
22
+ public static void destroyGlobalRS() {
23
+ if (globalRS != null) {
24
+ globalRS.destroy();
25
+ globalRS = null;
26
+ }
27
+ }
28
+ public static class NV21ToBitmap {
29
+ private RenderScript rs;
30
+ private ScriptIntrinsicYuvToRGB yuvToRgbIntrinsic;
31
+ private Type.Builder yuvType, rgbaType;
32
+
33
+ public NV21ToBitmap(Context context) {
34
+ rs = YuvHelper.getGlobalRS(context);
35
+ yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs));
36
+ yuvType = new Type.Builder(rs, Element.U8(rs));
37
+ rgbaType = new Type.Builder(rs, Element.RGBA_8888(rs));
38
+ }
39
+
40
+ public void cleanup() {
41
+ try {
42
+ if (yuvToRgbIntrinsic != null) {
43
+ yuvToRgbIntrinsic.destroy();
44
+ yuvToRgbIntrinsic = null;
45
+ }
46
+ // 不销毁全局 rs
47
+ // rs = null;
48
+ } catch (Exception e) {
49
+ // Ignore
50
+ }
51
+ }
52
+
53
+ public Bitmap nv21ToBitmap(byte[] nv21, int width, int height) {
54
+ Allocation in = null;
55
+ Allocation out = null;
56
+ try {
57
+ yuvType.setX(nv21.length);
58
+ in = Allocation.createTyped(rs, yuvType.create(), Allocation.USAGE_SCRIPT);
59
+ in.copyFrom(nv21);
60
+
61
+ rgbaType.setX(width).setY(height);
62
+ out = Allocation.createTyped(rs, rgbaType.create(), Allocation.USAGE_SCRIPT);
63
+ yuvToRgbIntrinsic.setInput(in);
64
+ yuvToRgbIntrinsic.forEach(out);
65
+
66
+ Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
67
+ out.copyTo(bmp);
68
+
69
+ return bmp;
70
+ } finally {
71
+ if (in != null) {
72
+ in.destroy();
73
+ }
74
+ if (out != null) {
75
+ out.destroy();
76
+ }
77
+ }
78
+ }
79
+ }
80
+
81
+ public static void NV21toI420(ByteBuffer input, ByteBuffer output, final int width, final int height) {
82
+ final int size = width * height;
83
+ final int quarter = size / 4;
84
+ final int v0 = size + quarter;
85
+
86
+ System.arraycopy(input.array(), 0, output.array(), 0, size);
87
+
88
+ for (int u = size, v = v0, o = size; u < v0; u++, v++, o += 2) {
89
+ output.array()[v] = input.array()[o];
90
+ output.array()[u] = input.array()[o + 1];
91
+ }
92
+ output.limit(width * height * 3 / 2);
93
+ output.position(0);
94
+ }
95
+
96
+ public static void NV21toNV12(ByteBuffer input, ByteBuffer output, final int width, final int height) {
97
+ final int size = width * height;
98
+
99
+ System.arraycopy(input.array(), 0, output.array(), 0, size);
100
+ for (int i = size; i < 1.5f * size; i += 2) {
101
+ output.array()[i] = input.array()[i + 1];
102
+ output.array()[i + 1] = input.array()[i];
103
+ }
104
+ output.position(0);
105
+ output.limit(width * height * 3 / 2);
106
+ }
107
+
108
+ public static void NV12toI420(ByteBuffer input, ByteBuffer output, final int width, final int height) {
109
+ final int size = width * height;
110
+ final int quarter = size / 4;
111
+ final int v0 = size + quarter;
112
+
113
+ System.arraycopy(input.array(), 0, output.array(), 0, size);
114
+
115
+ for (int u = size, v = v0, o = size; u < v0; u++, v++, o += 2) {
116
+ output.array()[v] = input.array()[o + 1];
117
+ output.array()[u] = input.array()[o];
118
+ }
119
+ }
120
+
121
+ public static void I420toNV21(ByteBuffer input, ByteBuffer output, final int width, final int height) {
122
+ final int size = width * height;
123
+ final int quarter = size / 4;
124
+ final int v0 = size + quarter;
125
+
126
+ System.arraycopy(input.array(), 0, output.array(), 0, size);
127
+
128
+ for (int u = size, v = v0, o = size; u < v0; u++, v++, o += 2) {
129
+ output.array()[o + 1] = input.array()[v];
130
+ output.array()[o] = input.array()[u];
131
+ }
132
+ }
133
+
134
+ public static Bitmap rotateBitmap(Bitmap origin, float alpha, boolean horizontalMirror, boolean verticalMirror) {
135
+ if (origin == null || origin.isRecycled()) {
136
+ return null;
137
+ }
138
+
139
+ try {
140
+ int width = origin.getWidth();
141
+ int height = origin.getHeight();
142
+ Matrix matrix = new Matrix();
143
+ float sx = 1;
144
+ float sy = 1;
145
+ if (horizontalMirror) {
146
+ sx = -1;
147
+ }
148
+ if (verticalMirror) {
149
+ sy = -1;
150
+ }
151
+ matrix.postScale(sx, sy);
152
+ matrix.postRotate(alpha);
153
+
154
+ if (origin.isRecycled()) {
155
+ return null;
156
+ }
157
+
158
+ return Bitmap.createBitmap(origin, 0, 0, width, height, matrix, false);
159
+ } catch (IllegalStateException e) {
160
+ return null;
161
+ } catch (Exception e) {
162
+ return null;
163
+ }
164
+ }
165
+ }