|
3 | 3 | #import <AVFoundation/AVFoundation.h>
|
4 | 4 | #import <CoreGraphics/CGImage.h>
|
5 | 5 | #import <WebRTC/WebRTC.h>
|
| 6 | +#import <WebRTC/RTCYUVPlanarBuffer.h> |
| 7 | + |
6 | 8 | #import <objc/runtime.h>
|
| 9 | +#include "libyuv.h" |
7 | 10 |
|
8 | 11 | #import "FlutterWebRTCPlugin.h"
|
9 | 12 |
|
@@ -71,15 +74,99 @@ - (void)setVideoTrack:(RTCVideoTrack *)videoTrack {
|
71 | 74 | }
|
72 | 75 | }
|
73 | 76 |
|
| 77 | + |
| 78 | +-(id<RTCI420Buffer>) correctRotation:(const id<RTCI420Buffer>) src |
| 79 | + withRotation:(RTCVideoRotation) rotation |
| 80 | +{ |
| 81 | + |
| 82 | + int rotated_width = src.width; |
| 83 | + int rotated_height = src.height; |
| 84 | + |
| 85 | + if (rotation == RTCVideoRotation_90 || |
| 86 | + rotation == RTCVideoRotation_270) { |
| 87 | + int temp = rotated_width; |
| 88 | + rotated_width = rotated_height; |
| 89 | + rotated_height = temp; |
| 90 | + } |
| 91 | + |
| 92 | + id<RTCI420Buffer> buffer = [[RTCI420Buffer alloc] initWithWidth:rotated_width height:rotated_height]; |
| 93 | + |
| 94 | + I420Rotate(src.dataY, src.strideY, |
| 95 | + src.dataU, src.strideU, |
| 96 | + src.dataV, src.strideV, |
| 97 | + (uint8_t*)buffer.dataY, buffer.strideY, |
| 98 | + (uint8_t*)buffer.dataU,buffer.strideU, |
| 99 | + (uint8_t*)buffer.dataV, buffer.strideV, |
| 100 | + src.width, src.height, |
| 101 | + (RotationModeEnum)rotation); |
| 102 | + |
| 103 | + return buffer; |
| 104 | +} |
| 105 | + |
| 106 | +-(void)copyI420ToCVPixelBuffer:(CVPixelBufferRef)outputPixelBuffer withFrame:(RTCVideoFrame *) frame |
| 107 | +{ |
| 108 | + id<RTCI420Buffer> i420Buffer = [self correctRotation:[frame.buffer toI420] withRotation:frame.rotation]; |
| 109 | + CVPixelBufferLockBaseAddress(outputPixelBuffer, 0); |
| 110 | + |
| 111 | + const OSType pixelFormat = CVPixelBufferGetPixelFormatType(outputPixelBuffer); |
| 112 | + if (pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange || |
| 113 | + pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange) { |
| 114 | + // NV12 |
| 115 | + uint8_t* dstY = CVPixelBufferGetBaseAddressOfPlane(outputPixelBuffer, 0); |
| 116 | + const size_t dstYStride = CVPixelBufferGetBytesPerRowOfPlane(outputPixelBuffer, 0); |
| 117 | + uint8_t* dstUV = CVPixelBufferGetBaseAddressOfPlane(outputPixelBuffer, 1); |
| 118 | + const size_t dstUVStride = CVPixelBufferGetBytesPerRowOfPlane(outputPixelBuffer, 1); |
| 119 | + |
| 120 | + I420ToNV12(i420Buffer.dataY, |
| 121 | + i420Buffer.strideY, |
| 122 | + i420Buffer.dataU, |
| 123 | + i420Buffer.strideU, |
| 124 | + i420Buffer.dataV, |
| 125 | + i420Buffer.strideV, |
| 126 | + dstY, |
| 127 | + (int)dstYStride, |
| 128 | + dstUV, |
| 129 | + (int)dstUVStride, |
| 130 | + i420Buffer.width, |
| 131 | + i420Buffer.height); |
| 132 | + } else { |
| 133 | + uint8_t* dst = CVPixelBufferGetBaseAddress(outputPixelBuffer); |
| 134 | + const size_t bytesPerRow = CVPixelBufferGetBytesPerRow(outputPixelBuffer); |
| 135 | + |
| 136 | + if (pixelFormat == kCVPixelFormatType_32BGRA) { |
| 137 | + // Corresponds to libyuv::FOURCC_ARGB |
| 138 | + I420ToARGB(i420Buffer.dataY, |
| 139 | + i420Buffer.strideY, |
| 140 | + i420Buffer.dataU, |
| 141 | + i420Buffer.strideU, |
| <
9E88
code>142 | + i420Buffer.dataV, |
| 143 | + i420Buffer.strideV, |
| 144 | + dst, |
| 145 | + (int)bytesPerRow, |
| 146 | + i420Buffer.width, |
| 147 | + i420Buffer.height); |
| 148 | + } else if (pixelFormat == kCVPixelFormatType_32ARGB) { |
| 149 | + // Corresponds to libyuv::FOURCC_BGRA |
| 150 | + I420ToBGRA(i420Buffer.dataY, |
| 151 | + i420Buffer.strideY, |
| 152 | + i420Buffer.dataU, |
| 153 | + i420Buffer.strideU, |
| 154 | + i420Buffer.dataV, |
| 155 | + i420Buffer.strideV, |
| 156 | + dst, |
| 157 | + (int)bytesPerRow, |
| 158 | + i420Buffer.width, |
| 159 | + i420Buffer.height); |
| 160 | + } |
| 161 | + } |
| 162 | + |
| 163 | + CVPixelBufferUnlockBaseAddress(outputPixelBuffer, 0); |
| 164 | +} |
| 165 | + |
74 | 166 | #pragma mark - RTCVideoRenderer methods
|
75 | 167 | - (void)renderFrame:(RTCVideoFrame *)frame {
|
76 |
| - |
77 |
| - //TODO: got a frame => scale to _renderSize => convert to BGRA32 pixelBufferRef |
78 |
| - RTCI420Buffer *buffer = [[frame buffer] toI420]; |
79 |
| - buffer.dataY; |
80 |
| - buffer.dataU; |
81 |
| - buffer.dataV; |
82 |
| - //TODO: copy it somehow, I dunno what to do with this data |
| 168 | + |
| 169 | + [self copyI420ToCVPixelBuffer:_pixelBufferRef withFrame:frame]; |
83 | 170 |
|
84 | 171 | __weak FlutterRTCVideoRenderer *weakSelf = self;
|
85 | 172 |
|
|
0 commit comments