最近在做mtk android 12 的项目时,遇到状态栏屏幕录制报错问题
屏幕的分辨率为1920x1200的,MediaRecorde提示尺寸不支持,看下源码
/**
* 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(final int screenWidth, final 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();
int screenWidthAligned = screenWidth;
if (screenWidthAligned % vc.getWidthAlignment() != 0) {
screenWidthAligned -= (screenWidthAligned % vc.getWidthAlignment());
}
int screenHeightAligned = screenHeight;
if (screenHeightAligned % vc.getHeightAlignment() != 0) {
screenHeightAligned -= (screenHeightAligned % vc.getHeightAlignment());
}
if (width >= screenWidthAligned && height >= screenHeightAligned
&& vc.isSizeSupported(screenWidthAligned, screenHeightAligned)) {
// Desired size is supported, now get the rate
int maxRate = vc.getSupportedFrameRatesFor(screenWidthAligned,
screenHeightAligned).getUpper().intValue();
if (maxRate < refreshRate) {
refreshRate = maxRate;
}
Log.d(TAG, "Screen size supported at rate " + refreshRate);
return new int[]{screenWidthAligned, screenHeightAligned, refreshRate};
}
// Otherwise, continue searching
double scale = Math.min(((double) width / screenWidth),
((double) height / screenHeight));
if (scale > maxScale) {
maxScale = Math.min(1, 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};
}
这就是SystemUI获取屏幕录制时支持的尺寸和帧率,录制成功需要尺寸和帧率都支持才可以录制成功.此时录制直接报错int maxRate = maxInfo.getSupportedFrameRatesFor(scaledWidth, scaledHeight).getUpper().intValue();,提示错误为尺寸不支持.所以我们这边只需要修改默认尺寸和帧率就可以了
private void prepare() throws IOException, RemoteException, RuntimeException {
//Setup media projection
IBinder b = ServiceManager.getService(MEDIA_PROJECTION_SERVICE);
IMediaProjectionManager mediaService =
IMediaProjectionManager.Stub.asInterface(b);
IMediaProjection proj = null;
proj = mediaService.createProjection(mUser, mContext.getPackageName(),
MediaProjectionManager.TYPE_SCREEN_CAPTURE, false);
IBinder projection = proj.asBinder();
mMediaProjection = new MediaProjection(mContext,
IMediaProjection.Stub.asInterface(projection));
File cacheDir = mContext.getCacheDir();
cacheDir.mkdirs();
mTempVideoFile = File.createTempFile("temp", ".mp4", cacheDir);
// Set up media recorder
mMediaRecorder = new MediaRecorder();
// Set up audio source
if (mAudioSource == MIC) {
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
}
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
// Set up video
DisplayMetrics metrics = new DisplayMetrics();
WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
wm.getDefaultDisplay().getRealMetrics(metrics);
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];*/
//Modify start
//int[] dimens = getSupportedSize(metrics.widthPixels, metrics.heightPixels, refreshRate);
final boolean isPortrait = mContext.getResources().getConfiguration().orientation
== Configuration.ORIENTATION_PORTRAIT;
int width;
int height;
Log.d(TAG, "[prepare] isPortrait " + isPortrait);
if (isPortrait) {
width = 1080;
height = 1920;
} else {
width = 1920;
height = 1080;
}
refreshRate = 30;
//Modify end
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(width, height);
mMediaRecorder.setVideoFrameRate(refreshRate);
mMediaRecorder.setVideoEncodingBitRate(vidBitRate);
mMediaRecorder.setMaxDuration(MAX_DURATION_MS);
mMediaRecorder.setMaxFileSize(MAX_FILESIZE_BYTES);
// Set up audio
if (mAudioSource == MIC) {
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.HE_AAC);
mMediaRecorder.setAudioChannels(TOTAL_NUM_TRACKS);
mMediaRecorder.setAudioEncodingBitRate(AUDIO_BIT_RATE);
mMediaRecorder.setAudioSamplingRate(AUDIO_SAMPLE_RATE);
}
mMediaRecorder.setOutputFile(mTempVideoFile);
mMediaRecorder.prepare();
// Create surface
mInputSurface = mMediaRecorder.getSurface();
mVirtualDisplay = mMediaProjection.createVirtualDisplay(
"Recording Display",
width,
height,
metrics.densityDpi,
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
mInputSurface,
null,
null);
mMediaRecorder.setOnInfoListener(mListener);
if (mAudioSource == INTERNAL ||
mAudioSource == MIC_AND_INTERNAL) {
mTempAudioFile = File.createTempFile("temp", ".aac",
mContext.getCacheDir());
mAudio = new ScreenInternalAudioRecorder(mTempAudioFile.getAbsolutePath(),
mMediaProjection, mAudioSource == MIC_AND_INTERNAL);
}
}
屏幕录制尺寸支持问题已解决,由于我这边还出现了一个frameworks层的DisplayLayout.java文件报了一个NullPointerException,还需要加一个null判断
路径:frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
/** sets this DisplayLayout to a copy of another on. */
public void set(DisplayLayout dl) {
//Modify start
if(dl!=null){
mUiMode = dl.mUiMode;
mWidth = dl.mWidth;
mHeight = dl.mHeight;
mCutout = dl.mCutout;
mRotation = dl.mRotation;
mDensityDpi = dl.mDensityDpi;
mHasNavigationBar = dl.mHasNavigationBar;
mHasStatusBar = dl.mHasStatusBar;
mNavBarFrameHeight = dl.mNavBarFrameHeight;
mNonDecorInsets.set(dl.mNonDecorInsets);
mStableInsets.set(dl.mStableInsets);
}
//Modify end
}
至此,屏幕录制报错问题解决