9
9
10
10
#include " libyuv.h"
11
11
12
+ #define clamp (a ) (a>255 ?255 :(a<0 ?0 :a))
13
+
12
14
@import CoreImage;
13
15
@import CoreVideo;
14
16
@@ -36,19 +38,51 @@ - (void)setSize:(CGSize)size
36
38
{
37
39
}
38
40
39
- - (void )renderFrame : (nullable RTCVideoFrame *)frame
40
- {
41
- #if TARGET_OS_IPHONE
42
- if (_gotFrame || frame == nil ) return ;
43
- _gotFrame = true ;
44
-
45
- id <RTCVideoFrameBuffer> buffer = frame.buffer ;
46
- CVPixelBufferRef pixelBufferRef = ((RTCCVPixelBuffer *) buffer).pixelBuffer ;
41
+ // Thanks Juan Giorello https://groups.google.com/g/discuss-webrtc/c/ULGIodbbLvM
42
+ + (UIImage *)convertFrameToUIImage : (RTCVideoFrame *)frame {
43
+ // https://chromium.googlesource.com/external/webrtc/+/refs/heads/main/sdk/objc/base/RTCVideoFrame.h
44
+ // RTCVideoFrameBuffer *rtcFrameBuffer = (RTCVideoFrameBuffer *)frame.buffer;
45
+ // RTCI420Buffer *buffer = [rtcFrameBuffer toI420];
47
46
48
- CIImage *ciImage = [CIImage imageWithCVPixelBuffer: pixelBufferRef];
49
- CIContext *context = [CIContext contextWithOptions: nil ];
50
- CGImageRef cgImage = [context createCGImage: ciImage
51
- fromRect: CGRectMake (0 , 0 , frame.width, frame.height)];
47
+ // https://chromium.googlesource.com/external/webrtc/+/refs/heads/main/sdk/objc/base/RTCVideoFrameBuffer.h
48
+ // This guarantees the buffer will be RTCI420Buffer
49
+ RTCI420Buffer *buffer = [frame.buffer toI420 ];
50
+
51
+
52
+ int width = buffer.width ;
53
+ int height = buffer.height ;
54
+ int bytesPerPixel = 4 ;
55
+ uint8_t *rgbBuffer = malloc (width * height * bytesPerPixel);
56
+
57
+ for (int row = 0 ; row < height; row++) {
58
+ const uint8_t *yLine = &buffer.dataY [row * buffer.strideY];
59
+ const uint8_t *uLine = &buffer.dataU [(row >> 1 ) * buffer.strideU];
60
+ const uint8_t *vLine = &buffer.dataV [(row >> 1 ) * buffer.strideV];
61
+
62
+ for (int x = 0 ; x < width; x++) {
63
+ int16_t y = yLine[x];
64
+ int16_t u = uLine[x >> 1 ] - 128 ;
65
+ int16_t v = vLine[x >> 1 ] - 128 ;
66
+
67
+ int16_t r = roundf (y + v * 1.4 );
68
+ int16_t g = roundf (y + u * -0.343 + v * -0.711 );
69
+ int16_t b = roundf (y + u * 1.765 );
70
+
71
+ uint8_t *rgb = &rgbBuffer[(row * width + x) * bytesPerPixel];
72
+ rgb[0 ] = 0xff ;
73
+ rgb[1 ] = clamp (b);
74
+ rgb[2 ] = clamp (g);
75
+ rgb[3 ] = clamp (r);
76
+ }
77
+ }
78
+
79
+ CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB ();
80
+ CGContextRef context = CGBitmapContextCreate (rgbBuffer, width, height, 8 , width * bytesPerPixel, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipLast );
81
+
82
+ CGImageRef cgImage = CGBitmapContextCreateImage (context);
83
+ CGContextRelease (context);
84
+ CGColorSpaceRelease (colorSpace);
85
+ free (rgbBuffer);
52
86
53
87
UIImageOrientation orientation;
54
88
switch (frame.rotation ) {
@@ -65,8 +99,19 @@ - (void)renderFrame:(nullable RTCVideoFrame *)frame
65
99
break ;
66
100
}
67
101
68
- UIImage *uiImage = [UIImage imageWithCGImage: cgImage scale: 1 orientation: orientation];
102
+ UIImage *image = [UIImage imageWithCGImage: cgImage scale: 1 orientation: orientation];
69
103
CGImageRelease (cgImage);
104
+
105
+ return image;
106
+ }
107
+
108
+ - (void )renderFrame : (nullable RTCVideoFrame *)frame
109
+ {
110
+ #if TARGET_OS_IPHONE
111
+ if (_gotFrame || frame == nil ) return ;
112
+ _gotFrame = true ;
113
+
114
+ UIImage *uiImage = [FlutterRTCFrameCapturer convertFrameToUIImage: frame];
70
115
NSData *jpgData = UIImageJPEGRepresentation (uiImage, 0 .9f );
71
116
72
117
if ([jpgData writeToFile: _path atomically: NO ]) {
0 commit comments