Commit 16343676 authored by Johannes Kron's avatar Johannes Kron Committed by Commit Bot

Implement RTCVideoDecoderFactory::GetSupportedFormats()

This CL is part of fixing a bug where RTCRtpReceiver.getCapabilities()
returns encoder capabilities instead of decoder capabilities.
First step in fixing this bug is to implement
RTCVideoDecoderFactory::GetSupportedFormats().

Bug: chromium:1029737
Change-Id: I7d3adf204bbe9e6867b2af66aefb3bf5db543249
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1947660
Commit-Queue: Johannes Kron <kron@chromium.org>
Reviewed-by: default avatarHenrik Boström <hbos@chromium.org>
Cr-Commit-Position: refs/heads/master@{#722452}
parent 23a34733
......@@ -18,6 +18,7 @@ include_rules = [
"+media/video/gpu_video_accelerator_factories.h",
"+media/video/video_decode_accelerator.h",
"+media/video/h264_parser.h",
"+media/video/supported_video_decoder_config.h",
"+media/video/video_encode_accelerator.h",
"+third_party/blink/renderer/platform/bindings/script_wrappable.h",
"+third_party/blink/renderer/platform/heap",
......
......@@ -68,12 +68,6 @@ const int32_t kMaxDecodeHistory = 32;
// requesting fallback to software decode.
const int32_t kMaxConsecutiveErrors = 5;
// Currently, RTCVideoDecoderAdapter only tries one VideoDecoderImplementation.
// Since we use it in multiple places, memorize it here to make it clear that
// they must be changed together.
constexpr media::VideoDecoderImplementation kImplementation =
media::VideoDecoderImplementation::kDefault;
// Map webrtc::VideoCodecType to media::VideoCodec.
media::VideoCodec ToVideoCodec(webrtc::VideoCodecType video_codec_type) {
switch (video_codec_type) {
......
......@@ -17,6 +17,7 @@
#include "media/base/video_codecs.h"
#include "media/base/video_decoder.h"
#include "media/base/video_decoder_config.h"
#include "media/video/supported_video_decoder_config.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/deque.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
......@@ -51,6 +52,12 @@ namespace blink {
// way to synchronize this correctly.
class PLATFORM_EXPORT RTCVideoDecoderAdapter : public webrtc::VideoDecoder {
public:
// Currently, RTCVideoDecoderAdapter only tries one
// VideoDecoderImplementation.
// Since we use it in multiple places, memorize it here to make it clear that
// they must be changed together.
static constexpr media::VideoDecoderImplementation kImplementation =
media::VideoDecoderImplementation::kDefault;
// Creates and initializes an RTCVideoDecoderAdapter. Returns nullptr if
// |format| cannot be supported.
// Called on the worker thread.
......
......@@ -4,17 +4,128 @@
#include "third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_factory.h"
#include <array>
#include <memory>
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "build/build_config.h"
#include "media/base/media_util.h"
#include "media/base/video_codecs.h"
#include "media/video/gpu_video_accelerator_factories.h"
#include "third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_adapter.h"
#include "third_party/webrtc/media/base/h264_profile_level_id.h"
#include "third_party/webrtc/media/base/media_constants.h"
#include "third_party/webrtc/media/base/vp9_profile.h"
#include "ui/gfx/color_space.h"
#include "ui/gfx/geometry/size.h"
namespace blink {
namespace {
const int kDefaultFps = 30;
// Any reasonable size, will be overridden by the decoder anyway.
const gfx::Size kDefaultSize(640, 480);
struct CodecConfig {
media::VideoCodec codec;
media::VideoCodecProfile profile;
};
constexpr std::array<CodecConfig, 6> kCodecConfigs = {{
{media::kCodecVP8, media::VP8PROFILE_ANY},
{media::kCodecVP9, media::VP9PROFILE_PROFILE0},
{media::kCodecVP9, media::VP9PROFILE_PROFILE2},
{media::kCodecH264, media::H264PROFILE_BASELINE},
{media::kCodecH264, media::H264PROFILE_MAIN},
{media::kCodecH264, media::H264PROFILE_HIGH},
}};
// Translate from media::VideoDecoderConfig to webrtc::SdpVideoFormat, or return
// nothing if the profile isn't supported.
base::Optional<webrtc::SdpVideoFormat> VdcToWebRtcFormat(
const media::VideoDecoderConfig& config) {
switch (config.codec()) {
case media::VideoCodec::kCodecVP8:
return webrtc::SdpVideoFormat("VP8");
case media::VideoCodec::kCodecVP9: {
webrtc::VP9Profile vp9_profile;
switch (config.profile()) {
case media::VP9PROFILE_PROFILE0:
vp9_profile = webrtc::VP9Profile::kProfile0;
break;
case media::VP9PROFILE_PROFILE2:
vp9_profile = webrtc::VP9Profile::kProfile2;
break;
default:
// Unsupported profile in WebRTC.
return base::nullopt;
}
return webrtc::SdpVideoFormat(
"VP9", {{webrtc::kVP9FmtpProfileId,
webrtc::VP9ProfileToString(vp9_profile)}});
}
case media::VideoCodec::kCodecH264: {
webrtc::H264::Profile h264_profile;
switch (config.profile()) {
case media::H264PROFILE_BASELINE:
h264_profile = webrtc::H264::kProfileBaseline;
break;
case media::H264PROFILE_MAIN:
h264_profile = webrtc::H264::kProfileMain;
break;
case media::H264PROFILE_HIGH:
h264_profile = webrtc::H264::kProfileHigh;
break;
default:
// Unsupported H264 profile in WebRTC.
return base::nullopt;
}
const int width = config.visible_rect().width();
const int height = config.visible_rect().height();
const absl::optional<webrtc::H264::Level> h264_level =
webrtc::H264::SupportedLevel(width * height, kDefaultFps);
const webrtc::H264::ProfileLevelId profile_level_id(
h264_profile, h264_level.value_or(webrtc::H264::kLevel1));
webrtc::SdpVideoFormat format("H264");
format.parameters = {
{cricket::kH264FmtpProfileLevelId,
*webrtc::H264::ProfileLevelIdToString(profile_level_id)},
{cricket::kH264FmtpLevelAsymmetryAllowed, "1"},
{cricket::kH264FmtpPacketizationMode, "1"}};
return format;
}
default:
return base::nullopt;
}
}
// Due to https://crbug.com/345569, HW decoders do not distinguish between
// Constrained Baseline(CBP) and Baseline(BP) profiles. Since CBP is a subset of
// BP, we can report support for both. It is safe to do so when SW fallback is
// available.
// TODO(emircan): Remove this when the bug referred above is fixed.
void MapBaselineProfile(
std::vector<webrtc::SdpVideoFormat>* supported_formats) {
for (const auto& format : *supported_formats) {
const absl::optional<webrtc::H264::ProfileLevelId> profile_level_id =
webrtc::H264::ParseSdpProfileLevelId(format.parameters);
if (profile_level_id &&
profile_level_id->profile == webrtc::H264::kProfileBaseline) {
webrtc::SdpVideoFormat cbp_format = format;
webrtc::H264::ProfileLevelId cbp_profile = *profile_level_id;
cbp_profile.profile = webrtc::H264::kProfileConstrainedBaseline;
cbp_format.parameters[cricket::kH264FmtpProfileLevelId] =
*webrtc::H264::ProfileLevelIdToString(cbp_profile);
supported_formats->push_back(cbp_format);
return;
}
}
}
// This extra indirection is needed so that we can delete the decoder on the
// correct thread.
class ScopedVideoDecoder : public webrtc::VideoDecoder {
......@@ -66,8 +177,25 @@ RTCVideoDecoderFactory::RTCVideoDecoderFactory(
std::vector<webrtc::SdpVideoFormat>
RTCVideoDecoderFactory::GetSupportedFormats() const {
NOTREACHED();
return std::vector<webrtc::SdpVideoFormat>();
std::vector<webrtc::SdpVideoFormat> supported_formats;
for (auto& codec_config : kCodecConfigs) {
media::VideoDecoderConfig config(
codec_config.codec, codec_config.profile,
media::VideoDecoderConfig::AlphaMode::kIsOpaque,
media::VideoColorSpace(), media::kNoTransformation, kDefaultSize,
gfx::Rect(kDefaultSize), kDefaultSize, media::EmptyExtraData(),
media::EncryptionScheme::kUnencrypted);
if (gpu_factories_->IsDecoderConfigSupported(
RTCVideoDecoderAdapter::kImplementation, config) ==
media::GpuVideoAcceleratorFactories::Supported::kTrue) {
base::Optional<webrtc::SdpVideoFormat> format = VdcToWebRtcFormat(config);
if (format) {
supported_formats.push_back(*format);
}
}
}
MapBaselineProfile(&supported_formats);
return supported_formats;
}
RTCVideoDecoderFactory::~RTCVideoDecoderFactory() {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment