blob: eab4c87e02fff60985f99aaa8427f315d12898ad [file] [log] [blame]
// Copyright 2018 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "starboard/shared/starboard/media/media_support_internal.h"
#include "starboard/shared/starboard/media/video_capabilities.h"
#include "starboard/shared/uwp/application_uwp.h"
#include "starboard/shared/uwp/extended_resources_manager.h"
#include "starboard/shared/uwp/xb1_get_type.h"
#include "starboard/shared/win32/video_decoder.h"
#include "starboard/window.h"
using ::starboard::shared::starboard::media::MimeType;
namespace {
using ::starboard::shared::uwp::ApplicationUwp;
using ::starboard::shared::uwp::ExtendedResourcesManager;
class XboxVideoCapabilities {
public:
XboxVideoCapabilities() {
bool limit_to_2k = false;
SbWindowSize window_size = ApplicationUwp::Get()->GetVisibleAreaSize();
if (window_size.width <= 1920 || window_size.height <= 1080) {
limit_to_2k = true;
}
#ifdef ENABLE_H264_4K_SUPPORT
// Documentation claims the following resolution constraints for H264
// decoder:
// (https://docs.microsoft.com/en-us/windows/win32/medfound/h-264-video-decoder)
// - minimum Resolution 48*48 pixels
// - maximum Resolution 4096*2304 pixels
// For Windows 8 and higher the maximum guaranteed resolution for DXVA
// acceleration is 1920*1088 pixels.
// At higher resolutions, decoding is done with DXVA, if it is supported by
// the underlying hardware, otherwise, decoding is done with software.
// Therefore platforms must explicitly opt-in to support 4k H264.
hw_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecH264, 4096, 2304, 60);
#else // ENABLE_H264_4K_SUPPORT
hw_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecH264, 1920, 1088, 60);
#endif // ENABLE_H264_4K_SUPPORT
switch (starboard::shared::uwp::GetXboxType()) {
case starboard::shared::uwp::kXboxOneBase:
// Horizontal video resolutions
gpu_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecVp9, 2560, 1440,
30);
gpu_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecVp9, 1920, 1080,
60);
gpu_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecAv1, 2560, 1440,
30);
gpu_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecAv1, 1920, 1080,
60);
// Vertical video resolutions
gpu_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecVp9, 1440, 2560,
30);
gpu_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecVp9, 1080, 1920,
60);
gpu_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecAv1, 1440, 2560,
30);
gpu_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecAv1, 1080, 1920,
60);
break;
case starboard::shared::uwp::kXboxOneS:
if (!limit_to_2k) {
// Horizontal video resolution
gpu_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecVp9, 3840,
2160, 30);
// Vertical video resolution
gpu_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecVp9, 2160,
3840, 30);
}
// Horizontal video resolutions
gpu_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecVp9, 2560, 1440,
60);
gpu_decoder_capabilities_.AddHdrRule(kSbMediaVideoCodecVp9, 2560, 1440,
60);
gpu_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecAv1, 2560, 1440,
30);
gpu_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecAv1, 1920, 1080,
60);
gpu_decoder_capabilities_.AddHdrRule(kSbMediaVideoCodecAv1, 2560, 1440,
30);
gpu_decoder_capabilities_.AddHdrRule(kSbMediaVideoCodecAv1, 1920, 1080,
60);
// Vertical video resolutions
gpu_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecVp9, 1440, 2560,
60);
gpu_decoder_capabilities_.AddHdrRule(kSbMediaVideoCodecVp9, 1440, 2560,
60);
gpu_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecAv1, 1440, 2560,
30);
gpu_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecAv1, 1080, 1920,
60);
gpu_decoder_capabilities_.AddHdrRule(kSbMediaVideoCodecAv1, 1440, 2560,
30);
gpu_decoder_capabilities_.AddHdrRule(kSbMediaVideoCodecAv1, 1080, 1920,
60);
break;
case starboard::shared::uwp::kXboxOneX:
// Horizontal video resolutions
hw_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecVp9, 3840, 2160,
60);
hw_decoder_capabilities_.AddHdrRule(kSbMediaVideoCodecVp9, 3840, 2160,
30);
hw_decoder_capabilities_.AddHdrRule(kSbMediaVideoCodecVp9, 2560, 1440,
60);
// Vertical video resolutions
hw_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecVp9, 2160, 3840,
30);
hw_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecVp9, 2160, 3840,
60);
hw_decoder_capabilities_.AddHdrRule(kSbMediaVideoCodecVp9, 2160, 3840,
30);
hw_decoder_capabilities_.AddHdrRule(kSbMediaVideoCodecVp9, 1440, 2560,
60);
break;
case starboard::shared::uwp::kXboxSeriesS:
// Horizontal video resolutions
hw_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecVp9, 3840, 2160,
60);
hw_decoder_capabilities_.AddHdrRule(kSbMediaVideoCodecVp9, 3840, 2160,
60);
// Vertical video resolutions
// Microsoft Vp9 MFT component is limited by 3840x2160 resolution
// so vertical video resolutions is the same as horizontal
// Horizontal video resolutions
hw_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecAv1, 3840, 2160,
30);
hw_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecAv1, 3840, 2160,
60);
hw_decoder_capabilities_.AddHdrRule(kSbMediaVideoCodecAv1, 3840, 2160,
30);
hw_decoder_capabilities_.AddHdrRule(kSbMediaVideoCodecAv1, 1920, 1080,
60);
// Vertical video resolutions
hw_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecAv1, 2160, 3840,
30);
hw_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecAv1, 2160, 3840,
60);
hw_decoder_capabilities_.AddHdrRule(kSbMediaVideoCodecAv1, 2160, 3840,
30);
hw_decoder_capabilities_.AddHdrRule(kSbMediaVideoCodecAv1, 1080, 1920,
60);
break;
case starboard::shared::uwp::kXboxSeriesX:
// Horizontal video resolutions
hw_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecVp9, 3840, 2160,
60);
hw_decoder_capabilities_.AddHdrRule(kSbMediaVideoCodecVp9, 3840, 2160,
60);
// Vertical video resolutions vor vp9 is the same as horizontal
// Horizontal video resolutions
hw_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecAv1, 3840, 2160,
30);
hw_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecAv1, 2560, 1440,
60);
hw_decoder_capabilities_.AddHdrRule(kSbMediaVideoCodecAv1, 2560, 1440,
30);
hw_decoder_capabilities_.AddHdrRule(kSbMediaVideoCodecAv1, 1920, 1080,
60);
// Vertical video resolutions
hw_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecAv1, 2160, 3840,
30);
hw_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecAv1, 1440, 2560,
60);
hw_decoder_capabilities_.AddHdrRule(kSbMediaVideoCodecAv1, 1440, 2560,
30);
hw_decoder_capabilities_.AddHdrRule(kSbMediaVideoCodecAv1, 1080, 1920,
60);
break;
default:
// If you appeared here you likely added new XBox model name but not
// specified corresponded case here to add rule for SDR and HDR
// supported resolution/framerate.
SB_NOTREACHED();
}
}
bool IsSupported(SbMediaVideoCodec codec,
int bit_depth,
SbMediaPrimaryId primary_id,
SbMediaTransferId transfer_id,
SbMediaMatrixId matrix_id,
int width,
int height,
int fps) const {
bool is_supported = hw_decoder_capabilities_.IsSupported(
codec, transfer_id, width, height, fps);
if (ExtendedResourcesManager::GetInstance()->IsGpuDecoderReady() &&
!is_supported) {
is_supported = gpu_decoder_capabilities_.IsSupported(codec, transfer_id,
width, height, fps);
}
if (starboard::shared::starboard::media::IsSDRVideo(
bit_depth, primary_id, transfer_id, matrix_id)) {
return is_supported;
}
#if SB_API_VERSION < 14
// AV1 decoder only supports YUVI420 compact texture format. The new format
// is only supported after
// 14.
if (codec == kSbMediaVideoCodecAv1) {
return false;
}
#endif // SB_API_VERSION >= 14
is_supported &= ApplicationUwp::Get()->IsHdrSupported();
is_supported &= bit_depth == 10;
is_supported &= primary_id == kSbMediaPrimaryIdBt2020;
is_supported &= transfer_id == kSbMediaTransferIdSmpteSt2084;
// According to https://support.google.com/youtube/answer/7126552
// upload requirements the color matrix should be Rec.2020
// non-constant luminance.
is_supported &= matrix_id == kSbMediaMatrixIdBt2020NonconstantLuminance;
return is_supported;
}
private:
// We use gpu accelerated software decoder on kXboxOneBase and kXboxOneS. The
// software decoder initialization takes some time at app launch, and will be
// only available after initialization. So, we use |gpu_decoder_capabilities_|
// and ExtendedResourcesManager::IsGpuDecoderReady() to determine the device
// capabilities with software decoder. |hw_decoder_capabilities_| is
// determined by the device type and would not change at all.
starboard::shared::starboard::media::VideoCapabilities
hw_decoder_capabilities_;
starboard::shared::starboard::media::VideoCapabilities
gpu_decoder_capabilities_;
};
} // namespace
bool SbMediaIsVideoSupported(SbMediaVideoCodec video_codec,
const MimeType* mime_type,
int profile,
int level,
int bit_depth,
SbMediaPrimaryId primary_id,
SbMediaTransferId transfer_id,
SbMediaMatrixId matrix_id,
int frame_width,
int frame_height,
int64_t bitrate,
int fps,
bool decode_to_texture_required) {
if (bitrate > kSbMediaMaxVideoBitrateInBitsPerSecond) {
return false;
}
// To avoid massive dropping frames, only support video's fps
// that is at most 20% higher than the refresh rate of display
// in HDR mode.
if (1.2 * ApplicationUwp::Get()->GetRefreshRate() < fps) {
return false;
}
static const XboxVideoCapabilities xbox_video_capabilities;
return xbox_video_capabilities.IsSupported(video_codec, bit_depth, primary_id,
transfer_id, matrix_id,
frame_width, frame_height, fps);
}