@byteplus/react-native-live-push 1.1.3-rc.2 → 1.1.3-rc.4
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 +161 -141
- package/android/src/main/java/com/volcengine/velive/rn/push/mixer/MixerView.java +9 -1
- package/android/src/main/java/com/volcengine/velive/rn/push/mixer/TextureMgr.java +3 -3
- package/android/src/main/java/com/volcengine/velive/rn/push/mixer/YuvHelper.java +16 -5
- package/ios/VeLiveMixerHelper.m +222 -164
- package/ios/VeLiveMixerView.m +120 -112
- package/lib/commonjs/index.js +14 -1374
- package/lib/commonjs/typescript/core/keytype.d.ts +1 -0
- package/lib/module/index.js +15 -1375
- package/lib/module/typescript/core/keytype.d.ts +1 -0
- package/lib/typescript/core/keytype.d.ts +1 -0
- package/package.json +1 -1
|
@@ -4,34 +4,31 @@ import android.graphics.Bitmap;
|
|
|
4
4
|
import android.util.Log;
|
|
5
5
|
import android.view.View;
|
|
6
6
|
import android.view.ViewTreeObserver;
|
|
7
|
-
|
|
8
7
|
import com.ss.avframework.live.VeLivePusher;
|
|
9
8
|
import com.ss.avframework.live.VeLivePusherDef.VeLiveMixVideoLayout;
|
|
10
|
-
import com.ss.avframework.live.VeLivePusherDef.VeLiveStreamMixDescription;
|
|
11
9
|
import com.ss.avframework.live.VeLivePusherDef.VeLivePusherRenderMode;
|
|
10
|
+
import com.ss.avframework.live.VeLivePusherDef.VeLiveStreamMixDescription;
|
|
12
11
|
import com.ss.avframework.live.VeLiveVideoFrame;
|
|
13
|
-
|
|
14
|
-
import org.json.JSONObject;
|
|
15
|
-
|
|
16
12
|
import java.util.HashMap;
|
|
17
13
|
import java.util.Map;
|
|
18
14
|
import java.util.concurrent.ConcurrentHashMap;
|
|
19
|
-
|
|
20
15
|
import javax.annotation.Nullable;
|
|
16
|
+
import org.json.JSONObject;
|
|
21
17
|
|
|
22
18
|
public class MixerManager {
|
|
23
|
-
public
|
|
19
|
+
public static Map<String, View> cachedMixedViews = new HashMap<>();
|
|
24
20
|
|
|
25
21
|
private static final String TAG = "MixerManager";
|
|
26
22
|
|
|
27
23
|
private VeLivePusher pusher;
|
|
28
|
-
private final Map<String, VeLiveMixVideoLayout> mixedViewLayout =
|
|
29
|
-
|
|
30
|
-
private final Map<String, Integer>
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
24
|
+
private final Map<String, VeLiveMixVideoLayout> mixedViewLayout =
|
|
25
|
+
new ConcurrentHashMap<>();
|
|
26
|
+
private final Map<String, Integer> viewIdToStreamId =
|
|
27
|
+
new ConcurrentHashMap<>();
|
|
28
|
+
private final Map<String, Integer> pendingCallbacks =
|
|
29
|
+
new ConcurrentHashMap<>();
|
|
30
|
+
|
|
31
|
+
public void setPusher(VeLivePusher pusher) { this.pusher = pusher; }
|
|
35
32
|
|
|
36
33
|
/**
|
|
37
34
|
* Add a view to the mixer
|
|
@@ -40,85 +37,81 @@ public class MixerManager {
|
|
|
40
37
|
* @return streamId for this view
|
|
41
38
|
*/
|
|
42
39
|
public int addView(String viewId, JSONObject viewInfo) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
return videoStreamId;
|
|
101
|
-
} catch (Exception e) {
|
|
102
|
-
return -1;
|
|
103
|
-
}
|
|
40
|
+
try {
|
|
41
|
+
if (pusher == null || pusher.getMixerManager() == null) {
|
|
42
|
+
return -1;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (viewIdToStreamId.containsKey(viewId)) {
|
|
46
|
+
return viewIdToStreamId.get(viewId);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
int videoStreamId = pusher.getMixerManager().addVideoStream();
|
|
50
|
+
VeLiveStreamMixDescription description = new VeLiveStreamMixDescription();
|
|
51
|
+
VeLiveMixVideoLayout layout = new VeLiveMixVideoLayout();
|
|
52
|
+
layout.x = (float)viewInfo.getDouble("x");
|
|
53
|
+
layout.y = (float)viewInfo.getDouble("y");
|
|
54
|
+
layout.width = (float)viewInfo.getDouble("width");
|
|
55
|
+
layout.height = (float)viewInfo.getDouble("height");
|
|
56
|
+
layout.alpha = (float)viewInfo.optDouble("alpha", 1.0);
|
|
57
|
+
layout.zOrder = viewInfo.optInt("zOrder", 0);
|
|
58
|
+
int renderModeValue = viewInfo.optInt("renderMode", 0);
|
|
59
|
+
VeLivePusherRenderMode[] renderModes = VeLivePusherRenderMode.values();
|
|
60
|
+
if (renderModeValue >= 0 && renderModeValue < renderModes.length) {
|
|
61
|
+
layout.renderMode = renderModes[renderModeValue];
|
|
62
|
+
} else {
|
|
63
|
+
layout.renderMode = VeLivePusherRenderMode.values()[0];
|
|
64
|
+
}
|
|
65
|
+
layout.streamId = videoStreamId;
|
|
66
|
+
description.mixVideoStreams.add(layout);
|
|
67
|
+
mixedViewLayout.put(viewId, layout);
|
|
68
|
+
viewIdToStreamId.put(viewId, videoStreamId);
|
|
69
|
+
pusher.getMixerManager().updateStreamMixDescription(description);
|
|
70
|
+
|
|
71
|
+
View view = cachedMixedViews.get(viewId);
|
|
72
|
+
if (view instanceof MixerView) {
|
|
73
|
+
MixerView mixerView = (MixerView)view;
|
|
74
|
+
setupCallbackForMixerView(mixerView, videoStreamId);
|
|
75
|
+
|
|
76
|
+
android.os.Handler mainHandler =
|
|
77
|
+
new android.os.Handler(android.os.Looper.getMainLooper());
|
|
78
|
+
mainHandler.postDelayed(new Runnable() {
|
|
79
|
+
@Override
|
|
80
|
+
public void run() {
|
|
81
|
+
try {
|
|
82
|
+
mixerView.performManualCapture();
|
|
83
|
+
} catch (Exception e) {
|
|
84
|
+
Log.w(TAG, "Failed to perform manual capture after addView", e);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}, 300);
|
|
88
|
+
} else {
|
|
89
|
+
pendingCallbacks.put(viewId, videoStreamId);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return videoStreamId;
|
|
93
|
+
} catch (Exception e) {
|
|
94
|
+
return -1;
|
|
95
|
+
}
|
|
104
96
|
}
|
|
105
|
-
|
|
97
|
+
|
|
106
98
|
/**
|
|
107
99
|
* Update view configuration
|
|
108
100
|
*/
|
|
109
101
|
public boolean updateView(String viewId, JSONObject viewInfo) {
|
|
110
102
|
try {
|
|
111
103
|
VeLiveMixVideoLayout layout = mixedViewLayout.get(viewId);
|
|
112
|
-
if(layout == null) {
|
|
104
|
+
if (layout == null) {
|
|
113
105
|
return false;
|
|
114
106
|
}
|
|
115
107
|
VeLiveStreamMixDescription description = new VeLiveStreamMixDescription();
|
|
116
|
-
layout.x = (float)
|
|
117
|
-
layout.y = (float)
|
|
118
|
-
layout.width = (float)
|
|
119
|
-
layout.height = (float)
|
|
108
|
+
layout.x = (float)viewInfo.getDouble("x");
|
|
109
|
+
layout.y = (float)viewInfo.getDouble("y");
|
|
110
|
+
layout.width = (float)viewInfo.getDouble("width");
|
|
111
|
+
layout.height = (float)viewInfo.getDouble("height");
|
|
112
|
+
layout.alpha = (float)viewInfo.optDouble("alpha", 1.0);
|
|
120
113
|
Integer streamId = viewIdToStreamId.get(viewId);
|
|
121
|
-
if(streamId != null) {
|
|
114
|
+
if (streamId != null) {
|
|
122
115
|
layout.streamId = streamId;
|
|
123
116
|
}
|
|
124
117
|
if (viewInfo.has("zOrder")) {
|
|
@@ -134,10 +127,22 @@ public class MixerManager {
|
|
|
134
127
|
mixedViewLayout.put(viewId, layout);
|
|
135
128
|
description.mixVideoStreams.add(layout);
|
|
136
129
|
pusher.getMixerManager().updateStreamMixDescription(description);
|
|
130
|
+
|
|
137
131
|
View view = cachedMixedViews.get(viewId);
|
|
138
132
|
if (view instanceof MixerView) {
|
|
139
|
-
MixerView mixerView = (MixerView)
|
|
140
|
-
|
|
133
|
+
MixerView mixerView = (MixerView)view;
|
|
134
|
+
android.os.Handler mainHandler =
|
|
135
|
+
new android.os.Handler(android.os.Looper.getMainLooper());
|
|
136
|
+
mainHandler.postDelayed(new Runnable() {
|
|
137
|
+
@Override
|
|
138
|
+
public void run() {
|
|
139
|
+
try {
|
|
140
|
+
mixerView.performManualCapture();
|
|
141
|
+
} catch (Exception e) {
|
|
142
|
+
Log.w(TAG, "Failed to perform manual capture after update", e);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}, 300);
|
|
141
146
|
}
|
|
142
147
|
return true;
|
|
143
148
|
} catch (Exception e) {
|
|
@@ -154,15 +159,15 @@ public class MixerManager {
|
|
|
154
159
|
if (layout == null) {
|
|
155
160
|
return false;
|
|
156
161
|
}
|
|
157
|
-
|
|
162
|
+
|
|
158
163
|
viewIdToStreamId.remove(viewId);
|
|
159
|
-
|
|
164
|
+
|
|
160
165
|
View view = cachedMixedViews.get(viewId);
|
|
161
166
|
if (view instanceof MixerView) {
|
|
162
|
-
MixerView mixerView = (MixerView)
|
|
167
|
+
MixerView mixerView = (MixerView)view;
|
|
163
168
|
mixerView.setBitmapCaptureCallback(null);
|
|
164
169
|
}
|
|
165
|
-
|
|
170
|
+
|
|
166
171
|
pusher.getMixerManager().removeVideoStream(layout.streamId);
|
|
167
172
|
return true;
|
|
168
173
|
|
|
@@ -177,7 +182,7 @@ public class MixerManager {
|
|
|
177
182
|
public void captureView(String viewId) {
|
|
178
183
|
View view = cachedMixedViews.get(viewId);
|
|
179
184
|
if (view instanceof MixerView) {
|
|
180
|
-
MixerView mixerView = (MixerView)
|
|
185
|
+
MixerView mixerView = (MixerView)view;
|
|
181
186
|
mixerView.performManualCapture();
|
|
182
187
|
}
|
|
183
188
|
}
|
|
@@ -192,28 +197,33 @@ public class MixerManager {
|
|
|
192
197
|
Integer streamId = instance.pendingCallbacks.remove(viewId);
|
|
193
198
|
if (streamId != null) {
|
|
194
199
|
setupCallbackForMixerView(mixerView, streamId);
|
|
195
|
-
|
|
196
|
-
android.os.Handler mainHandler =
|
|
200
|
+
|
|
201
|
+
android.os.Handler mainHandler =
|
|
202
|
+
new android.os.Handler(android.os.Looper.getMainLooper());
|
|
197
203
|
mainHandler.postDelayed(new Runnable() {
|
|
198
204
|
@Override
|
|
199
205
|
public void run() {
|
|
200
206
|
try {
|
|
201
|
-
VeLiveMixVideoLayout layout =
|
|
202
|
-
|
|
203
|
-
|
|
207
|
+
VeLiveMixVideoLayout layout =
|
|
208
|
+
instance.mixedViewLayout.get(viewId);
|
|
209
|
+
if (layout != null && instance.pusher != null &&
|
|
210
|
+
instance.pusher.getMixerManager() != null) {
|
|
211
|
+
VeLiveStreamMixDescription description =
|
|
212
|
+
new VeLiveStreamMixDescription();
|
|
204
213
|
description.mixVideoStreams.add(layout);
|
|
205
|
-
instance.pusher.getMixerManager().updateStreamMixDescription(
|
|
214
|
+
instance.pusher.getMixerManager().updateStreamMixDescription(
|
|
215
|
+
description);
|
|
206
216
|
}
|
|
207
217
|
mixerView.performManualCapture();
|
|
208
218
|
} catch (Exception e) {
|
|
209
|
-
|
|
219
|
+
Log.w(TAG, "Failed to perform operations in onViewReady", e);
|
|
210
220
|
}
|
|
211
221
|
}
|
|
212
|
-
},
|
|
222
|
+
}, 300);
|
|
213
223
|
}
|
|
214
224
|
}
|
|
215
225
|
} catch (Exception e) {
|
|
216
|
-
|
|
226
|
+
Log.w(TAG, "Error in onViewReady", e);
|
|
217
227
|
}
|
|
218
228
|
}
|
|
219
229
|
|
|
@@ -225,18 +235,18 @@ public class MixerManager {
|
|
|
225
235
|
if (bitmap == null || bitmap.isRecycled()) {
|
|
226
236
|
return;
|
|
227
237
|
}
|
|
228
|
-
|
|
238
|
+
|
|
229
239
|
if (pusher == null || pusher.getMixerManager() == null) {
|
|
230
240
|
return;
|
|
231
241
|
}
|
|
232
|
-
|
|
242
|
+
|
|
233
243
|
int width = bitmap.getWidth();
|
|
234
244
|
int height = bitmap.getHeight();
|
|
235
|
-
|
|
245
|
+
|
|
236
246
|
if (width <= 0 || height <= 0) {
|
|
237
247
|
return;
|
|
238
248
|
}
|
|
239
|
-
|
|
249
|
+
|
|
240
250
|
TextureMgr textureMgr = new TextureMgr(width, height);
|
|
241
251
|
textureMgr.dealWithTexture(bitmap, new TextureMgr.RenderListener() {
|
|
242
252
|
@Override
|
|
@@ -245,15 +255,22 @@ public class MixerManager {
|
|
|
245
255
|
if (texture <= 0) {
|
|
246
256
|
return;
|
|
247
257
|
}
|
|
248
|
-
|
|
258
|
+
|
|
249
259
|
long pts = System.currentTimeMillis() * 1000;
|
|
250
|
-
VeLiveVideoFrame videoFrame =
|
|
251
|
-
|
|
260
|
+
VeLiveVideoFrame videoFrame =
|
|
261
|
+
new VeLiveVideoFrame(width, height, pts, texture, false, null);
|
|
262
|
+
|
|
252
263
|
if (pusher != null && pusher.getMixerManager() != null) {
|
|
253
|
-
pusher.getMixerManager().sendCustomVideoFrame(videoFrame,
|
|
264
|
+
pusher.getMixerManager().sendCustomVideoFrame(videoFrame,
|
|
265
|
+
streamId);
|
|
254
266
|
}
|
|
255
267
|
} catch (Exception e) {
|
|
256
268
|
// Ignore
|
|
269
|
+
} finally {
|
|
270
|
+
if (bitmap != null && !bitmap.isRecycled()) {
|
|
271
|
+
bitmap.recycle();
|
|
272
|
+
}
|
|
273
|
+
textureMgr.cleanup();
|
|
257
274
|
}
|
|
258
275
|
}
|
|
259
276
|
});
|
|
@@ -261,16 +278,17 @@ public class MixerManager {
|
|
|
261
278
|
// Ignore
|
|
262
279
|
}
|
|
263
280
|
}
|
|
264
|
-
|
|
281
|
+
|
|
265
282
|
/**
|
|
266
283
|
* Static method to set up callback for MixerView
|
|
267
284
|
* Now with intelligent layout waiting logic
|
|
268
285
|
*/
|
|
269
|
-
private static void setupCallbackForMixerView(MixerView mixerView,
|
|
286
|
+
private static void setupCallbackForMixerView(MixerView mixerView,
|
|
287
|
+
int streamId) {
|
|
270
288
|
if (mixerView == null) {
|
|
271
289
|
return;
|
|
272
290
|
}
|
|
273
|
-
|
|
291
|
+
|
|
274
292
|
mixerView.setBitmapCaptureCallback(new BitmapCaptureCallback() {
|
|
275
293
|
@Override
|
|
276
294
|
public void onBitmapCaptured(Bitmap bitmap) {
|
|
@@ -284,13 +302,13 @@ public class MixerManager {
|
|
|
284
302
|
// Ignore
|
|
285
303
|
}
|
|
286
304
|
}
|
|
287
|
-
|
|
305
|
+
|
|
288
306
|
@Override
|
|
289
307
|
public void onCaptureError(String error) {
|
|
290
308
|
// Ignore
|
|
291
309
|
}
|
|
292
310
|
});
|
|
293
|
-
|
|
311
|
+
|
|
294
312
|
if (mixerView.getWidth() > 0 && mixerView.getHeight() > 0) {
|
|
295
313
|
try {
|
|
296
314
|
mixerView.performManualCapture();
|
|
@@ -298,32 +316,36 @@ public class MixerManager {
|
|
|
298
316
|
// Ignore
|
|
299
317
|
}
|
|
300
318
|
} else {
|
|
301
|
-
ViewTreeObserver.OnGlobalLayoutListener layoutListener =
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
319
|
+
ViewTreeObserver.OnGlobalLayoutListener layoutListener =
|
|
320
|
+
new ViewTreeObserver.OnGlobalLayoutListener() {
|
|
321
|
+
@Override
|
|
322
|
+
public void onGlobalLayout() {
|
|
323
|
+
try {
|
|
324
|
+
if (mixerView.getViewTreeObserver().isAlive()) {
|
|
325
|
+
if (mixerView.getWidth() > 0 && mixerView.getHeight() > 0) {
|
|
326
|
+
mixerView.getViewTreeObserver()
|
|
327
|
+
.removeOnGlobalLayoutListener(this);
|
|
328
|
+
mixerView.performManualCapture();
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
} catch (Exception e) {
|
|
332
|
+
// Ignore
|
|
309
333
|
}
|
|
310
334
|
}
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
};
|
|
316
|
-
|
|
335
|
+
};
|
|
336
|
+
|
|
317
337
|
try {
|
|
318
|
-
mixerView.getViewTreeObserver().addOnGlobalLayoutListener(
|
|
338
|
+
mixerView.getViewTreeObserver().addOnGlobalLayoutListener(
|
|
339
|
+
layoutListener);
|
|
319
340
|
} catch (Exception e) {
|
|
320
341
|
// Ignore
|
|
321
342
|
}
|
|
322
343
|
}
|
|
323
344
|
}
|
|
324
|
-
|
|
345
|
+
|
|
325
346
|
/**
|
|
326
|
-
* Static version of sendBitmapToMixer - finds the active MixerManager
|
|
347
|
+
* Static version of sendBitmapToMixer - finds the active MixerManager
|
|
348
|
+
* instance
|
|
327
349
|
*/
|
|
328
350
|
private static void sendBitmapToMixerStatic(int streamId, Bitmap bitmap) {
|
|
329
351
|
try {
|
|
@@ -335,7 +357,7 @@ public class MixerManager {
|
|
|
335
357
|
// Ignore
|
|
336
358
|
}
|
|
337
359
|
}
|
|
338
|
-
|
|
360
|
+
|
|
339
361
|
/**
|
|
340
362
|
* Find the active MixerManager instance
|
|
341
363
|
*/
|
|
@@ -346,44 +368,42 @@ public class MixerManager {
|
|
|
346
368
|
}
|
|
347
369
|
return null;
|
|
348
370
|
}
|
|
349
|
-
|
|
371
|
+
|
|
350
372
|
private static volatile MixerManager currentInstance;
|
|
351
|
-
|
|
373
|
+
|
|
352
374
|
public MixerManager() {
|
|
353
|
-
synchronized (MixerManager.class) {
|
|
354
|
-
currentInstance = this;
|
|
355
|
-
}
|
|
375
|
+
synchronized (MixerManager.class) { currentInstance = this; }
|
|
356
376
|
}
|
|
357
|
-
|
|
377
|
+
|
|
358
378
|
/**
|
|
359
|
-
*
|
|
379
|
+
* cleanup method to release resources
|
|
360
380
|
*/
|
|
361
381
|
public void cleanup() {
|
|
362
382
|
try {
|
|
363
383
|
for (String viewId : cachedMixedViews.keySet()) {
|
|
364
384
|
View view = cachedMixedViews.get(viewId);
|
|
365
385
|
if (view instanceof MixerView) {
|
|
366
|
-
MixerView mixerView = (MixerView)
|
|
386
|
+
MixerView mixerView = (MixerView)view;
|
|
367
387
|
mixerView.setBitmapCaptureCallback(null);
|
|
368
388
|
}
|
|
369
389
|
}
|
|
370
|
-
|
|
390
|
+
|
|
371
391
|
mixedViewLayout.clear();
|
|
372
392
|
viewIdToStreamId.clear();
|
|
373
393
|
pendingCallbacks.clear();
|
|
374
|
-
|
|
394
|
+
|
|
375
395
|
synchronized (MixerManager.class) {
|
|
376
396
|
if (currentInstance == this) {
|
|
377
397
|
currentInstance = null;
|
|
378
398
|
}
|
|
379
399
|
}
|
|
380
|
-
|
|
400
|
+
|
|
381
401
|
pusher = null;
|
|
382
402
|
} catch (Exception e) {
|
|
383
403
|
// Ignore
|
|
384
404
|
}
|
|
385
405
|
}
|
|
386
|
-
|
|
406
|
+
|
|
387
407
|
// Callback interface for bitmap capture
|
|
388
408
|
public interface BitmapCaptureCallback {
|
|
389
409
|
void onBitmapCaptured(Bitmap bitmap);
|
|
@@ -255,7 +255,8 @@ public class MixerView extends FrameLayout {
|
|
|
255
255
|
}
|
|
256
256
|
|
|
257
257
|
long currentTime = System.currentTimeMillis();
|
|
258
|
-
|
|
258
|
+
long minInterval = 33; // 30 FPS ~ 33ms per frame
|
|
259
|
+
if (currentTime - lastCaptureTime < minInterval) {
|
|
259
260
|
return;
|
|
260
261
|
}
|
|
261
262
|
lastCaptureTime = currentTime;
|
|
@@ -316,6 +317,7 @@ public class MixerView extends FrameLayout {
|
|
|
316
317
|
// Call callback first if set (for MixerManager)
|
|
317
318
|
if (bitmapCaptureCallback != null) {
|
|
318
319
|
try {
|
|
320
|
+
// only capture if the callback is set
|
|
319
321
|
bitmapCaptureCallback.onBitmapCaptured(bitmap);
|
|
320
322
|
} catch (Exception e) {
|
|
321
323
|
if (bitmapCaptureCallback != null) {
|
|
@@ -339,6 +341,12 @@ public class MixerView extends FrameLayout {
|
|
|
339
341
|
} catch (IllegalStateException e) {
|
|
340
342
|
// Ignore
|
|
341
343
|
}
|
|
344
|
+
|
|
345
|
+
// if no callback, recycle immediately to avoid accumulation
|
|
346
|
+
if (bitmap != null && !bitmap.isRecycled()) {
|
|
347
|
+
bitmap.recycle();
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
342
350
|
}
|
|
343
351
|
|
|
344
352
|
// Clean up old bitmap
|
|
@@ -137,14 +137,14 @@ public class TextureMgr {
|
|
|
137
137
|
GLThreadManager.getMainGlHandle().post(() -> {
|
|
138
138
|
if (texture > 0) {
|
|
139
139
|
Bitmap processedBitmap = null;
|
|
140
|
+
boolean needRecycle = false;
|
|
140
141
|
try {
|
|
141
142
|
if (bitmap == null || bitmap.isRecycled()) {
|
|
142
143
|
return;
|
|
143
144
|
}
|
|
144
|
-
|
|
145
145
|
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
|
|
146
146
|
processedBitmap = YuvHelper.rotateBitmap(bitmap, 0, false, true);
|
|
147
|
-
|
|
147
|
+
needRecycle = (processedBitmap != null && processedBitmap != bitmap);
|
|
148
148
|
if (processedBitmap != null && !processedBitmap.isRecycled()) {
|
|
149
149
|
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, processedBitmap, 0);
|
|
150
150
|
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
|
|
@@ -158,7 +158,7 @@ public class TextureMgr {
|
|
|
158
158
|
} catch (Exception e) {
|
|
159
159
|
// Ignore
|
|
160
160
|
} finally {
|
|
161
|
-
if (
|
|
161
|
+
if (needRecycle && processedBitmap != null && !processedBitmap.isRecycled()) {
|
|
162
162
|
processedBitmap.recycle();
|
|
163
163
|
}
|
|
164
164
|
}
|
|
@@ -12,13 +12,26 @@ import android.renderscript.Type;
|
|
|
12
12
|
import java.nio.ByteBuffer;
|
|
13
13
|
|
|
14
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
|
+
}
|
|
15
28
|
public static class NV21ToBitmap {
|
|
16
29
|
private RenderScript rs;
|
|
17
30
|
private ScriptIntrinsicYuvToRGB yuvToRgbIntrinsic;
|
|
18
31
|
private Type.Builder yuvType, rgbaType;
|
|
19
32
|
|
|
20
33
|
public NV21ToBitmap(Context context) {
|
|
21
|
-
rs =
|
|
34
|
+
rs = YuvHelper.getGlobalRS(context);
|
|
22
35
|
yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs));
|
|
23
36
|
yuvType = new Type.Builder(rs, Element.U8(rs));
|
|
24
37
|
rgbaType = new Type.Builder(rs, Element.RGBA_8888(rs));
|
|
@@ -30,10 +43,8 @@ public class YuvHelper {
|
|
|
30
43
|
yuvToRgbIntrinsic.destroy();
|
|
31
44
|
yuvToRgbIntrinsic = null;
|
|
32
45
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
rs = null;
|
|
36
|
-
}
|
|
46
|
+
// 不销毁全局 rs
|
|
47
|
+
// rs = null;
|
|
37
48
|
} catch (Exception e) {
|
|
38
49
|
// Ignore
|
|
39
50
|
}
|