Revert "Support more formats in RTCVideoFrame"
This reverts commit bd2220a9c496ef2e8567b68d4be9435a110bdc34. Reason for revert: Broke external clients Original change's description: > Support more formats in RTCVideoFrame > > Implement Obj-C version of webrtc::VideoFrameBuffer and use that in > RTCVideoFrame. > > Bug: webrtc:7785 > Change-Id: I49f42bcf451dd6769b3a79a65fe7b400dce22677 > Reviewed-on: https://chromium-review.googlesource.com/536773 > Commit-Queue: Anders Carlsson <andersc@webrtc.org> > Reviewed-by: Magnus Jedvert <magjed@webrtc.org> > Cr-Commit-Position: refs/heads/master@{#18691} TBR=magjed@webrtc.org,andersc@webrtc.org Change-Id: Id765dd9543ed0613a6b2de108b268c3501025fcd No-Presubmit: true No-Tree-Checks: true No-Try: true Bug: webrtc:7785 Reviewed-on: https://chromium-review.googlesource.com/542837 Reviewed-by: Anders Carlsson <andersc@webrtc.org> Commit-Queue: Anders Carlsson <andersc@webrtc.org> Cr-Commit-Position: refs/heads/master@{#18697}
This commit is contained in:
committed by
Commit Bot
parent
0f15f926e3
commit
0789dab2cb
@ -105,11 +105,8 @@ if (is_ios || is_mac) {
|
|||||||
sources = [
|
sources = [
|
||||||
"objc/Framework/Classes/Video/RTCAVFoundationVideoCapturerInternal.h",
|
"objc/Framework/Classes/Video/RTCAVFoundationVideoCapturerInternal.h",
|
||||||
"objc/Framework/Classes/Video/RTCAVFoundationVideoCapturerInternal.mm",
|
"objc/Framework/Classes/Video/RTCAVFoundationVideoCapturerInternal.mm",
|
||||||
"objc/Framework/Classes/Video/RTCCVPixelBuffer.mm",
|
|
||||||
"objc/Framework/Classes/Video/RTCDefaultShader.h",
|
"objc/Framework/Classes/Video/RTCDefaultShader.h",
|
||||||
"objc/Framework/Classes/Video/RTCDefaultShader.mm",
|
"objc/Framework/Classes/Video/RTCDefaultShader.mm",
|
||||||
"objc/Framework/Classes/Video/RTCI420Buffer+Private.h",
|
|
||||||
"objc/Framework/Classes/Video/RTCI420Buffer.mm",
|
|
||||||
"objc/Framework/Classes/Video/RTCI420TextureCache.h",
|
"objc/Framework/Classes/Video/RTCI420TextureCache.h",
|
||||||
"objc/Framework/Classes/Video/RTCI420TextureCache.mm",
|
"objc/Framework/Classes/Video/RTCI420TextureCache.mm",
|
||||||
"objc/Framework/Classes/Video/RTCOpenGLDefines.h",
|
"objc/Framework/Classes/Video/RTCOpenGLDefines.h",
|
||||||
@ -119,11 +116,8 @@ if (is_ios || is_mac) {
|
|||||||
"objc/Framework/Classes/Video/avfoundationformatmapper.mm",
|
"objc/Framework/Classes/Video/avfoundationformatmapper.mm",
|
||||||
"objc/Framework/Classes/Video/avfoundationvideocapturer.h",
|
"objc/Framework/Classes/Video/avfoundationvideocapturer.h",
|
||||||
"objc/Framework/Classes/Video/avfoundationvideocapturer.mm",
|
"objc/Framework/Classes/Video/avfoundationvideocapturer.mm",
|
||||||
"objc/Framework/Classes/Video/objc_frame_buffer.h",
|
|
||||||
"objc/Framework/Classes/Video/objc_frame_buffer.mm",
|
|
||||||
"objc/Framework/Classes/Video/objcvideotracksource.h",
|
"objc/Framework/Classes/Video/objcvideotracksource.h",
|
||||||
"objc/Framework/Classes/Video/objcvideotracksource.mm",
|
"objc/Framework/Classes/Video/objcvideotracksource.mm",
|
||||||
"objc/Framework/Headers/WebRTC/RTCVideoFrameBuffer.h",
|
|
||||||
]
|
]
|
||||||
libs = []
|
libs = []
|
||||||
if (is_ios) {
|
if (is_ios) {
|
||||||
@ -148,6 +142,8 @@ if (is_ios || is_mac) {
|
|||||||
|
|
||||||
deps = [
|
deps = [
|
||||||
":objc_common",
|
":objc_common",
|
||||||
|
":objc_corevideoframebuffer",
|
||||||
|
":objc_videotoolbox",
|
||||||
"../api:libjingle_peerconnection_api",
|
"../api:libjingle_peerconnection_api",
|
||||||
"../base:rtc_base",
|
"../base:rtc_base",
|
||||||
"../common_video",
|
"../common_video",
|
||||||
@ -274,6 +270,7 @@ if (is_ios || is_mac) {
|
|||||||
"objc/Framework/Classes/PeerConnection/RTCSessionDescription.mm",
|
"objc/Framework/Classes/PeerConnection/RTCSessionDescription.mm",
|
||||||
"objc/Framework/Classes/PeerConnection/RTCTracing.mm",
|
"objc/Framework/Classes/PeerConnection/RTCTracing.mm",
|
||||||
"objc/Framework/Classes/PeerConnection/RTCVideoCapturer.m",
|
"objc/Framework/Classes/PeerConnection/RTCVideoCapturer.m",
|
||||||
|
"objc/Framework/Classes/PeerConnection/RTCVideoFrame+Private.h",
|
||||||
"objc/Framework/Classes/PeerConnection/RTCVideoFrame.mm",
|
"objc/Framework/Classes/PeerConnection/RTCVideoFrame.mm",
|
||||||
"objc/Framework/Classes/PeerConnection/RTCVideoRendererAdapter+Private.h",
|
"objc/Framework/Classes/PeerConnection/RTCVideoRendererAdapter+Private.h",
|
||||||
"objc/Framework/Classes/PeerConnection/RTCVideoRendererAdapter.h",
|
"objc/Framework/Classes/PeerConnection/RTCVideoRendererAdapter.h",
|
||||||
@ -310,7 +307,6 @@ if (is_ios || is_mac) {
|
|||||||
"objc/Framework/Headers/WebRTC/RTCTracing.h",
|
"objc/Framework/Headers/WebRTC/RTCTracing.h",
|
||||||
"objc/Framework/Headers/WebRTC/RTCVideoCapturer.h",
|
"objc/Framework/Headers/WebRTC/RTCVideoCapturer.h",
|
||||||
"objc/Framework/Headers/WebRTC/RTCVideoFrame.h",
|
"objc/Framework/Headers/WebRTC/RTCVideoFrame.h",
|
||||||
"objc/Framework/Headers/WebRTC/RTCVideoFrameBuffer.h",
|
|
||||||
"objc/Framework/Headers/WebRTC/RTCVideoRenderer.h",
|
"objc/Framework/Headers/WebRTC/RTCVideoRenderer.h",
|
||||||
"objc/Framework/Headers/WebRTC/RTCVideoSource.h",
|
"objc/Framework/Headers/WebRTC/RTCVideoSource.h",
|
||||||
"objc/Framework/Headers/WebRTC/RTCVideoTrack.h",
|
"objc/Framework/Headers/WebRTC/RTCVideoTrack.h",
|
||||||
@ -339,11 +335,10 @@ if (is_ios || is_mac) {
|
|||||||
|
|
||||||
deps = [
|
deps = [
|
||||||
":objc_common",
|
":objc_common",
|
||||||
|
":objc_corevideoframebuffer",
|
||||||
":objc_video",
|
":objc_video",
|
||||||
":objc_videotoolbox",
|
|
||||||
"../api:video_frame_api",
|
"../api:video_frame_api",
|
||||||
"../base:rtc_base",
|
"../base:rtc_base",
|
||||||
"../common_video",
|
|
||||||
"../media:rtc_media_base",
|
"../media:rtc_media_base",
|
||||||
"../pc:libjingle_peerconnection",
|
"../pc:libjingle_peerconnection",
|
||||||
]
|
]
|
||||||
@ -459,7 +454,6 @@ if (is_ios || is_mac) {
|
|||||||
"objc/Framework/Headers/WebRTC/RTCTracing.h",
|
"objc/Framework/Headers/WebRTC/RTCTracing.h",
|
||||||
"objc/Framework/Headers/WebRTC/RTCVideoCapturer.h",
|
"objc/Framework/Headers/WebRTC/RTCVideoCapturer.h",
|
||||||
"objc/Framework/Headers/WebRTC/RTCVideoFrame.h",
|
"objc/Framework/Headers/WebRTC/RTCVideoFrame.h",
|
||||||
"objc/Framework/Headers/WebRTC/RTCVideoFrameBuffer.h",
|
|
||||||
"objc/Framework/Headers/WebRTC/RTCVideoRenderer.h",
|
"objc/Framework/Headers/WebRTC/RTCVideoRenderer.h",
|
||||||
"objc/Framework/Headers/WebRTC/RTCVideoSource.h",
|
"objc/Framework/Headers/WebRTC/RTCVideoSource.h",
|
||||||
"objc/Framework/Headers/WebRTC/RTCVideoTrack.h",
|
"objc/Framework/Headers/WebRTC/RTCVideoTrack.h",
|
||||||
@ -551,14 +545,13 @@ if (is_ios || is_mac) {
|
|||||||
"objc/Framework/Classes/VideoToolbox/nalu_rewriter.h",
|
"objc/Framework/Classes/VideoToolbox/nalu_rewriter.h",
|
||||||
"objc/Framework/Classes/VideoToolbox/videocodecfactory.h",
|
"objc/Framework/Classes/VideoToolbox/videocodecfactory.h",
|
||||||
"objc/Framework/Classes/VideoToolbox/videocodecfactory.mm",
|
"objc/Framework/Classes/VideoToolbox/videocodecfactory.mm",
|
||||||
"objc/Framework/Headers/WebRTC/RTCVideoFrameBuffer.h",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
configs += [ "..:common_objc" ]
|
configs += [ "..:common_objc" ]
|
||||||
|
|
||||||
deps = [
|
deps = [
|
||||||
":objc_common",
|
":objc_common",
|
||||||
":objc_video",
|
":objc_corevideoframebuffer",
|
||||||
"../base:rtc_base_approved",
|
"../base:rtc_base_approved",
|
||||||
"../common_video",
|
"../common_video",
|
||||||
"../media:rtc_media",
|
"../media:rtc_media",
|
||||||
|
|||||||
@ -9,7 +9,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#import "RTCMTLI420Renderer.h"
|
#import "RTCMTLI420Renderer.h"
|
||||||
#import "WebRTC/RTCVideoFrameBuffer.h"
|
|
||||||
|
|
||||||
#import <Metal/Metal.h>
|
#import <Metal/Metal.h>
|
||||||
#import <MetalKit/MetalKit.h>
|
#import <MetalKit/MetalKit.h>
|
||||||
@ -97,8 +96,6 @@ static NSString *const shaderSource = MTL_STRINGIFY(
|
|||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
id<RTCI420Buffer> buffer = [frame.buffer toI420];
|
|
||||||
|
|
||||||
// Luma (y) texture.
|
// Luma (y) texture.
|
||||||
if (!_descriptor || (_width != frame.width && _height != frame.height)) {
|
if (!_descriptor || (_width != frame.width && _height != frame.height)) {
|
||||||
_width = frame.width;
|
_width = frame.width;
|
||||||
@ -114,8 +111,8 @@ static NSString *const shaderSource = MTL_STRINGIFY(
|
|||||||
// Chroma (u,v) textures
|
// Chroma (u,v) textures
|
||||||
[_yTexture replaceRegion:MTLRegionMake2D(0, 0, _width, _height)
|
[_yTexture replaceRegion:MTLRegionMake2D(0, 0, _width, _height)
|
||||||
mipmapLevel:0
|
mipmapLevel:0
|
||||||
withBytes:buffer.dataY
|
withBytes:frame.dataY
|
||||||
bytesPerRow:buffer.strideY];
|
bytesPerRow:frame.strideY];
|
||||||
|
|
||||||
if (!_chromaDescriptor ||
|
if (!_chromaDescriptor ||
|
||||||
(_chromaWidth != frame.width / 2 && _chromaHeight != frame.height / 2)) {
|
(_chromaWidth != frame.width / 2 && _chromaHeight != frame.height / 2)) {
|
||||||
@ -133,12 +130,12 @@ static NSString *const shaderSource = MTL_STRINGIFY(
|
|||||||
|
|
||||||
[_uTexture replaceRegion:MTLRegionMake2D(0, 0, _chromaWidth, _chromaHeight)
|
[_uTexture replaceRegion:MTLRegionMake2D(0, 0, _chromaWidth, _chromaHeight)
|
||||||
mipmapLevel:0
|
mipmapLevel:0
|
||||||
withBytes:buffer.dataU
|
withBytes:frame.dataU
|
||||||
bytesPerRow:buffer.strideU];
|
bytesPerRow:frame.strideU];
|
||||||
[_vTexture replaceRegion:MTLRegionMake2D(0, 0, _chromaWidth, _chromaHeight)
|
[_vTexture replaceRegion:MTLRegionMake2D(0, 0, _chromaWidth, _chromaHeight)
|
||||||
mipmapLevel:0
|
mipmapLevel:0
|
||||||
withBytes:buffer.dataV
|
withBytes:frame.dataV
|
||||||
bytesPerRow:buffer.strideV];
|
bytesPerRow:frame.strideV];
|
||||||
|
|
||||||
return (_uTexture != nil) && (_yTexture != nil) && (_vTexture != nil);
|
return (_uTexture != nil) && (_yTexture != nil) && (_vTexture != nil);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,7 +15,6 @@
|
|||||||
|
|
||||||
#import "WebRTC/RTCLogging.h"
|
#import "WebRTC/RTCLogging.h"
|
||||||
#import "WebRTC/RTCVideoFrame.h"
|
#import "WebRTC/RTCVideoFrame.h"
|
||||||
#import "WebRTC/RTCVideoFrameBuffer.h"
|
|
||||||
|
|
||||||
#import "RTCMTLRenderer+Private.h"
|
#import "RTCMTLRenderer+Private.h"
|
||||||
|
|
||||||
@ -86,7 +85,7 @@ static NSString *const shaderSource = MTL_STRINGIFY(
|
|||||||
|
|
||||||
- (BOOL)setupTexturesForFrame:(nonnull RTCVideoFrame *)frame {
|
- (BOOL)setupTexturesForFrame:(nonnull RTCVideoFrame *)frame {
|
||||||
[super setupTexturesForFrame:frame];
|
[super setupTexturesForFrame:frame];
|
||||||
CVPixelBufferRef pixelBuffer = ((RTCCVPixelBuffer *)frame.buffer).pixelBuffer;
|
CVPixelBufferRef pixelBuffer = frame.nativeHandle;
|
||||||
|
|
||||||
id<MTLTexture> lumaTexture = nil;
|
id<MTLTexture> lumaTexture = nil;
|
||||||
id<MTLTexture> chromaTexture = nil;
|
id<MTLTexture> chromaTexture = nil;
|
||||||
|
|||||||
@ -15,7 +15,6 @@
|
|||||||
|
|
||||||
#import "WebRTC/RTCLogging.h"
|
#import "WebRTC/RTCLogging.h"
|
||||||
#import "WebRTC/RTCVideoFrame.h"
|
#import "WebRTC/RTCVideoFrame.h"
|
||||||
#import "WebRTC/RTCVideoFrameBuffer.h"
|
|
||||||
|
|
||||||
#import "RTCMTLI420Renderer.h"
|
#import "RTCMTLI420Renderer.h"
|
||||||
#import "RTCMTLNV12Renderer.h"
|
#import "RTCMTLNV12Renderer.h"
|
||||||
@ -109,7 +108,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
id<RTCMTLRenderer> renderer = nil;
|
id<RTCMTLRenderer> renderer = nil;
|
||||||
if ([self.videoFrame.buffer isKindOfClass:[RTCCVPixelBuffer class]]) {
|
if (self.videoFrame.nativeHandle) {
|
||||||
if (!self.rendererNV12) {
|
if (!self.rendererNV12) {
|
||||||
self.rendererNV12 = [RTCMTLVideoView createNV12Renderer];
|
self.rendererNV12 = [RTCMTLVideoView createNV12Renderer];
|
||||||
if (![self.rendererNV12 addRenderingDestination:self.metalView]) {
|
if (![self.rendererNV12 addRenderingDestination:self.metalView]) {
|
||||||
|
|||||||
@ -12,7 +12,6 @@
|
|||||||
|
|
||||||
#import "WebRTC/RTCCameraVideoCapturer.h"
|
#import "WebRTC/RTCCameraVideoCapturer.h"
|
||||||
#import "WebRTC/RTCLogging.h"
|
#import "WebRTC/RTCLogging.h"
|
||||||
#import "WebRTC/RTCVideoFrameBuffer.h"
|
|
||||||
|
|
||||||
#if TARGET_OS_IPHONE
|
#if TARGET_OS_IPHONE
|
||||||
#import "WebRTC/UIDevice+RTCDevice.h"
|
#import "WebRTC/UIDevice+RTCDevice.h"
|
||||||
@ -192,12 +191,11 @@ static inline BOOL IsMediaSubTypeSupported(FourCharCode mediaSubType) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RTCCVPixelBuffer *rtcPixelBuffer = [[RTCCVPixelBuffer alloc] initWithPixelBuffer:pixelBuffer];
|
|
||||||
int64_t timeStampNs = CMTimeGetSeconds(CMSampleBufferGetPresentationTimeStamp(sampleBuffer)) *
|
int64_t timeStampNs = CMTimeGetSeconds(CMSampleBufferGetPresentationTimeStamp(sampleBuffer)) *
|
||||||
kNanosecondsPerSecond;
|
kNanosecondsPerSecond;
|
||||||
RTCVideoFrame *videoFrame = [[RTCVideoFrame alloc] initWithBuffer:rtcPixelBuffer
|
RTCVideoFrame *videoFrame = [[RTCVideoFrame alloc] initWithPixelBuffer:pixelBuffer
|
||||||
rotation:_rotation
|
rotation:_rotation
|
||||||
timeStampNs:timeStampNs];
|
timeStampNs:timeStampNs];
|
||||||
[self.delegate capturer:self didCaptureVideoFrame:videoFrame];
|
[self.delegate capturer:self didCaptureVideoFrame:videoFrame];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -11,7 +11,6 @@
|
|||||||
#import "RTCFileVideoCapturer.h"
|
#import "RTCFileVideoCapturer.h"
|
||||||
|
|
||||||
#import "WebRTC/RTCLogging.h"
|
#import "WebRTC/RTCLogging.h"
|
||||||
#import "WebRTC/RTCVideoFrameBuffer.h"
|
|
||||||
|
|
||||||
@implementation RTCFileVideoCapturer {
|
@implementation RTCFileVideoCapturer {
|
||||||
AVAssetReader *_reader;
|
AVAssetReader *_reader;
|
||||||
@ -134,11 +133,10 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RTCCVPixelBuffer *rtcPixelBuffer = [[RTCCVPixelBuffer alloc] initWithPixelBuffer:pixelBuffer];
|
|
||||||
NSTimeInterval timeStampSeconds = CACurrentMediaTime();
|
NSTimeInterval timeStampSeconds = CACurrentMediaTime();
|
||||||
int64_t timeStampNs = lroundf(timeStampSeconds * NSEC_PER_SEC);
|
int64_t timeStampNs = lroundf(timeStampSeconds * NSEC_PER_SEC);
|
||||||
RTCVideoFrame *videoFrame =
|
RTCVideoFrame *videoFrame =
|
||||||
[[RTCVideoFrame alloc] initWithBuffer:rtcPixelBuffer rotation:0 timeStampNs:timeStampNs];
|
[[RTCVideoFrame alloc] initWithPixelBuffer:pixelBuffer rotation:0 timeStampNs:timeStampNs];
|
||||||
CFRelease(sampleBuffer);
|
CFRelease(sampleBuffer);
|
||||||
|
|
||||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||||
|
|||||||
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license
|
||||||
|
* that can be found in the LICENSE file in the root of the source
|
||||||
|
* tree. An additional intellectual property rights grant can be found
|
||||||
|
* in the file PATENTS. All contributing project authors may
|
||||||
|
* be found in the AUTHORS file in the root of the source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "WebRTC/RTCVideoFrame.h"
|
||||||
|
|
||||||
|
#include "webrtc/api/video/video_frame_buffer.h"
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface RTCVideoFrame ()
|
||||||
|
|
||||||
|
@property(nonatomic, readonly) rtc::scoped_refptr<webrtc::VideoFrameBuffer> videoBuffer;
|
||||||
|
|
||||||
|
- (instancetype)initWithVideoBuffer:
|
||||||
|
(rtc::scoped_refptr<webrtc::VideoFrameBuffer>)videoBuffer
|
||||||
|
rotation:(RTCVideoRotation)rotation
|
||||||
|
timeStampNs:(int64_t)timeStampNs
|
||||||
|
NS_DESIGNATED_INITIALIZER;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@ -8,22 +8,22 @@
|
|||||||
* be found in the AUTHORS file in the root of the source tree.
|
* be found in the AUTHORS file in the root of the source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#import "webrtc/sdk/objc/Framework/Headers/WebRTC/RTCVideoFrame.h"
|
#import "RTCVideoFrame+Private.h"
|
||||||
#import "webrtc/sdk/objc/Framework/Headers/WebRTC/RTCVideoFrameBuffer.h"
|
|
||||||
|
#include "webrtc/sdk/objc/Framework/Classes/Video/corevideo_frame_buffer.h"
|
||||||
|
|
||||||
@implementation RTCVideoFrame {
|
@implementation RTCVideoFrame {
|
||||||
|
rtc::scoped_refptr<webrtc::VideoFrameBuffer> _videoBuffer;
|
||||||
RTCVideoRotation _rotation;
|
RTCVideoRotation _rotation;
|
||||||
int64_t _timeStampNs;
|
int64_t _timeStampNs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@synthesize buffer = _buffer;
|
|
||||||
|
|
||||||
- (int)width {
|
- (int)width {
|
||||||
return _buffer.width;
|
return _videoBuffer->width();
|
||||||
}
|
}
|
||||||
|
|
||||||
- (int)height {
|
- (int)height {
|
||||||
return _buffer.height;
|
return _videoBuffer->height();
|
||||||
}
|
}
|
||||||
|
|
||||||
- (RTCVideoRotation)rotation {
|
- (RTCVideoRotation)rotation {
|
||||||
@ -31,51 +31,27 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (const uint8_t *)dataY {
|
- (const uint8_t *)dataY {
|
||||||
if ([_buffer conformsToProtocol:@protocol(RTCI420Buffer)]) {
|
return _videoBuffer->GetI420()->DataY();
|
||||||
return ((id<RTCI420Buffer>)_buffer).dataY;
|
|
||||||
} else {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (const uint8_t *)dataU {
|
- (const uint8_t *)dataU {
|
||||||
if ([_buffer conformsToProtocol:@protocol(RTCI420Buffer)]) {
|
return _videoBuffer->GetI420()->DataU();
|
||||||
return ((id<RTCI420Buffer>)_buffer).dataU;
|
|
||||||
} else {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (const uint8_t *)dataV {
|
- (const uint8_t *)dataV {
|
||||||
if ([_buffer conformsToProtocol:@protocol(RTCI420Buffer)]) {
|
return _videoBuffer->GetI420()->DataV();
|
||||||
return ((id<RTCI420Buffer>)_buffer).dataV;
|
|
||||||
} else {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (int)strideY {
|
- (int)strideY {
|
||||||
if ([_buffer conformsToProtocol:@protocol(RTCI420Buffer)]) {
|
return _videoBuffer->GetI420()->StrideY();
|
||||||
return ((id<RTCI420Buffer>)_buffer).strideY;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (int)strideU {
|
- (int)strideU {
|
||||||
if ([_buffer conformsToProtocol:@protocol(RTCI420Buffer)]) {
|
return _videoBuffer->GetI420()->StrideU();
|
||||||
return ((id<RTCI420Buffer>)_buffer).strideU;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (int)strideV {
|
- (int)strideV {
|
||||||
if ([_buffer conformsToProtocol:@protocol(RTCI420Buffer)]) {
|
return _videoBuffer->GetI420()->StrideV();
|
||||||
return ((id<RTCI420Buffer>)_buffer).strideV;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (int64_t)timeStampNs {
|
- (int64_t)timeStampNs {
|
||||||
@ -83,25 +59,26 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (CVPixelBufferRef)nativeHandle {
|
- (CVPixelBufferRef)nativeHandle {
|
||||||
if ([_buffer isKindOfClass:[RTCCVPixelBuffer class]]) {
|
return (_videoBuffer->type() == webrtc::VideoFrameBuffer::Type::kNative) ?
|
||||||
return ((RTCCVPixelBuffer *)_buffer).pixelBuffer;
|
static_cast<webrtc::CoreVideoFrameBuffer *>(_videoBuffer.get())->pixel_buffer() :
|
||||||
} else {
|
nil;
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (RTCVideoFrame *)newI420VideoFrame {
|
- (RTCVideoFrame *)newI420VideoFrame {
|
||||||
return [[RTCVideoFrame alloc] initWithBuffer:[_buffer toI420]
|
return [[RTCVideoFrame alloc]
|
||||||
rotation:_rotation
|
initWithVideoBuffer:_videoBuffer->ToI420()
|
||||||
timeStampNs:_timeStampNs];
|
rotation:_rotation
|
||||||
|
timeStampNs:_timeStampNs];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initWithPixelBuffer:(CVPixelBufferRef)pixelBuffer
|
- (instancetype)initWithPixelBuffer:(CVPixelBufferRef)pixelBuffer
|
||||||
rotation:(RTCVideoRotation)rotation
|
rotation:(RTCVideoRotation)rotation
|
||||||
timeStampNs:(int64_t)timeStampNs {
|
timeStampNs:(int64_t)timeStampNs {
|
||||||
return [self initWithBuffer:[[RTCCVPixelBuffer alloc] initWithPixelBuffer:pixelBuffer]
|
rtc::scoped_refptr<webrtc::VideoFrameBuffer> videoBuffer(
|
||||||
rotation:rotation
|
new rtc::RefCountedObject<webrtc::CoreVideoFrameBuffer>(pixelBuffer));
|
||||||
timeStampNs:timeStampNs];
|
return [self initWithVideoBuffer:videoBuffer
|
||||||
|
rotation:rotation
|
||||||
|
timeStampNs:timeStampNs];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initWithPixelBuffer:(CVPixelBufferRef)pixelBuffer
|
- (instancetype)initWithPixelBuffer:(CVPixelBufferRef)pixelBuffer
|
||||||
@ -113,26 +90,33 @@
|
|||||||
cropY:(int)cropY
|
cropY:(int)cropY
|
||||||
rotation:(RTCVideoRotation)rotation
|
rotation:(RTCVideoRotation)rotation
|
||||||
timeStampNs:(int64_t)timeStampNs {
|
timeStampNs:(int64_t)timeStampNs {
|
||||||
RTCCVPixelBuffer *rtcPixelBuffer = [[RTCCVPixelBuffer alloc] initWithPixelBuffer:pixelBuffer
|
rtc::scoped_refptr<webrtc::VideoFrameBuffer> videoBuffer(
|
||||||
adaptedWidth:scaledWidth
|
new rtc::RefCountedObject<webrtc::CoreVideoFrameBuffer>(
|
||||||
adaptedHeight:scaledHeight
|
pixelBuffer,
|
||||||
cropWidth:cropWidth
|
scaledWidth, scaledHeight,
|
||||||
cropHeight:cropHeight
|
cropWidth, cropHeight,
|
||||||
cropX:cropX
|
cropX, cropY));
|
||||||
cropY:cropY];
|
return [self initWithVideoBuffer:videoBuffer
|
||||||
return [self initWithBuffer:rtcPixelBuffer rotation:rotation timeStampNs:timeStampNs];
|
rotation:rotation
|
||||||
|
timeStampNs:timeStampNs];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initWithBuffer:(id<RTCVideoFrameBuffer>)buffer
|
#pragma mark - Private
|
||||||
rotation:(RTCVideoRotation)rotation
|
|
||||||
timeStampNs:(int64_t)timeStampNs {
|
- (instancetype)initWithVideoBuffer:
|
||||||
|
(rtc::scoped_refptr<webrtc::VideoFrameBuffer>)videoBuffer
|
||||||
|
rotation:(RTCVideoRotation)rotation
|
||||||
|
timeStampNs:(int64_t)timeStampNs {
|
||||||
if (self = [super init]) {
|
if (self = [super init]) {
|
||||||
_buffer = buffer;
|
_videoBuffer = videoBuffer;
|
||||||
_rotation = rotation;
|
_rotation = rotation;
|
||||||
_timeStampNs = timeStampNs;
|
_timeStampNs = timeStampNs;
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (rtc::scoped_refptr<webrtc::VideoFrameBuffer>)videoBuffer {
|
||||||
|
return _videoBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@ -8,11 +8,9 @@
|
|||||||
* be found in the AUTHORS file in the root of the source tree.
|
* be found in the AUTHORS file in the root of the source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#import "RTCI420Buffer+Private.h"
|
|
||||||
#import "RTCVideoRendererAdapter+Private.h"
|
#import "RTCVideoRendererAdapter+Private.h"
|
||||||
#import "WebRTC/RTCVideoFrame.h"
|
|
||||||
#import "WebRTC/RTCVideoFrameBuffer.h"
|
#import "RTCVideoFrame+Private.h"
|
||||||
#import "objc_frame_buffer.h"
|
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@ -27,20 +25,12 @@ class VideoRendererAdapter
|
|||||||
}
|
}
|
||||||
|
|
||||||
void OnFrame(const webrtc::VideoFrame& nativeVideoFrame) override {
|
void OnFrame(const webrtc::VideoFrame& nativeVideoFrame) override {
|
||||||
rtc::scoped_refptr<VideoFrameBuffer> video_frame_buffer = nativeVideoFrame.video_frame_buffer();
|
|
||||||
id<RTCVideoFrameBuffer> rtc_frame_buffer;
|
|
||||||
if (video_frame_buffer->type() == VideoFrameBuffer::Type::kNative) {
|
|
||||||
rtc::scoped_refptr<ObjCFrameBuffer> objc_frame_buffer(
|
|
||||||
static_cast<ObjCFrameBuffer*>(video_frame_buffer.get()));
|
|
||||||
rtc_frame_buffer = (id<RTCVideoFrameBuffer>)objc_frame_buffer->wrapped_frame_buffer();
|
|
||||||
} else {
|
|
||||||
rtc_frame_buffer = [[RTCI420Buffer alloc] initWithFrameBuffer:video_frame_buffer->ToI420()];
|
|
||||||
}
|
|
||||||
RTCVideoFrame* videoFrame = [[RTCVideoFrame alloc]
|
RTCVideoFrame* videoFrame = [[RTCVideoFrame alloc]
|
||||||
initWithBuffer:rtc_frame_buffer
|
initWithVideoBuffer:nativeVideoFrame.video_frame_buffer()
|
||||||
rotation:static_cast<RTCVideoRotation>(nativeVideoFrame.rotation())
|
rotation:static_cast<RTCVideoRotation>(
|
||||||
timeStampNs:nativeVideoFrame.timestamp_us() * rtc::kNumNanosecsPerMicrosec];
|
nativeVideoFrame.rotation())
|
||||||
|
timeStampNs:nativeVideoFrame.timestamp_us() *
|
||||||
|
rtc::kNumNanosecsPerMicrosec];
|
||||||
CGSize current_size = (videoFrame.rotation % 180 == 0)
|
CGSize current_size = (videoFrame.rotation % 180 == 0)
|
||||||
? CGSizeMake(videoFrame.width, videoFrame.height)
|
? CGSizeMake(videoFrame.width, videoFrame.height)
|
||||||
: CGSizeMake(videoFrame.height, videoFrame.width);
|
: CGSizeMake(videoFrame.height, videoFrame.width);
|
||||||
|
|||||||
@ -17,7 +17,6 @@
|
|||||||
#import "RTCNV12TextureCache.h"
|
#import "RTCNV12TextureCache.h"
|
||||||
#import "WebRTC/RTCLogging.h"
|
#import "WebRTC/RTCLogging.h"
|
||||||
#import "WebRTC/RTCVideoFrame.h"
|
#import "WebRTC/RTCVideoFrame.h"
|
||||||
#import "WebRTC/RTCVideoFrameBuffer.h"
|
|
||||||
|
|
||||||
// RTCDisplayLinkTimer wraps a CADisplayLink and is set to fire every two screen
|
// RTCDisplayLinkTimer wraps a CADisplayLink and is set to fire every two screen
|
||||||
// refreshes, which should be 30fps. We wrap the display link in order to avoid
|
// refreshes, which should be 30fps. We wrap the display link in order to avoid
|
||||||
@ -221,7 +220,7 @@
|
|||||||
}
|
}
|
||||||
[self ensureGLContext];
|
[self ensureGLContext];
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
if ([frame.buffer isKindOfClass:[RTCCVPixelBuffer class]]) {
|
if (frame.nativeHandle) {
|
||||||
if (!_nv12TextureCache) {
|
if (!_nv12TextureCache) {
|
||||||
_nv12TextureCache = [[RTCNV12TextureCache alloc] initWithContext:_glContext];
|
_nv12TextureCache = [[RTCNV12TextureCache alloc] initWithContext:_glContext];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,188 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2017 The WebRTC project authors. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by a BSD-style license
|
|
||||||
* that can be found in the LICENSE file in the root of the source
|
|
||||||
* tree. An additional intellectual property rights grant can be found
|
|
||||||
* in the file PATENTS. All contributing project authors may
|
|
||||||
* be found in the AUTHORS file in the root of the source tree.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import "WebRTC/RTCVideoFrameBuffer.h"
|
|
||||||
|
|
||||||
#include "webrtc/base/checks.h"
|
|
||||||
#include "webrtc/base/logging.h"
|
|
||||||
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
|
|
||||||
|
|
||||||
@implementation RTCCVPixelBuffer {
|
|
||||||
int _width;
|
|
||||||
int _height;
|
|
||||||
int _bufferWidth;
|
|
||||||
int _bufferHeight;
|
|
||||||
int _cropWidth;
|
|
||||||
int _cropHeight;
|
|
||||||
int _cropX;
|
|
||||||
int _cropY;
|
|
||||||
}
|
|
||||||
|
|
||||||
@synthesize pixelBuffer = _pixelBuffer;
|
|
||||||
|
|
||||||
- (instancetype)initWithPixelBuffer:(CVPixelBufferRef)pixelBuffer {
|
|
||||||
return [self initWithPixelBuffer:pixelBuffer
|
|
||||||
adaptedWidth:CVPixelBufferGetWidth(pixelBuffer)
|
|
||||||
adaptedHeight:CVPixelBufferGetHeight(pixelBuffer)
|
|
||||||
cropWidth:CVPixelBufferGetWidth(pixelBuffer)
|
|
||||||
cropHeight:CVPixelBufferGetHeight(pixelBuffer)
|
|
||||||
cropX:0
|
|
||||||
cropY:0];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype)initWithPixelBuffer:(CVPixelBufferRef)pixelBuffer
|
|
||||||
adaptedWidth:(int)adaptedWidth
|
|
||||||
adaptedHeight:(int)adaptedHeight
|
|
||||||
cropWidth:(int)cropWidth
|
|
||||||
cropHeight:(int)cropHeight
|
|
||||||
cropX:(int)cropX
|
|
||||||
cropY:(int)cropY {
|
|
||||||
if (self = [super init]) {
|
|
||||||
_width = adaptedWidth;
|
|
||||||
_height = adaptedHeight;
|
|
||||||
_pixelBuffer = pixelBuffer;
|
|
||||||
_bufferWidth = CVPixelBufferGetWidth(_pixelBuffer);
|
|
||||||
_bufferHeight = CVPixelBufferGetHeight(_pixelBuffer);
|
|
||||||
_cropWidth = cropWidth;
|
|
||||||
_cropHeight = cropHeight;
|
|
||||||
// Can only crop at even pixels.
|
|
||||||
_cropX = cropX & ~1;
|
|
||||||
_cropY = cropY & ~1;
|
|
||||||
CVBufferRetain(_pixelBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)dealloc {
|
|
||||||
CVBufferRelease(_pixelBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (int)width {
|
|
||||||
return _width;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (int)height {
|
|
||||||
return _height;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)requiresCropping {
|
|
||||||
return _cropWidth != _bufferWidth || _cropHeight != _bufferHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)requiresScalingToWidth:(int)width height:(int)height {
|
|
||||||
return _cropWidth != width || _cropHeight != height;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (int)bufferSizeForCroppingAndScalingToWidth:(int)width height:(int)height {
|
|
||||||
int srcChromaWidth = (_cropWidth + 1) / 2;
|
|
||||||
int srcChromaHeight = (_cropHeight + 1) / 2;
|
|
||||||
int dstChromaWidth = (width + 1) / 2;
|
|
||||||
int dstChromaHeight = (height + 1) / 2;
|
|
||||||
|
|
||||||
return srcChromaWidth * srcChromaHeight * 2 + dstChromaWidth * dstChromaHeight * 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)cropAndScaleTo:(CVPixelBufferRef)outputPixelBuffer withTempBuffer:(uint8_t*)tmpBuffer {
|
|
||||||
// Prepare output pointers.
|
|
||||||
RTC_DCHECK_EQ(CVPixelBufferGetPixelFormatType(outputPixelBuffer),
|
|
||||||
kCVPixelFormatType_420YpCbCr8BiPlanarFullRange);
|
|
||||||
CVReturn cvRet = CVPixelBufferLockBaseAddress(outputPixelBuffer, 0);
|
|
||||||
if (cvRet != kCVReturnSuccess) {
|
|
||||||
LOG(LS_ERROR) << "Failed to lock base address: " << cvRet;
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
const int dstWidth = CVPixelBufferGetWidth(outputPixelBuffer);
|
|
||||||
const int dstHeight = CVPixelBufferGetHeight(outputPixelBuffer);
|
|
||||||
uint8_t* dstY =
|
|
||||||
reinterpret_cast<uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(outputPixelBuffer, 0));
|
|
||||||
const int dstYStride = CVPixelBufferGetBytesPerRowOfPlane(outputPixelBuffer, 0);
|
|
||||||
uint8_t* dstUV =
|
|
||||||
reinterpret_cast<uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(outputPixelBuffer, 1));
|
|
||||||
const int dstUVStride = CVPixelBufferGetBytesPerRowOfPlane(outputPixelBuffer, 1);
|
|
||||||
|
|
||||||
// Prepare source pointers.
|
|
||||||
const OSType srcPixelFormat = CVPixelBufferGetPixelFormatType(_pixelBuffer);
|
|
||||||
RTC_DCHECK(srcPixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange ||
|
|
||||||
srcPixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange);
|
|
||||||
CVPixelBufferLockBaseAddress(_pixelBuffer, kCVPixelBufferLock_ReadOnly);
|
|
||||||
const uint8_t* srcY =
|
|
||||||
static_cast<const uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(_pixelBuffer, 0));
|
|
||||||
const int srcYStride = CVPixelBufferGetBytesPerRowOfPlane(_pixelBuffer, 0);
|
|
||||||
const uint8_t* srcUV =
|
|
||||||
static_cast<const uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(_pixelBuffer, 1));
|
|
||||||
const int srcUVStride = CVPixelBufferGetBytesPerRowOfPlane(_pixelBuffer, 1);
|
|
||||||
|
|
||||||
// Crop just by modifying pointers.
|
|
||||||
srcY += srcYStride * _cropY + _cropX;
|
|
||||||
srcUV += srcUVStride * (_cropY / 2) + _cropX;
|
|
||||||
|
|
||||||
webrtc::NV12Scale(tmpBuffer,
|
|
||||||
srcY,
|
|
||||||
srcYStride,
|
|
||||||
srcUV,
|
|
||||||
srcUVStride,
|
|
||||||
_cropWidth,
|
|
||||||
_cropHeight,
|
|
||||||
dstY,
|
|
||||||
dstYStride,
|
|
||||||
dstUV,
|
|
||||||
dstUVStride,
|
|
||||||
dstWidth,
|
|
||||||
dstHeight);
|
|
||||||
|
|
||||||
CVPixelBufferUnlockBaseAddress(_pixelBuffer, kCVPixelBufferLock_ReadOnly);
|
|
||||||
CVPixelBufferUnlockBaseAddress(outputPixelBuffer, 0);
|
|
||||||
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id<RTCI420Buffer>)toI420 {
|
|
||||||
const OSType pixelFormat = CVPixelBufferGetPixelFormatType(_pixelBuffer);
|
|
||||||
RTC_DCHECK(pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange ||
|
|
||||||
pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange);
|
|
||||||
|
|
||||||
CVPixelBufferLockBaseAddress(_pixelBuffer, kCVPixelBufferLock_ReadOnly);
|
|
||||||
const uint8_t* srcY =
|
|
||||||
static_cast<const uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(_pixelBuffer, 0));
|
|
||||||
const int srcYStride = CVPixelBufferGetBytesPerRowOfPlane(_pixelBuffer, 0);
|
|
||||||
const uint8_t* srcUV =
|
|
||||||
static_cast<const uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(_pixelBuffer, 1));
|
|
||||||
const int srcUVStride = CVPixelBufferGetBytesPerRowOfPlane(_pixelBuffer, 1);
|
|
||||||
|
|
||||||
// Crop just by modifying pointers.
|
|
||||||
srcY += srcYStride * _cropY + _cropX;
|
|
||||||
srcUV += srcUVStride * (_cropY / 2) + _cropX;
|
|
||||||
|
|
||||||
// TODO(magjed): Use a frame buffer pool.
|
|
||||||
webrtc::NV12ToI420Scaler nv12ToI420Scaler;
|
|
||||||
RTCMutableI420Buffer* i420Buffer =
|
|
||||||
[[RTCMutableI420Buffer alloc] initWithWidth:[self width] height:[self height]];
|
|
||||||
nv12ToI420Scaler.NV12ToI420Scale(srcY,
|
|
||||||
srcYStride,
|
|
||||||
srcUV,
|
|
||||||
srcUVStride,
|
|
||||||
_cropWidth,
|
|
||||||
_cropHeight,
|
|
||||||
i420Buffer.mutableDataY,
|
|
||||||
i420Buffer.strideY,
|
|
||||||
i420Buffer.mutableDataU,
|
|
||||||
i420Buffer.strideU,
|
|
||||||
i420Buffer.mutableDataV,
|
|
||||||
i420Buffer.strideV,
|
|
||||||
i420Buffer.width,
|
|
||||||
i420Buffer.height);
|
|
||||||
|
|
||||||
CVPixelBufferUnlockBaseAddress(_pixelBuffer, kCVPixelBufferLock_ReadOnly);
|
|
||||||
|
|
||||||
return i420Buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2017 The WebRTC project authors. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by a BSD-style license
|
|
||||||
* that can be found in the LICENSE file in the root of the source
|
|
||||||
* tree. An additional intellectual property rights grant can be found
|
|
||||||
* in the file PATENTS. All contributing project authors may
|
|
||||||
* be found in the AUTHORS file in the root of the source tree.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import "WebRTC/RTCVideoFrameBuffer.h"
|
|
||||||
|
|
||||||
#include "webrtc/api/video/i420_buffer.h"
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
@interface RTCI420Buffer ()
|
|
||||||
|
|
||||||
/** Initialize an RTCI420Buffer with its backing I420BufferInterface. */
|
|
||||||
- (instancetype)initWithFrameBuffer:(rtc::scoped_refptr<webrtc::I420BufferInterface>)i420Buffer;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
@ -1,108 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2017 The WebRTC project authors. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by a BSD-style license
|
|
||||||
* that can be found in the LICENSE file in the root of the source
|
|
||||||
* tree. An additional intellectual property rights grant can be found
|
|
||||||
* in the file PATENTS. All contributing project authors may
|
|
||||||
* be found in the AUTHORS file in the root of the source tree.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import "WebRTC/RTCVideoFrameBuffer.h"
|
|
||||||
|
|
||||||
#include "webrtc/api/video/i420_buffer.h"
|
|
||||||
|
|
||||||
@implementation RTCI420Buffer {
|
|
||||||
@protected
|
|
||||||
rtc::scoped_refptr<webrtc::I420BufferInterface> _i420Buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype)initWithWidth:(int)width height:(int)height {
|
|
||||||
if (self = [super init]) {
|
|
||||||
_i420Buffer = webrtc::I420Buffer::Create(width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype)initWithWidth:(int)width
|
|
||||||
height:(int)height
|
|
||||||
strideY:(int)strideY
|
|
||||||
strideU:(int)strideU
|
|
||||||
strideV:(int)strideV {
|
|
||||||
if (self = [super init]) {
|
|
||||||
_i420Buffer = webrtc::I420Buffer::Create(width, height, strideY, strideU, strideV);
|
|
||||||
}
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype)initWithFrameBuffer:(rtc::scoped_refptr<webrtc::I420BufferInterface>)i420Buffer {
|
|
||||||
if (self = [super init]) {
|
|
||||||
_i420Buffer = i420Buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (int)width {
|
|
||||||
return _i420Buffer->width();
|
|
||||||
}
|
|
||||||
|
|
||||||
- (int)height {
|
|
||||||
return _i420Buffer->height();
|
|
||||||
}
|
|
||||||
|
|
||||||
- (int)strideY {
|
|
||||||
return _i420Buffer->StrideY();
|
|
||||||
}
|
|
||||||
|
|
||||||
- (int)strideU {
|
|
||||||
return _i420Buffer->StrideU();
|
|
||||||
}
|
|
||||||
|
|
||||||
- (int)strideV {
|
|
||||||
return _i420Buffer->StrideV();
|
|
||||||
}
|
|
||||||
|
|
||||||
- (int)chromaWidth {
|
|
||||||
return _i420Buffer->ChromaWidth();
|
|
||||||
}
|
|
||||||
|
|
||||||
- (int)chromaHeight {
|
|
||||||
return _i420Buffer->ChromaHeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
- (const uint8_t *)dataY {
|
|
||||||
return _i420Buffer->DataY();
|
|
||||||
}
|
|
||||||
|
|
||||||
- (const uint8_t *)dataU {
|
|
||||||
return _i420Buffer->DataU();
|
|
||||||
}
|
|
||||||
|
|
||||||
- (const uint8_t *)dataV {
|
|
||||||
return _i420Buffer->DataV();
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id<RTCI420Buffer>)toI420 {
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation RTCMutableI420Buffer
|
|
||||||
|
|
||||||
- (uint8_t *)mutableDataY {
|
|
||||||
return static_cast<webrtc::I420Buffer *>(_i420Buffer.get())->MutableDataY();
|
|
||||||
}
|
|
||||||
|
|
||||||
- (uint8_t *)mutableDataU {
|
|
||||||
return static_cast<webrtc::I420Buffer *>(_i420Buffer.get())->MutableDataU();
|
|
||||||
}
|
|
||||||
|
|
||||||
- (uint8_t *)mutableDataV {
|
|
||||||
return static_cast<webrtc::I420Buffer *>(_i420Buffer.get())->MutableDataV();
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -9,7 +9,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#import "RTCI420TextureCache.h"
|
#import "RTCI420TextureCache.h"
|
||||||
#import "WebRTC/RTCVideoFrameBuffer.h"
|
|
||||||
|
|
||||||
#if TARGET_OS_IPHONE
|
#if TARGET_OS_IPHONE
|
||||||
#import <OpenGLES/ES3/gl.h>
|
#import <OpenGLES/ES3/gl.h>
|
||||||
@ -124,32 +123,31 @@ static const GLsizei kNumTextures = kNumTexturesPerSet * kNumTextureSets;
|
|||||||
- (void)uploadFrameToTextures:(RTCVideoFrame *)frame {
|
- (void)uploadFrameToTextures:(RTCVideoFrame *)frame {
|
||||||
_currentTextureSet = (_currentTextureSet + 1) % kNumTextureSets;
|
_currentTextureSet = (_currentTextureSet + 1) % kNumTextureSets;
|
||||||
|
|
||||||
id<RTCI420Buffer> buffer = [frame.buffer toI420];
|
const int chromaWidth = (frame.width + 1) / 2;
|
||||||
|
const int chromaHeight = (frame.height + 1) / 2;
|
||||||
const int chromaWidth = buffer.chromaWidth;
|
if (frame.strideY != frame.width ||
|
||||||
const int chromaHeight = buffer.chromaHeight;
|
frame.strideU != chromaWidth ||
|
||||||
if (buffer.strideY != frame.width || buffer.strideU != chromaWidth ||
|
frame.strideV != chromaWidth) {
|
||||||
buffer.strideV != chromaWidth) {
|
_planeBuffer.resize(frame.width * frame.height);
|
||||||
_planeBuffer.resize(buffer.width * buffer.height);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[self uploadPlane:buffer.dataY
|
[self uploadPlane:frame.dataY
|
||||||
texture:self.yTexture
|
texture:self.yTexture
|
||||||
width:buffer.width
|
width:frame.width
|
||||||
height:buffer.height
|
height:frame.height
|
||||||
stride:buffer.strideY];
|
stride:frame.strideY];
|
||||||
|
|
||||||
[self uploadPlane:buffer.dataU
|
[self uploadPlane:frame.dataU
|
||||||
texture:self.uTexture
|
texture:self.uTexture
|
||||||
width:chromaWidth
|
width:chromaWidth
|
||||||
height:chromaHeight
|
height:chromaHeight
|
||||||
stride:buffer.strideU];
|
stride:frame.strideU];
|
||||||
|
|
||||||
[self uploadPlane:buffer.dataV
|
[self uploadPlane:frame.dataV
|
||||||
texture:self.vTexture
|
texture:self.vTexture
|
||||||
width:chromaWidth
|
width:chromaWidth
|
||||||
height:chromaHeight
|
height:chromaHeight
|
||||||
stride:buffer.strideV];
|
stride:frame.strideV];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@ -11,7 +11,6 @@
|
|||||||
#import "RTCNV12TextureCache.h"
|
#import "RTCNV12TextureCache.h"
|
||||||
|
|
||||||
#import "WebRTC/RTCVideoFrame.h"
|
#import "WebRTC/RTCVideoFrame.h"
|
||||||
#import "WebRTC/RTCVideoFrameBuffer.h"
|
|
||||||
|
|
||||||
@implementation RTCNV12TextureCache {
|
@implementation RTCNV12TextureCache {
|
||||||
CVOpenGLESTextureCacheRef _textureCache;
|
CVOpenGLESTextureCacheRef _textureCache;
|
||||||
@ -74,10 +73,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)uploadFrameToTextures:(RTCVideoFrame *)frame {
|
- (BOOL)uploadFrameToTextures:(RTCVideoFrame *)frame {
|
||||||
NSAssert([frame.buffer isKindOfClass:[RTCCVPixelBuffer class]],
|
CVPixelBufferRef pixelBuffer = frame.nativeHandle;
|
||||||
@"frame must be CVPixelBuffer backed");
|
NSParameterAssert(pixelBuffer);
|
||||||
RTCCVPixelBuffer *rtcPixelBuffer = (RTCCVPixelBuffer *)frame.buffer;
|
|
||||||
CVPixelBufferRef pixelBuffer = rtcPixelBuffer.pixelBuffer;
|
|
||||||
return [self loadTexture:&_yTextureRef
|
return [self loadTexture:&_yTextureRef
|
||||||
pixelBuffer:pixelBuffer
|
pixelBuffer:pixelBuffer
|
||||||
planeIndex:0
|
planeIndex:0
|
||||||
|
|||||||
@ -15,7 +15,6 @@
|
|||||||
#import "RTCAVFoundationVideoCapturerInternal.h"
|
#import "RTCAVFoundationVideoCapturerInternal.h"
|
||||||
#import "RTCDispatcher+Private.h"
|
#import "RTCDispatcher+Private.h"
|
||||||
#import "WebRTC/RTCLogging.h"
|
#import "WebRTC/RTCLogging.h"
|
||||||
#import "WebRTC/RTCVideoFrameBuffer.h"
|
|
||||||
|
|
||||||
#include "avfoundationformatmapper.h"
|
#include "avfoundationformatmapper.h"
|
||||||
|
|
||||||
@ -24,7 +23,7 @@
|
|||||||
#include "webrtc/base/checks.h"
|
#include "webrtc/base/checks.h"
|
||||||
#include "webrtc/base/logging.h"
|
#include "webrtc/base/logging.h"
|
||||||
#include "webrtc/base/thread.h"
|
#include "webrtc/base/thread.h"
|
||||||
#include "webrtc/sdk/objc/Framework/Classes/Video/objc_frame_buffer.h"
|
#include "webrtc/sdk/objc/Framework/Classes/Video/corevideo_frame_buffer.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
|
||||||
@ -151,15 +150,12 @@ void AVFoundationVideoCapturer::CaptureSampleBuffer(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RTCCVPixelBuffer* rtcPixelBuffer = [[RTCCVPixelBuffer alloc] initWithPixelBuffer:image_buffer
|
|
||||||
adaptedWidth:adapted_width
|
|
||||||
adaptedHeight:adapted_height
|
|
||||||
cropWidth:crop_width
|
|
||||||
cropHeight:crop_height
|
|
||||||
cropX:crop_x
|
|
||||||
cropY:crop_y];
|
|
||||||
rtc::scoped_refptr<VideoFrameBuffer> buffer =
|
rtc::scoped_refptr<VideoFrameBuffer> buffer =
|
||||||
new rtc::RefCountedObject<ObjCFrameBuffer>(rtcPixelBuffer);
|
new rtc::RefCountedObject<CoreVideoFrameBuffer>(
|
||||||
|
image_buffer,
|
||||||
|
adapted_width, adapted_height,
|
||||||
|
crop_width, crop_height,
|
||||||
|
crop_x, crop_y);
|
||||||
|
|
||||||
// Applying rotation is only supported for legacy reasons and performance is
|
// Applying rotation is only supported for legacy reasons and performance is
|
||||||
// not critical here.
|
// not critical here.
|
||||||
|
|||||||
@ -1,44 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2017 The WebRTC project authors. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by a BSD-style license
|
|
||||||
* that can be found in the LICENSE file in the root of the source
|
|
||||||
* tree. An additional intellectual property rights grant can be found
|
|
||||||
* in the file PATENTS. All contributing project authors may
|
|
||||||
* be found in the AUTHORS file in the root of the source tree.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_SDK_OBJC_FRAMEWORK_CLASSES_VIDEO_OBJC_FRAME_BUFFER_H_
|
|
||||||
#define WEBRTC_SDK_OBJC_FRAMEWORK_CLASSES_VIDEO_OBJC_FRAME_BUFFER_H_
|
|
||||||
|
|
||||||
#import <CoreVideo/CoreVideo.h>
|
|
||||||
|
|
||||||
#include "webrtc/common_video/include/video_frame_buffer.h"
|
|
||||||
|
|
||||||
@protocol RTCVideoFrameBuffer;
|
|
||||||
|
|
||||||
namespace webrtc {
|
|
||||||
|
|
||||||
class ObjCFrameBuffer : public VideoFrameBuffer {
|
|
||||||
public:
|
|
||||||
explicit ObjCFrameBuffer(id<RTCVideoFrameBuffer>);
|
|
||||||
~ObjCFrameBuffer() override;
|
|
||||||
|
|
||||||
Type type() const override;
|
|
||||||
|
|
||||||
int width() const override;
|
|
||||||
int height() const override;
|
|
||||||
|
|
||||||
rtc::scoped_refptr<I420BufferInterface> ToI420() override;
|
|
||||||
|
|
||||||
id<RTCVideoFrameBuffer> wrapped_frame_buffer() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
id<RTCVideoFrameBuffer> frame_buffer_;
|
|
||||||
int width_;
|
|
||||||
int height_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace webrtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_SDK_OBJC_FRAMEWORK_CLASSES_VIDEO_OBJC_FRAME_BUFFER_H_
|
|
||||||
@ -1,78 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2017 The WebRTC project authors. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by a BSD-style license
|
|
||||||
* that can be found in the LICENSE file in the root of the source
|
|
||||||
* tree. An additional intellectual property rights grant can be found
|
|
||||||
* in the file PATENTS. All contributing project authors may
|
|
||||||
* be found in the AUTHORS file in the root of the source tree.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "webrtc/sdk/objc/Framework/Classes/Video/objc_frame_buffer.h"
|
|
||||||
|
|
||||||
#import "WebRTC/RTCVideoFrameBuffer.h"
|
|
||||||
|
|
||||||
namespace webrtc {
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
/** ObjCFrameBuffer that conforms to I420BufferInterface by wrapping RTCI420Buffer */
|
|
||||||
class ObjCI420FrameBuffer : public I420BufferInterface {
|
|
||||||
public:
|
|
||||||
explicit ObjCI420FrameBuffer(id<RTCI420Buffer> frame_buffer)
|
|
||||||
: frame_buffer_(frame_buffer), width_(frame_buffer.width), height_(frame_buffer.height) {}
|
|
||||||
~ObjCI420FrameBuffer() override{};
|
|
||||||
|
|
||||||
int width() const override { return width_; }
|
|
||||||
|
|
||||||
int height() const override { return height_; }
|
|
||||||
|
|
||||||
const uint8_t* DataY() const override { return frame_buffer_.dataY; }
|
|
||||||
|
|
||||||
const uint8_t* DataU() const override { return frame_buffer_.dataU; }
|
|
||||||
|
|
||||||
const uint8_t* DataV() const override { return frame_buffer_.dataV; }
|
|
||||||
|
|
||||||
int StrideY() const override { return frame_buffer_.strideY; }
|
|
||||||
|
|
||||||
int StrideU() const override { return frame_buffer_.strideU; }
|
|
||||||
|
|
||||||
int StrideV() const override { return frame_buffer_.strideV; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
id<RTCI420Buffer> frame_buffer_;
|
|
||||||
int width_;
|
|
||||||
int height_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
ObjCFrameBuffer::ObjCFrameBuffer(id<RTCVideoFrameBuffer> frame_buffer)
|
|
||||||
: frame_buffer_(frame_buffer), width_(frame_buffer.width), height_(frame_buffer.height) {}
|
|
||||||
|
|
||||||
ObjCFrameBuffer::~ObjCFrameBuffer() {}
|
|
||||||
|
|
||||||
VideoFrameBuffer::Type ObjCFrameBuffer::type() const {
|
|
||||||
return Type::kNative;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ObjCFrameBuffer::width() const {
|
|
||||||
return width_;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ObjCFrameBuffer::height() const {
|
|
||||||
return height_;
|
|
||||||
}
|
|
||||||
|
|
||||||
rtc::scoped_refptr<I420BufferInterface> ObjCFrameBuffer::ToI420() {
|
|
||||||
rtc::scoped_refptr<I420BufferInterface> buffer =
|
|
||||||
new rtc::RefCountedObject<ObjCI420FrameBuffer>([frame_buffer_ toI420]);
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
id<RTCVideoFrameBuffer> ObjCFrameBuffer::wrapped_frame_buffer() const {
|
|
||||||
return frame_buffer_;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace webrtc
|
|
||||||
@ -10,11 +10,10 @@
|
|||||||
|
|
||||||
#include "webrtc/sdk/objc/Framework/Classes/Video/objcvideotracksource.h"
|
#include "webrtc/sdk/objc/Framework/Classes/Video/objcvideotracksource.h"
|
||||||
|
|
||||||
#import "WebRTC/RTCVideoFrame.h"
|
#import "RTCVideoFrame+Private.h"
|
||||||
#import "WebRTC/RTCVideoFrameBuffer.h"
|
|
||||||
|
|
||||||
#include "webrtc/api/video/i420_buffer.h"
|
#include "webrtc/api/video/i420_buffer.h"
|
||||||
#include "webrtc/sdk/objc/Framework/Classes/Video/objc_frame_buffer.h"
|
#include "webrtc/sdk/objc/Framework/Classes/Video/corevideo_frame_buffer.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
|
||||||
@ -44,24 +43,18 @@ void ObjcVideoTrackSource::OnCapturedFrame(RTCVideoFrame* frame) {
|
|||||||
rtc::scoped_refptr<VideoFrameBuffer> buffer;
|
rtc::scoped_refptr<VideoFrameBuffer> buffer;
|
||||||
if (adapted_width == frame.width && adapted_height == frame.height) {
|
if (adapted_width == frame.width && adapted_height == frame.height) {
|
||||||
// No adaption - optimized path.
|
// No adaption - optimized path.
|
||||||
buffer = new rtc::RefCountedObject<ObjCFrameBuffer>(frame.buffer);
|
buffer = frame.videoBuffer;
|
||||||
} else if ([frame.buffer isKindOfClass:[RTCCVPixelBuffer class]]) {
|
} else if (frame.nativeHandle) {
|
||||||
// Adapted CVPixelBuffer frame.
|
// Adapted CVPixelBuffer frame.
|
||||||
RTCCVPixelBuffer *rtcPixelBuffer = (RTCCVPixelBuffer *)frame.buffer;
|
buffer = new rtc::RefCountedObject<CoreVideoFrameBuffer>(
|
||||||
buffer = new rtc::RefCountedObject<ObjCFrameBuffer>([[RTCCVPixelBuffer alloc]
|
static_cast<CVPixelBufferRef>(frame.nativeHandle), adapted_width, adapted_height,
|
||||||
initWithPixelBuffer:rtcPixelBuffer.pixelBuffer
|
crop_width, crop_height, crop_x, crop_y);
|
||||||
adaptedWidth:adapted_width
|
|
||||||
adaptedHeight:adapted_height
|
|
||||||
cropWidth:crop_width
|
|
||||||
cropHeight:crop_height
|
|
||||||
cropX:crop_x
|
|
||||||
cropY:crop_y]);
|
|
||||||
} else {
|
} else {
|
||||||
// Adapted I420 frame.
|
// Adapted I420 frame.
|
||||||
// TODO(magjed): Optimize this I420 path.
|
// TODO(magjed): Optimize this I420 path.
|
||||||
rtc::scoped_refptr<I420Buffer> i420_buffer = I420Buffer::Create(adapted_width, adapted_height);
|
rtc::scoped_refptr<I420Buffer> i420_buffer = I420Buffer::Create(adapted_width, adapted_height);
|
||||||
buffer = new rtc::RefCountedObject<ObjCFrameBuffer>(frame.buffer);
|
i420_buffer->CropAndScaleFrom(
|
||||||
i420_buffer->CropAndScaleFrom(*buffer->ToI420(), crop_x, crop_y, crop_width, crop_height);
|
*frame.videoBuffer->ToI420(), crop_x, crop_y, crop_width, crop_height);
|
||||||
buffer = i420_buffer;
|
buffer = i420_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -18,11 +18,9 @@
|
|||||||
#include "webrtc/base/checks.h"
|
#include "webrtc/base/checks.h"
|
||||||
#include "webrtc/base/logging.h"
|
#include "webrtc/base/logging.h"
|
||||||
#include "webrtc/common_video/include/video_frame.h"
|
#include "webrtc/common_video/include/video_frame.h"
|
||||||
#include "webrtc/sdk/objc/Framework/Classes/Video/objc_frame_buffer.h"
|
#include "webrtc/sdk/objc/Framework/Classes/Video/corevideo_frame_buffer.h"
|
||||||
#include "webrtc/sdk/objc/Framework/Classes/VideoToolbox/nalu_rewriter.h"
|
#include "webrtc/sdk/objc/Framework/Classes/VideoToolbox/nalu_rewriter.h"
|
||||||
|
|
||||||
#import "WebRTC/RTCVideoFrameBuffer.h"
|
|
||||||
|
|
||||||
#if defined(WEBRTC_IOS)
|
#if defined(WEBRTC_IOS)
|
||||||
#import "Common/RTCUIApplicationStatusObserver.h"
|
#import "Common/RTCUIApplicationStatusObserver.h"
|
||||||
#endif
|
#endif
|
||||||
@ -66,8 +64,8 @@ void VTDecompressionOutputCallback(void* decoder,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// TODO(tkchin): Handle CVO properly.
|
// TODO(tkchin): Handle CVO properly.
|
||||||
rtc::scoped_refptr<VideoFrameBuffer> buffer = new rtc::RefCountedObject<ObjCFrameBuffer>(
|
rtc::scoped_refptr<VideoFrameBuffer> buffer =
|
||||||
[[RTCCVPixelBuffer alloc] initWithPixelBuffer:image_buffer]);
|
new rtc::RefCountedObject<CoreVideoFrameBuffer>(image_buffer);
|
||||||
VideoFrame decoded_frame(buffer, decode_params->timestamp,
|
VideoFrame decoded_frame(buffer, decode_params->timestamp,
|
||||||
CMTimeGetSeconds(timestamp) * kMsPerSec,
|
CMTimeGetSeconds(timestamp) * kMsPerSec,
|
||||||
kVideoRotation_0);
|
kVideoRotation_0);
|
||||||
|
|||||||
@ -19,12 +19,11 @@
|
|||||||
#import "Common/RTCUIApplicationStatusObserver.h"
|
#import "Common/RTCUIApplicationStatusObserver.h"
|
||||||
#import "WebRTC/UIDevice+RTCDevice.h"
|
#import "WebRTC/UIDevice+RTCDevice.h"
|
||||||
#endif
|
#endif
|
||||||
#import "WebRTC/RTCVideoFrameBuffer.h"
|
|
||||||
#include "libyuv/convert_from.h"
|
#include "libyuv/convert_from.h"
|
||||||
#include "webrtc/base/checks.h"
|
#include "webrtc/base/checks.h"
|
||||||
#include "webrtc/base/logging.h"
|
#include "webrtc/base/logging.h"
|
||||||
#include "webrtc/common_video/h264/profile_level_id.h"
|
#include "webrtc/common_video/h264/profile_level_id.h"
|
||||||
#include "webrtc/sdk/objc/Framework/Classes/Video/objc_frame_buffer.h"
|
#include "webrtc/sdk/objc/Framework/Classes/Video/corevideo_frame_buffer.h"
|
||||||
#include "webrtc/sdk/objc/Framework/Classes/VideoToolbox/nalu_rewriter.h"
|
#include "webrtc/sdk/objc/Framework/Classes/VideoToolbox/nalu_rewriter.h"
|
||||||
#include "webrtc/system_wrappers/include/clock.h"
|
#include "webrtc/system_wrappers/include/clock.h"
|
||||||
|
|
||||||
@ -412,49 +411,29 @@ int H264VideoToolboxEncoder::Encode(
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
CVPixelBufferRef pixel_buffer = nullptr;
|
CVPixelBufferRef pixel_buffer;
|
||||||
if (frame.video_frame_buffer()->type() == VideoFrameBuffer::Type::kNative) {
|
if (frame.video_frame_buffer()->type() == VideoFrameBuffer::Type::kNative) {
|
||||||
// Native frame.
|
rtc::scoped_refptr<CoreVideoFrameBuffer> core_video_frame_buffer(
|
||||||
rtc::scoped_refptr<ObjCFrameBuffer> objc_frame_buffer(
|
static_cast<CoreVideoFrameBuffer*>(frame.video_frame_buffer().get()));
|
||||||
static_cast<ObjCFrameBuffer*>(frame.video_frame_buffer().get()));
|
if (!core_video_frame_buffer->RequiresCropping()) {
|
||||||
id<RTCVideoFrameBuffer> wrapped_frame_buffer =
|
pixel_buffer = core_video_frame_buffer->pixel_buffer();
|
||||||
(id<RTCVideoFrameBuffer>)objc_frame_buffer->wrapped_frame_buffer();
|
// This pixel buffer might have a higher resolution than what the
|
||||||
|
// compression session is configured to. The compression session can
|
||||||
if ([wrapped_frame_buffer isKindOfClass:[RTCCVPixelBuffer class]]) {
|
// handle that and will output encoded frames in the configured
|
||||||
RTCCVPixelBuffer* rtc_pixel_buffer = (RTCCVPixelBuffer*)wrapped_frame_buffer;
|
// resolution regardless of the input pixel buffer resolution.
|
||||||
if (![rtc_pixel_buffer requiresCropping]) {
|
CVBufferRetain(pixel_buffer);
|
||||||
// This pixel buffer might have a higher resolution than what the
|
} else {
|
||||||
// compression session is configured to. The compression session can
|
// Cropping required, we need to crop and scale to a new pixel buffer.
|
||||||
// handle that and will output encoded frames in the configured
|
pixel_buffer = internal::CreatePixelBuffer(pixel_buffer_pool);
|
||||||
// resolution regardless of the input pixel buffer resolution.
|
if (!pixel_buffer) {
|
||||||
pixel_buffer = rtc_pixel_buffer.pixelBuffer;
|
return WEBRTC_VIDEO_CODEC_ERROR;
|
||||||
CVBufferRetain(pixel_buffer);
|
}
|
||||||
} else {
|
if (!core_video_frame_buffer->CropAndScaleTo(&nv12_scale_buffer_,
|
||||||
// Cropping required, we need to crop and scale to a new pixel buffer.
|
pixel_buffer)) {
|
||||||
pixel_buffer = internal::CreatePixelBuffer(pixel_buffer_pool);
|
return WEBRTC_VIDEO_CODEC_ERROR;
|
||||||
if (!pixel_buffer) {
|
|
||||||
return WEBRTC_VIDEO_CODEC_ERROR;
|
|
||||||
}
|
|
||||||
int dst_width = CVPixelBufferGetWidth(pixel_buffer);
|
|
||||||
int dst_height = CVPixelBufferGetHeight(pixel_buffer);
|
|
||||||
if ([rtc_pixel_buffer requiresScalingToWidth:dst_width height:dst_height]) {
|
|
||||||
int size =
|
|
||||||
[rtc_pixel_buffer bufferSizeForCroppingAndScalingToWidth:dst_width height:dst_height];
|
|
||||||
nv12_scale_buffer_.resize(size);
|
|
||||||
} else {
|
|
||||||
nv12_scale_buffer_.clear();
|
|
||||||
}
|
|
||||||
nv12_scale_buffer_.shrink_to_fit();
|
|
||||||
if (![rtc_pixel_buffer cropAndScaleTo:pixel_buffer
|
|
||||||
withTempBuffer:nv12_scale_buffer_.data()]) {
|
|
||||||
return WEBRTC_VIDEO_CODEC_ERROR;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
|
||||||
if (!pixel_buffer) {
|
|
||||||
// We did not have a native frame, or the ObjCVideoFrame wrapped a non-native frame
|
|
||||||
pixel_buffer = internal::CreatePixelBuffer(pixel_buffer_pool);
|
pixel_buffer = internal::CreatePixelBuffer(pixel_buffer_pool);
|
||||||
if (!pixel_buffer) {
|
if (!pixel_buffer) {
|
||||||
return WEBRTC_VIDEO_CODEC_ERROR;
|
return WEBRTC_VIDEO_CODEC_ERROR;
|
||||||
|
|||||||
@ -22,8 +22,6 @@ typedef NS_ENUM(NSInteger, RTCVideoRotation) {
|
|||||||
RTCVideoRotation_270 = 270,
|
RTCVideoRotation_270 = 270,
|
||||||
};
|
};
|
||||||
|
|
||||||
@protocol RTCVideoFrameBuffer;
|
|
||||||
|
|
||||||
// RTCVideoFrame is an ObjectiveC version of webrtc::VideoFrame.
|
// RTCVideoFrame is an ObjectiveC version of webrtc::VideoFrame.
|
||||||
RTC_EXPORT
|
RTC_EXPORT
|
||||||
@interface RTCVideoFrame : NSObject
|
@interface RTCVideoFrame : NSObject
|
||||||
@ -38,35 +36,27 @@ RTC_EXPORT
|
|||||||
* is null. It is always possible to get such a frame by calling
|
* is null. It is always possible to get such a frame by calling
|
||||||
* newI420VideoFrame.
|
* newI420VideoFrame.
|
||||||
*/
|
*/
|
||||||
@property(nonatomic, readonly, nullable)
|
@property(nonatomic, readonly, nullable) const uint8_t *dataY;
|
||||||
const uint8_t *dataY DEPRECATED_MSG_ATTRIBUTE("use [buffer toI420]");
|
@property(nonatomic, readonly, nullable) const uint8_t *dataU;
|
||||||
@property(nonatomic, readonly, nullable)
|
@property(nonatomic, readonly, nullable) const uint8_t *dataV;
|
||||||
const uint8_t *dataU DEPRECATED_MSG_ATTRIBUTE("use [buffer toI420]");
|
@property(nonatomic, readonly) int strideY;
|
||||||
@property(nonatomic, readonly, nullable)
|
@property(nonatomic, readonly) int strideU;
|
||||||
const uint8_t *dataV DEPRECATED_MSG_ATTRIBUTE("use [buffer toI420]");
|
@property(nonatomic, readonly) int strideV;
|
||||||
@property(nonatomic, readonly) int strideY DEPRECATED_MSG_ATTRIBUTE("use [buffer toI420]");
|
|
||||||
@property(nonatomic, readonly) int strideU DEPRECATED_MSG_ATTRIBUTE("use [buffer toI420]");
|
|
||||||
@property(nonatomic, readonly) int strideV DEPRECATED_MSG_ATTRIBUTE("use [buffer toI420]");
|
|
||||||
|
|
||||||
/** Timestamp in nanoseconds. */
|
/** Timestamp in nanoseconds. */
|
||||||
@property(nonatomic, readonly) int64_t timeStampNs;
|
@property(nonatomic, readonly) int64_t timeStampNs;
|
||||||
|
|
||||||
/** The native handle should be a pixel buffer on iOS. */
|
/** The native handle should be a pixel buffer on iOS. */
|
||||||
@property(nonatomic, readonly)
|
@property(nonatomic, readonly) CVPixelBufferRef nativeHandle;
|
||||||
CVPixelBufferRef nativeHandle DEPRECATED_MSG_ATTRIBUTE("use buffer instead");
|
|
||||||
|
|
||||||
@property(nonatomic, readonly) id<RTCVideoFrameBuffer> buffer;
|
|
||||||
|
|
||||||
- (instancetype)init NS_UNAVAILABLE;
|
- (instancetype)init NS_UNAVAILABLE;
|
||||||
- (instancetype)new NS_UNAVAILABLE;
|
- (instancetype)new NS_UNAVAILABLE;
|
||||||
|
|
||||||
/** Initialize an RTCVideoFrame from a pixel buffer, rotation, and timestamp.
|
/** Initialize an RTCVideoFrame from a pixel buffer, rotation, and timestamp.
|
||||||
* Deprecated - initialize with a RTCCVPixelBuffer instead
|
|
||||||
*/
|
*/
|
||||||
- (instancetype)initWithPixelBuffer:(CVPixelBufferRef)pixelBuffer
|
- (instancetype)initWithPixelBuffer:(CVPixelBufferRef)pixelBuffer
|
||||||
rotation:(RTCVideoRotation)rotation
|
rotation:(RTCVideoRotation)rotation
|
||||||
timeStampNs:(int64_t)timeStampNs
|
timeStampNs:(int64_t)timeStampNs;
|
||||||
DEPRECATED_MSG_ATTRIBUTE("use initWithBuffer instead");
|
|
||||||
|
|
||||||
/** Initialize an RTCVideoFrame from a pixel buffer combined with cropping and
|
/** Initialize an RTCVideoFrame from a pixel buffer combined with cropping and
|
||||||
* scaling. Cropping will be applied first on the pixel buffer, followed by
|
* scaling. Cropping will be applied first on the pixel buffer, followed by
|
||||||
@ -80,14 +70,7 @@ RTC_EXPORT
|
|||||||
cropX:(int)cropX
|
cropX:(int)cropX
|
||||||
cropY:(int)cropY
|
cropY:(int)cropY
|
||||||
rotation:(RTCVideoRotation)rotation
|
rotation:(RTCVideoRotation)rotation
|
||||||
timeStampNs:(int64_t)timeStampNs
|
timeStampNs:(int64_t)timeStampNs;
|
||||||
DEPRECATED_MSG_ATTRIBUTE("use initWithBuffer instead");
|
|
||||||
|
|
||||||
/** Initialize an RTCVideoFrame from a frame buffer, rotation, and timestamp.
|
|
||||||
*/
|
|
||||||
- (instancetype)initWithBuffer:(id<RTCVideoFrameBuffer>)frameBuffer
|
|
||||||
rotation:(RTCVideoRotation)rotation
|
|
||||||
timeStampNs:(int64_t)timeStampNs;
|
|
||||||
|
|
||||||
/** Return a frame that is guaranteed to be I420, i.e. it is possible to access
|
/** Return a frame that is guaranteed to be I420, i.e. it is possible to access
|
||||||
* the YUV data on it.
|
* the YUV data on it.
|
||||||
|
|||||||
@ -1,99 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2017 The WebRTC project authors. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by a BSD-style license
|
|
||||||
* that can be found in the LICENSE file in the root of the source
|
|
||||||
* tree. An additional intellectual property rights grant can be found
|
|
||||||
* in the file PATENTS. All contributing project authors may
|
|
||||||
* be found in the AUTHORS file in the root of the source tree.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <AVFoundation/AVFoundation.h>
|
|
||||||
#import <WebRTC/RTCMacros.h>
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
@protocol RTCI420Buffer;
|
|
||||||
|
|
||||||
// RTCVideoFrameBuffer is an ObjectiveC version of webrtc::VideoFrameBuffer.
|
|
||||||
RTC_EXPORT
|
|
||||||
@protocol RTCVideoFrameBuffer <NSObject>
|
|
||||||
|
|
||||||
@property(nonatomic, readonly) int width;
|
|
||||||
@property(nonatomic, readonly) int height;
|
|
||||||
|
|
||||||
- (id<RTCI420Buffer>)toI420;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
/** Protocol for RTCVideoFrameBuffers containing YUV planar data. */
|
|
||||||
@protocol RTCYUVPlanarBuffer <RTCVideoFrameBuffer>
|
|
||||||
|
|
||||||
@property(nonatomic, readonly) int chromaWidth;
|
|
||||||
@property(nonatomic, readonly) int chromaHeight;
|
|
||||||
@property(nonatomic, readonly) const uint8_t *dataY;
|
|
||||||
@property(nonatomic, readonly) const uint8_t *dataU;
|
|
||||||
@property(nonatomic, readonly) const uint8_t *dataV;
|
|
||||||
@property(nonatomic, readonly) int strideY;
|
|
||||||
@property(nonatomic, readonly) int strideU;
|
|
||||||
@property(nonatomic, readonly) int strideV;
|
|
||||||
|
|
||||||
- (instancetype)initWithWidth:(int)width height:(int)height;
|
|
||||||
- (instancetype)initWithWidth:(int)width
|
|
||||||
height:(int)height
|
|
||||||
strideY:(int)strideY
|
|
||||||
strideU:(int)strideU
|
|
||||||
strideV:(int)strideV;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
/** Extension of the YUV planar data buffer with mutable data access */
|
|
||||||
@protocol RTCMutableYUVPlanarBuffer <RTCYUVPlanarBuffer>
|
|
||||||
|
|
||||||
@property(nonatomic, readonly) uint8_t *mutableDataY;
|
|
||||||
@property(nonatomic, readonly) uint8_t *mutableDataU;
|
|
||||||
@property(nonatomic, readonly) uint8_t *mutableDataV;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
/** Protocol for RTCYUVPlanarBuffers containing I420 data */
|
|
||||||
@protocol RTCI420Buffer <RTCYUVPlanarBuffer>
|
|
||||||
@end
|
|
||||||
|
|
||||||
/** Extension of the I420 buffer with mutable data access */
|
|
||||||
@protocol RTCMutableI420Buffer <RTCI420Buffer, RTCMutableYUVPlanarBuffer>
|
|
||||||
@end
|
|
||||||
|
|
||||||
/** RTCVideoFrameBuffer containing a CVPixelBufferRef */
|
|
||||||
@interface RTCCVPixelBuffer : NSObject <RTCVideoFrameBuffer>
|
|
||||||
|
|
||||||
@property(nonatomic, readonly) CVPixelBufferRef pixelBuffer;
|
|
||||||
|
|
||||||
- (instancetype)initWithPixelBuffer:(CVPixelBufferRef)pixelBuffer;
|
|
||||||
- (instancetype)initWithPixelBuffer:(CVPixelBufferRef)pixelBuffer
|
|
||||||
adaptedWidth:(int)adaptedWidth
|
|
||||||
adaptedHeight:(int)adaptedHeight
|
|
||||||
cropWidth:(int)cropWidth
|
|
||||||
cropHeight:(int)cropHeight
|
|
||||||
cropX:(int)cropX
|
|
||||||
cropY:(int)cropY;
|
|
||||||
|
|
||||||
- (BOOL)requiresCropping;
|
|
||||||
- (BOOL)requiresScalingToWidth:(int)width height:(int)height;
|
|
||||||
- (int)bufferSizeForCroppingAndScalingToWidth:(int)width height:(int)height;
|
|
||||||
/** The minimum size of the |tmpBuffer| must be the number of bytes returned from the
|
|
||||||
* bufferSizeForCroppingAndScalingToWidth:height: method.
|
|
||||||
*/
|
|
||||||
- (BOOL)cropAndScaleTo:(CVPixelBufferRef)outputPixelBuffer withTempBuffer:(uint8_t *)tmpBuffer;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
/** RTCI420Buffer implements the RTCI420Buffer protocol */
|
|
||||||
@interface RTCI420Buffer : NSObject <RTCI420Buffer>
|
|
||||||
@end
|
|
||||||
|
|
||||||
/** Mutable version of RTCI420Buffer */
|
|
||||||
@interface RTCMutableI420Buffer : RTCI420Buffer <RTCMutableI420Buffer>
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
@ -15,7 +15,6 @@
|
|||||||
|
|
||||||
#include <Metal/RTCMTLNV12Renderer.h>
|
#include <Metal/RTCMTLNV12Renderer.h>
|
||||||
#include <WebRTC/RTCMTLVideoView.h>
|
#include <WebRTC/RTCMTLVideoView.h>
|
||||||
#include <WebRTC/RTCVideoFrameBuffer.h>
|
|
||||||
|
|
||||||
// Extension of RTCMTLVideoView for testing purposes.
|
// Extension of RTCMTLVideoView for testing purposes.
|
||||||
@interface RTCMTLVideoView (Testing)
|
@interface RTCMTLVideoView (Testing)
|
||||||
@ -60,14 +59,12 @@
|
|||||||
self.frameMock = nil;
|
self.frameMock = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)frameMockWithCVPixelBuffer:(BOOL)hasCVPixelBuffer {
|
- (id)frameMockWithNativeHandle:(BOOL)hasNativeHandle {
|
||||||
id frameMock = OCMClassMock([RTCVideoFrame class]);
|
id frameMock = OCMClassMock([RTCVideoFrame class]);
|
||||||
if (hasCVPixelBuffer) {
|
if (hasNativeHandle) {
|
||||||
OCMStub([frameMock buffer])
|
OCMStub([frameMock nativeHandle]).andReturn((CVPixelBufferRef)[OCMArg anyPointer]);
|
||||||
.andReturn(
|
|
||||||
[[RTCCVPixelBuffer alloc] initWithPixelBuffer:(CVPixelBufferRef)[OCMArg anyPointer]]);
|
|
||||||
} else {
|
} else {
|
||||||
OCMStub([frameMock buffer]).andReturn([[RTCI420Buffer alloc] initWithWidth:200 height:200]);
|
OCMStub([frameMock nativeHandle]).andReturn((CVPixelBufferRef) nullptr);
|
||||||
}
|
}
|
||||||
return frameMock;
|
return frameMock;
|
||||||
}
|
}
|
||||||
@ -102,7 +99,7 @@
|
|||||||
RTCMTLVideoView *realView = [[RTCMTLVideoView alloc] init];
|
RTCMTLVideoView *realView = [[RTCMTLVideoView alloc] init];
|
||||||
self.frameMock = OCMClassMock([RTCVideoFrame class]);
|
self.frameMock = OCMClassMock([RTCVideoFrame class]);
|
||||||
|
|
||||||
[[self.frameMock reject] buffer];
|
[[self.frameMock reject] nativeHandle];
|
||||||
[[self.classMock reject] createNV12Renderer];
|
[[self.classMock reject] createNV12Renderer];
|
||||||
[[self.classMock reject] createI420Renderer];
|
[[self.classMock reject] createI420Renderer];
|
||||||
|
|
||||||
@ -119,7 +116,7 @@
|
|||||||
// given
|
// given
|
||||||
OCMStub([self.classMock isMetalAvailable]).andReturn(YES);
|
OCMStub([self.classMock isMetalAvailable]).andReturn(YES);
|
||||||
self.rendererI420Mock = [self rendererMockWithSuccessfulSetup:YES];
|
self.rendererI420Mock = [self rendererMockWithSuccessfulSetup:YES];
|
||||||
self.frameMock = [self frameMockWithCVPixelBuffer:NO];
|
self.frameMock = [self frameMockWithNativeHandle:NO];
|
||||||
|
|
||||||
OCMExpect([self.rendererI420Mock drawFrame:self.frameMock]);
|
OCMExpect([self.rendererI420Mock drawFrame:self.frameMock]);
|
||||||
OCMExpect([self.classMock createI420Renderer]).andReturn(self.rendererI420Mock);
|
OCMExpect([self.classMock createI420Renderer]).andReturn(self.rendererI420Mock);
|
||||||
@ -140,7 +137,7 @@
|
|||||||
// given
|
// given
|
||||||
OCMStub([self.classMock isMetalAvailable]).andReturn(YES);
|
OCMStub([self.classMock isMetalAvailable]).andReturn(YES);
|
||||||
self.rendererNV12Mock = [self rendererMockWithSuccessfulSetup:YES];
|
self.rendererNV12Mock = [self rendererMockWithSuccessfulSetup:YES];
|
||||||
self.frameMock = [self frameMockWithCVPixelBuffer:YES];
|
self.frameMock = [self frameMockWithNativeHandle:YES];
|
||||||
|
|
||||||
OCMExpect([self.rendererNV12Mock drawFrame:self.frameMock]);
|
OCMExpect([self.rendererNV12Mock drawFrame:self.frameMock]);
|
||||||
OCMExpect([self.classMock createNV12Renderer]).andReturn(self.rendererNV12Mock);
|
OCMExpect([self.classMock createNV12Renderer]).andReturn(self.rendererNV12Mock);
|
||||||
|
|||||||
Reference in New Issue
Block a user