Reland of Injectable Obj-C video codecs (patchset #1 id:1 of https://codereview.webrtc.org/2975963002/ )

Reason for revert:
New CL for fixing the issues

Original issue's description:
> Revert of Injectable Obj-C video codecs (patchset #8 id:140001 of https://codereview.webrtc.org/2966023002/ )
>
> Reason for revert:
> Causes no video in certain scenarios. Please come up with a test plan or unit test to prevent such problems in the future.
>
> Original issue's description:
> > Injectable Obj-C video codecs
> >
> > Initial CL for this effort, with a working RTCVideoEncoder/Decoder for H264
> > (wrapping the VideoToolbox codec).
> >
> > Some notes / things left to do:
> >   - There are some hard-coded references to codec types that are supported by
> >     webrtc::VideoCodec, cricket::VideoCodec, webrtc::CodecSpecificInfo etc
> >     since we need to convert to/from these types in ObjCVideoEncoder/Decoder.
> >     These types would need to be more codec agnostic to avoid this.
> >   - Most interfaces are borrowed from the design document for injectable
> >     codecs in Android. Some data in the corresponding C++ classes is discarded
> >     when converting to the Obj-C version, since it has fewer fields. I have not
> >     verified whether all data that we do keep is needed, or whether we might be
> >     losing anything useful in these conversions.
> >   - Implement the VideoToolbox codec code directly in the RTCVideoEncoderH264
> >     classes, instead of wrapping webrtc::H264VideoToolboxEncoder / decoder.
> >     Eliminates converting between ObjC/C++ types outside the ObjCVideoEncoder/
> >     Decoder wrapper classes.
> >   - List the injected codec factory's supported codecs in the list of codecs in
> >     AppRTCMobile.
> >
> > BUG=webrtc:7924
> > R=magjed@webrtc.org
> >
> > Review-Url: https://codereview.webrtc.org/2966023002 .
> > Cr-Commit-Position: refs/heads/master@{#18928}
> > Committed: a0349c138d
>
> TBR=magjed@webrtc.org,andersc@webrtc.org
> # Not skipping CQ checks because original CL landed more than 1 days ago.
> BUG=webrtc:7924
> NOTRY=true
>
> Review-Url: https://codereview.webrtc.org/2975963002
> Cr-Commit-Position: refs/heads/master@{#18979}
> Committed: 1095ada7ad

R=magjed@webrtc.org
TBR=tkchin@webrtc.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=webrtc:7924

Review-Url: https://codereview.webrtc.org/2981583002 .
Cr-Commit-Position: refs/heads/master@{#19002}
This commit is contained in:
Anders Carlsson
2017-07-13 16:03:55 +02:00
parent a8a3515997
commit a5f1de1e65
21 changed files with 1443 additions and 10 deletions

View File

@ -0,0 +1,74 @@
/*
* 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/RTCVideoCodec.h"
#import "RTCVideoCodec+Private.h"
@implementation RTCEncodedImage
@synthesize buffer = _buffer;
@synthesize encodedWidth = _encodedWidth;
@synthesize encodedHeight = _encodedHeight;
@synthesize timeStamp = _timeStamp;
@synthesize captureTimeMs = _captureTimeMs;
@synthesize ntpTimeMs = _ntpTimeMs;
@synthesize isTimingFrame = _isTimingFrame;
@synthesize encodeStartMs = _encodeStartMs;
@synthesize encodeFinishMs = _encodeFinishMs;
@synthesize frameType = _frameType;
@synthesize rotation = _rotation;
@synthesize completeFrame = _completeFrame;
@synthesize qp = _qp;
- (instancetype)initWithEncodedImage:(webrtc::EncodedImage)encodedImage {
if (self = [super init]) {
// Wrap the buffer in NSData without copying, do not take ownership.
_buffer = [NSData dataWithBytesNoCopy:encodedImage._buffer
length:encodedImage._length
freeWhenDone:NO];
_encodedWidth = encodedImage._encodedWidth;
_encodedHeight = encodedImage._encodedHeight;
_timeStamp = encodedImage._timeStamp;
_captureTimeMs = encodedImage.capture_time_ms_;
_ntpTimeMs = encodedImage.ntp_time_ms_;
_isTimingFrame = encodedImage.timing_.is_timing_frame;
_encodeStartMs = encodedImage.timing_.encode_start_ms;
_encodeFinishMs = encodedImage.timing_.encode_finish_ms;
_frameType = (RTCFrameType)encodedImage._frameType;
_rotation = encodedImage.rotation_;
_completeFrame = encodedImage._completeFrame;
_qp = encodedImage.qp_ == -1 ? nil : @(encodedImage.qp_);
}
return self;
}
- (webrtc::EncodedImage)toCpp {
// Return the pointer without copying.
webrtc::EncodedImage encodedImage(
(uint8_t *)_buffer.bytes, (size_t)_buffer.length, (size_t)_buffer.length);
encodedImage._encodedWidth = _encodedWidth;
encodedImage._encodedHeight = _encodedHeight;
encodedImage._timeStamp = _timeStamp;
encodedImage.capture_time_ms_ = _captureTimeMs;
encodedImage.ntp_time_ms_ = _ntpTimeMs;
encodedImage.timing_.is_timing_frame = _isTimingFrame;
encodedImage.timing_.encode_start_ms = _encodeStartMs;
encodedImage.timing_.encode_finish_ms = _encodeFinishMs;
encodedImage._frameType = webrtc::FrameType(_frameType);
encodedImage.rotation_ = webrtc::VideoRotation(_rotation);
encodedImage._completeFrame = _completeFrame;
encodedImage.qp_ = _qp ? _qp.intValue : -1;
return encodedImage;
}
@end

View File

@ -11,6 +11,7 @@
#import "RTCPeerConnectionFactory+Private.h"
#import "NSString+StdString.h"
#import "RTCAVFoundationVideoSource+Private.h"
#import "RTCAudioSource+Private.h"
#import "RTCAudioTrack+Private.h"
#import "RTCMediaConstraints+Private.h"
@ -18,11 +19,15 @@
#import "RTCPeerConnection+Private.h"
#import "RTCVideoSource+Private.h"
#import "RTCVideoTrack+Private.h"
#import "RTCAVFoundationVideoSource+Private.h"
#import "WebRTC/RTCLogging.h"
#import "WebRTC/RTCVideoCodecFactory.h"
#ifndef HAVE_NO_MEDIA
#import "WebRTC/RTCVideoCodecH264.h"
#endif
#include "PeerConnection/objc_video_decoder_factory.h"
#include "PeerConnection/objc_video_encoder_factory.h"
#include "Video/objcvideotracksource.h"
#include "VideoToolbox/videocodecfactory.h"
#include "webrtc/api/videosourceproxy.h"
// Adding the nogncheck to disable the including header check.
// The no-media version PeerConnectionFactory doesn't depend on media related
@ -41,7 +46,17 @@
@synthesize nativeFactory = _nativeFactory;
- (instancetype)init {
if ((self = [super init])) {
#ifdef HAVE_NO_MEDIA
return [self initWithEncoderFactory:nil decoderFactory:nil];
#else
return [self initWithEncoderFactory:[[RTCVideoEncoderFactoryH264 alloc] init]
decoderFactory:[[RTCVideoDecoderFactoryH264 alloc] init]];
#endif
}
- (instancetype)initWithEncoderFactory:(nullable id<RTCVideoEncoderFactory>)encoderFactory
decoderFactory:(nullable id<RTCVideoDecoderFactory>)decoderFactory {
if (self = [super init]) {
_networkThread = rtc::Thread::CreateWithSocketServer();
BOOL result = _networkThread->Start();
NSAssert(result, @"Failed to start network thread.");
@ -68,8 +83,14 @@
std::unique_ptr<webrtc::CallFactoryInterface>(),
std::unique_ptr<webrtc::RtcEventLogFactoryInterface>());
#else
const auto encoder_factory = new webrtc::VideoToolboxVideoEncoderFactory();
const auto decoder_factory = new webrtc::VideoToolboxVideoDecoderFactory();
cricket::WebRtcVideoEncoderFactory *encoder_factory = nullptr;
cricket::WebRtcVideoDecoderFactory *decoder_factory = nullptr;
if (encoderFactory) {
encoder_factory = new webrtc::ObjCVideoEncoderFactory(encoderFactory);
}
if (decoderFactory) {
decoder_factory = new webrtc::ObjCVideoDecoderFactory(decoderFactory);
}
// Ownership of encoder/decoder factories is passed on to the
// peerconnectionfactory, that handles deleting them.

View File

@ -0,0 +1,61 @@
/*
* 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/RTCVideoCodec.h"
#include "webrtc/modules/include/module_common_types.h"
@implementation RTCRtpFragmentationHeader
@synthesize fragmentationOffset = _fragmentationOffset;
@synthesize fragmentationLength = _fragmentationLength;
@synthesize fragmentationTimeDiff = _fragmentationTimeDiff;
@synthesize fragmentationPlType = _fragmentationPlType;
- (instancetype)initWithFragmentationHeader:
(const webrtc::RTPFragmentationHeader *__nullable)fragmentationHeader {
if (self = [super init]) {
if (fragmentationHeader) {
int count = fragmentationHeader->fragmentationVectorSize;
NSMutableArray *offsets = [NSMutableArray array];
NSMutableArray *lengths = [NSMutableArray array];
NSMutableArray *timeDiffs = [NSMutableArray array];
NSMutableArray *plTypes = [NSMutableArray array];
for (int i = 0; i < count; ++i) {
[offsets addObject:@(fragmentationHeader->fragmentationOffset[i])];
[lengths addObject:@(fragmentationHeader->fragmentationLength[i])];
[timeDiffs addObject:@(fragmentationHeader->fragmentationTimeDiff[i])];
[plTypes addObject:@(fragmentationHeader->fragmentationPlType[i])];
}
_fragmentationOffset = [offsets copy];
_fragmentationLength = [lengths copy];
_fragmentationTimeDiff = [timeDiffs copy];
_fragmentationPlType = [plTypes copy];
}
}
return self;
}
- (webrtc::RTPFragmentationHeader *)toCpp {
webrtc::RTPFragmentationHeader *fragmentationHeader = new webrtc::RTPFragmentationHeader;
fragmentationHeader->VerifyAndAllocateFragmentationHeader(_fragmentationOffset.count);
for (NSUInteger i = 0; i < _fragmentationOffset.count; ++i) {
fragmentationHeader->fragmentationOffset[i] = (size_t)_fragmentationOffset[i].unsignedIntValue;
fragmentationHeader->fragmentationLength[i] = (size_t)_fragmentationLength[i].unsignedIntValue;
fragmentationHeader->fragmentationTimeDiff[i] =
(uint16_t)_fragmentationOffset[i].unsignedIntValue;
fragmentationHeader->fragmentationPlType[i] = (uint8_t)_fragmentationOffset[i].unsignedIntValue;
}
return fragmentationHeader;
}
@end

View File

@ -0,0 +1,57 @@
/*
* 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/RTCVideoCodec.h"
#import "WebRTC/RTCVideoCodecH264.h"
#include "webrtc/common_video/include/video_frame.h"
#include "webrtc/media/base/codec.h"
#include "webrtc/modules/video_coding/include/video_codec_interface.h"
NS_ASSUME_NONNULL_BEGIN
/* Interfaces for converting to/from internal C++ formats. */
@interface RTCEncodedImage ()
- (instancetype)initWithEncodedImage:(webrtc::EncodedImage)encodedImage;
- (webrtc::EncodedImage)toCpp;
@end
@interface RTCVideoEncoderSettings ()
- (instancetype)initWithVideoCodec:(const webrtc::VideoCodec *__nullable)videoCodec;
- (webrtc::VideoCodec *)toCpp;
@end
@interface RTCCodecSpecificInfoH264 ()
- (webrtc::CodecSpecificInfo)toCpp;
@end
@interface RTCRtpFragmentationHeader ()
- (instancetype)initWithFragmentationHeader:
(const webrtc::RTPFragmentationHeader *__nullable)fragmentationHeader;
- (webrtc::RTPFragmentationHeader *)toCpp;
@end
@interface RTCVideoCodecInfo ()
- (instancetype)initWithVideoCodec:(cricket::VideoCodec)videoCodec;
- (cricket::VideoCodec)toCpp;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,114 @@
/*
* 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/RTCVideoCodec.h"
#import "RTCVideoCodec+Private.h"
#import "WebRTC/RTCVideoCodecFactory.h"
#include "webrtc/sdk/objc/Framework/Classes/Common/helpers.h"
@implementation RTCVideoCodecInfo
@synthesize payload = _payload;
@synthesize name = _name;
@synthesize parameters = _parameters;
- (instancetype)initWithPayload:(int)payload
name:(NSString *)name
parameters:(NSDictionary<NSString *, NSString *> *)parameters {
if (self = [super init]) {
_payload = payload;
_name = name;
_parameters = parameters;
}
return self;
}
- (instancetype)initWithVideoCodec:(cricket::VideoCodec)videoCodec {
NSMutableDictionary *params = [NSMutableDictionary dictionary];
for (auto it = videoCodec.params.begin(); it != videoCodec.params.end(); ++it) {
[params setObject:webrtc::ios::NSStringFromStdString(it->second)
forKey:webrtc::ios::NSStringFromStdString(it->first)];
}
return [self initWithPayload:videoCodec.id
name:webrtc::ios::NSStringFromStdString(videoCodec.name)
parameters:params];
}
- (cricket::VideoCodec)toCpp {
cricket::VideoCodec codec(webrtc::ios::StdStringFromNSString(_name));
for (NSString *paramKey in [_parameters allKeys]) {
codec.SetParam(webrtc::ios::StdStringFromNSString(paramKey),
webrtc::ios::StdStringFromNSString(_parameters[paramKey]));
}
return codec;
}
@end
@implementation RTCVideoEncoderSettings
@synthesize name = _name;
@synthesize width = _width;
@synthesize height = _height;
@synthesize startBitrate = _startBitrate;
@synthesize maxBitrate = _maxBitrate;
@synthesize minBitrate = _minBitrate;
@synthesize targetBitrate = _targetBitrate;
@synthesize maxFramerate = _maxFramerate;
@synthesize qpMax = _qpMax;
- (instancetype)initWithVideoCodec:(const webrtc::VideoCodec *__nullable)videoCodec {
if (self = [super init]) {
if (videoCodec) {
rtc::Optional<const char *> codecName = CodecTypeToPayloadName(videoCodec->codecType);
if (codecName) {
_name = [NSString stringWithUTF8String:codecName.value()];
}
_width = videoCodec->width;
_height = videoCodec->height;
_startBitrate = videoCodec->startBitrate;
_maxBitrate = videoCodec->maxBitrate;
_minBitrate = videoCodec->minBitrate;
_targetBitrate = videoCodec->targetBitrate;
_maxFramerate = videoCodec->maxFramerate;
_qpMax = videoCodec->qpMax;
}
}
return self;
}
- (webrtc::VideoCodec *)toCpp {
webrtc::VideoCodec *codecSettings = new webrtc::VideoCodec;
rtc::Optional<webrtc::VideoCodecType> codecType =
webrtc::PayloadNameToCodecType(webrtc::ios::StdStringFromNSString(_name));
if (codecType) {
codecSettings->codecType = codecType.value();
}
codecSettings->width = _width;
codecSettings->height = _height;
codecSettings->startBitrate = _startBitrate;
codecSettings->maxBitrate = _maxBitrate;
codecSettings->minBitrate = _minBitrate;
codecSettings->targetBitrate = _targetBitrate;
codecSettings->maxFramerate = _maxFramerate;
codecSettings->qpMax = _qpMax;
return codecSettings;
}
@end

View File

@ -0,0 +1,262 @@
/*
* 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/RTCVideoCodecH264.h"
#include <vector>
#import "RTCVideoCodec+Private.h"
#import "WebRTC/RTCVideoCodec.h"
#import "WebRTC/RTCVideoFrame.h"
#import "WebRTC/RTCVideoFrameBuffer.h"
#include "webrtc/rtc_base/timeutils.h"
#include "webrtc/sdk/objc/Framework/Classes/Video/objc_frame_buffer.h"
#include "webrtc/sdk/objc/Framework/Classes/VideoToolbox/decoder.h"
#include "webrtc/sdk/objc/Framework/Classes/VideoToolbox/encoder.h"
#include "webrtc/system_wrappers/include/field_trial.h"
const size_t kDefaultPayloadSize = 1440;
const char kHighProfileExperiment[] = "WebRTC-H264HighProfile";
bool IsHighProfileEnabled() {
return webrtc::field_trial::IsEnabled(kHighProfileExperiment);
}
// H264 specific settings.
@implementation RTCCodecSpecificInfoH264
@synthesize packetizationMode = _packetizationMode;
- (webrtc::CodecSpecificInfo)toCpp {
webrtc::CodecSpecificInfo codecSpecificInfo;
codecSpecificInfo.codecType = webrtc::kVideoCodecH264;
codecSpecificInfo.codec_name = "H264";
codecSpecificInfo.codecSpecific.H264.packetization_mode =
(webrtc::H264PacketizationMode)_packetizationMode;
return codecSpecificInfo;
}
@end
namespace {
class H264VideoToolboxEncodeCompleteCallback : public webrtc::EncodedImageCallback {
public:
Result OnEncodedImage(const webrtc::EncodedImage &encoded_image,
const webrtc::CodecSpecificInfo *codec_specific_info,
const webrtc::RTPFragmentationHeader *fragmentation) {
RTCEncodedImage *image = [[RTCEncodedImage alloc] initWithEncodedImage:encoded_image];
RTCCodecSpecificInfoH264 *info = [[RTCCodecSpecificInfoH264 alloc] init];
info.packetizationMode =
(RTCH264PacketizationMode)codec_specific_info->codecSpecific.H264.packetization_mode;
RTCRtpFragmentationHeader *header =
[[RTCRtpFragmentationHeader alloc] initWithFragmentationHeader:fragmentation];
callback(image, info, header);
return Result(Result::OK, 0);
}
RTCVideoEncoderCallback callback;
};
class H264VideoToolboxDecodeCompleteCallback : public webrtc::DecodedImageCallback {
public:
int32_t Decoded(webrtc::VideoFrame &decodedImage) {
rtc::scoped_refptr<webrtc::VideoFrameBuffer> video_frame_buffer =
decodedImage.video_frame_buffer();
id<RTCVideoFrameBuffer> rtcFrameBuffer;
rtc::scoped_refptr<webrtc::ObjCFrameBuffer> objc_frame_buffer(
static_cast<webrtc::ObjCFrameBuffer *>(video_frame_buffer.get()));
rtcFrameBuffer = (id<RTCVideoFrameBuffer>)objc_frame_buffer->wrapped_frame_buffer();
RTCVideoFrame *videoFrame = [[RTCVideoFrame alloc]
initWithBuffer:rtcFrameBuffer
rotation:static_cast<RTCVideoRotation>(decodedImage.rotation())
timeStampNs:decodedImage.timestamp_us() * rtc::kNumNanosecsPerMicrosec];
videoFrame.timeStamp = decodedImage.timestamp();
callback(videoFrame);
return 0;
}
RTCVideoDecoderCallback callback;
};
} // namespace
// Encoder.
@implementation RTCVideoEncoderH264 {
webrtc::H264VideoToolboxEncoder *_videoToolboxEncoder;
H264VideoToolboxEncodeCompleteCallback *_toolboxCallback;
}
- (instancetype)initWithCodecInfo:(RTCVideoCodecInfo *)codecInfo {
if (self = [super init]) {
cricket::VideoCodec codec = [codecInfo toCpp];
_videoToolboxEncoder = new webrtc::H264VideoToolboxEncoder(codec);
}
return self;
}
- (void)setCallback:(RTCVideoEncoderCallback)callback {
_toolboxCallback = new H264VideoToolboxEncodeCompleteCallback();
_toolboxCallback->callback = callback;
_videoToolboxEncoder->RegisterEncodeCompleteCallback(_toolboxCallback);
}
- (int)initEncodeWithSettings:(RTCVideoEncoderSettings *)settings numberOfCores:(int)numberOfCores {
webrtc::VideoCodec *codecSettings = [settings toCpp];
return _videoToolboxEncoder->InitEncode(codecSettings, numberOfCores, kDefaultPayloadSize);
}
- (int)releaseEncode {
return _videoToolboxEncoder->Release();
}
- (int)encode:(RTCVideoFrame *)frame
codecSpecificInfo:(id<RTCCodecSpecificInfo>)info
frameTypes:(NSArray<NSNumber *> *)frameTypes {
rtc::scoped_refptr<webrtc::VideoFrameBuffer> frameBuffer =
new rtc::RefCountedObject<webrtc::ObjCFrameBuffer>(frame.buffer);
webrtc::VideoFrame videoFrame(frameBuffer,
(webrtc::VideoRotation)frame.rotation,
frame.timeStampNs / rtc::kNumNanosecsPerMicrosec);
videoFrame.set_timestamp(frame.timeStamp);
// Handle types than can be converted into one of webrtc::CodecSpecificInfo's hard coded cases.
webrtc::CodecSpecificInfo codecSpecificInfo;
if ([info isKindOfClass:[RTCCodecSpecificInfoH264 class]]) {
codecSpecificInfo = [(RTCCodecSpecificInfoH264 *)info toCpp];
}
std::vector<webrtc::FrameType> nativeFrameTypes;
for (NSNumber *frameType in frameTypes) {
RTCFrameType rtcFrameType = (RTCFrameType)frameType.unsignedIntegerValue;
nativeFrameTypes.push_back((webrtc::FrameType)rtcFrameType);
}
return _videoToolboxEncoder->Encode(videoFrame, &codecSpecificInfo, &nativeFrameTypes);
}
- (BOOL)setBitrate:(uint32_t)bitrateKbit framerate:(uint32_t)framerate {
return _videoToolboxEncoder->SetRates(bitrateKbit, framerate) == WEBRTC_VIDEO_CODEC_OK;
}
@end
// Decoder.
@implementation RTCVideoDecoderH264 {
webrtc::H264VideoToolboxDecoder *_videoToolboxDecoder;
H264VideoToolboxDecodeCompleteCallback *_toolboxCallback;
}
- (instancetype)init {
if (self = [super init]) {
cricket::VideoCodec codec(cricket::kH264CodecName);
_videoToolboxDecoder = new webrtc::H264VideoToolboxDecoder();
}
return self;
}
- (int)initDecodeWithSettings:(RTCVideoEncoderSettings *)settings numberOfCores:(int)numberOfCores {
webrtc::VideoCodec *codecSettings = [settings toCpp];
return _videoToolboxDecoder->InitDecode(codecSettings, numberOfCores);
}
- (void)setCallback:(RTCVideoDecoderCallback)callback {
_toolboxCallback = new H264VideoToolboxDecodeCompleteCallback();
_toolboxCallback->callback = callback;
_videoToolboxDecoder->RegisterDecodeCompleteCallback(_toolboxCallback);
}
- (int32_t)releaseDecode {
return _videoToolboxDecoder->Release();
}
- (int)decode:(RTCEncodedImage *)encodedImage
missingFrames:(BOOL)missingFrames
fragmentationHeader:(RTCRtpFragmentationHeader *)fragmentationHeader
codecSpecificInfo:(__nullable id<RTCCodecSpecificInfo>)info
renderTimeMs:(int64_t)renderTimeMs {
webrtc::EncodedImage image = [encodedImage toCpp];
// Handle types than can be converted into one of webrtc::CodecSpecificInfo's hard coded cases.
webrtc::CodecSpecificInfo codecSpecificInfo;
if ([info isKindOfClass:[RTCCodecSpecificInfoH264 class]]) {
codecSpecificInfo = [(RTCCodecSpecificInfoH264 *)info toCpp];
}
webrtc::RTPFragmentationHeader *header = [fragmentationHeader toCpp];
return _videoToolboxDecoder->Decode(
image, missingFrames, header, &codecSpecificInfo, renderTimeMs);
}
@end
// Encoder factory.
@implementation RTCVideoEncoderFactoryH264
- (NSArray<RTCVideoCodecInfo *> *)supportedCodecs {
NSMutableArray<RTCVideoCodecInfo *> *codecs = [NSMutableArray array];
NSString *codecName = [NSString stringWithUTF8String:cricket::kH264CodecName];
if (IsHighProfileEnabled()) {
NSDictionary<NSString *, NSString *> *constrainedHighParams = @{
@"profile-level-id" : @"640c1f", // Level 3.1 Constrained High.
@"level-asymmetry-allowed" : @"1",
@"packetization-mode" : @"1",
};
RTCVideoCodecInfo *constrainedHighInfo =
[[RTCVideoCodecInfo alloc] initWithPayload:0
name:codecName
parameters:constrainedHighParams];
[codecs addObject:constrainedHighInfo];
}
NSDictionary<NSString *, NSString *> *constrainedBaselineParams = @{
@"profile-level-id" : @"42e01f", // Level 3.1 Constrained Baseline.
@"level-asymmetry-allowed" : @"1",
@"packetization-mode" : @"1",
};
RTCVideoCodecInfo *constrainedBaselineInfo =
[[RTCVideoCodecInfo alloc] initWithPayload:0
name:codecName
parameters:constrainedBaselineParams];
[codecs addObject:constrainedBaselineInfo];
return [codecs copy];
}
- (id<RTCVideoEncoder>)createEncoder:(RTCVideoCodecInfo *)info {
return [[RTCVideoEncoderH264 alloc] initWithCodecInfo:info];
}
@end
// Decoder factory.
@implementation RTCVideoDecoderFactoryH264
- (id<RTCVideoDecoder>)createDecoder:(RTCVideoCodecInfo *)info {
return [[RTCVideoDecoderH264 alloc] init];
}
- (NSArray<RTCVideoCodecInfo *> *)supportedCodecs {
NSString *codecName = [NSString stringWithUTF8String:cricket::kH264CodecName];
return @[ [[RTCVideoCodecInfo alloc] initWithPayload:0 name:codecName parameters:@{}] ];
}
@end

View File

@ -17,6 +17,7 @@
}
@synthesize buffer = _buffer;
@synthesize timeStamp;
- (int)width {
return _buffer.width;

View File

@ -0,0 +1,39 @@
/*
* 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_PEERCONNECTION_OBJC_VIDEO_DECODER_FACTORY_H_
#define WEBRTC_SDK_OBJC_FRAMEWORK_CLASSES_PEERCONNECTION_OBJC_VIDEO_DECODER_FACTORY_H_
#include "webrtc/media/base/codec.h"
#include "webrtc/media/engine/webrtcvideodecoderfactory.h"
@protocol RTCVideoDecoderFactory;
namespace webrtc {
class ObjCVideoDecoderFactory : public cricket::WebRtcVideoDecoderFactory {
public:
explicit ObjCVideoDecoderFactory(id<RTCVideoDecoderFactory>);
~ObjCVideoDecoderFactory();
id<RTCVideoDecoderFactory> wrapped_decoder_factory() const;
webrtc::VideoDecoder* CreateVideoDecoder(
webrtc::VideoCodecType type) override;
void DestroyVideoDecoder(webrtc::VideoDecoder* decoder) override;
private:
id<RTCVideoDecoderFactory> decoder_factory_;
std::vector<cricket::VideoCodec> supported_codecs_;
};
} // namespace webrtc
#endif // WEBRTC_SDK_OBJC_FRAMEWORK_CLASSES_PEERCONNECTION_OBJC_VIDEO_DECODER_FACTORY_H_

View File

@ -0,0 +1,124 @@
/*
* 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/PeerConnection/objc_video_decoder_factory.h"
#import "RTCVideoCodec+Private.h"
#import "WebRTC/RTCVideoCodec.h"
#import "WebRTC/RTCVideoCodecFactory.h"
#import "WebRTC/RTCVideoCodecH264.h"
#import "WebRTC/RTCVideoFrame.h"
#import "WebRTC/RTCVideoFrameBuffer.h"
#include "webrtc/api/video_codecs/video_decoder.h"
#include "webrtc/modules/include/module_common_types.h"
#include "webrtc/modules/video_coding/include/video_codec_interface.h"
#include "webrtc/modules/video_coding/include/video_error_codes.h"
#include "webrtc/rtc_base/logging.h"
#include "webrtc/rtc_base/timeutils.h"
#include "webrtc/sdk/objc/Framework/Classes/Video/objc_frame_buffer.h"
namespace webrtc {
namespace {
class ObjCVideoDecoder : public VideoDecoder {
public:
ObjCVideoDecoder(id<RTCVideoDecoder> decoder) : decoder_(decoder) {}
~ObjCVideoDecoder() {}
int32_t InitDecode(const VideoCodec *codec_settings, int32_t number_of_cores) {
RTCVideoEncoderSettings *settings =
[[RTCVideoEncoderSettings alloc] initWithVideoCodec:codec_settings];
return [decoder_ initDecodeWithSettings:settings numberOfCores:number_of_cores];
}
int32_t Decode(const EncodedImage &input_image,
bool missing_frames,
const RTPFragmentationHeader *fragmentation,
const CodecSpecificInfo *codec_specific_info = NULL,
int64_t render_time_ms = -1) {
RTCEncodedImage *encodedImage = [[RTCEncodedImage alloc] initWithEncodedImage:input_image];
RTCRtpFragmentationHeader *header =
[[RTCRtpFragmentationHeader alloc] initWithFragmentationHeader:fragmentation];
// webrtc::CodecSpecificInfo only handles a hard coded list of codecs
id<RTCCodecSpecificInfo> rtcCodecSpecificInfo = nil;
if (codec_specific_info) {
if (codec_specific_info->codecType == kVideoCodecH264) {
RTCCodecSpecificInfoH264 *h264Info = [[RTCCodecSpecificInfoH264 alloc] init];
h264Info.packetizationMode =
(RTCH264PacketizationMode)codec_specific_info->codecSpecific.H264.packetization_mode;
rtcCodecSpecificInfo = h264Info;
}
}
return [decoder_ decode:encodedImage
missingFrames:missing_frames
fragmentationHeader:header
codecSpecificInfo:rtcCodecSpecificInfo
renderTimeMs:render_time_ms];
}
int32_t RegisterDecodeCompleteCallback(DecodedImageCallback *callback) {
[decoder_ setCallback:^(RTCVideoFrame *frame) {
const rtc::scoped_refptr<VideoFrameBuffer> buffer =
new rtc::RefCountedObject<ObjCFrameBuffer>(frame.buffer);
VideoFrame videoFrame(buffer,
(uint32_t)(frame.timeStampNs / rtc::kNumNanosecsPerMicrosec),
0,
(VideoRotation)frame.rotation);
videoFrame.set_timestamp(frame.timeStamp);
callback->Decoded(videoFrame);
}];
return WEBRTC_VIDEO_CODEC_OK;
}
int32_t Release() { return [decoder_ releaseDecode]; }
private:
id<RTCVideoDecoder> decoder_;
};
} // namespace
ObjCVideoDecoderFactory::ObjCVideoDecoderFactory(id<RTCVideoDecoderFactory> decoder_factory)
: decoder_factory_(decoder_factory) {}
ObjCVideoDecoderFactory::~ObjCVideoDecoderFactory() {}
id<RTCVideoDecoderFactory> ObjCVideoDecoderFactory::wrapped_decoder_factory() const {
return decoder_factory_;
}
VideoDecoder *ObjCVideoDecoderFactory::CreateVideoDecoder(VideoCodecType type) {
const rtc::Optional<const char *> codec_name = CodecTypeToPayloadName(type);
if (!codec_name) {
LOG(LS_ERROR) << "Invalid codec type: " << type;
return nullptr;
}
NSString *codecName = [NSString stringWithUTF8String:codec_name.value()];
for (RTCVideoCodecInfo *codecInfo in decoder_factory_.supportedCodecs) {
if ([codecName isEqualToString:codecInfo.name]) {
id<RTCVideoDecoder> decoder = [decoder_factory_ createDecoder:codecInfo];
return new ObjCVideoDecoder(decoder);
}
}
return nullptr;
}
void ObjCVideoDecoderFactory::DestroyVideoDecoder(VideoDecoder *decoder) {
delete decoder;
decoder = nullptr;
}
} // namespace webrtc

View File

@ -0,0 +1,41 @@
/*
* 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_PEERCONNECTION_OBJC_VIDEO_ENCODER_FACTORY_H_
#define WEBRTC_SDK_OBJC_FRAMEWORK_CLASSES_PEERCONNECTION_OBJC_VIDEO_ENCODER_FACTORY_H_
#import <Foundation/Foundation.h>
#include "webrtc/media/engine/webrtcvideoencoderfactory.h"
@protocol RTCVideoEncoderFactory;
namespace webrtc {
class ObjCVideoEncoderFactory : public cricket::WebRtcVideoEncoderFactory {
public:
explicit ObjCVideoEncoderFactory(id<RTCVideoEncoderFactory>);
~ObjCVideoEncoderFactory();
id<RTCVideoEncoderFactory> wrapped_encoder_factory() const;
webrtc::VideoEncoder* CreateVideoEncoder(
const cricket::VideoCodec& codec) override;
const std::vector<cricket::VideoCodec>& supported_codecs() const override;
void DestroyVideoEncoder(webrtc::VideoEncoder* encoder) override;
private:
id<RTCVideoEncoderFactory> encoder_factory_;
mutable std::vector<cricket::VideoCodec> supported_codecs_;
};
} // namespace webrtc
#endif // WEBRTC_SDK_OBJC_FRAMEWORK_CLASSES_PEERCONNECTION_OBJC_VIDEO_ENCODER_FACTORY_H_

View File

@ -0,0 +1,149 @@
/*
* 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/PeerConnection/objc_video_encoder_factory.h"
#import "RTCVideoCodec+Private.h"
#import "WebRTC/RTCVideoCodec.h"
#import "WebRTC/RTCVideoCodecFactory.h"
#import "WebRTC/RTCVideoCodecH264.h"
#import "WebRTC/RTCVideoFrame.h"
#import "WebRTC/RTCVideoFrameBuffer.h"
#include "webrtc/api/video/video_frame.h"
#include "webrtc/api/video_codecs/video_encoder.h"
#include "webrtc/modules/include/module_common_types.h"
#include "webrtc/modules/video_coding/include/video_codec_interface.h"
#include "webrtc/modules/video_coding/include/video_error_codes.h"
#include "webrtc/rtc_base/logging.h"
#include "webrtc/rtc_base/timeutils.h"
#include "webrtc/sdk/objc/Framework/Classes/Common/helpers.h"
#include "webrtc/sdk/objc/Framework/Classes/Video/objc_frame_buffer.h"
namespace webrtc {
namespace {
class ObjCVideoEncoder : public VideoEncoder {
public:
ObjCVideoEncoder(id<RTCVideoEncoder> encoder) : encoder_(encoder) {}
~ObjCVideoEncoder() {}
int32_t InitEncode(const VideoCodec *codec_settings,
int32_t number_of_cores,
size_t max_payload_size) {
RTCVideoEncoderSettings *settings =
[[RTCVideoEncoderSettings alloc] initWithVideoCodec:codec_settings];
return [encoder_ initEncodeWithSettings:settings numberOfCores:number_of_cores];
}
int32_t RegisterEncodeCompleteCallback(EncodedImageCallback *callback) {
[encoder_ setCallback:^(RTCEncodedImage *frame,
id<RTCCodecSpecificInfo> info,
RTCRtpFragmentationHeader *header) {
EncodedImage encodedImage = [frame toCpp];
// Handle types than can be converted into one of webrtc::CodecSpecificInfo's hard coded
// cases.
CodecSpecificInfo codecSpecificInfo;
if ([info isKindOfClass:[RTCCodecSpecificInfoH264 class]]) {
codecSpecificInfo = [(RTCCodecSpecificInfoH264 *)info toCpp];
}
RTPFragmentationHeader *fragmentationHeader = [header toCpp];
callback->OnEncodedImage(encodedImage, &codecSpecificInfo, fragmentationHeader);
}];
return WEBRTC_VIDEO_CODEC_OK;
}
int32_t Release() { return [encoder_ releaseEncode]; }
int32_t Encode(const VideoFrame &frame,
const CodecSpecificInfo *codec_specific_info,
const std::vector<FrameType> *frame_types) {
RTC_CHECK(frame.video_frame_buffer()->type() == VideoFrameBuffer::Type::kNative);
id<RTCVideoFrameBuffer> frame_buffer =
static_cast<ObjCFrameBuffer *>(frame.video_frame_buffer().get())->wrapped_frame_buffer();
RTCVideoFrame *rtcFrame =
[[RTCVideoFrame alloc] initWithBuffer:frame_buffer
rotation:RTCVideoRotation(frame.rotation())
timeStampNs:frame.timestamp_us() * rtc::kNumNanosecsPerMicrosec];
rtcFrame.timeStamp = frame.timestamp();
// webrtc::CodecSpecificInfo only handles a hard coded list of codecs
id<RTCCodecSpecificInfo> rtcCodecSpecificInfo = nil;
if (codec_specific_info) {
if (strcmp(codec_specific_info->codec_name, "H264") == 0) {
RTCCodecSpecificInfoH264 *h264Info = [[RTCCodecSpecificInfoH264 alloc] init];
h264Info.packetizationMode =
(RTCH264PacketizationMode)codec_specific_info->codecSpecific.H264.packetization_mode;
rtcCodecSpecificInfo = h264Info;
}
}
NSMutableArray<NSNumber *> *rtcFrameTypes = [NSMutableArray array];
for (size_t i = 0; i < frame_types->size(); ++i) {
[rtcFrameTypes addObject:@(RTCFrameType(frame_types->at(i)))];
}
return
[encoder_ encode:rtcFrame codecSpecificInfo:rtcCodecSpecificInfo frameTypes:rtcFrameTypes];
}
int32_t SetChannelParameters(uint32_t packet_loss, int64_t rtt) { return WEBRTC_VIDEO_CODEC_OK; }
int32_t SetRates(uint32_t bitrate, uint32_t framerate) {
if ([encoder_ setBitrate:bitrate framerate:framerate]) {
return WEBRTC_VIDEO_CODEC_OK;
} else {
return WEBRTC_VIDEO_CODEC_ERROR;
}
}
bool SupportsNativeHandle() const { return true; }
private:
id<RTCVideoEncoder> encoder_;
};
} // namespace
ObjCVideoEncoderFactory::ObjCVideoEncoderFactory(id<RTCVideoEncoderFactory> encoder_factory)
: encoder_factory_(encoder_factory) {}
ObjCVideoEncoderFactory::~ObjCVideoEncoderFactory() {}
id<RTCVideoEncoderFactory> ObjCVideoEncoderFactory::wrapped_encoder_factory() const {
return encoder_factory_;
}
webrtc::VideoEncoder *ObjCVideoEncoderFactory::CreateVideoEncoder(
const cricket::VideoCodec &codec) {
RTCVideoCodecInfo *info = [[RTCVideoCodecInfo alloc] initWithVideoCodec:codec];
id<RTCVideoEncoder> encoder = [encoder_factory_ createEncoder:info];
return new ObjCVideoEncoder(encoder);
}
const std::vector<cricket::VideoCodec> &ObjCVideoEncoderFactory::supported_codecs() const {
supported_codecs_.clear();
for (RTCVideoCodecInfo *supportedCodec in encoder_factory_.supportedCodecs) {
cricket::VideoCodec codec = [supportedCodec toCpp];
supported_codecs_.push_back(codec);
}
return supported_codecs_;
}
void ObjCVideoEncoderFactory::DestroyVideoEncoder(webrtc::VideoEncoder *encoder) {
delete encoder;
encoder = nullptr;
}
} // namespace webrtc