@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.
- package/android/build.gradle +2 -2
- package/android/src/main/java/com/volcengine/velive/rn/push/ClassHelper.java +9 -0
- package/android/src/main/java/com/volcengine/velive/rn/push/NativeVariableManager.java +5 -8
- package/android/src/main/java/com/volcengine/velive/rn/push/VeLivePushModule.java +14 -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 +410 -0
- package/android/src/main/java/com/volcengine/velive/rn/push/mixer/MixerView.java +328 -0
- package/android/src/main/java/com/volcengine/velive/rn/push/mixer/MixerViewManager.java +43 -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 +165 -0
- package/ios/VeLiveMixerHelper.h +49 -0
- package/ios/VeLiveMixerHelper.m +646 -0
- package/ios/VeLiveMixerView.h +62 -0
- package/ios/VeLiveMixerView.m +547 -0
- package/ios/VeLiveMixerViewManager.m +56 -0
- package/lib/commonjs/index.js +22697 -20359
- package/lib/commonjs/typescript/android/index.d.ts +44 -0
- package/lib/commonjs/typescript/codegen/android/api.d.ts +1068 -0
- package/lib/commonjs/typescript/codegen/android/callback.d.ts +333 -0
- package/lib/commonjs/typescript/codegen/android/errorcode.d.ts +92 -0
- package/lib/commonjs/typescript/codegen/android/index.d.ts +5 -0
- package/lib/commonjs/typescript/codegen/android/keytype.d.ts +1693 -0
- package/lib/commonjs/typescript/codegen/android/types.d.ts +33 -0
- package/lib/commonjs/typescript/codegen/ios/api.d.ts +1125 -0
- package/lib/commonjs/typescript/codegen/ios/callback.d.ts +242 -0
- package/lib/commonjs/typescript/codegen/ios/errorcode.d.ts +154 -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 +1154 -0
- package/lib/commonjs/typescript/codegen/ios/types.d.ts +46 -0
- package/lib/commonjs/typescript/codegen/pack/api.d.ts +1470 -0
- package/lib/commonjs/typescript/codegen/pack/callback.d.ts +446 -0
- package/lib/commonjs/typescript/codegen/pack/errorcode.d.ts +109 -0
- package/lib/commonjs/typescript/codegen/pack/index.d.ts +5 -0
- package/lib/commonjs/typescript/codegen/pack/keytype.d.ts +2248 -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 +18 -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 +13 -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 +44 -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 +22694 -20360
- package/lib/module/typescript/android/index.d.ts +44 -0
- package/lib/module/typescript/codegen/android/api.d.ts +1068 -0
- package/lib/module/typescript/codegen/android/callback.d.ts +333 -0
- package/lib/module/typescript/codegen/android/errorcode.d.ts +92 -0
- package/lib/module/typescript/codegen/android/index.d.ts +5 -0
- package/lib/module/typescript/codegen/android/keytype.d.ts +1693 -0
- package/lib/module/typescript/codegen/android/types.d.ts +33 -0
- package/lib/module/typescript/codegen/ios/api.d.ts +1125 -0
- package/lib/module/typescript/codegen/ios/callback.d.ts +242 -0
- package/lib/module/typescript/codegen/ios/errorcode.d.ts +154 -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 +1154 -0
- package/lib/module/typescript/codegen/ios/types.d.ts +46 -0
- package/lib/module/typescript/codegen/pack/api.d.ts +1470 -0
- package/lib/module/typescript/codegen/pack/callback.d.ts +446 -0
- package/lib/module/typescript/codegen/pack/errorcode.d.ts +109 -0
- package/lib/module/typescript/codegen/pack/index.d.ts +5 -0
- package/lib/module/typescript/codegen/pack/keytype.d.ts +2248 -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 +18 -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 +13 -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 +44 -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/android/index.d.ts +0 -3
- package/lib/typescript/codegen/android/api.d.ts +194 -762
- package/lib/typescript/codegen/android/callback.d.ts +85 -48
- package/lib/typescript/codegen/android/errorcode.d.ts +30 -0
- package/lib/typescript/codegen/android/keytype.d.ts +514 -122
- package/lib/typescript/codegen/ios/api.d.ts +380 -351
- package/lib/typescript/codegen/ios/callback.d.ts +33 -6
- package/lib/typescript/codegen/ios/errorcode.d.ts +52 -2
- package/lib/typescript/codegen/ios/keytype.d.ts +313 -35
- package/lib/typescript/codegen/pack/api.d.ts +302 -821
- package/lib/typescript/codegen/pack/callback.d.ts +54 -49
- package/lib/typescript/codegen/pack/errorcode.d.ts +38 -5
- package/lib/typescript/codegen/pack/keytype.d.ts +672 -228
- package/lib/typescript/core/api.d.ts +18 -2
- package/lib/typescript/core/keytype.d.ts +15 -0
- package/lib/typescript/core/mixer.d.ts +26 -0
- package/lib/typescript/core/pusher.d.ts +0 -3
- 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 +44 -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
- package/react-native-velive-push.podspec +3 -3
- package/android/src/main/java/com/volcengine/velive/rn/push/ScreenCaptureHelper.java +0 -73
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
//
|
|
2
|
+
// VeLiveMixerHelper.h
|
|
3
|
+
// react-native-live-push
|
|
4
|
+
//
|
|
5
|
+
// Created by ByteDance on 2024/12/09.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#import "VeLiveMixerView.h"
|
|
9
|
+
#import <CoreVideo/CoreVideo.h>
|
|
10
|
+
#import <Foundation/Foundation.h>
|
|
11
|
+
|
|
12
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
13
|
+
|
|
14
|
+
// Forward declaration
|
|
15
|
+
@class VeLivePusher;
|
|
16
|
+
|
|
17
|
+
// Mixer helper class - fully aligned with Android MixerManager.java
|
|
18
|
+
@interface VeLiveMixerHelper : NSObject <VeLiveBitmapCaptureCallback>
|
|
19
|
+
|
|
20
|
+
// Aligned with Android's static cachedMixedViews
|
|
21
|
+
@property(class, nonatomic, strong)
|
|
22
|
+
NSMutableDictionary<NSString *, VeLiveMixerUIView *> *cachedMixedViews;
|
|
23
|
+
|
|
24
|
+
@property(nonatomic, weak) VeLivePusher *pusher;
|
|
25
|
+
|
|
26
|
+
- (instancetype)initWithPusher:(VeLivePusher *)pusher;
|
|
27
|
+
|
|
28
|
+
// Public methods - fully aligned with Android MixerManager's public interface
|
|
29
|
+
- (void)setPusher:(VeLivePusher *)pusher;
|
|
30
|
+
- (int)addView:(NSString *)viewId config:(NSDictionary *)viewInfo;
|
|
31
|
+
- (BOOL)updateView:(NSString *)viewId config:(NSDictionary *)viewInfo;
|
|
32
|
+
- (BOOL)removeView:(NSString *)viewId;
|
|
33
|
+
- (void)captureView:(NSString *)viewId;
|
|
34
|
+
|
|
35
|
+
// Static methods - for sending captured content to mixer
|
|
36
|
+
+ (void)setupCallbackForMixerView:(VeLiveMixerUIView *)mixerView
|
|
37
|
+
streamId:(int)streamId;
|
|
38
|
+
+ (void)sendBitmapToMixerStatic:(int)streamId bitmap:(UIImage *)bitmap;
|
|
39
|
+
+ (void)sendPixelBufferToMixerStatic:(int)streamId
|
|
40
|
+
pixelBuffer:(CVPixelBufferRef)pixelBuffer;
|
|
41
|
+
+ (VeLiveMixerHelper *)findActiveMixerManager;
|
|
42
|
+
+ (void)onViewReady:(NSString *)viewId mixerView:(VeLiveMixerUIView *)mixerView;
|
|
43
|
+
|
|
44
|
+
// Resource cleanup
|
|
45
|
+
- (void)cleanup;
|
|
46
|
+
|
|
47
|
+
@end
|
|
48
|
+
|
|
49
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,646 @@
|
|
|
1
|
+
//
|
|
2
|
+
// VeLiveMixerHelper.m
|
|
3
|
+
// react-native-live-push
|
|
4
|
+
//
|
|
5
|
+
// Created by ByteDance on 2024/12/09.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#import "VeLiveMixerHelper.h"
|
|
9
|
+
#import <TTSDKFramework/VeLivePusher.h>
|
|
10
|
+
#import <UIKit/UIKit.h>
|
|
11
|
+
#import <mach/mach.h>
|
|
12
|
+
#import <mach/task_info.h>
|
|
13
|
+
#include <objc/NSObjCRuntime.h>
|
|
14
|
+
|
|
15
|
+
static NSString *TAG = @"VeLiveMixerHelper";
|
|
16
|
+
|
|
17
|
+
#pragma mark - Forward Declaration
|
|
18
|
+
|
|
19
|
+
@class VeLiveMixerBitmapCallback;
|
|
20
|
+
|
|
21
|
+
#pragma mark - VeLiveMixerHelper Implementation
|
|
22
|
+
|
|
23
|
+
@interface VeLiveMixerHelper ()
|
|
24
|
+
|
|
25
|
+
@property(nonatomic, strong)
|
|
26
|
+
NSMutableDictionary<NSString *, NSDictionary *> *mixedViewLayout;
|
|
27
|
+
@property(nonatomic, strong)
|
|
28
|
+
NSMutableDictionary<NSString *, NSNumber *> *viewIdToStreamId;
|
|
29
|
+
@property(nonatomic, strong)
|
|
30
|
+
NSMutableDictionary<NSString *, NSNumber *> *pendingCallbacks;
|
|
31
|
+
@property(nonatomic, strong)
|
|
32
|
+
NSMutableDictionary<NSString *, VeLiveMixerBitmapCallback *> *callbacks;
|
|
33
|
+
@property(nonatomic, strong) NSTimer *memoryMonitorTimer;
|
|
34
|
+
|
|
35
|
+
@end
|
|
36
|
+
|
|
37
|
+
#pragma mark - VeLiveMixerBitmapCallback Declaration
|
|
38
|
+
|
|
39
|
+
@interface VeLiveMixerBitmapCallback : NSObject <VeLiveBitmapCaptureCallback>
|
|
40
|
+
@property(nonatomic, assign) int streamId;
|
|
41
|
+
- (instancetype)initWithStreamId:(int)streamId;
|
|
42
|
+
@end
|
|
43
|
+
|
|
44
|
+
@implementation VeLiveMixerHelper
|
|
45
|
+
|
|
46
|
+
// Aligned with Android's static cachedMixedViews
|
|
47
|
+
static NSMutableDictionary<NSString *, VeLiveMixerUIView *> *_cachedMixedViews =
|
|
48
|
+
nil;
|
|
49
|
+
static VeLiveMixerHelper *currentInstance =
|
|
50
|
+
nil; // Strong reference to prevent ARC deallocation
|
|
51
|
+
|
|
52
|
+
+ (NSMutableDictionary<NSString *, VeLiveMixerUIView *> *)cachedMixedViews {
|
|
53
|
+
if (!_cachedMixedViews) {
|
|
54
|
+
_cachedMixedViews = [[NSMutableDictionary alloc] init];
|
|
55
|
+
}
|
|
56
|
+
return _cachedMixedViews;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
+ (void)setCachedMixedViews:
|
|
60
|
+
(NSMutableDictionary<NSString *, VeLiveMixerUIView *> *)cachedMixedViews {
|
|
61
|
+
_cachedMixedViews = cachedMixedViews;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
- (instancetype)init {
|
|
65
|
+
self = [super init];
|
|
66
|
+
if (self) {
|
|
67
|
+
[self commonInit];
|
|
68
|
+
}
|
|
69
|
+
return self;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
- (instancetype)initWithPusher:(VeLivePusher *)pusher {
|
|
73
|
+
self = [super init];
|
|
74
|
+
if (self) {
|
|
75
|
+
_pusher = pusher;
|
|
76
|
+
[self commonInit];
|
|
77
|
+
[self startMemoryMonitoring];
|
|
78
|
+
}
|
|
79
|
+
return self;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
- (void)commonInit {
|
|
83
|
+
_mixedViewLayout = [[NSMutableDictionary alloc] init];
|
|
84
|
+
_viewIdToStreamId = [[NSMutableDictionary alloc] init];
|
|
85
|
+
_pendingCallbacks = [[NSMutableDictionary alloc] init];
|
|
86
|
+
_callbacks = [[NSMutableDictionary alloc] init];
|
|
87
|
+
|
|
88
|
+
currentInstance = self;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
#pragma mark - Lazy Loading Properties
|
|
92
|
+
|
|
93
|
+
- (NSMutableDictionary *)mixedViewLayout {
|
|
94
|
+
if (!_mixedViewLayout) {
|
|
95
|
+
_mixedViewLayout = [[NSMutableDictionary alloc] init];
|
|
96
|
+
}
|
|
97
|
+
return _mixedViewLayout;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
- (NSMutableDictionary *)viewIdToStreamId {
|
|
101
|
+
if (!_viewIdToStreamId) {
|
|
102
|
+
_viewIdToStreamId = [[NSMutableDictionary alloc] init];
|
|
103
|
+
}
|
|
104
|
+
return _viewIdToStreamId;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
- (NSMutableDictionary *)pendingCallbacks {
|
|
108
|
+
if (!_pendingCallbacks) {
|
|
109
|
+
_pendingCallbacks = [[NSMutableDictionary alloc] init];
|
|
110
|
+
}
|
|
111
|
+
return _pendingCallbacks;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
- (NSMutableDictionary *)callbacks {
|
|
115
|
+
if (!_callbacks) {
|
|
116
|
+
_callbacks = [[NSMutableDictionary alloc] init];
|
|
117
|
+
}
|
|
118
|
+
return _callbacks;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
#pragma mark - Public Methods
|
|
122
|
+
|
|
123
|
+
- (void)setPusher:(VeLivePusher *)pusher {
|
|
124
|
+
_pusher = pusher;
|
|
125
|
+
|
|
126
|
+
if (currentInstance != self) {
|
|
127
|
+
currentInstance = self;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
- (int)addView:(NSString *)viewId config:(NSDictionary *)viewInfo {
|
|
132
|
+
@try {
|
|
133
|
+
if (!self.pusher) {
|
|
134
|
+
return -1;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
VeLiveMixerUIView *view = [VeLiveMixerHelper cachedMixedViews][viewId];
|
|
138
|
+
if (![view isKindOfClass:[VeLiveMixerUIView class]]) {
|
|
139
|
+
// View not ready, store pending callback
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
NSNumber *existingStreamId = [self.viewIdToStreamId objectForKey:viewId];
|
|
143
|
+
if (existingStreamId != nil) {
|
|
144
|
+
return [existingStreamId intValue];
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
int videoStreamId = [[self.pusher getMixerManager] addVideoStream];
|
|
148
|
+
|
|
149
|
+
NSDictionary *layout = @{
|
|
150
|
+
@"x" : viewInfo[@"x"] ?: @(0),
|
|
151
|
+
@"y" : viewInfo[@"y"] ?: @(0),
|
|
152
|
+
@"width" : viewInfo[@"width"] ?: @(0),
|
|
153
|
+
@"height" : viewInfo[@"height"] ?: @(0),
|
|
154
|
+
@"alpha" : viewInfo[@"alpha"] ?: @(1.0),
|
|
155
|
+
@"zOrder" : viewInfo[@"zOrder"] ?: @(1),
|
|
156
|
+
@"renderMode" : viewInfo[@"renderMode"] ?: @(0),
|
|
157
|
+
@"streamId" : @(videoStreamId)
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
VeLiveStreamMixDescription *description =
|
|
161
|
+
[[VeLiveStreamMixDescription alloc] init];
|
|
162
|
+
VeLiveMixVideoLayout *videoLayout = [[VeLiveMixVideoLayout alloc] init];
|
|
163
|
+
videoLayout.streamId = videoStreamId;
|
|
164
|
+
videoLayout.x = [viewInfo[@"x"] floatValue];
|
|
165
|
+
videoLayout.y = [viewInfo[@"y"] floatValue];
|
|
166
|
+
videoLayout.width = [viewInfo[@"width"] floatValue];
|
|
167
|
+
videoLayout.height = [viewInfo[@"height"] floatValue];
|
|
168
|
+
videoLayout.zOrder = [viewInfo[@"zOrder"] intValue];
|
|
169
|
+
videoLayout.alpha = [viewInfo[@"alpha"] floatValue] ?: 1.0;
|
|
170
|
+
videoLayout.renderMode = [viewInfo[@"renderMode"] intValue];
|
|
171
|
+
description.mixVideoStreams = @[ videoLayout ];
|
|
172
|
+
[self.pusher.getMixerManager updateStreamMixDescription:description];
|
|
173
|
+
|
|
174
|
+
[self.mixedViewLayout setObject:layout forKey:viewId];
|
|
175
|
+
[self.viewIdToStreamId setObject:@(videoStreamId) forKey:viewId];
|
|
176
|
+
|
|
177
|
+
if ([view isKindOfClass:[VeLiveMixerUIView class]]) {
|
|
178
|
+
[VeLiveMixerHelper setupCallbackForMixerView:view streamId:videoStreamId];
|
|
179
|
+
|
|
180
|
+
// Delayed capture execution to ensure view layout completion
|
|
181
|
+
dispatch_after(
|
|
182
|
+
dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)),
|
|
183
|
+
dispatch_get_main_queue(), ^{
|
|
184
|
+
@try {
|
|
185
|
+
if (view && view.bitmapCaptureCallback) {
|
|
186
|
+
[view performCaptureWithTrigger:@"addView"];
|
|
187
|
+
}
|
|
188
|
+
} @catch (NSException *exception) {
|
|
189
|
+
// Ignore
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
} else {
|
|
193
|
+
[self.pendingCallbacks setObject:@(videoStreamId) forKey:viewId];
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return videoStreamId;
|
|
197
|
+
} @catch (NSException *exception) {
|
|
198
|
+
return -1;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
- (BOOL)updateView:(NSString *)viewId config:(NSDictionary *)viewInfo {
|
|
203
|
+
@try {
|
|
204
|
+
NSDictionary *layout = [self.mixedViewLayout objectForKey:viewId];
|
|
205
|
+
if (!layout) {
|
|
206
|
+
return NO;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
NSNumber *streamIdNumber = [self.viewIdToStreamId objectForKey:viewId];
|
|
210
|
+
int videoStreamId = [streamIdNumber intValue];
|
|
211
|
+
|
|
212
|
+
NSMutableDictionary *updatedLayout = [layout mutableCopy];
|
|
213
|
+
[updatedLayout setObject:(viewInfo[@"x"] ?: layout[@"x"]) forKey:@"x"];
|
|
214
|
+
[updatedLayout setObject:(viewInfo[@"y"] ?: layout[@"y"]) forKey:@"y"];
|
|
215
|
+
[updatedLayout setObject:(viewInfo[@"width"] ?: layout[@"width"])
|
|
216
|
+
forKey:@"width"];
|
|
217
|
+
[updatedLayout setObject:(viewInfo[@"height"] ?: layout[@"height"])
|
|
218
|
+
forKey:@"height"];
|
|
219
|
+
[updatedLayout setObject:(viewInfo[@"zOrder"] ?: layout[@"zOrder"])
|
|
220
|
+
forKey:@"zOrder"];
|
|
221
|
+
[updatedLayout setObject:(viewInfo[@"alpha"] ?: layout[@"alpha"])
|
|
222
|
+
forKey:@"alpha"];
|
|
223
|
+
[updatedLayout setObject:(viewInfo[@"renderMode"] ?: layout[@"renderMode"])
|
|
224
|
+
forKey:@"renderMode"];
|
|
225
|
+
|
|
226
|
+
VeLiveStreamMixDescription *description =
|
|
227
|
+
[[VeLiveStreamMixDescription alloc] init];
|
|
228
|
+
VeLiveMixVideoLayout *videoLayout = [[VeLiveMixVideoLayout alloc] init];
|
|
229
|
+
videoLayout.streamId = videoStreamId;
|
|
230
|
+
videoLayout.x = [updatedLayout[@"x"] floatValue];
|
|
231
|
+
videoLayout.y = [updatedLayout[@"y"] floatValue];
|
|
232
|
+
videoLayout.width = [updatedLayout[@"width"] floatValue];
|
|
233
|
+
videoLayout.height = [updatedLayout[@"height"] floatValue];
|
|
234
|
+
videoLayout.alpha = [updatedLayout[@"alpha"] floatValue];
|
|
235
|
+
videoLayout.zOrder = [updatedLayout[@"zOrder"] intValue];
|
|
236
|
+
videoLayout.renderMode = [updatedLayout[@"renderMode"] intValue];
|
|
237
|
+
description.mixVideoStreams = @[ videoLayout ];
|
|
238
|
+
[self.pusher.getMixerManager updateStreamMixDescription:description];
|
|
239
|
+
|
|
240
|
+
[self.mixedViewLayout setObject:updatedLayout forKey:viewId];
|
|
241
|
+
|
|
242
|
+
// Delayed capture execution to ensure property updates completion
|
|
243
|
+
VeLiveMixerUIView *mixerView =
|
|
244
|
+
[[VeLiveMixerHelper cachedMixedViews] objectForKey:viewId];
|
|
245
|
+
if ([mixerView isKindOfClass:[VeLiveMixerUIView class]]) {
|
|
246
|
+
dispatch_after(
|
|
247
|
+
dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)),
|
|
248
|
+
dispatch_get_main_queue(), ^{
|
|
249
|
+
@try {
|
|
250
|
+
[mixerView performCaptureWithTrigger:@"update"];
|
|
251
|
+
} @catch (NSException *exception) {
|
|
252
|
+
// Ignore
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return YES;
|
|
258
|
+
} @catch (NSException *exception) {
|
|
259
|
+
return NO;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
- (BOOL)removeView:(NSString *)viewId {
|
|
264
|
+
@try {
|
|
265
|
+
NSDictionary *layout = [self.mixedViewLayout objectForKey:viewId];
|
|
266
|
+
if (!layout) {
|
|
267
|
+
return NO;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
NSNumber *streamIdNumber = [self.viewIdToStreamId objectForKey:viewId];
|
|
271
|
+
if (streamIdNumber) {
|
|
272
|
+
int streamId = [streamIdNumber intValue];
|
|
273
|
+
[self.pusher.getMixerManager removeVideoStream:streamId];
|
|
274
|
+
|
|
275
|
+
NSString *callbackKey = [NSString stringWithFormat:@"%d", streamId];
|
|
276
|
+
[self.callbacks removeObjectForKey:callbackKey];
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
[self.viewIdToStreamId removeObjectForKey:viewId];
|
|
280
|
+
[self.pendingCallbacks removeObjectForKey:viewId];
|
|
281
|
+
|
|
282
|
+
VeLiveMixerUIView *view =
|
|
283
|
+
[[VeLiveMixerHelper cachedMixedViews] objectForKey:viewId];
|
|
284
|
+
if ([view isKindOfClass:[VeLiveMixerUIView class]]) {
|
|
285
|
+
view.bitmapCaptureCallback = nil;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
[self.mixedViewLayout removeObjectForKey:viewId];
|
|
289
|
+
|
|
290
|
+
return YES;
|
|
291
|
+
} @catch (NSException *exception) {
|
|
292
|
+
return NO;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
- (void)captureView:(NSString *)viewId {
|
|
297
|
+
VeLiveMixerUIView *view =
|
|
298
|
+
[[VeLiveMixerHelper cachedMixedViews] objectForKey:viewId];
|
|
299
|
+
if ([view isKindOfClass:[VeLiveMixerUIView class]]) {
|
|
300
|
+
[view performCaptureWithTrigger:@"manual"];
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
#pragma mark - Static Methods
|
|
305
|
+
|
|
306
|
+
+ (void)setupCallbackForMixerView:(VeLiveMixerUIView *)mixerView
|
|
307
|
+
streamId:(int)streamId {
|
|
308
|
+
if (mixerView == nil) {
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
VeLiveMixerHelper *instance = [VeLiveMixerHelper findActiveMixerManager];
|
|
313
|
+
if (!instance) {
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
VeLiveMixerBitmapCallback *callback =
|
|
318
|
+
[[VeLiveMixerBitmapCallback alloc] initWithStreamId:streamId];
|
|
319
|
+
|
|
320
|
+
NSString *callbackKey = [NSString stringWithFormat:@"%d", streamId];
|
|
321
|
+
[instance.callbacks setObject:callback forKey:callbackKey];
|
|
322
|
+
|
|
323
|
+
mixerView.bitmapCaptureCallback = callback;
|
|
324
|
+
|
|
325
|
+
dispatch_after(
|
|
326
|
+
dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)),
|
|
327
|
+
dispatch_get_main_queue(), ^{
|
|
328
|
+
@try {
|
|
329
|
+
if (mixerView && mixerView.bitmapCaptureCallback) {
|
|
330
|
+
VeLiveMixerHelper *instance =
|
|
331
|
+
[VeLiveMixerHelper findActiveMixerManager];
|
|
332
|
+
if (instance && instance.pusher) {
|
|
333
|
+
@try {
|
|
334
|
+
NSString *viewId = mixerView.viewId;
|
|
335
|
+
NSDictionary *layout =
|
|
336
|
+
[instance.mixedViewLayout objectForKey:viewId];
|
|
337
|
+
if (layout) {
|
|
338
|
+
VeLiveStreamMixDescription *description =
|
|
339
|
+
[[VeLiveStreamMixDescription alloc] init];
|
|
340
|
+
VeLiveMixVideoLayout *videoLayout =
|
|
341
|
+
[[VeLiveMixVideoLayout alloc] init];
|
|
342
|
+
videoLayout.streamId = streamId;
|
|
343
|
+
videoLayout.x = [layout[@"x"] floatValue];
|
|
344
|
+
videoLayout.y = [layout[@"y"] floatValue];
|
|
345
|
+
videoLayout.width = [layout[@"width"] floatValue];
|
|
346
|
+
videoLayout.height = [layout[@"height"] floatValue];
|
|
347
|
+
videoLayout.zOrder = [layout[@"zOrder"] intValue];
|
|
348
|
+
videoLayout.alpha = [layout[@"alpha"] floatValue];
|
|
349
|
+
videoLayout.renderMode = [layout[@"renderMode"] intValue];
|
|
350
|
+
description.mixVideoStreams = @[ videoLayout ];
|
|
351
|
+
[instance.pusher.getMixerManager
|
|
352
|
+
updateStreamMixDescription:description];
|
|
353
|
+
}
|
|
354
|
+
} @catch (NSException *e) {
|
|
355
|
+
// Ignore
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
[mixerView performCaptureWithTrigger:@"update"];
|
|
360
|
+
}
|
|
361
|
+
} @catch (NSException *exception) {
|
|
362
|
+
// Ignore
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
+ (void)sendBitmapToMixerStatic:(int)streamId bitmap:(UIImage *)bitmap {
|
|
368
|
+
VeLiveMixerHelper *instance = [VeLiveMixerHelper findActiveMixerManager];
|
|
369
|
+
if (instance && instance.pusher) {
|
|
370
|
+
[instance sendBitmapToMixer:streamId bitmap:bitmap];
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// New: Send pixelBuffer directly to mixer, avoiding UIImage conversion overhead
|
|
375
|
+
+ (void)sendPixelBufferToMixerStatic:(int)streamId
|
|
376
|
+
pixelBuffer:(CVPixelBufferRef)pixelBuffer {
|
|
377
|
+
VeLiveMixerHelper *instance = [VeLiveMixerHelper findActiveMixerManager];
|
|
378
|
+
if (instance && instance.pusher) {
|
|
379
|
+
[instance sendPixelBufferToMixer:streamId pixelBuffer:pixelBuffer];
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
+ (VeLiveMixerHelper *)findActiveMixerManager {
|
|
384
|
+
return currentInstance;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
+ (void)onViewReady:(NSString *)viewId
|
|
388
|
+
mixerView:(VeLiveMixerUIView *)mixerView {
|
|
389
|
+
@try {
|
|
390
|
+
VeLiveMixerHelper *instance = [VeLiveMixerHelper findActiveMixerManager];
|
|
391
|
+
if (instance != nil) {
|
|
392
|
+
NSNumber *streamIdNumber =
|
|
393
|
+
[instance.pendingCallbacks objectForKey:viewId];
|
|
394
|
+
if (streamIdNumber != nil) {
|
|
395
|
+
int streamId = [streamIdNumber intValue];
|
|
396
|
+
[instance.pendingCallbacks removeObjectForKey:viewId];
|
|
397
|
+
[VeLiveMixerHelper setupCallbackForMixerView:mixerView
|
|
398
|
+
streamId:streamId];
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
} @catch (NSException *exception) {
|
|
402
|
+
// Ignore
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
- (void)cleanup {
|
|
407
|
+
[self stopMemoryMonitoring];
|
|
408
|
+
|
|
409
|
+
for (NSString *viewId in self.mixedViewLayout.allKeys) {
|
|
410
|
+
VeLiveMixerUIView *view =
|
|
411
|
+
[[VeLiveMixerHelper cachedMixedViews] objectForKey:viewId];
|
|
412
|
+
if ([view isKindOfClass:[VeLiveMixerUIView class]]) {
|
|
413
|
+
view.bitmapCaptureCallback = nil;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
[self.mixedViewLayout removeAllObjects];
|
|
418
|
+
[self.pendingCallbacks removeAllObjects];
|
|
419
|
+
[self.callbacks removeAllObjects];
|
|
420
|
+
|
|
421
|
+
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
|
|
422
|
+
@autoreleasepool {
|
|
423
|
+
[[NSURLCache sharedURLCache] removeAllCachedResponses];
|
|
424
|
+
[[NSURLCache sharedURLCache] setMemoryCapacity:0];
|
|
425
|
+
[[NSURLCache sharedURLCache] setMemoryCapacity:10 * 1024 * 1024];
|
|
426
|
+
|
|
427
|
+
[[NSNotificationCenter defaultCenter]
|
|
428
|
+
postNotificationName:UIApplicationDidReceiveMemoryWarningNotification
|
|
429
|
+
object:nil];
|
|
430
|
+
|
|
431
|
+
dispatch_after(
|
|
432
|
+
dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)),
|
|
433
|
+
dispatch_get_main_queue(),
|
|
434
|
+
^{
|
|
435
|
+
// Final cleanup completed
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
- (void)dealloc {
|
|
442
|
+
[self cleanup];
|
|
443
|
+
|
|
444
|
+
if (currentInstance == self) {
|
|
445
|
+
currentInstance = nil;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
#pragma mark - Memory Monitoring
|
|
450
|
+
|
|
451
|
+
- (void)startMemoryMonitoring {
|
|
452
|
+
self.memoryMonitorTimer =
|
|
453
|
+
[NSTimer scheduledTimerWithTimeInterval:30.0
|
|
454
|
+
target:self
|
|
455
|
+
selector:@selector(checkMemoryUsage)
|
|
456
|
+
userInfo:nil
|
|
457
|
+
repeats:YES];
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
- (void)stopMemoryMonitoring {
|
|
461
|
+
if (self.memoryMonitorTimer) {
|
|
462
|
+
[self.memoryMonitorTimer invalidate];
|
|
463
|
+
self.memoryMonitorTimer = nil;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
- (void)checkMemoryUsage {
|
|
468
|
+
@autoreleasepool {
|
|
469
|
+
struct task_basic_info info;
|
|
470
|
+
mach_msg_type_number_t size = TASK_BASIC_INFO_COUNT;
|
|
471
|
+
kern_return_t kerr =
|
|
472
|
+
task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &size);
|
|
473
|
+
|
|
474
|
+
if (kerr == KERN_SUCCESS) {
|
|
475
|
+
double memoryUsageMB = info.resident_size / 1024.0 / 1024.0;
|
|
476
|
+
|
|
477
|
+
if (memoryUsageMB > 200.0) {
|
|
478
|
+
[self performMemoryCleanup];
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
- (void)performMemoryCleanup {
|
|
485
|
+
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
|
|
486
|
+
@autoreleasepool {
|
|
487
|
+
NSMutableDictionary *cachedViews = [VeLiveMixerHelper cachedMixedViews];
|
|
488
|
+
for (NSString *viewId in cachedViews.allKeys) {
|
|
489
|
+
VeLiveMixerUIView *view = [cachedViews objectForKey:viewId];
|
|
490
|
+
if ([view isKindOfClass:[VeLiveMixerUIView class]]) {
|
|
491
|
+
if ([view.captureMode isEqualToString:@"realtime"]) {
|
|
492
|
+
[view stopCapture];
|
|
493
|
+
|
|
494
|
+
dispatch_after(
|
|
495
|
+
dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)),
|
|
496
|
+
dispatch_get_main_queue(), ^{
|
|
497
|
+
if (view && [cachedViews objectForKey:viewId] == view) {
|
|
498
|
+
[view startCapture];
|
|
499
|
+
}
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
[[NSURLCache sharedURLCache] removeAllCachedResponses];
|
|
506
|
+
[[NSURLCache sharedURLCache] setMemoryCapacity:5 * 1024 * 1024];
|
|
507
|
+
|
|
508
|
+
[[NSNotificationCenter defaultCenter]
|
|
509
|
+
postNotificationName:UIApplicationDidReceiveMemoryWarningNotification
|
|
510
|
+
object:nil];
|
|
511
|
+
}
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
#pragma mark - Private Methods
|
|
516
|
+
|
|
517
|
+
// Send UIImage to mixer (via pixelBuffer conversion)
|
|
518
|
+
- (void)sendBitmapToMixer:(int)streamId bitmap:(UIImage *)bitmap {
|
|
519
|
+
@autoreleasepool {
|
|
520
|
+
if (!self.pusher || !bitmap) {
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
CVPixelBufferRef pixelBuffer = NULL;
|
|
525
|
+
|
|
526
|
+
@try {
|
|
527
|
+
pixelBuffer = [self pixelBufferFromUIImage:bitmap];
|
|
528
|
+
if (!pixelBuffer) {
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// Use new pixelBuffer method
|
|
533
|
+
[self sendPixelBufferToMixer:streamId pixelBuffer:pixelBuffer];
|
|
534
|
+
|
|
535
|
+
} @finally {
|
|
536
|
+
if (pixelBuffer) {
|
|
537
|
+
CVPixelBufferRelease(pixelBuffer);
|
|
538
|
+
pixelBuffer = NULL;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// Send pixelBuffer directly to mixer, better performance
|
|
545
|
+
- (void)sendPixelBufferToMixer:(int)streamId
|
|
546
|
+
pixelBuffer:(CVPixelBufferRef)pixelBuffer {
|
|
547
|
+
@autoreleasepool {
|
|
548
|
+
if (!self.pusher || !pixelBuffer) {
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
@try {
|
|
553
|
+
VeLiveVideoFrame *videoFrame = [[VeLiveVideoFrame alloc] init];
|
|
554
|
+
videoFrame.bufferType = VeLiveVideoBufferTypePixelBuffer;
|
|
555
|
+
videoFrame.pts = CMTimeMakeWithSeconds(CACurrentMediaTime(), 1000000000);
|
|
556
|
+
videoFrame.pixelBuffer = pixelBuffer;
|
|
557
|
+
|
|
558
|
+
[[self.pusher getMixerManager] sendCustomVideoFrame:videoFrame
|
|
559
|
+
streamId:streamId];
|
|
560
|
+
} @catch (NSException *exception) {
|
|
561
|
+
// Handle exception silently
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
#pragma mark - Helper Methods
|
|
567
|
+
|
|
568
|
+
- (CVPixelBufferRef)pixelBufferFromUIImage:(UIImage *)image {
|
|
569
|
+
if (!image) {
|
|
570
|
+
return NULL;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
CGImageRef cgImage = image.CGImage;
|
|
574
|
+
if (!cgImage) {
|
|
575
|
+
return NULL;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
CGFloat width = CGImageGetWidth(cgImage);
|
|
579
|
+
CGFloat height = CGImageGetHeight(cgImage);
|
|
580
|
+
|
|
581
|
+
NSDictionary *options = @{
|
|
582
|
+
(NSString *)kCVPixelBufferCGImageCompatibilityKey : @YES,
|
|
583
|
+
(NSString *)kCVPixelBufferCGBitmapContextCompatibilityKey : @YES,
|
|
584
|
+
(NSString *)kCVPixelBufferIOSurfacePropertiesKey : @{}
|
|
585
|
+
};
|
|
586
|
+
|
|
587
|
+
CVPixelBufferRef pixelBuffer = NULL;
|
|
588
|
+
CVReturn status = CVPixelBufferCreate(
|
|
589
|
+
kCFAllocatorDefault, width, height, kCVPixelFormatType_32BGRA,
|
|
590
|
+
(__bridge CFDictionaryRef)options, &pixelBuffer);
|
|
591
|
+
|
|
592
|
+
if (status != kCVReturnSuccess || !pixelBuffer) {
|
|
593
|
+
return NULL;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
CVPixelBufferLockBaseAddress(pixelBuffer, 0);
|
|
597
|
+
|
|
598
|
+
void *pixelData = CVPixelBufferGetBaseAddress(pixelBuffer);
|
|
599
|
+
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer);
|
|
600
|
+
|
|
601
|
+
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
|
602
|
+
CGContextRef context = CGBitmapContextCreate(
|
|
603
|
+
pixelData, width, height, 8, bytesPerRow, colorSpace,
|
|
604
|
+
kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host);
|
|
605
|
+
|
|
606
|
+
if (!context) {
|
|
607
|
+
CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
|
|
608
|
+
CVPixelBufferRelease(pixelBuffer);
|
|
609
|
+
CGColorSpaceRelease(colorSpace);
|
|
610
|
+
return NULL;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
CGContextDrawImage(context, CGRectMake(0, 0, width, height), cgImage);
|
|
614
|
+
|
|
615
|
+
CGContextRelease(context);
|
|
616
|
+
CGColorSpaceRelease(colorSpace);
|
|
617
|
+
CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
|
|
618
|
+
|
|
619
|
+
return pixelBuffer;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
@end
|
|
623
|
+
|
|
624
|
+
#pragma mark - VeLiveMixerBitmapCallback Implementation
|
|
625
|
+
|
|
626
|
+
@implementation VeLiveMixerBitmapCallback
|
|
627
|
+
|
|
628
|
+
- (instancetype)initWithStreamId:(int)streamId {
|
|
629
|
+
self = [super init];
|
|
630
|
+
if (self) {
|
|
631
|
+
_streamId = streamId;
|
|
632
|
+
}
|
|
633
|
+
return self;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
- (void)onBitmapCaptured:(UIImage *)bitmap {
|
|
637
|
+
if (bitmap != nil) {
|
|
638
|
+
[VeLiveMixerHelper sendBitmapToMixerStatic:self.streamId bitmap:bitmap];
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
- (void)onCaptureError:(NSString *)error {
|
|
643
|
+
// Ignore
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
@end
|