Add codec name H265 to support H265 in WebRTC

Bug: webrtc:13485
Change-Id: I352b15a65867f0d56fc8e9a9e03081bd3258108e
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/316283
Reviewed-by: Sergey Silkin <ssilkin@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Sergey Silkin <ssilkin@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#40773}
This commit is contained in:
qwu16 2023-09-20 13:10:31 +08:00 committed by WebRTC LUCI CQ
parent 9596002743
commit ae82df718c
45 changed files with 217 additions and 8 deletions

View file

@ -302,6 +302,10 @@ config("common_config") {
defines += [ "RTC_ENABLE_VP9" ] defines += [ "RTC_ENABLE_VP9" ]
} }
if (rtc_use_h265) {
defines += [ "RTC_ENABLE_H265" ]
}
if (rtc_include_dav1d_in_internal_decoder_factory) { if (rtc_include_dav1d_in_internal_decoder_factory) {
defines += [ "RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY" ] defines += [ "RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY" ]
} }

View file

@ -51,6 +51,10 @@ std::unique_ptr<VideoRtpDepacketizer> CreateDepacketizer(
return std::make_unique<VideoRtpDepacketizerAv1>(); return std::make_unique<VideoRtpDepacketizerAv1>();
case RtpVideoFrameAssembler::kGeneric: case RtpVideoFrameAssembler::kGeneric:
return std::make_unique<VideoRtpDepacketizerGeneric>(); return std::make_unique<VideoRtpDepacketizerGeneric>();
case RtpVideoFrameAssembler::kH265:
// TODO(bugs.webrtc.org/13485): Implement VideoRtpDepacketizerH265
RTC_DCHECK_NOTREACHED();
return nullptr;
} }
RTC_DCHECK_NOTREACHED(); RTC_DCHECK_NOTREACHED();
return nullptr; return nullptr;

View file

@ -52,7 +52,7 @@ class RtpVideoFrameAssembler {
// FrameVector is just a vector-like type of std::unique_ptr<EncodedFrame>. // FrameVector is just a vector-like type of std::unique_ptr<EncodedFrame>.
// The vector type may change without notice. // The vector type may change without notice.
using FrameVector = absl::InlinedVector<AssembledFrame, 3>; using FrameVector = absl::InlinedVector<AssembledFrame, 3>;
enum PayloadFormat { kRaw, kH264, kVp8, kVp9, kAv1, kGeneric }; enum PayloadFormat { kRaw, kH264, kVp8, kVp9, kAv1, kGeneric, kH265 };
explicit RtpVideoFrameAssembler(PayloadFormat payload_format); explicit RtpVideoFrameAssembler(PayloadFormat payload_format);
RtpVideoFrameAssembler(const RtpVideoFrameAssembler& other) = delete; RtpVideoFrameAssembler(const RtpVideoFrameAssembler& other) = delete;

View file

@ -89,6 +89,9 @@ class PacketBuilder {
case PayloadFormat::kAv1: { case PayloadFormat::kAv1: {
return kVideoCodecAV1; return kVideoCodecAV1;
} }
case PayloadFormat::kH265: {
return kVideoCodecH265;
}
case PayloadFormat::kGeneric: { case PayloadFormat::kGeneric: {
return kVideoCodecGeneric; return kVideoCodecGeneric;
} }

View file

@ -22,6 +22,7 @@ enum VideoCodecType {
kVideoCodecAV1, kVideoCodecAV1,
kVideoCodecH264, kVideoCodecH264,
kVideoCodecMultiplex, kVideoCodecMultiplex,
kVideoCodecH265,
}; };
} // namespace webrtc } // namespace webrtc

View file

@ -15,6 +15,9 @@
#include "api/array_view.h" #include "api/array_view.h"
#include "api/video_codecs/av1_profile.h" #include "api/video_codecs/av1_profile.h"
#include "api/video_codecs/h264_profile_level_id.h" #include "api/video_codecs/h264_profile_level_id.h"
#ifdef RTC_ENABLE_H265
#include "api/video_codecs/h265_profile_tier_level.h"
#endif
#include "api/video_codecs/video_codec.h" #include "api/video_codecs/video_codec.h"
#include "api/video_codecs/vp9_profile.h" #include "api/video_codecs/vp9_profile.h"
#include "rtc_base/checks.h" #include "rtc_base/checks.h"
@ -61,6 +64,10 @@ bool IsSameCodecSpecific(const SdpVideoFormat& format1,
return VP9IsSameProfile(format1.parameters, format2.parameters); return VP9IsSameProfile(format1.parameters, format2.parameters);
case kVideoCodecAV1: case kVideoCodecAV1:
return AV1IsSameProfile(format1.parameters, format2.parameters); return AV1IsSameProfile(format1.parameters, format2.parameters);
#ifdef RTC_ENABLE_H265
case kVideoCodecH265:
return H265IsSameProfileTierLevel(format1.parameters, format2.parameters);
#endif
default: default:
return true; return true;
} }

View file

@ -25,12 +25,18 @@ TEST(SdpVideoFormatTest, SameCodecNameNoParameters) {
EXPECT_TRUE(Sdp("VP8").IsSameCodec(Sdp("vp8"))); EXPECT_TRUE(Sdp("VP8").IsSameCodec(Sdp("vp8")));
EXPECT_TRUE(Sdp("VP9").IsSameCodec(Sdp("vp9"))); EXPECT_TRUE(Sdp("VP9").IsSameCodec(Sdp("vp9")));
EXPECT_TRUE(Sdp("AV1").IsSameCodec(Sdp("Av1"))); EXPECT_TRUE(Sdp("AV1").IsSameCodec(Sdp("Av1")));
#ifdef RTC_ENABLE_H265
EXPECT_TRUE(Sdp("H265").IsSameCodec(Sdp("h265")));
#endif
} }
TEST(SdpVideoFormatTest, DifferentCodecNameNoParameters) { TEST(SdpVideoFormatTest, DifferentCodecNameNoParameters) {
EXPECT_FALSE(Sdp("H264").IsSameCodec(Sdp("VP8"))); EXPECT_FALSE(Sdp("H264").IsSameCodec(Sdp("VP8")));
EXPECT_FALSE(Sdp("VP8").IsSameCodec(Sdp("VP9"))); EXPECT_FALSE(Sdp("VP8").IsSameCodec(Sdp("VP9")));
EXPECT_FALSE(Sdp("AV1").IsSameCodec(Sdp("VP8"))); EXPECT_FALSE(Sdp("AV1").IsSameCodec(Sdp("VP8")));
#ifdef RTC_ENABLE_H265
EXPECT_FALSE(Sdp("H265").IsSameCodec(Sdp("VP8")));
#endif
} }
TEST(SdpVideoFormatTest, SameCodecNameSameParameters) { TEST(SdpVideoFormatTest, SameCodecNameSameParameters) {
@ -50,6 +56,17 @@ TEST(SdpVideoFormatTest, SameCodecNameSameParameters) {
.IsSameCodec(Sdp("AV1", Params{{"profile", "0"}}))); .IsSameCodec(Sdp("AV1", Params{{"profile", "0"}})));
EXPECT_TRUE(Sdp("AV1", Params{{"profile", "2"}}) EXPECT_TRUE(Sdp("AV1", Params{{"profile", "2"}})
.IsSameCodec(Sdp("AV1", Params{{"profile", "2"}}))); .IsSameCodec(Sdp("AV1", Params{{"profile", "2"}})));
#ifdef RTC_ENABLE_H265
EXPECT_TRUE(Sdp("H265").IsSameCodec(Sdp(
"H265",
Params{{"profile-id", "1"}, {"tier-flag", "0"}, {"level-id", "93"}})));
EXPECT_TRUE(
Sdp("H265",
Params{{"profile-id", "2"}, {"tier-flag", "0"}, {"level-id", "93"}})
.IsSameCodec(Sdp("H265", Params{{"profile-id", "2"},
{"tier-flag", "0"},
{"level-id", "93"}})));
#endif
} }
TEST(SdpVideoFormatTest, SameCodecNameDifferentParameters) { TEST(SdpVideoFormatTest, SameCodecNameDifferentParameters) {
@ -69,6 +86,35 @@ TEST(SdpVideoFormatTest, SameCodecNameDifferentParameters) {
.IsSameCodec(Sdp("AV1", Params{{"profile", "1"}}))); .IsSameCodec(Sdp("AV1", Params{{"profile", "1"}})));
EXPECT_FALSE(Sdp("AV1", Params{{"profile", "1"}}) EXPECT_FALSE(Sdp("AV1", Params{{"profile", "1"}})
.IsSameCodec(Sdp("AV1", Params{{"profile", "2"}}))); .IsSameCodec(Sdp("AV1", Params{{"profile", "2"}})));
#ifdef RTC_ENABLE_H265
EXPECT_FALSE(Sdp("H265").IsSameCodec(Sdp(
"H265",
Params{{"profile-id", "0"}, {"tier-flag", "0"}, {"level-id", "93"}})));
EXPECT_FALSE(Sdp("H265").IsSameCodec(Sdp(
"H265",
Params{{"profile-id", "1"}, {"tier-flag", "1"}, {"level-id", "93"}})));
EXPECT_FALSE(Sdp("H265").IsSameCodec(Sdp(
"H265",
Params{{"profile-id", "1"}, {"tier-flag", "0"}, {"level-id", "90"}})));
EXPECT_FALSE(
Sdp("H265",
Params{{"profile-id", "2"}, {"tier-flag", "0"}, {"level-id", "93"}})
.IsSameCodec(Sdp("H265", Params{{"profile-id", "1"},
{"tier-flag", "0"},
{"level-id", "93"}})));
EXPECT_FALSE(
Sdp("H265",
Params{{"profile-id", "1"}, {"tier-flag", "1"}, {"level-id", "120"}})
.IsSameCodec(Sdp("H265", Params{{"profile-id", "1"},
{"tier-flag", "0"},
{"level-id", "120"}})));
EXPECT_FALSE(
Sdp("H265",
Params{{"profile-id", "1"}, {"tier-flag", "0"}, {"level-id", "93"}})
.IsSameCodec(Sdp("H265", Params{{"profile-id", "1"},
{"tier-flag", "0"},
{"level-id", "90"}})));
#endif
} }
TEST(SdpVideoFormatTest, DifferentCodecNameSameParameters) { TEST(SdpVideoFormatTest, DifferentCodecNameSameParameters) {
@ -86,6 +132,12 @@ TEST(SdpVideoFormatTest, DifferentCodecNameSameParameters) {
.IsSameCodec(Sdp("H264", Params{{"profile", "0"}}))); .IsSameCodec(Sdp("H264", Params{{"profile", "0"}})));
EXPECT_FALSE(Sdp("AV1", Params{{"profile", "2"}}) EXPECT_FALSE(Sdp("AV1", Params{{"profile", "2"}})
.IsSameCodec(Sdp("VP9", Params{{"profile", "2"}}))); .IsSameCodec(Sdp("VP9", Params{{"profile", "2"}})));
#ifdef RTC_ENABLE_H265
EXPECT_FALSE(Sdp("H265", Params{{"profile-id", "0"}})
.IsSameCodec(Sdp("H264", Params{{"profile-id", "0"}})));
EXPECT_FALSE(Sdp("H265", Params{{"profile-id", "2"}})
.IsSameCodec(Sdp("VP9", Params{{"profile-id", "2"}})));
#endif
} }
TEST(SdpVideoFormatTest, H264PacketizationMode) { TEST(SdpVideoFormatTest, H264PacketizationMode) {

View file

@ -28,6 +28,7 @@ constexpr char kPayloadNameAv1x[] = "AV1X";
constexpr char kPayloadNameH264[] = "H264"; constexpr char kPayloadNameH264[] = "H264";
constexpr char kPayloadNameGeneric[] = "Generic"; constexpr char kPayloadNameGeneric[] = "Generic";
constexpr char kPayloadNameMultiplex[] = "Multiplex"; constexpr char kPayloadNameMultiplex[] = "Multiplex";
constexpr char kPayloadNameH265[] = "H265";
} // namespace } // namespace
bool VideoCodecVP8::operator==(const VideoCodecVP8& other) const { bool VideoCodecVP8::operator==(const VideoCodecVP8& other) const {
@ -126,6 +127,8 @@ const char* CodecTypeToPayloadString(VideoCodecType type) {
return kPayloadNameMultiplex; return kPayloadNameMultiplex;
case kVideoCodecGeneric: case kVideoCodecGeneric:
return kPayloadNameGeneric; return kPayloadNameGeneric;
case kVideoCodecH265:
return kPayloadNameH265;
} }
RTC_CHECK_NOTREACHED(); RTC_CHECK_NOTREACHED();
} }
@ -142,6 +145,8 @@ VideoCodecType PayloadStringToCodecType(const std::string& name) {
return kVideoCodecH264; return kVideoCodecH264;
if (absl::EqualsIgnoreCase(name, kPayloadNameMultiplex)) if (absl::EqualsIgnoreCase(name, kPayloadNameMultiplex))
return kVideoCodecMultiplex; return kVideoCodecMultiplex;
if (absl::EqualsIgnoreCase(name, kPayloadNameH265))
return kVideoCodecH265;
return kVideoCodecGeneric; return kVideoCodecGeneric;
} }

View file

@ -170,6 +170,10 @@ void VideoDecoderSoftwareFallbackWrapper::UpdateFallbackDecoderHistograms() {
RTC_HISTOGRAM_COUNTS_100000(kFallbackHistogramsUmaPrefix + "Multiplex", RTC_HISTOGRAM_COUNTS_100000(kFallbackHistogramsUmaPrefix + "Multiplex",
hw_decoded_frames_since_last_fallback_); hw_decoded_frames_since_last_fallback_);
break; break;
case kVideoCodecH265:
RTC_HISTOGRAM_COUNTS_100000(kFallbackHistogramsUmaPrefix + "H265",
hw_decoded_frames_since_last_fallback_);
break;
} }
} }

View file

@ -100,6 +100,7 @@ void PopulateRtpWithCodecSpecifics(const CodecSpecificInfo& info,
case kVideoCodecGeneric: case kVideoCodecGeneric:
rtp->codec = kVideoCodecGeneric; rtp->codec = kVideoCodecGeneric;
return; return;
// TODO(bugs.webrtc.org/13485): Implement H265 codec specific info
default: default:
return; return;
} }
@ -341,6 +342,9 @@ void RtpPayloadParams::SetGeneric(const CodecSpecificInfo* codec_specific_info,
return; return;
case VideoCodecType::kVideoCodecMultiplex: case VideoCodecType::kVideoCodecMultiplex:
return; return;
case VideoCodecType::kVideoCodecH265:
// TODO(bugs.webrtc.org/13485): Implement H265 to generic descriptor.
return;
} }
RTC_DCHECK_NOTREACHED() << "Unsupported codec."; RTC_DCHECK_NOTREACHED() << "Unsupported codec.";
} }
@ -402,6 +406,7 @@ absl::optional<FrameDependencyStructure> RtpPayloadParams::GenericStructure(
} }
case VideoCodecType::kVideoCodecAV1: case VideoCodecType::kVideoCodecAV1:
case VideoCodecType::kVideoCodecH264: case VideoCodecType::kVideoCodecH264:
case VideoCodecType::kVideoCodecH265:
case VideoCodecType::kVideoCodecMultiplex: case VideoCodecType::kVideoCodecMultiplex:
return absl::nullopt; return absl::nullopt;
} }

View file

@ -110,6 +110,8 @@ rtclog2::FrameDecodedEvents::Codec ConvertToProtoFormat(VideoCodecType codec) {
case VideoCodecType::kVideoCodecMultiplex: case VideoCodecType::kVideoCodecMultiplex:
// This codec type is afaik not used. // This codec type is afaik not used.
return rtclog2::FrameDecodedEvents::CODEC_UNKNOWN; return rtclog2::FrameDecodedEvents::CODEC_UNKNOWN;
case VideoCodecType::kVideoCodecH265:
return rtclog2::FrameDecodedEvents::CODEC_H265;
} }
RTC_DCHECK_NOTREACHED(); RTC_DCHECK_NOTREACHED();
return rtclog2::FrameDecodedEvents::CODEC_UNKNOWN; return rtclog2::FrameDecodedEvents::CODEC_UNKNOWN;

View file

@ -339,6 +339,7 @@ message FrameDecodedEvents {
CODEC_VP9 = 3; CODEC_VP9 = 3;
CODEC_AV1 = 4; CODEC_AV1 = 4;
CODEC_H264 = 5; CODEC_H264 = 5;
CODEC_H265 = 6;
} }
// required // required

View file

@ -261,6 +261,8 @@ VideoCodecType GetRuntimeCodecType(rtclog2::FrameDecodedEvents::Codec codec) {
return VideoCodecType::kVideoCodecAV1; return VideoCodecType::kVideoCodecAV1;
case rtclog2::FrameDecodedEvents::CODEC_H264: case rtclog2::FrameDecodedEvents::CODEC_H264:
return VideoCodecType::kVideoCodecH264; return VideoCodecType::kVideoCodecH264;
case rtclog2::FrameDecodedEvents::CODEC_H265:
return VideoCodecType::kVideoCodecH265;
case rtclog2::FrameDecodedEvents::CODEC_UNKNOWN: case rtclog2::FrameDecodedEvents::CODEC_UNKNOWN:
RTC_LOG(LS_ERROR) << "Unknown codec type. Assuming " RTC_LOG(LS_ERROR) << "Unknown codec type. Assuming "
"VideoCodecType::kVideoCodecMultiplex"; "VideoCodecType::kVideoCodecMultiplex";

View file

@ -169,11 +169,11 @@ std::unique_ptr<RtcEventFrameDecoded> EventGenerator::NewFrameDecodedEvent(
constexpr int kMaxHeight = 8640; constexpr int kMaxHeight = 8640;
constexpr int kMinWidth = 16; constexpr int kMinWidth = 16;
constexpr int kMinHeight = 16; constexpr int kMinHeight = 16;
constexpr int kNumCodecTypes = 5; constexpr int kNumCodecTypes = 6;
constexpr VideoCodecType kCodecList[kNumCodecTypes] = { constexpr VideoCodecType kCodecList[kNumCodecTypes] = {
kVideoCodecGeneric, kVideoCodecVP8, kVideoCodecVP9, kVideoCodecAV1, kVideoCodecGeneric, kVideoCodecVP8, kVideoCodecVP9,
kVideoCodecH264}; kVideoCodecAV1, kVideoCodecH264, kVideoCodecH265};
const int64_t render_time_ms = const int64_t render_time_ms =
rtc::TimeMillis() + prng_.Rand(kMinRenderDelayMs, kMaxRenderDelayMs); rtc::TimeMillis() + prng_.Rand(kMinRenderDelayMs, kMaxRenderDelayMs);
const int width = prng_.Rand(kMinWidth, kMaxWidth); const int width = prng_.Rand(kMinWidth, kMaxWidth);

View file

@ -33,6 +33,9 @@ std::unique_ptr<VideoRtpDepacketizer> CreateVideoRtpDepacketizer(
return std::make_unique<VideoRtpDepacketizerVp9>(); return std::make_unique<VideoRtpDepacketizerVp9>();
case kVideoCodecAV1: case kVideoCodecAV1:
return std::make_unique<VideoRtpDepacketizerAv1>(); return std::make_unique<VideoRtpDepacketizerAv1>();
case kVideoCodecH265:
// TODO(bugs.webrtc.org/13485): Implement VideoRtpDepacketizerH265.
return nullptr;
case kVideoCodecGeneric: case kVideoCodecGeneric:
case kVideoCodecMultiplex: case kVideoCodecMultiplex:
return std::make_unique<VideoRtpDepacketizerGeneric>(); return std::make_unique<VideoRtpDepacketizerGeneric>();

View file

@ -57,6 +57,7 @@ std::unique_ptr<RtpPacketizer> RtpPacketizer::Create(
return std::make_unique<RtpPacketizerAv1>( return std::make_unique<RtpPacketizerAv1>(
payload, limits, rtp_video_header.frame_type, payload, limits, rtp_video_header.frame_type,
rtp_video_header.is_last_frame_in_picture); rtp_video_header.is_last_frame_in_picture);
// TODO(bugs.webrtc.org/13485): Implement RtpPacketizerH265.
default: { default: {
return std::make_unique<RtpPacketizerGeneric>(payload, limits, return std::make_unique<RtpPacketizerGeneric>(payload, limits,
rtp_video_header); rtp_video_header);

View file

@ -92,6 +92,10 @@ bool IsBaseLayer(const RTPVideoHeader& video_header) {
// TODO(kron): Implement logic for H264 once WebRTC supports temporal // TODO(kron): Implement logic for H264 once WebRTC supports temporal
// layers for H264. // layers for H264.
break; break;
case kVideoCodecH265:
// TODO(bugs.webrtc.org/13485): Implement logic for H265 once WebRTC
// supports temporal layers for H265.
break;
default: default:
break; break;
} }

View file

@ -59,6 +59,9 @@ VideoFrameMetadata RTPVideoHeader::GetAsMetadata() const {
metadata.SetRTPVideoHeaderCodecSpecifics( metadata.SetRTPVideoHeaderCodecSpecifics(
absl::get<RTPVideoHeaderH264>(video_type_header)); absl::get<RTPVideoHeaderH264>(video_type_header));
break; break;
case VideoCodecType::kVideoCodecH265:
// TODO(bugs.webrtc.org/13485)
break;
default: default:
// Codec-specifics are not supported for this codec. // Codec-specifics are not supported for this codec.
break; break;

View file

@ -93,6 +93,9 @@ int MultiplexEncoderAdapter::InitEncode(
key_frame_interval_ = video_codec.H264()->keyFrameInterval; key_frame_interval_ = video_codec.H264()->keyFrameInterval;
video_codec.H264()->keyFrameInterval = 0; video_codec.H264()->keyFrameInterval = 0;
break; break;
case kVideoCodecH265:
// TODO(bugs.webrtc.org/13485)
break;
default: default:
break; break;
} }

View file

@ -137,6 +137,9 @@ std::string CodecSpecificToString(const VideoCodec& codec) {
ss << "\nnum_temporal_layers: " ss << "\nnum_temporal_layers: "
<< static_cast<int>(codec.H264().numberOfTemporalLayers); << static_cast<int>(codec.H264().numberOfTemporalLayers);
break; break;
case kVideoCodecH265:
// TODO(bugs.webrtc.org/13485)
break;
default: default:
break; break;
} }
@ -246,6 +249,9 @@ void VideoCodecTestFixtureImpl::Config::SetCodecSettings(
codec_settings.H264()->numberOfTemporalLayers = codec_settings.H264()->numberOfTemporalLayers =
static_cast<uint8_t>(num_temporal_layers); static_cast<uint8_t>(num_temporal_layers);
break; break;
case kVideoCodecH265:
// TODO(bugs.webrtc.org/13485)
break;
default: default:
break; break;
} }

View file

@ -140,6 +140,10 @@ void VCMEncodedFrame::CopyCodecSpecific(const RTPVideoHeader* header) {
_codecSpecificInfo.codecType = kVideoCodecAV1; _codecSpecificInfo.codecType = kVideoCodecAV1;
break; break;
} }
case kVideoCodecH265: {
_codecSpecificInfo.codecType = kVideoCodecH265;
break;
}
default: { default: {
_codecSpecificInfo.codecType = kVideoCodecGeneric; _codecSpecificInfo.codecType = kVideoCodecGeneric;
break; break;

View file

@ -29,6 +29,7 @@ constexpr uint8_t kVp8Header[kCodecTypeBytesCount] = {'V', 'P', '8', '0'};
constexpr uint8_t kVp9Header[kCodecTypeBytesCount] = {'V', 'P', '9', '0'}; constexpr uint8_t kVp9Header[kCodecTypeBytesCount] = {'V', 'P', '9', '0'};
constexpr uint8_t kAv1Header[kCodecTypeBytesCount] = {'A', 'V', '0', '1'}; constexpr uint8_t kAv1Header[kCodecTypeBytesCount] = {'A', 'V', '0', '1'};
constexpr uint8_t kH264Header[kCodecTypeBytesCount] = {'H', '2', '6', '4'}; constexpr uint8_t kH264Header[kCodecTypeBytesCount] = {'H', '2', '6', '4'};
constexpr uint8_t kH265Header[kCodecTypeBytesCount] = {'H', '2', '6', '5'};
// RTP standard required 90kHz clock rate. // RTP standard required 90kHz clock rate.
constexpr int32_t kRtpClockRateHz = 90000; constexpr int32_t kRtpClockRateHz = 90000;
@ -192,6 +193,9 @@ absl::optional<VideoCodecType> IvfFileReader::ParseCodecType(uint8_t* buffer,
if (memcmp(&buffer[start_pos], kH264Header, kCodecTypeBytesCount) == 0) { if (memcmp(&buffer[start_pos], kH264Header, kCodecTypeBytesCount) == 0) {
return VideoCodecType::kVideoCodecH264; return VideoCodecType::kVideoCodecH264;
} }
if (memcmp(&buffer[start_pos], kH265Header, kCodecTypeBytesCount) == 0) {
return VideoCodecType::kVideoCodecH265;
}
has_error_ = true; has_error_ = true;
RTC_LOG(LS_ERROR) << "Unknown codec type: " RTC_LOG(LS_ERROR) << "Unknown codec type: "
<< std::string( << std::string(

View file

@ -92,6 +92,12 @@ bool IvfFileWriter::WriteHeader() {
ivf_header[10] = '6'; ivf_header[10] = '6';
ivf_header[11] = '4'; ivf_header[11] = '4';
break; break;
case kVideoCodecH265:
ivf_header[8] = 'H';
ivf_header[9] = '2';
ivf_header[10] = '6';
ivf_header[11] = '5';
break;
default: default:
// For unknown codec type use **** code. You can specify actual payload // For unknown codec type use **** code. You can specify actual payload
// format when playing the video with ffplay: ffplay -f H263 file.ivf // format when playing the video with ffplay: ffplay -f H263 file.ivf

View file

@ -36,6 +36,8 @@ absl::optional<uint32_t> QpParser::Parse(VideoCodecType codec_type,
} }
} else if (codec_type == kVideoCodecH264) { } else if (codec_type == kVideoCodecH264) {
return h264_parsers_[spatial_idx].Parse(frame_data, frame_size); return h264_parsers_[spatial_idx].Parse(frame_data, frame_size);
} else if (codec_type == kVideoCodecH265) {
// TODO(bugs.webrtc.org/13485)
} }
return absl::nullopt; return absl::nullopt;

View file

@ -94,6 +94,9 @@ int SimulcastUtility::NumberOfTemporalLayers(const VideoCodec& codec,
case kVideoCodecH264: case kVideoCodecH264:
num_temporal_layers = codec.H264().numberOfTemporalLayers; num_temporal_layers = codec.H264().numberOfTemporalLayers;
break; break;
case kVideoCodecH265:
// TODO(bugs.webrtc.org/13485)
break;
default: default:
break; break;
} }

View file

@ -344,6 +344,9 @@ VideoCodec VideoCodecInitializer::VideoEncoderConfigToVideoCodec(
kMaxTemporalStreams); kMaxTemporalStreams);
break; break;
} }
case kVideoCodecH265:
// TODO(bugs.webrtc.org/13485)
break;
default: default:
// TODO(pbos): Support encoder_settings codec-agnostically. // TODO(pbos): Support encoder_settings codec-agnostically.
RTC_DCHECK(!config.encoder_specific_settings) RTC_DCHECK(!config.encoder_specific_settings)

View file

@ -159,6 +159,8 @@ absl::optional<VideoEncoder::QpThresholds> GetThresholds(
low = config.vp9.GetQpLow(); low = config.vp9.GetQpLow();
high = config.vp9.GetQpHigh(); high = config.vp9.GetQpHigh();
break; break;
case kVideoCodecH265:
// TODO(bugs.webrtc.org/13485): Use H264 QP thresholds for now.
case kVideoCodecH264: case kVideoCodecH264:
low = config.h264.GetQpLow(); low = config.h264.GetQpLow();
high = config.h264.GetQpHigh(); high = config.h264.GetQpHigh();
@ -194,6 +196,8 @@ int GetFps(VideoCodecType type,
case kVideoCodecVP8: case kVideoCodecVP8:
fps = config->vp8.GetFps(); fps = config->vp8.GetFps();
break; break;
case kVideoCodecH265:
// TODO(bugs.webrtc.org/13485): Use VP9 bitrate limits for now.
case kVideoCodecVP9: case kVideoCodecVP9:
fps = config->vp9.GetFps(); fps = config->vp9.GetFps();
break; break;
@ -226,6 +230,8 @@ absl::optional<int> GetKbps(
case kVideoCodecVP8: case kVideoCodecVP8:
kbps = config->vp8.GetKbps(); kbps = config->vp8.GetKbps();
break; break;
case kVideoCodecH265:
// TODO(bugs.webrtc.org/13485): Use VP9 bitrate limits for now.
case kVideoCodecVP9: case kVideoCodecVP9:
kbps = config->vp9.GetKbps(); kbps = config->vp9.GetKbps();
break; break;
@ -259,6 +265,8 @@ absl::optional<int> GetKbpsRes(
case kVideoCodecVP8: case kVideoCodecVP8:
kbps_res = config->vp8.GetKbpsRes(); kbps_res = config->vp8.GetKbpsRes();
break; break;
case kVideoCodecH265:
// TODO(bugs.webrtc.org/13485): Use VP9 bitrate limits for now.
case kVideoCodecVP9: case kVideoCodecVP9:
kbps_res = config->vp9.GetKbpsRes(); kbps_res = config->vp9.GetKbpsRes();
break; break;

View file

@ -94,6 +94,8 @@ absl::optional<DataRate> GetExperimentalMinVideoBitrate(VideoCodecType type) {
switch (type) { switch (type) {
case kVideoCodecVP8: case kVideoCodecVP8:
return min_bitrate_vp8.GetOptional(); return min_bitrate_vp8.GetOptional();
case kVideoCodecH265:
// TODO(bugs.webrtc.org/13485): Use VP9 bitrate limits for now.
case kVideoCodecVP9: case kVideoCodecVP9:
return min_bitrate_vp9.GetOptional(); return min_bitrate_vp9.GetOptional();
case kVideoCodecAV1: case kVideoCodecAV1:

View file

@ -81,6 +81,8 @@ QualityScalingExperiment::GetQpThresholds(VideoCodecType codec_type) {
return GetThresholds(settings->vp8_low, settings->vp8_high, kMaxVp8Qp); return GetThresholds(settings->vp8_low, settings->vp8_high, kMaxVp8Qp);
case kVideoCodecVP9: case kVideoCodecVP9:
return GetThresholds(settings->vp9_low, settings->vp9_high, kMaxVp9Qp); return GetThresholds(settings->vp9_low, settings->vp9_high, kMaxVp9Qp);
case kVideoCodecH265:
// TODO(bugs.webrtc.org/13485): Use H264 QP thresholds for now.
case kVideoCodecH264: case kVideoCodecH264:
return GetThresholds(settings->h264_low, settings->h264_high, kMaxH264Qp); return GetThresholds(settings->h264_low, settings->h264_high, kMaxH264Qp);
case kVideoCodecGeneric: case kVideoCodecGeneric:

View file

@ -430,7 +430,8 @@ bool Convert(std::string inputfile,
{VideoCodecType::kVideoCodecVP9, "VP9"}, {VideoCodecType::kVideoCodecVP9, "VP9"},
{VideoCodecType::kVideoCodecAV1, "AV1"}, {VideoCodecType::kVideoCodecAV1, "AV1"},
{VideoCodecType::kVideoCodecH264, "H264"}, {VideoCodecType::kVideoCodecH264, "H264"},
{VideoCodecType::kVideoCodecMultiplex, "MULTIPLEX"}}; {VideoCodecType::kVideoCodecMultiplex, "MULTIPLEX"},
{VideoCodecType::kVideoCodecH265, "H265"}};
fprintf(output, fprintf(output,
"FRAME_DECODED %" PRId64 " render_time=%" PRId64 "FRAME_DECODED %" PRId64 " render_time=%" PRId64

View file

@ -295,7 +295,9 @@ class TestVideoEncoderFactoryWrapper final {
RTC_LOG(LS_WARNING) << "Failed to configure svc bitrates for av1."; RTC_LOG(LS_WARNING) << "Failed to configure svc bitrates for av1.";
} }
break; break;
case kVideoCodecH265:
// TODO(bugs.webrtc.org/13485)
break;
default: default:
RTC_CHECK_NOTREACHED(); RTC_CHECK_NOTREACHED();
break; break;

View file

@ -267,6 +267,8 @@ class DecoderIvfFileWriter : public test::FakeDecoder {
video_codec_type_ = VideoCodecType::kVideoCodecH264; video_codec_type_ = VideoCodecType::kVideoCodecH264;
} else if (codec == "AV1") { } else if (codec == "AV1") {
video_codec_type_ = VideoCodecType::kVideoCodecAV1; video_codec_type_ = VideoCodecType::kVideoCodecAV1;
} else if (codec == "H265") {
video_codec_type_ = VideoCodecType::kVideoCodecH265;
} else { } else {
RTC_LOG(LS_ERROR) << "Unsupported video codec " << codec; RTC_LOG(LS_ERROR) << "Unsupported video codec " << codec;
RTC_DCHECK_NOTREACHED(); RTC_DCHECK_NOTREACHED();

View file

@ -255,6 +255,13 @@ absl::optional<uint8_t> VideoDecoderWrapper::ParseQP(
qp = h264_bitstream_parser_.GetLastSliceQp(); qp = h264_bitstream_parser_.GetLastSliceQp();
break; break;
} }
#ifdef RTC_ENABLE_H265
case kVideoCodecH265:
h265_bitstream_parser_.ParseBitstream(buffer);
qp = h265_bitstream_parser_.GetLastSliceQp().value_or(-1);
success = (qp >= 0);
break;
#endif
default: default:
break; // Default is to not provide QP. break; // Default is to not provide QP.
} }

View file

@ -19,6 +19,9 @@
#include "api/sequence_checker.h" #include "api/sequence_checker.h"
#include "api/video_codecs/video_decoder.h" #include "api/video_codecs/video_decoder.h"
#include "common_video/h264/h264_bitstream_parser.h" #include "common_video/h264/h264_bitstream_parser.h"
#ifdef RTC_ENABLE_H265
#include "common_video/h265/h265_bitstream_parser.h"
#endif
#include "rtc_base/race_checker.h" #include "rtc_base/race_checker.h"
#include "rtc_base/synchronization/mutex.h" #include "rtc_base/synchronization/mutex.h"
#include "sdk/android/src/jni/jni_helpers.h" #include "sdk/android/src/jni/jni_helpers.h"
@ -96,6 +99,10 @@ class VideoDecoderWrapper : public VideoDecoder {
bool initialized_ RTC_GUARDED_BY(decoder_thread_checker_); bool initialized_ RTC_GUARDED_BY(decoder_thread_checker_);
H264BitstreamParser h264_bitstream_parser_ H264BitstreamParser h264_bitstream_parser_
RTC_GUARDED_BY(decoder_thread_checker_); RTC_GUARDED_BY(decoder_thread_checker_);
#ifdef RTC_ENABLE_H265
H265BitstreamParser h265_bitstream_parser_
RTC_GUARDED_BY(decoder_thread_checker_);
#endif
DecodedImageCallback* callback_ RTC_GUARDED_BY(callback_race_checker_); DecodedImageCallback* callback_ RTC_GUARDED_BY(callback_race_checker_);

View file

@ -227,6 +227,8 @@ VideoEncoderWrapper::GetScalingSettingsInternal(JNIEnv* jni) const {
return VideoEncoder::ScalingSettings(kLowVp9QpThreshold, return VideoEncoder::ScalingSettings(kLowVp9QpThreshold,
kHighVp9QpThreshold); kHighVp9QpThreshold);
} }
case kVideoCodecH265:
// TODO(bugs.webrtc.org/13485): Use H264 QP thresholds for now.
case kVideoCodecH264: { case kVideoCodecH264: {
// Same as in h264_encoder_impl.cc. // Same as in h264_encoder_impl.cc.
static const int kLowH264QpThreshold = 24; static const int kLowH264QpThreshold = 24;
@ -355,6 +357,13 @@ int VideoEncoderWrapper::ParseQp(rtc::ArrayView<const uint8_t> buffer) {
qp = h264_bitstream_parser_.GetLastSliceQp().value_or(-1); qp = h264_bitstream_parser_.GetLastSliceQp().value_or(-1);
success = (qp >= 0); success = (qp >= 0);
break; break;
#ifdef RTC_ENABLE_H265
case kVideoCodecH265:
h265_bitstream_parser_.ParseBitstream(buffer);
qp = h265_bitstream_parser_.GetLastSliceQp().value_or(-1);
success = (qp >= 0);
break;
#endif
default: // Default is to not provide QP. default: // Default is to not provide QP.
success = false; success = false;
break; break;

View file

@ -21,6 +21,9 @@
#include "absl/types/optional.h" #include "absl/types/optional.h"
#include "api/video_codecs/video_encoder.h" #include "api/video_codecs/video_encoder.h"
#include "common_video/h264/h264_bitstream_parser.h" #include "common_video/h264/h264_bitstream_parser.h"
#ifdef RTC_ENABLE_H265
#include "common_video/h265/h265_bitstream_parser.h"
#endif
#include "modules/video_coding/codecs/vp9/include/vp9_globals.h" #include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
#include "modules/video_coding/svc/scalable_video_controller_no_layering.h" #include "modules/video_coding/svc/scalable_video_controller_no_layering.h"
#include "rtc_base/synchronization/mutex.h" #include "rtc_base/synchronization/mutex.h"
@ -103,6 +106,9 @@ class VideoEncoderWrapper : public VideoEncoder {
VideoCodec codec_settings_; VideoCodec codec_settings_;
EncoderInfo encoder_info_; EncoderInfo encoder_info_;
H264BitstreamParser h264_bitstream_parser_; H264BitstreamParser h264_bitstream_parser_;
#ifdef RTC_ENABLE_H265
H265BitstreamParser h265_bitstream_parser_;
#endif
// Fills frame dependencies in codec-agnostic format. // Fills frame dependencies in codec-agnostic format.
ScalableVideoControllerNoLayering svc_controller_; ScalableVideoControllerNoLayering svc_controller_;

View file

@ -120,6 +120,9 @@ void FuzzOneInput(const uint8_t* data, size_t size) {
reader.CopyTo( reader.CopyTo(
&video_header.video_type_header.emplace<RTPVideoHeaderH264>()); &video_header.video_type_header.emplace<RTPVideoHeaderH264>());
break; break;
case kVideoCodecH265:
// TODO(bugs.webrtc.org/13485)
break;
default: default:
break; break;
} }

View file

@ -51,6 +51,8 @@ uint8_t CodecTypeToPayloadType(VideoCodecType codec_type) {
return VideoTestConstants::kPayloadTypeVP9; return VideoTestConstants::kPayloadTypeVP9;
case VideoCodecType::kVideoCodecH264: case VideoCodecType::kVideoCodecH264:
return VideoTestConstants::kPayloadTypeH264; return VideoTestConstants::kPayloadTypeH264;
case VideoCodecType::kVideoCodecH265:
return VideoTestConstants::kPayloadTypeH265;
default: default:
RTC_DCHECK_NOTREACHED(); RTC_DCHECK_NOTREACHED();
} }
@ -66,6 +68,8 @@ std::string CodecTypeToCodecName(VideoCodecType codec_type) {
return cricket::kVp9CodecName; return cricket::kVp9CodecName;
case VideoCodecType::kVideoCodecH264: case VideoCodecType::kVideoCodecH264:
return cricket::kH264CodecName; return cricket::kH264CodecName;
case VideoCodecType::kVideoCodecH265:
return cricket::kH265CodecName;
default: default:
RTC_DCHECK_NOTREACHED(); RTC_DCHECK_NOTREACHED();
} }
@ -203,6 +207,7 @@ CreateEncoderSpecificSettings(VideoStreamConfig config) {
return CreateVp9SpecificSettings(config); return CreateVp9SpecificSettings(config);
case Codec::kVideoCodecGeneric: case Codec::kVideoCodecGeneric:
case Codec::kVideoCodecAV1: case Codec::kVideoCodecAV1:
case Codec::kVideoCodecH265:
return nullptr; return nullptr;
case Codec::kVideoCodecMultiplex: case Codec::kVideoCodecMultiplex:
RTC_DCHECK_NOTREACHED(); RTC_DCHECK_NOTREACHED();

View file

@ -148,6 +148,9 @@ std::unique_ptr<VideoDecoder> IvfVideoFrameGenerator::CreateVideoDecoder(
if (codec_type == VideoCodecType::kVideoCodecAV1) { if (codec_type == VideoCodecType::kVideoCodecAV1) {
return CreateDav1dDecoder(); return CreateDav1dDecoder();
} }
if (codec_type == VideoCodecType::kVideoCodecH265) {
// TODO(bugs.webrtc.org/13485): implement H265 decoder
}
return nullptr; return nullptr;
} }

View file

@ -31,6 +31,7 @@ class VideoTestConstants {
kRtxRedPayloadType = 99, kRtxRedPayloadType = 99,
kVideoSendPayloadType = 100, kVideoSendPayloadType = 100,
kAudioSendPayloadType = 103, kAudioSendPayloadType = 103,
kPayloadTypeH265 = 117,
kRedPayloadType = 118, kRedPayloadType = 118,
kUlpfecPayloadType = 119, kUlpfecPayloadType = 119,
kFlexfecPayloadType = 120, kFlexfecPayloadType = 120,

View file

@ -266,6 +266,12 @@ void EncoderOvershootDetector::UpdateHistograms() {
RTC_HISTOGRAMS_COUNTS_10000(index, overshoot_histogram_prefix + "H264", RTC_HISTOGRAMS_COUNTS_10000(index, overshoot_histogram_prefix + "H264",
average_overshoot_percent); average_overshoot_percent);
break; break;
case VideoCodecType::kVideoCodecH265:
RTC_HISTOGRAMS_COUNTS_10000(index, rmse_histogram_prefix + "H265",
bitrate_rmse);
RTC_HISTOGRAMS_COUNTS_10000(index, overshoot_histogram_prefix + "H265",
average_overshoot_percent);
break;
case VideoCodecType::kVideoCodecGeneric: case VideoCodecType::kVideoCodecGeneric:
case VideoCodecType::kVideoCodecMultiplex: case VideoCodecType::kVideoCodecMultiplex:
break; break;

View file

@ -35,6 +35,8 @@ static std::string CodecTypeToHistogramSuffix(VideoCodecType codec) {
return "Av1"; return "Av1";
case kVideoCodecH264: case kVideoCodecH264:
return "H264"; return "H264";
case kVideoCodecH265:
return "H265";
case kVideoCodecGeneric: case kVideoCodecGeneric:
return "Generic"; return "Generic";
case kVideoCodecMultiplex: case kVideoCodecMultiplex:
@ -275,6 +277,8 @@ INSTANTIATE_TEST_SUITE_P(
{VideoCodecType::kVideoCodecAV1, false}, {VideoCodecType::kVideoCodecAV1, false},
{VideoCodecType::kVideoCodecAV1, true}, {VideoCodecType::kVideoCodecAV1, true},
{VideoCodecType::kVideoCodecH264, false}, {VideoCodecType::kVideoCodecH264, false},
{VideoCodecType::kVideoCodecH264, true}})); {VideoCodecType::kVideoCodecH264, true},
{VideoCodecType::kVideoCodecH265, false},
{VideoCodecType::kVideoCodecH265, true}}));
} // namespace webrtc } // namespace webrtc

View file

@ -47,6 +47,7 @@ enum HistogramCodecType {
kVideoVp9 = 2, kVideoVp9 = 2,
kVideoH264 = 3, kVideoH264 = 3,
kVideoAv1 = 4, kVideoAv1 = 4,
kVideoH265 = 5,
kVideoMax = 64, kVideoMax = 64,
}; };
@ -76,6 +77,8 @@ HistogramCodecType PayloadNameToHistogramCodecType(
return kVideoH264; return kVideoH264;
case kVideoCodecAV1: case kVideoCodecAV1:
return kVideoAv1; return kVideoAv1;
case kVideoCodecH265:
return kVideoH265;
default: default:
return kVideoUnknown; return kVideoUnknown;
} }

View file

@ -135,7 +135,9 @@ bool RequiresEncoderReset(const VideoCodec& prev_send_codec,
return true; return true;
} }
break; break;
case kVideoCodecH265:
// TODO(bugs.webrtc.org/13485): Implement new send codec H265
[[fallthrough]];
default: default:
break; break;
} }
@ -1351,6 +1353,7 @@ void VideoStreamEncoder::ReconfigureEncoder() {
// TODO(sprang): Add a better way to disable frame dropping. // TODO(sprang): Add a better way to disable frame dropping.
num_layers = codec.simulcastStream[0].numberOfTemporalLayers; num_layers = codec.simulcastStream[0].numberOfTemporalLayers;
} else { } else {
// TODO(bugs.webrtc.org/13485): Implement H265 temporal layer
num_layers = 1; num_layers = 1;
} }

View file

@ -8822,6 +8822,9 @@ class VideoStreamEncoderWithRealEncoderTest
mock_encoder_factory_for_multiplex_.get(), SdpVideoFormat("VP8"), mock_encoder_factory_for_multiplex_.get(), SdpVideoFormat("VP8"),
false); false);
break; break;
case kVideoCodecH265:
// TODO(bugs.webrtc.org/13485): Use a fake encoder
break;
default: default:
RTC_DCHECK_NOTREACHED(); RTC_DCHECK_NOTREACHED();
} }