@byteplus/react-native-live-push 1.1.3-rc.3 → 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 +156 -141
- package/ios/VeLiveMixerHelper.m +31 -2
- 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,12 +255,14 @@ 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
|
|
@@ -266,16 +278,17 @@ public class MixerManager {
|
|
|
266
278
|
// Ignore
|
|
267
279
|
}
|
|
268
280
|
}
|
|
269
|
-
|
|
281
|
+
|
|
270
282
|
/**
|
|
271
283
|
* Static method to set up callback for MixerView
|
|
272
284
|
* Now with intelligent layout waiting logic
|
|
273
285
|
*/
|
|
274
|
-
private static void setupCallbackForMixerView(MixerView mixerView,
|
|
286
|
+
private static void setupCallbackForMixerView(MixerView mixerView,
|
|
287
|
+
int streamId) {
|
|
275
288
|
if (mixerView == null) {
|
|
276
289
|
return;
|
|
277
290
|
}
|
|
278
|
-
|
|
291
|
+
|
|
279
292
|
mixerView.setBitmapCaptureCallback(new BitmapCaptureCallback() {
|
|
280
293
|
@Override
|
|
281
294
|
public void onBitmapCaptured(Bitmap bitmap) {
|
|
@@ -289,13 +302,13 @@ public class MixerManager {
|
|
|
289
302
|
// Ignore
|
|
290
303
|
}
|
|
291
304
|
}
|
|
292
|
-
|
|
305
|
+
|
|
293
306
|
@Override
|
|
294
307
|
public void onCaptureError(String error) {
|
|
295
308
|
// Ignore
|
|
296
309
|
}
|
|
297
310
|
});
|
|
298
|
-
|
|
311
|
+
|
|
299
312
|
if (mixerView.getWidth() > 0 && mixerView.getHeight() > 0) {
|
|
300
313
|
try {
|
|
301
314
|
mixerView.performManualCapture();
|
|
@@ -303,32 +316,36 @@ public class MixerManager {
|
|
|
303
316
|
// Ignore
|
|
304
317
|
}
|
|
305
318
|
} else {
|
|
306
|
-
ViewTreeObserver.OnGlobalLayoutListener layoutListener =
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
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
|
|
314
333
|
}
|
|
315
334
|
}
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
};
|
|
321
|
-
|
|
335
|
+
};
|
|
336
|
+
|
|
322
337
|
try {
|
|
323
|
-
mixerView.getViewTreeObserver().addOnGlobalLayoutListener(
|
|
338
|
+
mixerView.getViewTreeObserver().addOnGlobalLayoutListener(
|
|
339
|
+
layoutListener);
|
|
324
340
|
} catch (Exception e) {
|
|
325
341
|
// Ignore
|
|
326
342
|
}
|
|
327
343
|
}
|
|
328
344
|
}
|
|
329
|
-
|
|
345
|
+
|
|
330
346
|
/**
|
|
331
|
-
* Static version of sendBitmapToMixer - finds the active MixerManager
|
|
347
|
+
* Static version of sendBitmapToMixer - finds the active MixerManager
|
|
348
|
+
* instance
|
|
332
349
|
*/
|
|
333
350
|
private static void sendBitmapToMixerStatic(int streamId, Bitmap bitmap) {
|
|
334
351
|
try {
|
|
@@ -340,7 +357,7 @@ public class MixerManager {
|
|
|
340
357
|
// Ignore
|
|
341
358
|
}
|
|
342
359
|
}
|
|
343
|
-
|
|
360
|
+
|
|
344
361
|
/**
|
|
345
362
|
* Find the active MixerManager instance
|
|
346
363
|
*/
|
|
@@ -351,44 +368,42 @@ public class MixerManager {
|
|
|
351
368
|
}
|
|
352
369
|
return null;
|
|
353
370
|
}
|
|
354
|
-
|
|
371
|
+
|
|
355
372
|
private static volatile MixerManager currentInstance;
|
|
356
|
-
|
|
373
|
+
|
|
357
374
|
public MixerManager() {
|
|
358
|
-
synchronized (MixerManager.class) {
|
|
359
|
-
currentInstance = this;
|
|
360
|
-
}
|
|
375
|
+
synchronized (MixerManager.class) { currentInstance = this; }
|
|
361
376
|
}
|
|
362
|
-
|
|
377
|
+
|
|
363
378
|
/**
|
|
364
|
-
*
|
|
379
|
+
* cleanup method to release resources
|
|
365
380
|
*/
|
|
366
381
|
public void cleanup() {
|
|
367
382
|
try {
|
|
368
383
|
for (String viewId : cachedMixedViews.keySet()) {
|
|
369
384
|
View view = cachedMixedViews.get(viewId);
|
|
370
385
|
if (view instanceof MixerView) {
|
|
371
|
-
MixerView mixerView = (MixerView)
|
|
386
|
+
MixerView mixerView = (MixerView)view;
|
|
372
387
|
mixerView.setBitmapCaptureCallback(null);
|
|
373
388
|
}
|
|
374
389
|
}
|
|
375
|
-
|
|
390
|
+
|
|
376
391
|
mixedViewLayout.clear();
|
|
377
392
|
viewIdToStreamId.clear();
|
|
378
393
|
pendingCallbacks.clear();
|
|
379
|
-
|
|
394
|
+
|
|
380
395
|
synchronized (MixerManager.class) {
|
|
381
396
|
if (currentInstance == this) {
|
|
382
397
|
currentInstance = null;
|
|
383
398
|
}
|
|
384
399
|
}
|
|
385
|
-
|
|
400
|
+
|
|
386
401
|
pusher = null;
|
|
387
402
|
} catch (Exception e) {
|
|
388
403
|
// Ignore
|
|
389
404
|
}
|
|
390
405
|
}
|
|
391
|
-
|
|
406
|
+
|
|
392
407
|
// Callback interface for bitmap capture
|
|
393
408
|
public interface BitmapCaptureCallback {
|
|
394
409
|
void onBitmapCaptured(Bitmap bitmap);
|
package/ios/VeLiveMixerHelper.m
CHANGED
|
@@ -150,6 +150,7 @@ static VeLiveMixerHelper *currentInstance = nil; // 强引用,防止被ARC释
|
|
|
150
150
|
@"y" : viewInfo[@"y"] ?: @(0),
|
|
151
151
|
@"width" : viewInfo[@"width"] ?: @(0),
|
|
152
152
|
@"height" : viewInfo[@"height"] ?: @(0),
|
|
153
|
+
@"alpha" : viewInfo[@"alpha"] ?: @(1.0),
|
|
153
154
|
@"zOrder" : viewInfo[@"zOrder"] ?: @(1),
|
|
154
155
|
@"renderMode" : viewInfo[@"renderMode"] ?: @(0),
|
|
155
156
|
@"streamId" : @(videoStreamId)
|
|
@@ -164,6 +165,7 @@ static VeLiveMixerHelper *currentInstance = nil; // 强引用,防止被ARC释
|
|
|
164
165
|
videoLayout.width = [viewInfo[@"width"] floatValue];
|
|
165
166
|
videoLayout.height = [viewInfo[@"height"] floatValue];
|
|
166
167
|
videoLayout.zOrder = [viewInfo[@"zOrder"] intValue];
|
|
168
|
+
videoLayout.alpha = [viewInfo[@"alpha"] floatValue] ?: 1.0;
|
|
167
169
|
videoLayout.renderMode = [viewInfo[@"renderMode"] intValue];
|
|
168
170
|
description.mixVideoStreams = @[ videoLayout ];
|
|
169
171
|
[self.pusher.getMixerManager updateStreamMixDescription:description];
|
|
@@ -173,6 +175,19 @@ static VeLiveMixerHelper *currentInstance = nil; // 强引用,防止被ARC释
|
|
|
173
175
|
|
|
174
176
|
if ([view isKindOfClass:[VeLiveMixerUIView class]]) {
|
|
175
177
|
[VeLiveMixerHelper setupCallbackForMixerView:view streamId:videoStreamId];
|
|
178
|
+
|
|
179
|
+
// 延迟执行捕获,确保视图布局完成
|
|
180
|
+
dispatch_after(
|
|
181
|
+
dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)),
|
|
182
|
+
dispatch_get_main_queue(), ^{
|
|
183
|
+
@try {
|
|
184
|
+
if (view && view.bitmapCaptureCallback) {
|
|
185
|
+
[view performCaptureWithTrigger:@"addView"];
|
|
186
|
+
}
|
|
187
|
+
} @catch (NSException *exception) {
|
|
188
|
+
// Ignore
|
|
189
|
+
}
|
|
190
|
+
});
|
|
176
191
|
} else {
|
|
177
192
|
[self.pendingCallbacks setObject:@(videoStreamId) forKey:viewId];
|
|
178
193
|
}
|
|
@@ -202,6 +217,8 @@ static VeLiveMixerHelper *currentInstance = nil; // 强引用,防止被ARC释
|
|
|
202
217
|
forKey:@"height"];
|
|
203
218
|
[updatedLayout setObject:(viewInfo[@"zOrder"] ?: layout[@"zOrder"])
|
|
204
219
|
forKey:@"zOrder"];
|
|
220
|
+
[updatedLayout setObject:(viewInfo[@"alpha"] ?: layout[@"alpha"])
|
|
221
|
+
forKey:@"alpha"];
|
|
205
222
|
[updatedLayout setObject:(viewInfo[@"renderMode"] ?: layout[@"renderMode"])
|
|
206
223
|
forKey:@"renderMode"];
|
|
207
224
|
|
|
@@ -213,6 +230,7 @@ static VeLiveMixerHelper *currentInstance = nil; // 强引用,防止被ARC释
|
|
|
213
230
|
videoLayout.y = [updatedLayout[@"y"] floatValue];
|
|
214
231
|
videoLayout.width = [updatedLayout[@"width"] floatValue];
|
|
215
232
|
videoLayout.height = [updatedLayout[@"height"] floatValue];
|
|
233
|
+
videoLayout.alpha = [updatedLayout[@"alpha"] floatValue];
|
|
216
234
|
videoLayout.zOrder = [updatedLayout[@"zOrder"] intValue];
|
|
217
235
|
videoLayout.renderMode = [updatedLayout[@"renderMode"] intValue];
|
|
218
236
|
description.mixVideoStreams = @[ videoLayout ];
|
|
@@ -220,9 +238,20 @@ static VeLiveMixerHelper *currentInstance = nil; // 强引用,防止被ARC释
|
|
|
220
238
|
|
|
221
239
|
[self.mixedViewLayout setObject:updatedLayout forKey:viewId];
|
|
222
240
|
|
|
241
|
+
// 延迟执行捕获,确保属性更新完成
|
|
223
242
|
VeLiveMixerUIView *mixerView =
|
|
224
243
|
[[VeLiveMixerHelper cachedMixedViews] objectForKey:viewId];
|
|
225
|
-
[mixerView
|
|
244
|
+
if ([mixerView isKindOfClass:[VeLiveMixerUIView class]]) {
|
|
245
|
+
dispatch_after(
|
|
246
|
+
dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)),
|
|
247
|
+
dispatch_get_main_queue(), ^{
|
|
248
|
+
@try {
|
|
249
|
+
[mixerView performCaptureWithTrigger:@"update"];
|
|
250
|
+
} @catch (NSException *exception) {
|
|
251
|
+
// Ignore
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
}
|
|
226
255
|
|
|
227
256
|
return YES;
|
|
228
257
|
} @catch (NSException *exception) {
|
|
@@ -293,7 +322,7 @@ static VeLiveMixerHelper *currentInstance = nil; // 强引用,防止被ARC释
|
|
|
293
322
|
mixerView.bitmapCaptureCallback = callback;
|
|
294
323
|
|
|
295
324
|
dispatch_after(
|
|
296
|
-
dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.
|
|
325
|
+
dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)),
|
|
297
326
|
dispatch_get_main_queue(), ^{
|
|
298
327
|
@try {
|
|
299
328
|
if (mixerView && mixerView.bitmapCaptureCallback) {
|