h264.cc (6318B)
1 /* 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 * 10 */ 11 12 #include "modules/video_coding/codecs/h264/include/h264.h" 13 14 #include <memory> 15 #include <optional> 16 #include <string> 17 #include <vector> 18 19 #include "absl/base/nullability.h" 20 #include "absl/container/inlined_vector.h" 21 #include "api/environment/environment.h" 22 #include "api/video_codecs/h264_profile_level_id.h" 23 #include "api/video_codecs/scalability_mode.h" 24 #include "api/video_codecs/sdp_video_format.h" 25 #include "api/video_codecs/video_encoder.h" 26 #include "media/base/media_constants.h" 27 #include "modules/video_coding/codecs/h264/include/h264_globals.h" 28 #include "rtc_base/checks.h" 29 #include "rtc_base/logging.h" 30 #include "rtc_base/trace_event.h" 31 32 #if defined(WEBRTC_USE_H264) 33 #include "modules/video_coding/codecs/h264/h264_decoder_impl.h" 34 #include "modules/video_coding/codecs/h264/h264_encoder_impl.h" 35 #endif 36 37 namespace webrtc { 38 39 namespace { 40 41 #if defined(WEBRTC_USE_H264) 42 bool g_rtc_use_h264 = true; 43 #endif 44 45 // If H.264 OpenH264/FFmpeg codec is supported. 46 bool IsH264CodecSupported() { 47 #if defined(WEBRTC_USE_H264) 48 return g_rtc_use_h264; 49 #else 50 return false; 51 #endif 52 } 53 54 constexpr ScalabilityMode kSupportedScalabilityModes[] = { 55 ScalabilityMode::kL1T1, ScalabilityMode::kL1T2, ScalabilityMode::kL1T3}; 56 57 } // namespace 58 59 SdpVideoFormat CreateH264Format(H264Profile profile, 60 H264Level level, 61 const std::string& packetization_mode, 62 bool add_scalability_modes) { 63 const std::optional<std::string> profile_string = 64 H264ProfileLevelIdToString(H264ProfileLevelId(profile, level)); 65 RTC_CHECK(profile_string); 66 absl::InlinedVector<ScalabilityMode, kScalabilityModeCount> scalability_modes; 67 if (add_scalability_modes) { 68 for (const auto scalability_mode : kSupportedScalabilityModes) { 69 scalability_modes.push_back(scalability_mode); 70 } 71 } 72 return SdpVideoFormat(kH264CodecName, 73 {{kH264FmtpProfileLevelId, *profile_string}, 74 {kH264FmtpLevelAsymmetryAllowed, "1"}, 75 {kH264FmtpPacketizationMode, packetization_mode}}, 76 scalability_modes); 77 } 78 79 void DisableRtcUseH264() { 80 #if defined(WEBRTC_USE_H264) 81 g_rtc_use_h264 = false; 82 #endif 83 } 84 85 std::vector<SdpVideoFormat> SupportedH264Codecs(bool add_scalability_modes) { 86 TRACE_EVENT0("webrtc", __func__); 87 if (!IsH264CodecSupported()) 88 return std::vector<SdpVideoFormat>(); 89 // We only support encoding Constrained Baseline Profile (CBP), but the 90 // decoder supports more profiles. We can list all profiles here that are 91 // supported by the decoder and that are also supersets of CBP, i.e. the 92 // decoder for that profile is required to be able to decode CBP. This means 93 // we can encode and send CBP even though we negotiated a potentially 94 // higher profile. See the H264 spec for more information. 95 // 96 // We support both packetization modes 0 (mandatory) and 1 (optional, 97 // preferred). 98 return {CreateH264Format(H264Profile::kProfileBaseline, H264Level::kLevel3_1, 99 "1", add_scalability_modes), 100 CreateH264Format(H264Profile::kProfileBaseline, H264Level::kLevel3_1, 101 "0", add_scalability_modes), 102 CreateH264Format(H264Profile::kProfileConstrainedBaseline, 103 H264Level::kLevel3_1, "1", add_scalability_modes), 104 CreateH264Format(H264Profile::kProfileConstrainedBaseline, 105 H264Level::kLevel3_1, "0", add_scalability_modes), 106 CreateH264Format(H264Profile::kProfileMain, H264Level::kLevel3_1, "1", 107 add_scalability_modes), 108 CreateH264Format(H264Profile::kProfileMain, H264Level::kLevel3_1, "0", 109 add_scalability_modes)}; 110 } 111 112 std::vector<SdpVideoFormat> SupportedH264DecoderCodecs() { 113 TRACE_EVENT0("webrtc", __func__); 114 if (!IsH264CodecSupported()) 115 return std::vector<SdpVideoFormat>(); 116 117 std::vector<SdpVideoFormat> supportedCodecs = SupportedH264Codecs(); 118 119 // OpenH264 doesn't yet support High Predictive 4:4:4 encoding but it does 120 // support decoding. 121 supportedCodecs.push_back(CreateH264Format( 122 H264Profile::kProfilePredictiveHigh444, H264Level::kLevel3_1, "1")); 123 supportedCodecs.push_back(CreateH264Format( 124 H264Profile::kProfilePredictiveHigh444, H264Level::kLevel3_1, "0")); 125 126 return supportedCodecs; 127 } 128 129 H264EncoderSettings H264EncoderSettings::Parse(const SdpVideoFormat& format) { 130 if (auto it = format.parameters.find(kH264FmtpPacketizationMode); 131 it != format.parameters.end()) { 132 if (it->second == "0") { 133 return {.packetization_mode = H264PacketizationMode::SingleNalUnit}; 134 } else if (it->second == "1") { 135 return {.packetization_mode = H264PacketizationMode::NonInterleaved}; 136 } 137 } 138 return {}; 139 } 140 141 absl_nonnull std::unique_ptr<VideoEncoder> CreateH264Encoder( 142 [[maybe_unused]] const Environment& env, 143 [[maybe_unused]] H264EncoderSettings settings) { 144 #if defined(WEBRTC_USE_H264) 145 RTC_CHECK(g_rtc_use_h264); 146 RTC_LOG(LS_INFO) << "Creating H264EncoderImpl."; 147 return std::make_unique<H264EncoderImpl>(env, settings); 148 #else 149 RTC_CHECK_NOTREACHED(); 150 #endif 151 } 152 153 bool H264Encoder::IsSupported() { 154 return IsH264CodecSupported(); 155 } 156 157 bool H264Encoder::SupportsScalabilityMode(ScalabilityMode scalability_mode) { 158 for (const auto& entry : kSupportedScalabilityModes) { 159 if (entry == scalability_mode) { 160 return true; 161 } 162 } 163 return false; 164 } 165 166 std::unique_ptr<H264Decoder> H264Decoder::Create() { 167 RTC_DCHECK(H264Decoder::IsSupported()); 168 #if defined(WEBRTC_USE_H264) 169 RTC_CHECK(g_rtc_use_h264); 170 RTC_LOG(LS_INFO) << "Creating H264DecoderImpl."; 171 return std::make_unique<H264DecoderImpl>(); 172 #else 173 RTC_DCHECK_NOTREACHED(); 174 return nullptr; 175 #endif 176 } 177 178 bool H264Decoder::IsSupported() { 179 return IsH264CodecSupported(); 180 } 181 182 } // namespace webrtc