diff --git a/sdk/objc/native/src/objc_video_track_source.mm b/sdk/objc/native/src/objc_video_track_source.mm index 053158a7db..580180a1a2 100644 --- a/sdk/objc/native/src/objc_video_track_source.mm +++ b/sdk/objc/native/src/objc_video_track_source.mm @@ -33,8 +33,8 @@ namespace webrtc { -ObjCVideoTrackSource::ObjCVideoTrackSource() : - AdaptedVideoTrackSource(/* required resolution alignment */ 4) {} +ObjCVideoTrackSource::ObjCVideoTrackSource() + : AdaptedVideoTrackSource(/* required resolution alignment */ 2) {} ObjCVideoTrackSource::ObjCVideoTrackSource(RTCObjCVideoSourceAdapter *adapter) : adapter_(adapter) { adapter_.objCVideoTrackSource = this; diff --git a/sdk/objc/unittests/ObjCVideoTrackSource_xctest.mm b/sdk/objc/unittests/ObjCVideoTrackSource_xctest.mm index 8c940e44c3..a937957c19 100644 --- a/sdk/objc/unittests/ObjCVideoTrackSource_xctest.mm +++ b/sdk/objc/unittests/ObjCVideoTrackSource_xctest.mm @@ -112,6 +112,48 @@ class ObjCCallbackVideoSink : public rtc::VideoSinkInterface CVBufferRelease(pixelBufferRef); } +- (void)testOnCapturedFrameAdaptationResultsInCommonResolutions { + // Some of the most common resolutions used in the wild are 640x360, 480x270 and 320x180. + // Make sure that we properly scale down to exactly these resolutions. + CVPixelBufferRef pixelBufferRef = NULL; + CVPixelBufferCreate( + NULL, 720, 1280, kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, NULL, &pixelBufferRef); + + RTCCVPixelBuffer *buffer = [[RTCCVPixelBuffer alloc] initWithPixelBuffer:pixelBufferRef]; + + RTCVideoFrame *frame = [[RTCVideoFrame alloc] initWithBuffer:buffer + rotation:RTCVideoRotation_0 + timeStampNs:0]; + + cricket::FakeVideoRenderer *video_renderer = new cricket::FakeVideoRenderer(); + const rtc::VideoSinkWants video_sink_wants; + rtc::VideoSourceInterface *video_source_interface = _video_source; + video_source_interface->AddOrUpdateSink(video_renderer, video_sink_wants); + + _video_source->OnOutputFormatRequest(640, 360, 30); + _video_source->OnCapturedFrame(frame); + + XCTAssertEqual(video_renderer->num_rendered_frames(), 1); + XCTAssertEqual(video_renderer->width(), 360); + XCTAssertEqual(video_renderer->height(), 640); + + _video_source->OnOutputFormatRequest(480, 270, 30); + _video_source->OnCapturedFrame(frame); + + XCTAssertEqual(video_renderer->num_rendered_frames(), 2); + XCTAssertEqual(video_renderer->width(), 270); + XCTAssertEqual(video_renderer->height(), 480); + + _video_source->OnOutputFormatRequest(320, 180, 30); + _video_source->OnCapturedFrame(frame); + + XCTAssertEqual(video_renderer->num_rendered_frames(), 3); + XCTAssertEqual(video_renderer->width(), 180); + XCTAssertEqual(video_renderer->height(), 320); + + CVBufferRelease(pixelBufferRef); +} + - (void)testOnCapturedFrameWithoutAdaptation { CVPixelBufferRef pixelBufferRef = NULL; CVPixelBufferCreate( @@ -216,9 +258,10 @@ class ObjCCallbackVideoSink : public rtc::VideoSinkInterface CVPixelBufferCreate( NULL, 720, 1280, kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, NULL, &pixelBufferRef); + // Create a frame that's already adapted down. RTCCVPixelBuffer *buffer = [[RTCCVPixelBuffer alloc] initWithPixelBuffer:pixelBufferRef - adaptedWidth:700 - adaptedHeight:700 + adaptedWidth:640 + adaptedHeight:360 cropWidth:720 cropHeight:1280 cropX:0 @@ -228,14 +271,14 @@ class ObjCCallbackVideoSink : public rtc::VideoSinkInterface XCTestExpectation *callbackExpectation = [self expectationWithDescription:@"videoSinkCallback"]; ObjCCallbackVideoSink callback_video_sink(^void(RTCVideoFrame *outputFrame) { - XCTAssertEqual(outputFrame.width, 300); - XCTAssertEqual(outputFrame.height, 516); + XCTAssertEqual(outputFrame.width, 480); + XCTAssertEqual(outputFrame.height, 270); RTCCVPixelBuffer *outputBuffer = outputFrame.buffer; - XCTAssertEqual(outputBuffer.cropX, 150); - XCTAssertEqual(outputBuffer.cropY, 6); - XCTAssertEqual(outputBuffer.cropWidth, 400); - XCTAssertEqual(outputBuffer.cropHeight, 688); + XCTAssertEqual(outputBuffer.cropX, 0); + XCTAssertEqual(outputBuffer.cropY, 0); + XCTAssertEqual(outputBuffer.cropWidth, 640); + XCTAssertEqual(outputBuffer.cropHeight, 360); XCTAssertEqual(buffer.pixelBuffer, outputBuffer.pixelBuffer); [callbackExpectation fulfill]; @@ -245,7 +288,7 @@ class ObjCCallbackVideoSink : public rtc::VideoSinkInterface rtc::VideoSourceInterface *video_source_interface = _video_source; video_source_interface->AddOrUpdateSink(&callback_video_sink, video_sink_wants); - _video_source->OnOutputFormatRequest(640, 360, 30); + _video_source->OnOutputFormatRequest(480, 270, 30); _video_source->OnCapturedFrame(frame); [self waitForExpectations:@[ callbackExpectation ] timeout:10.0]; @@ -311,13 +354,13 @@ class ObjCCallbackVideoSink : public rtc::VideoSinkInterface XCTestExpectation *callbackExpectation = [self expectationWithDescription:@"videoSinkCallback"]; ObjCCallbackVideoSink callback_video_sink(^void(RTCVideoFrame *outputFrame) { XCTAssertEqual(outputFrame.width, 300); - XCTAssertEqual(outputFrame.height, 536); + XCTAssertEqual(outputFrame.height, 534); RTCCVPixelBuffer *outputBuffer = outputFrame.buffer; XCTAssertEqual(outputBuffer.cropX, 40); XCTAssertEqual(outputBuffer.cropY, 52); XCTAssertEqual(outputBuffer.cropWidth, 300); - XCTAssertEqual(outputBuffer.cropHeight, 536); + XCTAssertEqual(outputBuffer.cropHeight, 534); XCTAssertEqual(buffer.pixelBuffer, outputBuffer.pixelBuffer); [callbackExpectation fulfill];