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}
This commit is contained in:
magjed 2016-11-15 09:56:55 -08:00 committed by Commit bot
parent 4aecc5885a
commit 5d54e185d5
3 changed files with 131 additions and 6 deletions

View File

@ -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_);

View File

@ -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<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 @@ 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);

View File

@ -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;