blob: c7b8c3e3c7cd008e6afea72cdce2d69bddbd460d [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.media;
import android.content.Context;
import android.hardware.display.DisplayManager;
import android.media.MediaFormat;
import android.os.Build;
import android.util.Size;
import android.view.Display;
import androidx.annotation.Nullable;
import org.chromium.base.ContextUtils;
import org.chromium.base.Log;
import org.chromium.media.MediaCodecUtil.MimeTypes;
/**
* A utility class to make an estimate for the hints provided to MediaFormat as
* to the expected maximum resolution to prepare for.
*/
public class MaxAnticipatedResolutionEstimator {
private Context mContext;
private DisplayManager mDisplayManager;
private static final String TAG = "EstimateResolution";
private static final int SCREEN_WIDTH_4K = 3840;
private static final int SCREEN_HEIGHT_4K = 2160;
/**
* Class to represent display resolution.
*/
public static class Resolution {
int mWidth;
int mHeight;
public Resolution(int width, int height) {
mWidth = width;
mHeight = height;
}
public int getWidth() {
return mWidth;
}
public int getHeight() {
return mHeight;
}
}
private MaxAnticipatedResolutionEstimator() {}
public static Resolution getScreenResolution(MediaFormat format) {
Resolution resolution = getNativeResolution();
if (resolution == null) {
resolution.mWidth = format.getInteger(MediaFormat.KEY_WIDTH);
resolution.mHeight = format.getInteger(MediaFormat.KEY_HEIGHT);
}
// Cap screen size at 1080p for non-4K codecs
if (!format.getString(MediaFormat.KEY_MIME).equals(MimeTypes.VIDEO_HEVC)
&& !format.getString(MediaFormat.KEY_MIME).equals(MimeTypes.VIDEO_VP9)) {
resolution.mWidth = Math.min(resolution.mWidth, 1920);
resolution.mHeight = Math.min(resolution.mHeight, 1080);
}
return resolution;
}
@Nullable
public static Resolution getNativeResolution() {
// Starting with P, DisplayCompat relies on having read access to
// vendor.display-size (except for devices that correctly implement
// DisplayMode#getPhysicalHeight / getPhysicalWidth
// (e.g. Nvidia Shield).
// Unfortunately, before Q, SoC vendors did not grant such access to
// priv_app in their SELinux policy files. This means that for P devices
// (except Nvidia Shield), we should continue to guess display size by
// looking at the installed codecs.
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.P && !isNvidiaShield()
&& is4kVpxSupported()) {
Log.d(TAG, "Assuming 4K display capabilities because we can decode VP9 4K video.");
return new Resolution(SCREEN_WIDTH_4K, SCREEN_HEIGHT_4K);
}
// If we can't establish 4k support from the codecs, it's best to
// fall back on DisplayCompat.
Context context = ContextUtils.getApplicationContext();
DisplayManager displayManager =
(DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
DisplayCompat.ModeCompat[] supportedModes = DisplayCompat.getSupportedModes(
context, displayManager.getDisplay(Display.DEFAULT_DISPLAY));
// supportedModes always contain at least one native mode.
// All native modes are equal in resolution (but differ in refresh rates).
for (DisplayCompat.ModeCompat mode : supportedModes) {
if (mode.isNative()) {
return new Resolution(mode.getPhysicalWidth(), mode.getPhysicalHeight());
}
}
// Should never happen.
return null;
}
private static boolean isNvidiaShield() {
return "NVIDIA".equals(Build.MANUFACTURER) && Build.MODEL.startsWith("SHIELD");
}
private static boolean is4kVpxSupported() {
return ScreenResolutionUtil.isResolutionSupportedForType(
"video/x-vnd.on2.vp9", new Size(SCREEN_WIDTH_4K, SCREEN_HEIGHT_4K));
}
}