Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add HEVC support for iOS/Android #72

Open
wants to merge 1 commit into
base: m104_release
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,10 @@ config("common_inherited_config") {
if (is_ubsan) {
cflags += [ "-fsanitize=float-cast-overflow" ]
}

if (rtc_use_h265) {
defines += [ "WEBRTC_USE_H265" ]
}
}

# TODO(bugs.webrtc.org/9693): Remove the possibility to suppress this warning
Expand Down Expand Up @@ -293,6 +297,10 @@ config("common_config") {
defines += [ "WEBRTC_USE_H264" ]
}

if (rtc_use_h265) {
defines += [ "WEBRTC_USE_H265" ]
}

if (rtc_use_absl_mutex) {
defines += [ "WEBRTC_ABSL_MUTEX" ]
}
Expand Down
1 change: 1 addition & 0 deletions api/video/video_codec_type.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ enum VideoCodecType {
kVideoCodecVP9,
kVideoCodecAV1,
kVideoCodecH264,
kVideoCodecH265,
kVideoCodecMultiplex,
};

Expand Down
25 changes: 25 additions & 0 deletions api/video_codecs/video_codec.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ constexpr char kPayloadNameAv1[] = "AV1";
// needed.
constexpr char kPayloadNameAv1x[] = "AV1X";
constexpr char kPayloadNameH264[] = "H264";
constexpr char kPayloadNameH265[] = "H265";
constexpr char kPayloadNameGeneric[] = "Generic";
constexpr char kPayloadNameMultiplex[] = "Multiplex";
} // namespace
Expand All @@ -52,6 +53,15 @@ bool VideoCodecH264::operator==(const VideoCodecH264& other) const {
numberOfTemporalLayers == other.numberOfTemporalLayers);
}

bool VideoCodecH265::operator==(const VideoCodecH265& other) const {
return (frameDroppingOn == other.frameDroppingOn &&
keyFrameInterval == other.keyFrameInterval &&
vpsLen == other.vpsLen && spsLen == other.spsLen &&
ppsLen == other.ppsLen &&
(spsLen == 0 || memcmp(spsData, other.spsData, spsLen) == 0) &&
(ppsLen == 0 || memcmp(ppsData, other.ppsData, ppsLen) == 0));
}

VideoCodec::VideoCodec()
: codecType(kVideoCodecGeneric),
width(0),
Expand Down Expand Up @@ -102,6 +112,16 @@ const VideoCodecH264& VideoCodec::H264() const {
return codec_specific_.H264;
}

VideoCodecH265* VideoCodec::H265() {
RTC_DCHECK_EQ(codecType, kVideoCodecH265);
return &codec_specific_.H265;
}

const VideoCodecH265& VideoCodec::H265() const {
RTC_DCHECK_EQ(codecType, kVideoCodecH265);
return codec_specific_.H265;
}

const char* CodecTypeToPayloadString(VideoCodecType type) {
switch (type) {
case kVideoCodecVP8:
Expand All @@ -112,9 +132,12 @@ const char* CodecTypeToPayloadString(VideoCodecType type) {
return kPayloadNameAv1;
case kVideoCodecH264:
return kPayloadNameH264;
case kVideoCodecH265:
return kPayloadNameH265;
case kVideoCodecMultiplex:
return kPayloadNameMultiplex;
case kVideoCodecGeneric:
default:
return kPayloadNameGeneric;
}
RTC_CHECK_NOTREACHED();
Expand All @@ -132,6 +155,8 @@ VideoCodecType PayloadStringToCodecType(const std::string& name) {
return kVideoCodecH264;
if (absl::EqualsIgnoreCase(name, kPayloadNameMultiplex))
return kVideoCodecMultiplex;
if (absl::EqualsIgnoreCase(name, kPayloadNameH265))
return kVideoCodecH265;
return kVideoCodecGeneric;
}

Expand Down
18 changes: 18 additions & 0 deletions api/video_codecs/video_codec.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,21 @@ struct VideoCodecH264 {
uint8_t numberOfTemporalLayers;
};

struct VideoCodecH265 {
bool operator==(const VideoCodecH265& other) const;
bool operator!=(const VideoCodecH265& other) const {
return !(*this == other);
}
bool frameDroppingOn;
int keyFrameInterval;
const uint8_t* vpsData;
size_t vpsLen;
const uint8_t* spsData;
size_t spsLen;
const uint8_t* ppsData;
size_t ppsLen;
};

// Translates from name of codec to codec type and vice versa.
RTC_EXPORT const char* CodecTypeToPayloadString(VideoCodecType type);
RTC_EXPORT VideoCodecType PayloadStringToCodecType(const std::string& name);
Expand All @@ -90,6 +105,7 @@ union VideoCodecUnion {
VideoCodecVP8 VP8;
VideoCodecVP9 VP9;
VideoCodecH264 H264;
VideoCodecH265 H265;
};

enum class VideoCodecMode { kRealtimeVideo, kScreensharing };
Expand Down Expand Up @@ -169,6 +185,8 @@ class RTC_EXPORT VideoCodec {
const VideoCodecVP9& VP9() const;
VideoCodecH264* H264();
const VideoCodecH264& H264() const;
VideoCodecH265* H265();
const VideoCodecH265& H265() const;

private:
// TODO(hta): Consider replacing the union with a pointer type.
Expand Down
4 changes: 4 additions & 0 deletions api/video_codecs/video_decoder_software_fallback_wrapper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,10 @@ void VideoDecoderSoftwareFallbackWrapper::UpdateFallbackDecoderHistograms() {
RTC_HISTOGRAM_COUNTS_100000(kFallbackHistogramsUmaPrefix + "H264",
hw_decoded_frames_since_last_fallback_);
break;
case kVideoCodecH265:
RTC_HISTOGRAM_COUNTS_100000(kFallbackHistogramsUmaPrefix + "H265",
hw_decoded_frames_since_last_fallback_);
break;
case kVideoCodecMultiplex:
RTC_HISTOGRAM_COUNTS_100000(kFallbackHistogramsUmaPrefix + "Multiplex",
hw_decoded_frames_since_last_fallback_);
Expand Down
17 changes: 17 additions & 0 deletions api/video_codecs/video_encoder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,23 @@ VideoCodecH264 VideoEncoder::GetDefaultH264Settings() {
return h264_settings;
}

#ifdef WEBRTC_USE_H265
VideoCodecH265 VideoEncoder::GetDefaultH265Settings() {
VideoCodecH265 h265_settings;
memset(&h265_settings, 0, sizeof(h265_settings));

// h265_settings.profile = kProfileBase;
h265_settings.frameDroppingOn = true;
h265_settings.keyFrameInterval = 3000;
h265_settings.spsData = nullptr;
h265_settings.spsLen = 0;
h265_settings.ppsData = nullptr;
h265_settings.ppsLen = 0;

return h265_settings;
}
#endif

VideoEncoder::ScalingSettings::ScalingSettings() = default;

VideoEncoder::ScalingSettings::ScalingSettings(KOff) : ScalingSettings() {}
Expand Down
3 changes: 3 additions & 0 deletions api/video_codecs/video_encoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,9 @@ class RTC_EXPORT VideoEncoder {
static VideoCodecVP8 GetDefaultVp8Settings();
static VideoCodecVP9 GetDefaultVp9Settings();
static VideoCodecH264 GetDefaultH264Settings();
#ifdef WEBRTC_USE_H265
static VideoCodecH265 GetDefaultH265Settings();
#endif

virtual ~VideoEncoder() {}

Expand Down
20 changes: 20 additions & 0 deletions api/video_codecs/video_encoder_config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ void VideoEncoderConfig::EncoderSpecificSettings::FillEncoderSpecificSettings(
FillVideoCodecVp8(codec->VP8());
} else if (codec->codecType == kVideoCodecVP9) {
FillVideoCodecVp9(codec->VP9());
#ifdef WEBRTC_USE_H265
} else if (codec->codecType == kVideoCodecH265) {
FillVideoCodecH265(codec->H265());
#endif
} else {
RTC_DCHECK_NOTREACHED()
<< "Encoder specifics set/used for unknown codec type.";
Expand All @@ -112,6 +116,22 @@ void VideoEncoderConfig::EncoderSpecificSettings::FillVideoCodecVp9(
RTC_DCHECK_NOTREACHED();
}

#ifdef WEBRTC_USE_H265
void VideoEncoderConfig::EncoderSpecificSettings::FillVideoCodecH265(
VideoCodecH265* h265_settings) const {
RTC_DCHECK_NOTREACHED();
}

VideoEncoderConfig::H265EncoderSpecificSettings::H265EncoderSpecificSettings(
const VideoCodecH265& specifics)
: specifics_(specifics) {}

void VideoEncoderConfig::H265EncoderSpecificSettings::FillVideoCodecH265(
VideoCodecH265* h265_settings) const {
*h265_settings = specifics_;
}
#endif

VideoEncoderConfig::Vp8EncoderSpecificSettings::Vp8EncoderSpecificSettings(
const VideoCodecVP8& specifics)
: specifics_(specifics) {}
Expand Down
14 changes: 14 additions & 0 deletions api/video_codecs/video_encoder_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,26 @@ class VideoEncoderConfig {

virtual void FillVideoCodecVp8(VideoCodecVP8* vp8_settings) const;
virtual void FillVideoCodecVp9(VideoCodecVP9* vp9_settings) const;
#ifdef WEBRTC_USE_H265
virtual void FillVideoCodecH265(VideoCodecH265* h265_settings) const;
#endif

private:
~EncoderSpecificSettings() override {}
friend class VideoEncoderConfig;
};

#ifdef WEBRTC_USE_H265
class H265EncoderSpecificSettings : public EncoderSpecificSettings {
public:
explicit H265EncoderSpecificSettings(const VideoCodecH265& specifics);
void FillVideoCodecH265(VideoCodecH265* h265_settings) const override;

private:
VideoCodecH265 specifics_;
};
#endif

class Vp8EncoderSpecificSettings : public EncoderSpecificSettings {
public:
explicit Vp8EncoderSpecificSettings(const VideoCodecVP8& specifics);
Expand Down
6 changes: 6 additions & 0 deletions build_overrides/build.gni
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ ubsan_vptr_ignorelist_path =
# so we just ignore that assert. See https://crbug.com/648948 for more info.
ignore_elf32_limitations = true

if (is_win || is_ios || is_android) {
rtc_use_h265 = true
} else {
rtc_use_h265 = false
}

# Use bundled hermetic Xcode installation maintainted by Chromium,
# except for local iOS builds where it's unsupported.
# Allow for mac cross compile on linux machines.
Expand Down
35 changes: 35 additions & 0 deletions call/rtp_payload_params.cc
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,14 @@ void PopulateRtpWithCodecSpecifics(const CodecSpecificInfo& info,
rtp->simulcastIdx = spatial_index.value_or(0);
return;
}
#ifdef WEBRTC_USE_H265
case kVideoCodecH265: {
auto& h265_header = rtp->video_type_header.emplace<RTPVideoHeaderH265>();
h265_header.packetization_mode =
info.codecSpecific.H265.packetization_mode;
}
return;
#endif
case kVideoCodecMultiplex:
case kVideoCodecGeneric:
rtp->codec = kVideoCodecGeneric;
Expand Down Expand Up @@ -341,6 +349,12 @@ void RtpPayloadParams::SetGeneric(const CodecSpecificInfo* codec_specific_info,
is_keyframe, rtp_video_header);
}
return;
case VideoCodecType::kVideoCodecH265:
if (codec_specific_info) {
H265ToGeneric(codec_specific_info->codecSpecific.H265, frame_id,
is_keyframe, rtp_video_header);
}
return;
case VideoCodecType::kVideoCodecMultiplex:
return;
}
Expand Down Expand Up @@ -404,6 +418,7 @@ absl::optional<FrameDependencyStructure> RtpPayloadParams::GenericStructure(
}
case VideoCodecType::kVideoCodecAV1:
case VideoCodecType::kVideoCodecH264:
case VideoCodecType::kVideoCodecH265:
case VideoCodecType::kVideoCodecMultiplex:
return absl::nullopt;
}
Expand Down Expand Up @@ -486,6 +501,26 @@ void RtpPayloadParams::H264ToGeneric(const CodecSpecificInfoH264& h264_info,
last_shared_frame_id_[/*spatial_index*/ 0][temporal_index] = shared_frame_id;
}

void RtpPayloadParams::H265ToGeneric(const CodecSpecificInfoH265& h265_info,
int64_t shared_frame_id,
bool is_keyframe,
RTPVideoHeader* rtp_video_header) {
if (h265_info.picture_id <= 0) {
// picture_id is only used by cloud gaming.
return;
}
RTPVideoHeader::GenericDescriptorInfo& generic =
rtp_video_header->generic.emplace();
generic.frame_id = h265_info.picture_id;
generic.spatial_index = 0; // Not enabled at present.
generic.temporal_index = 0; // Not enabled at present.
for (int dep_idx = 0; dep_idx < 5; dep_idx++) {
if (h265_info.dependencies[dep_idx] <= 0)
break;
generic.dependencies[dep_idx] = h265_info.dependencies[dep_idx];
}
}

void RtpPayloadParams::Vp8ToGeneric(const CodecSpecificInfoVP8& vp8_info,
int64_t shared_frame_id,
bool is_keyframe,
Expand Down
4 changes: 4 additions & 0 deletions call/rtp_payload_params.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ class RtpPayloadParams final {
int64_t shared_frame_id,
bool is_keyframe,
RTPVideoHeader* rtp_video_header);
void H265ToGeneric(const CodecSpecificInfoH265& h265_info,
int64_t shared_frame_id,
bool is_keyframe,
RTPVideoHeader* rtp_video_header);

void GenericToGeneric(int64_t shared_frame_id,
bool is_keyframe,
Expand Down
12 changes: 12 additions & 0 deletions common_video/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,22 @@ rtc_library("common_video") {
"h264/h264_common.h",
"h264/pps_parser.cc",
"h264/pps_parser.h",
"h264/prefix_parser.cc",
"h264/prefix_parser.h",
"h264/sps_parser.cc",
"h264/sps_parser.h",
"h264/sps_vui_rewriter.cc",
"h264/sps_vui_rewriter.h",
"h265/h265_bitstream_parser.cc",
"h265/h265_bitstream_parser.h",
"h265/h265_common.cc",
"h265/h265_common.h",
"h265/h265_pps_parser.cc",
"h265/h265_pps_parser.h",
"h265/h265_sps_parser.cc",
"h265/h265_sps_parser.h",
"h265/h265_vps_parser.cc",
"h265/h265_vps_parser.h",
"include/bitrate_adjuster.h",
"include/incoming_video_stream.h",
"include/quality_limitation_reason.h",
Expand Down
Loading