Prepare iOS H264 HW encoder for High Profile
BUG=webrtc:6337
Review-Url: https://codereview.webrtc.org/2484493002
Cr-Commit-Position: refs/heads/master@{#15091}
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 3acdf64..2413f77 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 @@
class H264VideoToolboxEncoder : public H264Encoder {
public:
- H264VideoToolboxEncoder();
+ explicit H264VideoToolboxEncoder(const cricket::VideoCodec& codec);
~H264VideoToolboxEncoder() override;
@@ -82,6 +83,7 @@
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 d3ce820..6393959 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 @@
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<webrtc::H264::ProfileLevelId> 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 @@
// 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 @@
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 0772530..4bf7a4d 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 @@
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 @@
#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;