Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ed3caef9 authored by Beth Thibodeau's avatar Beth Thibodeau
Browse files

Downscale recording as needed for device codecs

Some devices cannot play back video at screen resolution, so check
whether any codecs can support screen resolution, or downscale the video
to the max supported size and refresh rate.

Fixes: 167978946
Test: manual
Change-Id: Ie174aa0db25f189c8e3601a81ad869777ba70a60
parent 7ae5a974
Loading
Loading
Loading
Loading
+90 −8
Original line number Diff line number Diff line
@@ -30,6 +30,8 @@ import android.graphics.Bitmap;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
import android.media.MediaFormat;
import android.media.MediaMuxer;
import android.media.MediaRecorder;
import android.media.ThumbnailUtils;
@@ -124,17 +126,19 @@ public class ScreenMediaRecorder {
        DisplayMetrics metrics = new DisplayMetrics();
        WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
        wm.getDefaultDisplay().getRealMetrics(metrics);
        int screenWidth = metrics.widthPixels;
        int screenHeight = metrics.heightPixels;
        int refereshRate = (int) wm.getDefaultDisplay().getRefreshRate();
        int vidBitRate = screenHeight * screenWidth * refereshRate / VIDEO_FRAME_RATE
        int refreshRate = (int) wm.getDefaultDisplay().getRefreshRate();
        int[] dimens = getSupportedSize(metrics.widthPixels, metrics.heightPixels, refreshRate);
        int width = dimens[0];
        int height = dimens[1];
        refreshRate = dimens[2];
        int vidBitRate = width * height * refreshRate / VIDEO_FRAME_RATE
                * VIDEO_FRAME_RATE_TO_RESOLUTION_RATIO;
        mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
        mMediaRecorder.setVideoEncodingProfileLevel(
                MediaCodecInfo.CodecProfileLevel.AVCProfileHigh,
                MediaCodecInfo.CodecProfileLevel.AVCLevel3);
        mMediaRecorder.setVideoSize(screenWidth, screenHeight);
        mMediaRecorder.setVideoFrameRate(refereshRate);
        mMediaRecorder.setVideoSize(width, height);
        mMediaRecorder.setVideoFrameRate(refreshRate);
        mMediaRecorder.setVideoEncodingBitRate(vidBitRate);
        mMediaRecorder.setMaxDuration(MAX_DURATION_MS);
        mMediaRecorder.setMaxFileSize(MAX_FILESIZE_BYTES);
@@ -153,8 +157,8 @@ public class ScreenMediaRecorder {
        mInputSurface = mMediaRecorder.getSurface();
        mVirtualDisplay = mMediaProjection.createVirtualDisplay(
                "Recording Display",
                screenWidth,
                screenHeight,
                width,
                height,
                metrics.densityDpi,
                DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                mInputSurface,
@@ -172,6 +176,84 @@ public class ScreenMediaRecorder {

    }

    /**
     * Find the highest supported screen resolution and refresh rate for the given dimensions on
     * this device, up to actual size and given rate.
     * If possible this will return the same values as given, but values may be smaller on some
     * devices.
     *
     * @param screenWidth Actual pixel width of screen
     * @param screenHeight Actual pixel height of screen
     * @param refreshRate Desired refresh rate
     * @return array with supported width, height, and refresh rate
     */
    private int[] getSupportedSize(int screenWidth, int screenHeight, int refreshRate) {
        double maxScale = 0;

        MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
        MediaCodecInfo.VideoCapabilities maxInfo = null;
        for (MediaCodecInfo codec : codecList.getCodecInfos()) {
            String videoType = MediaFormat.MIMETYPE_VIDEO_AVC;
            String[] types = codec.getSupportedTypes();
            for (String t : types) {
                if (!t.equalsIgnoreCase(videoType)) {
                    continue;
                }
                MediaCodecInfo.CodecCapabilities capabilities =
                        codec.getCapabilitiesForType(videoType);
                if (capabilities != null && capabilities.getVideoCapabilities() != null) {
                    MediaCodecInfo.VideoCapabilities vc = capabilities.getVideoCapabilities();

                    int width = vc.getSupportedWidths().getUpper();
                    int height = vc.getSupportedHeights().getUpper();

                    if (width >= screenWidth && height >= screenHeight
                            && vc.isSizeSupported(screenWidth, screenHeight)) {

                        // Desired size is supported, now get the rate
                        int maxRate = vc.getSupportedFrameRatesFor(screenWidth, screenHeight)
                                .getUpper().intValue();

                        if (maxRate < refreshRate) {
                            refreshRate = maxRate;
                        }
                        Log.d(TAG, "Screen size supported at rate " + refreshRate);
                        return new int[]{screenWidth, screenHeight, refreshRate};
                    }

                    // Otherwise, continue searching
                    double scale = Math.min(((double) width / screenWidth),
                            ((double) height / screenHeight));
                    if (scale > maxScale) {
                        maxScale = scale;
                        maxInfo = vc;
                    }
                }
            }
        }

        // Resize for max supported size
        int scaledWidth = (int) (screenWidth * maxScale);
        int scaledHeight = (int) (screenHeight * maxScale);
        if (scaledWidth % maxInfo.getWidthAlignment() != 0) {
            scaledWidth -= (scaledWidth % maxInfo.getWidthAlignment());
        }
        if (scaledHeight % maxInfo.getHeightAlignment() != 0) {
            scaledHeight -= (scaledHeight % maxInfo.getHeightAlignment());
        }

        // Find max supported rate for size
        int maxRate = maxInfo.getSupportedFrameRatesFor(scaledWidth, scaledHeight)
                .getUpper().intValue();
        if (maxRate < refreshRate) {
            refreshRate = maxRate;
        }

        Log.d(TAG, "Resized by " + maxScale + ": " + scaledWidth + ", " + scaledHeight
                + ", " + refreshRate);
        return new int[]{scaledWidth, scaledHeight, refreshRate};
    }

    /**
    * Start screen recording
    */