Skip to content

Commit 4db11f9

Browse files
committed
fix: Use CVPixelBuffer to build DesktopCapture Frame, fix the crash caused by non-CVPixelBuffer frame in RTCVideoEncoderH264 that cannot be cropped. (#63)
1 parent 775b83e commit 4db11f9

File tree

3 files changed

+122
-102
lines changed

3 files changed

+122
-102
lines changed

sdk/objc/native/src/objc_desktop_capture.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ class ObjCDesktopCapturer : public DesktopCapturer::Callback {
5757
webrtc::DesktopCaptureOptions options_;
5858
std::unique_ptr<webrtc::DesktopAndCursorComposer> capturer_;
5959
std::unique_ptr<rtc::Thread> thread_;
60-
rtc::scoped_refptr<webrtc::I420Buffer> i420_buffer_;
6160
CaptureState capture_state_ = CS_STOPPED;
6261
DesktopType type_;
6362
webrtc::DesktopCapturer::SourceId source_id_;

sdk/objc/native/src/objc_desktop_capture.mm

Lines changed: 49 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,15 @@
2121
#include "third_party/libyuv/include/libyuv.h"
2222

2323
#import "components/capturer/RTCDesktopCapturer+Private.h"
24+
#import "components/video_frame_buffer/RTCCVPixelBuffer.h"
2425

2526
namespace webrtc {
2627

2728
enum { kCaptureDelay = 33, kCaptureMessageId = 1000 };
2829

2930
ObjCDesktopCapturer::ObjCDesktopCapturer(DesktopType type,
30-
webrtc::DesktopCapturer::SourceId source_id,
31-
id<RTC_OBJC_TYPE(DesktopCapturerDelegate)> delegate)
31+
webrtc::DesktopCapturer::SourceId source_id,
32+
id<RTC_OBJC_TYPE(DesktopCapturerDelegate)> delegate)
3233
: thread_(rtc::Thread::Create()), source_id_(source_id), delegate_(delegate) {
3334
RTC_DCHECK(thread_);
3435
type_ = type;
@@ -38,9 +39,11 @@
3839
options_.set_allow_iosurface(true);
3940
thread_->BlockingCall([this, type] {
4041
if (type == kScreen) {
41-
capturer_ = std::make_unique<DesktopAndCursorComposer>(webrtc::DesktopCapturer::CreateScreenCapturer(options_), options_);
42-
} else {
43-
capturer_ = std::make_unique<DesktopAndCursorComposer>(webrtc::DesktopCapturer::CreateWindowCapturer(options_), options_);
42+
capturer_ = std::make_unique<DesktopAndCursorComposer>(
43+
webrtc::DesktopCapturer::CreateScreenCapturer(options_), options_);
44+
} else {
45+
capturer_ = std::make_unique<DesktopAndCursorComposer>(
46+
webrtc::DesktopCapturer::CreateWindowCapturer(options_), options_);
4447
}
4548
});
4649
}
@@ -61,19 +64,19 @@
6164
return capture_state_;
6265
}
6366

64-
if(fps >= 60) {
67+
if (fps >= 60) {
6568
capture_delay_ = uint32_t(1000.0 / 60.0);
6669
} else {
6770
capture_delay_ = uint32_t(1000.0 / fps);
6871
}
6972

70-
if(source_id_ != -1) {
71-
if(!capturer_->SelectSource(source_id_)) {
72-
capture_state_ = CS_FAILED;
73-
return capture_state_;
73+
if (source_id_ != -1) {
74+
if (!capturer_->SelectSource(source_id_)) {
75+
capture_state_ = CS_FAILED;
76+
return capture_state_;
7477
}
75-
if(type_ == kWindow) {
76-
if(!capturer_->FocusOnSelectedSource()) {
78+
if (type_ == kWindow) {
79+
if (!capturer_->FocusOnSelectedSource()) {
7780
capture_state_ = CS_FAILED;
7881
return capture_state_;
7982
}
@@ -103,7 +106,7 @@
103106
}
104107

105108
void ObjCDesktopCapturer::OnCaptureResult(webrtc::DesktopCapturer::Result result,
106-
std::unique_ptr<webrtc::DesktopFrame> frame) {
109+
std::unique_ptr<webrtc::DesktopFrame> frame) {
107110
if (result != result_) {
108111
if (result == webrtc::DesktopCapturer::Result::ERROR_PERMANENT) {
109112
[delegate_ didSourceCaptureError];
@@ -124,14 +127,14 @@
124127
}
125128

126129
if (result == webrtc::DesktopCapturer::Result::ERROR_TEMPORARY) {
127-
return;
130+
return;
128131
}
129132

130133
int width = frame->size().width();
131134
int height = frame->size().height();
132135
int real_width = width;
133136

134-
if(type_ == kWindow) {
137+
if (type_ == kWindow) {
135138
int multiple = 0;
136139
#if defined(WEBRTC_ARCH_X86_FAMILY)
137140
multiple = 16;
@@ -140,24 +143,26 @@
140143
#endif
141144
// A multiple of $multiple must be used as the width of the src frame,
142145
// and the right black border needs to be cropped during conversion.
143-
if( multiple != 0 && (width % multiple) != 0 ) {
146+
if (multiple != 0 && (width % multiple) != 0) {
144147
width = (width / multiple + 1) * multiple;
145148
}
146149
}
147-
148-
if (!i420_buffer_ || !i420_buffer_.get() ||
149-
i420_buffer_->width() * i420_buffer_->height() != real_width * height) {
150-
i420_buffer_ = webrtc::I420Buffer::Create(real_width, height);
151-
}
152150

153-
libyuv::ConvertToI420(frame->data(),
154-
0,
155-
i420_buffer_->MutableDataY(),
156-
i420_buffer_->StrideY(),
157-
i420_buffer_->MutableDataU(),
158-
i420_buffer_->StrideU(),
159-
i420_buffer_->MutableDataV(),
160-
i420_buffer_->StrideV(),
151+
CVPixelBufferRef pixelBuffer = NULL;
152+
153+
NSDictionary *pixelAttributes = @{(NSString *)kCVPixelBufferIOSurfacePropertiesKey : @{}};
154+
CVReturn res = CVPixelBufferCreate(kCFAllocatorDefault,
155+
width,
156+
height,
157+
kCVPixelFormatType_32BGRA,
158+
(__bridge CFDictionaryRef)(pixelAttributes),
159+
&pixelBuffer);
160+
CVPixelBufferLockBaseAddress(pixelBuffer, 0);
161+
uint8_t *pxdata = (uint8_t *)CVPixelBufferGetBaseAddress(pixelBuffer);
162+
libyuv::ConvertToARGB(reinterpret_cast<uint8_t *>(frame->data()),
163+
real_width * height * 4,
164+
reinterpret_cast<uint8_t *>(pxdata),
165+
width * 4,
161166
0,
162167
0,
163168
width,
@@ -166,17 +171,23 @@
166171
height,
167172
libyuv::kRotate0,
168173
libyuv::FOURCC_ARGB);
174+
CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
175+
176+
if (res != kCVReturnSuccess) {
177+
NSLog(@"Unable to create cvpixelbuffer %d", res);
178+
return;
179+
}
180+
181+
RTC_OBJC_TYPE(RTCCVPixelBuffer) *rtcPixelBuffer =
182+
[[RTC_OBJC_TYPE(RTCCVPixelBuffer) alloc] initWithPixelBuffer:pixelBuffer];
169183
NSTimeInterval timeStampSeconds = CACurrentMediaTime();
170184
int64_t timeStampNs = lroundf(timeStampSeconds * NSEC_PER_SEC);
171-
RTCVideoFrame* rtc_video_frame =
172-
ToObjCVideoFrame(
173-
webrtc::VideoFrame::Builder()
174-
.set_video_frame_buffer(i420_buffer_)
175-
.set_rotation(webrtc::kVideoRotation_0)
176-
.set_timestamp_us(timeStampNs / 1000)
177-
.build()
178-
);
179-
[delegate_ didCaptureVideoFrame:rtc_video_frame];
185+
RTC_OBJC_TYPE(RTCVideoFrame) *videoFrame =
186+
[[RTC_OBJC_TYPE(RTCVideoFrame) alloc] initWithBuffer:rtcPixelBuffer
187+
rotation:RTCVideoRotation_0
188+
timeStampNs:timeStampNs];
189+
CVPixelBufferRelease(pixelBuffer);
190+
[delegate_ didCaptureVideoFrame:videoFrame];
180191
}
181192

182193
void ObjCDesktopCapturer::CaptureFrame() {

0 commit comments

Comments
 (0)