8000 Fix IOS captureFrame and add support for remote stream captureFrame (… · dontcryme/flutter-webrtc@60bde85 · GitHub
[go: up one dir, main page]

Skip to content

Commit 60bde85

Browse files
MRobertEversMatthew Evers
andauthored
Fix IOS captureFrame and add support for remote stream captureFrame (flutter-webrtc#778)
* Fix IOS captureFrame and add support for remote stream captureFrame (flutter-webrtc#1) * fix: support screencapture on IOS for local and remote streams Co-authored-by: Matthew Evers <mevers@pivotint.com> * fix: re-include RTCOrientation Co-authored-by: Matthew Evers <mevers@pivotint.com>
1 parent aab3cb0 commit 60bde85

File tree

3 files changed

+60
-18
lines changed

3 files changed

+60
-18
lines changed

common/darwin/Classes/FlutterRTCFrameCapturer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,6 @@
99

1010
- (instan 8000 cetype)initWithTrack:(RTCVideoTrack *) track toPath:(NSString *) path result:(FlutterResult)result;
1111

12+
+ (UIImage *)convertFrameToUIImage:(RTCVideoFrame *)frame;
13+
1214
@end

common/darwin/Classes/FlutterRTCFrameCapturer.m

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
#include "libyuv.h"
1111

12+
#define clamp(a) (a>255?255:(a<0?0:a))
13+
1214
@import CoreImage;
1315
@import CoreVideo;
1416

@@ -36,19 +38,51 @@ - (void)setSize:(CGSize)size
3638
{
3739
}
3840

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];
4746

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);
5286

5387
UIImageOrientation orientation;
5488
switch (frame.rotation) {
@@ -65,8 +99,19 @@ - (void)renderFrame:(nullable RTCVideoFrame *)frame
6599
break;
66100
}
67101

68-
UIImage *uiImage = [UIImage imageWithCGImage:cgImage scale:1 orientation:orientation];
102+
UIImage *image = [UIImage imageWithCGImage:cgImage scale:1 orientation:orientation];
69103
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];
70115
NSData *jpgData = UIImageJPEGRepresentation(uiImage, 0.9f);
71116

72117
if ([jpgData writeToFile:_path atomically:NO]) {

common/darwin/Classes/FlutterRTCMediaStream.m

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -593,11 +593,6 @@ -(void)mediaStreamTrackSwitchCamera:(RTCMediaStreamTrack *)track result:(Flutter
593593

594594
-(void)mediaStreamTrackCaptureFrame:(RTCVideoTrack *)track toPath:(NSString *) path result:(FlutterResult)result
595595
{
596-
if (!self.videoCapturer) {
597-
NSLog(@"Video capturer is null. Can't capture frame.");
598-
return;
599-
}
600-
601596
self.frameCapturer = [[FlutterRTCFrameCapturer alloc] initWithTrack:track toPath:path result:result];
602597
}
603598

0 commit comments

Comments
 (0)
0