| /* |
| * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| * |
| */ |
| |
| #include "modules/video_coding/codecs/h264/include/h264.h" |
| |
| #include <memory> |
| #include <string> |
| |
| #include "absl/container/inlined_vector.h" |
| #include "absl/types/optional.h" |
| #include "api/video_codecs/sdp_video_format.h" |
| #include "media/base/media_constants.h" |
| #include "rtc_base/trace_event.h" |
| |
| #if defined(WEBRTC_USE_H264) |
| #include "modules/video_coding/codecs/h264/h264_decoder_impl.h" |
| #include "modules/video_coding/codecs/h264/h264_encoder_impl.h" |
| #endif |
| |
| #include "rtc_base/checks.h" |
| #include "rtc_base/logging.h" |
| |
| namespace webrtc { |
| |
| namespace { |
| |
| #if defined(WEBRTC_USE_H264) |
| bool g_rtc_use_h264 = true; |
| #endif |
| |
| // If H.264 OpenH264/FFmpeg codec is supported. |
| bool IsH264CodecSupported() { |
| #if defined(WEBRTC_USE_H264) |
| return g_rtc_use_h264; |
| #else |
| return false; |
| #endif |
| } |
| |
| constexpr ScalabilityMode kSupportedScalabilityModes[] = { |
| ScalabilityMode::kL1T1, ScalabilityMode::kL1T2, ScalabilityMode::kL1T3}; |
| |
| } // namespace |
| |
| SdpVideoFormat CreateH264Format(H264Profile profile, |
| H264Level level, |
| const std::string& packetization_mode, |
| bool add_scalability_modes) { |
| const absl::optional<std::string> profile_string = |
| H264ProfileLevelIdToString(H264ProfileLevelId(profile, level)); |
| RTC_CHECK(profile_string); |
| absl::InlinedVector<ScalabilityMode, kScalabilityModeCount> scalability_modes; |
| if (add_scalability_modes) { |
| for (const auto scalability_mode : kSupportedScalabilityModes) { |
| scalability_modes.push_back(scalability_mode); |
| } |
| } |
| return SdpVideoFormat( |
| cricket::kH264CodecName, |
| {{cricket::kH264FmtpProfileLevelId, *profile_string}, |
| {cricket::kH264FmtpLevelAsymmetryAllowed, "1"}, |
| {cricket::kH264FmtpPacketizationMode, packetization_mode}}, |
| scalability_modes); |
| } |
| |
| void DisableRtcUseH264() { |
| #if defined(WEBRTC_USE_H264) |
| g_rtc_use_h264 = false; |
| #endif |
| } |
| |
| std::vector<SdpVideoFormat> SupportedH264Codecs(bool add_scalability_modes) { |
| TRACE_EVENT0("webrtc", __func__); |
| if (!IsH264CodecSupported()) |
| return std::vector<SdpVideoFormat>(); |
| // We only support encoding Constrained Baseline Profile (CBP), but the |
| // decoder supports more profiles. We can list all profiles here that are |
| // supported by the decoder and that are also supersets of CBP, i.e. the |
| // decoder for that profile is required to be able to decode CBP. This means |
| // we can encode and send CBP even though we negotiated a potentially |
| // higher profile. See the H264 spec for more information. |
| // |
| // We support both packetization modes 0 (mandatory) and 1 (optional, |
| // preferred). |
| return {CreateH264Format(H264Profile::kProfileBaseline, H264Level::kLevel3_1, |
| "1", add_scalability_modes), |
| CreateH264Format(H264Profile::kProfileBaseline, H264Level::kLevel3_1, |
| "0", add_scalability_modes), |
| CreateH264Format(H264Profile::kProfileConstrainedBaseline, |
| H264Level::kLevel3_1, "1", add_scalability_modes), |
| CreateH264Format(H264Profile::kProfileConstrainedBaseline, |
| H264Level::kLevel3_1, "0", add_scalability_modes), |
| CreateH264Format(H264Profile::kProfileMain, H264Level::kLevel3_1, "1", |
| add_scalability_modes), |
| CreateH264Format(H264Profile::kProfileMain, H264Level::kLevel3_1, "0", |
| add_scalability_modes)}; |
| } |
| |
| std::vector<SdpVideoFormat> SupportedH264DecoderCodecs() { |
| TRACE_EVENT0("webrtc", __func__); |
| if (!IsH264CodecSupported()) |
| return std::vector<SdpVideoFormat>(); |
| |
| std::vector<SdpVideoFormat> supportedCodecs = SupportedH264Codecs(); |
| |
| // OpenH264 doesn't yet support High Predictive 4:4:4 encoding but it does |
| // support decoding. |
| supportedCodecs.push_back(CreateH264Format( |
| H264Profile::kProfilePredictiveHigh444, H264Level::kLevel3_1, "1")); |
| supportedCodecs.push_back(CreateH264Format( |
| H264Profile::kProfilePredictiveHigh444, H264Level::kLevel3_1, "0")); |
| |
| return supportedCodecs; |
| } |
| |
| H264EncoderSettings H264EncoderSettings::Parse(const SdpVideoFormat& format) { |
| if (auto it = format.parameters.find(cricket::kH264FmtpPacketizationMode); |
| it != format.parameters.end()) { |
| if (it->second == "0") { |
| return {.packetization_mode = H264PacketizationMode::SingleNalUnit}; |
| } else if (it->second == "1") { |
| return {.packetization_mode = H264PacketizationMode::NonInterleaved}; |
| } |
| } |
| return {}; |
| } |
| |
| absl::Nonnull<std::unique_ptr<VideoEncoder>> CreateH264Encoder( |
| const Environment& env, |
| H264EncoderSettings settings) { |
| #if defined(WEBRTC_USE_H264) |
| RTC_CHECK(g_rtc_use_h264); |
| RTC_LOG(LS_INFO) << "Creating H264EncoderImpl."; |
| return std::make_unique<H264EncoderImpl>(env, settings); |
| #else |
| RTC_CHECK_NOTREACHED(); |
| #endif |
| } |
| |
| bool H264Encoder::IsSupported() { |
| return IsH264CodecSupported(); |
| } |
| |
| bool H264Encoder::SupportsScalabilityMode(ScalabilityMode scalability_mode) { |
| for (const auto& entry : kSupportedScalabilityModes) { |
| if (entry == scalability_mode) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| std::unique_ptr<H264Decoder> H264Decoder::Create() { |
| RTC_DCHECK(H264Decoder::IsSupported()); |
| #if defined(WEBRTC_USE_H264) |
| RTC_CHECK(g_rtc_use_h264); |
| RTC_LOG(LS_INFO) << "Creating H264DecoderImpl."; |
| return std::make_unique<H264DecoderImpl>(); |
| #else |
| RTC_DCHECK_NOTREACHED(); |
| return nullptr; |
| #endif |
| } |
| |
| bool H264Decoder::IsSupported() { |
| return IsH264CodecSupported(); |
| } |
| |
| } // namespace webrtc |