diff --git a/webrtc/sdk/objc/Framework/Classes/h264_video_toolbox_encoder.h b/webrtc/sdk/objc/Framework/Classes/h264_video_toolbox_encoder.h index 3acdf641cd..2413f773b8 100644 --- a/webrtc/sdk/objc/Framework/Classes/h264_video_toolbox_encoder.h +++ b/webrtc/sdk/objc/Framework/Classes/h264_video_toolbox_encoder.h @@ -16,6 +16,7 @@ #include "webrtc/common_video/h264/h264_bitstream_parser.h" #include "webrtc/common_video/include/bitrate_adjuster.h" #include "webrtc/common_video/rotation.h" +#include "webrtc/media/base/codec.h" #include "webrtc/modules/video_coding/codecs/h264/include/h264.h" #include "webrtc/modules/video_coding/utility/quality_scaler.h" @@ -31,7 +32,7 @@ namespace webrtc { class H264VideoToolboxEncoder : public H264Encoder { public: - H264VideoToolboxEncoder(); + explicit H264VideoToolboxEncoder(const cricket::VideoCodec& codec); ~H264VideoToolboxEncoder() override; @@ -82,6 +83,7 @@ class H264VideoToolboxEncoder : public H264Encoder { uint32_t encoder_bitrate_bps_; int32_t width_; int32_t height_; + const CFStringRef profile_; rtc::CriticalSection quality_scaler_crit_; QualityScaler quality_scaler_ GUARDED_BY(quality_scaler_crit_); diff --git a/webrtc/sdk/objc/Framework/Classes/h264_video_toolbox_encoder.mm b/webrtc/sdk/objc/Framework/Classes/h264_video_toolbox_encoder.mm index d3ce8208e4..63939596f2 100644 --- a/webrtc/sdk/objc/Framework/Classes/h264_video_toolbox_encoder.mm +++ b/webrtc/sdk/objc/Framework/Classes/h264_video_toolbox_encoder.mm @@ -22,6 +22,7 @@ #include "libyuv/convert_from.h" #include "webrtc/base/checks.h" #include "webrtc/base/logging.h" +#include "webrtc/common_video/h264/profile_level_id.h" #include "webrtc/common_video/include/corevideo_frame_buffer.h" #include "webrtc/sdk/objc/Framework/Classes/h264_video_toolbox_nalu.h" #include "webrtc/system_wrappers/include/clock.h" @@ -224,6 +225,112 @@ void VTCompressionOutputCallback(void* encoder, encode_params->rotation); } +// Extract VideoToolbox profile out of the cricket::VideoCodec. If there is no +// specific VideoToolbox profile for the specified level, AutoLevel will be +// returned. The user must initialize the encoder with a resolution and +// framerate conforming to the selected H264 level regardless. +CFStringRef ExtractProfile(const cricket::VideoCodec& codec) { + const rtc::Optional profile_level_id = + webrtc::H264::ParseSdpProfileLevelId(codec.params); + RTC_DCHECK(profile_level_id); + switch (profile_level_id->profile) { + case webrtc::H264::kProfileConstrainedBaseline: + case webrtc::H264::kProfileBaseline: + switch (profile_level_id->level) { + case webrtc::H264::kLevel3: + return kVTProfileLevel_H264_Baseline_3_0; + case webrtc::H264::kLevel3_1: + return kVTProfileLevel_H264_Baseline_3_1; + case webrtc::H264::kLevel3_2: + return kVTProfileLevel_H264_Baseline_3_2; + case webrtc::H264::kLevel4: + return kVTProfileLevel_H264_Baseline_4_0; + case webrtc::H264::kLevel4_1: + return kVTProfileLevel_H264_Baseline_4_1; + case webrtc::H264::kLevel4_2: + return kVTProfileLevel_H264_Baseline_4_2; + case webrtc::H264::kLevel5: + return kVTProfileLevel_H264_Baseline_5_0; + case webrtc::H264::kLevel5_1: + return kVTProfileLevel_H264_Baseline_5_1; + case webrtc::H264::kLevel5_2: + return kVTProfileLevel_H264_Baseline_5_2; + case webrtc::H264::kLevel1: + case webrtc::H264::kLevel1_b: + case webrtc::H264::kLevel1_1: + case webrtc::H264::kLevel1_2: + case webrtc::H264::kLevel1_3: + case webrtc::H264::kLevel2: + case webrtc::H264::kLevel2_1: + case webrtc::H264::kLevel2_2: + return kVTProfileLevel_H264_Baseline_AutoLevel; + } + + case webrtc::H264::kProfileMain: + switch (profile_level_id->level) { + case webrtc::H264::kLevel3: + return kVTProfileLevel_H264_Main_3_0; + case webrtc::H264::kLevel3_1: + return kVTProfileLevel_H264_Main_3_1; + case webrtc::H264::kLevel3_2: + return kVTProfileLevel_H264_Main_3_2; + case webrtc::H264::kLevel4: + return kVTProfileLevel_H264_Main_4_0; + case webrtc::H264::kLevel4_1: + return kVTProfileLevel_H264_Main_4_1; + case webrtc::H264::kLevel4_2: + return kVTProfileLevel_H264_Main_4_2; + case webrtc::H264::kLevel5: + return kVTProfileLevel_H264_Main_5_0; + case webrtc::H264::kLevel5_1: + return kVTProfileLevel_H264_Main_5_1; + case webrtc::H264::kLevel5_2: + return kVTProfileLevel_H264_Main_5_2; + case webrtc::H264::kLevel1: + case webrtc::H264::kLevel1_b: + case webrtc::H264::kLevel1_1: + case webrtc::H264::kLevel1_2: + case webrtc::H264::kLevel1_3: + case webrtc::H264::kLevel2: + case webrtc::H264::kLevel2_1: + case webrtc::H264::kLevel2_2: + return kVTProfileLevel_H264_Main_AutoLevel; + } + + case webrtc::H264::kProfileConstrainedHigh: + case webrtc::H264::kProfileHigh: + switch (profile_level_id->level) { + case webrtc::H264::kLevel3: + return kVTProfileLevel_H264_High_3_0; + case webrtc::H264::kLevel3_1: + return kVTProfileLevel_H264_High_3_1; + case webrtc::H264::kLevel3_2: + return kVTProfileLevel_H264_High_3_2; + case webrtc::H264::kLevel4: + return kVTProfileLevel_H264_High_4_0; + case webrtc::H264::kLevel4_1: + return kVTProfileLevel_H264_High_4_1; + case webrtc::H264::kLevel4_2: + return kVTProfileLevel_H264_High_4_2; + case webrtc::H264::kLevel5: + return kVTProfileLevel_H264_High_5_0; + case webrtc::H264::kLevel5_1: + return kVTProfileLevel_H264_High_5_1; + case webrtc::H264::kLevel5_2: + return kVTProfileLevel_H264_High_5_2; + case webrtc::H264::kLevel1: + case webrtc::H264::kLevel1_b: + case webrtc::H264::kLevel1_1: + case webrtc::H264::kLevel1_2: + case webrtc::H264::kLevel1_3: + case webrtc::H264::kLevel2: + case webrtc::H264::kLevel2_1: + case webrtc::H264::kLevel2_2: + return kVTProfileLevel_H264_High_AutoLevel; + } + } +} + } // namespace internal namespace webrtc { @@ -235,10 +342,13 @@ namespace webrtc { // drastically reduced bitrate, so we want to avoid that. In steady state // conditions, 0.95 seems to give us better overall bitrate over long periods // of time. -H264VideoToolboxEncoder::H264VideoToolboxEncoder() +H264VideoToolboxEncoder::H264VideoToolboxEncoder( + const cricket::VideoCodec& codec) : callback_(nullptr), compression_session_(nullptr), - bitrate_adjuster_(Clock::GetRealTimeClock(), .5, .95) { + bitrate_adjuster_(Clock::GetRealTimeClock(), .5, .95), + profile_(internal::ExtractProfile(codec)) { + LOG(LS_INFO) << "Using profile " << internal::CFStringToString(profile_); } H264VideoToolboxEncoder::~H264VideoToolboxEncoder() { @@ -496,7 +606,7 @@ void H264VideoToolboxEncoder::ConfigureCompressionSession() { kVTCompressionPropertyKey_RealTime, true); internal::SetVTSessionProperty(compression_session_, kVTCompressionPropertyKey_ProfileLevel, - kVTProfileLevel_H264_Baseline_AutoLevel); + profile_); internal::SetVTSessionProperty(compression_session_, kVTCompressionPropertyKey_AllowFrameReordering, false); diff --git a/webrtc/sdk/objc/Framework/Classes/videotoolboxvideocodecfactory.cc b/webrtc/sdk/objc/Framework/Classes/videotoolboxvideocodecfactory.cc index 07725309bf..4bf7a4d559 100644 --- a/webrtc/sdk/objc/Framework/Classes/videotoolboxvideocodecfactory.cc +++ b/webrtc/sdk/objc/Framework/Classes/videotoolboxvideocodecfactory.cc @@ -10,6 +10,7 @@ #include "webrtc/sdk/objc/Framework/Classes/videotoolboxvideocodecfactory.h" #include "webrtc/base/logging.h" +#include "webrtc/common_video/h264/profile_level_id.h" #include "webrtc/media/base/codec.h" #if defined(WEBRTC_IOS) #include "webrtc/sdk/objc/Framework/Classes/h264_video_toolbox_encoder.h" @@ -38,7 +39,19 @@ namespace webrtc { VideoToolboxVideoEncoderFactory::VideoToolboxVideoEncoderFactory() { // Hardware H264 encoding only supported on iOS for now. #if defined(WEBRTC_IOS) - supported_codecs_.push_back(cricket::VideoCodec(cricket::kH264CodecName)); + // TODO(magjed): Push Constrained High profile as well when negotiation is + // ready, http://crbug/webrtc/6337. + cricket::VideoCodec constrained_baseline(cricket::kH264CodecName); + // TODO(magjed): Enumerate actual level instead of using hardcoded level 3.1. + // Level 3.1 is 1280x720@30fps which is enough for now. + const H264::ProfileLevelId constrained_baseline_profile( + H264::kProfileConstrainedBaseline, H264::kLevel3_1); + constrained_baseline.SetParam( + cricket::kH264FmtpProfileLevelId, + *H264::ProfileLevelIdToString(constrained_baseline_profile)); + constrained_baseline.SetParam(cricket::kH264FmtpLevelAsymmetryAllowed, "1"); + constrained_baseline.SetParam(cricket::kH264FmtpPacketizationMode, "1"); + supported_codecs_.push_back(constrained_baseline); #endif } @@ -49,7 +62,7 @@ VideoEncoder* VideoToolboxVideoEncoderFactory::CreateVideoEncoder( #if defined(WEBRTC_IOS) if (FindMatchingCodec(supported_codecs_, codec)) { LOG(LS_INFO) << "Creating HW encoder for " << codec.name; - return new H264VideoToolboxEncoder(); + return new H264VideoToolboxEncoder(codec); } #endif LOG(LS_INFO) << "No HW encoder found for codec " << codec.name;