1
1
#import " AgoraCVPixelBufferUtils.h"
2
+
3
+ #include < mutex>
4
+ #include < tuple>
5
+ #include < unordered_map>
6
+
2
7
#include < CoreVideo/CoreVideo.h>
8
+ #import < Foundation/Foundation.h>
9
+
10
+ #pragma mark - AgoraCVPixelBufferPool
11
+
12
+ struct AgoraCVPixelBufferPoolKey {
13
+ OSType type;
14
+ size_t width;
15
+ size_t height;
16
+
17
+ bool operator ==(const AgoraCVPixelBufferPoolKey &other) const {
18
+ return type == other.type && width == other.width && height == other.height ;
19
+ }
20
+
21
+ bool operator <(const AgoraCVPixelBufferPoolKey &other) const {
22
+ return std::tie (type, width, height) <
23
+ std::tie (other.type , other.width , other.height );
24
+ }
25
+ };
26
+
27
+ struct AgoraCVPixelBufferPoolKeyHash {
28
+ std::size_t operator ()(const AgoraCVPixelBufferPoolKey &key) const {
29
+ return std::hash<OSType >()(key.type ) ^ std::hash<size_t >()(key.width ) ^
30
+ std::hash<size_t >()(key.height );
31
+ }
32
+ };
33
+
34
+ @interface AgoraCVPixelBufferPool : NSObject
35
+
36
+ + (instancetype )sharedInstance ;
37
+
38
+ - (CVPixelBufferRef)createPixelBuffer : (OSType )type
39
+ width : (size_t )width
40
+ height : (size_t )height ;
41
+
42
+ - (void )freeAllCVPixelBufferPools ;
43
+
44
+ @end
45
+
46
+ @implementation AgoraCVPixelBufferPool {
47
+ std::mutex _mutex;
48
+ std::unordered_map<AgoraCVPixelBufferPoolKey, CVPixelBufferPoolRef,
49
+ AgoraCVPixelBufferPoolKeyHash>
50
+ _pools;
51
+ }
52
+
53
+ + (instancetype )sharedInstance {
54
+ static AgoraCVPixelBufferPool *instance = nil ;
55
+
56
+ // should we use this or just use a static global variable?
57
+ static dispatch_once_t onceToken;
58
+ dispatch_once (&onceToken, ^{
59
+ instance = [[AgoraCVPixelBufferPool alloc ] init ];
60
+ });
61
+
62
+ return instance;
63
+ }
64
+
65
+ - (CVPixelBufferRef)createPixelBuffer : (OSType )type
66
+ width : (size_t )width
67
+ height : (size_t )height {
68
+ std::lock_guard<std::mutex> lock (_mutex);
69
+ CVPixelBufferPoolRef pool = nil ;
70
+
71
+ AgoraCVPixelBufferPoolKey key = {type, width, height};
72
+ auto it = _pools.find (key);
73
+ if (it == _pools.end ()) {
74
+ NSMutableDictionary *attributes =
75
+ [NSMutableDictionary dictionaryWithDictionary: @{
76
+ (id )kCVPixelBufferIOSurfacePropertiesKey : @{},
77
+ #if defined(WEBRTC_IOS)
78
+ (id )kCVPixelBufferOpenGLESCompatibilityKey : @YES ,
79
+ #elif defined(WEBRTC_MAC)
80
+ (id )kCVPixelBufferOpenGLCompatibilityKey : @YES ,
81
+ #endif
82
+ (id )kCVPixelBufferCGImageCompatibilityKey : @YES ,
83
+ (id )kCVPixelBufferCGBitmapContextCompatibilityKey : @YES ,
84
+ (id )kCVPixelBufferPixelFormatTypeKey : @(key.type ),
85
+ (id )kCVPixelBufferWidthKey : @(key.width ),
86
+ (id )kCVPixelBufferHeightKey : @(key.height )
87
+ }];
88
+
89
+ if (@available (macOS 10.11 , *)) {
90
+ [attributes setObject: @YES
91
+ forKey: (id )kCVPixelBufferMetalCompatibilityKey ];
92
+ }
93
+ CVReturn status =
94
+ CVPixelBufferPoolCreate (kCFAllocatorDefault , nullptr ,
95
+ (__bridge CFDictionaryRef )attributes, &pool);
96
+ if (status != kCVReturnSuccess || !pool) {
97
+ return nil ;
98
+ }
99
+
100
+ _pools[key] = pool;
101
+ } else {
102
+ pool = it->second ;
103
+ }
104
+
105
+ CVPixelBufferRef pixelBuffer = nil ;
106
+ CVPixelBufferPoolCreatePixelBuffer (kCFAllocatorDefault , pool, &pixelBuffer);
107
+
108
+ return pixelBuffer;
109
+ }
110
+
111
+ - (void )freeAllCVPixelBufferPools {
112
+ std::lock_guard<std::mutex> lock (_mutex);
113
+ for (auto &pool : _pools) {
114
+ CVPixelBufferPoolFlush (pool.second , kCVPixelBufferPoolFlushExcessBuffers );
115
+ CVPixelBufferPoolRelease (pool.second );
116
+ }
117
+ _pools.clear ();
118
+ }
119
+
120
+ @end
121
+
122
+ #pragma mark - AgoraCVPixelBufferUtils
3
123
4
124
@implementation AgoraCVPixelBufferUtils
5
125
126
+ + (void )freeAllCVPixelBufferPools {
127
+ [[AgoraCVPixelBufferPool sharedInstance ] freeAllCVPixelBufferPools ];
128
+ }
129
+
6
130
+ (BOOL )copyNV12CVPixelBuffer : (CVPixelBufferRef _Nonnull)sourcePixelBuffer
7
131
destPixelBuffer : (CVPixelBufferRef _Nonnull)destPixelBuffer {
8
132
if (!sourcePixelBuffer || !destPixelBuffer) {
@@ -116,6 +240,8 @@ + (CVPixelBufferRef)copyCVPixelBuffer:
116
240
size_t sourceHeight = CVPixelBufferGetHeight (sourcePixelBuffer);
117
241
OSType sourceFormat = CVPixelBufferGetPixelFormatType (sourcePixelBuffer);
118
242
243
+ // create pixel buffer directly
244
+ #if 1
119
245
// Create new buffer with Metal compatibility
120
246
NSDictionary *pixelBufferAttributes = @{
121
247
// This key is required to generate SKPicture with CVPixelBufferRef in
@@ -130,6 +256,16 @@ + (CVPixelBufferRef)copyCVPixelBuffer:
130
256
if (status != kCVReturnSuccess || !destPixelBuffer) {
131
257
return nil ;
132
258
}
259
+ #else
260
+ // create pixel buffer from pool
261
+ CVPixelBufferRef destPixelBuffer =
262
+ [[AgoraCVPixelBufferPool sharedInstance] createPixelBuffer:sourceFormat
263
+ width:sourceWidth
264
+ height:sourceHeight];
265
+ if (!destPixelBuffer) {
266
+ return nil;
267
+ }
268
+ #endif
133
269
134
270
// Copy data based on format
135
271
BOOL success = NO ;
0 commit comments