android 屏幕镜像问题 android15 不更新图像

109 天前
 fenglirookie

private void getScreenSize() { DisplayMetrics metrics = new DisplayMetrics(); WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); windowManager.getDefaultDisplay().getRealMetrics(metrics);

    screenWidth = metrics.widthPixels;
    screenHeight = metrics.heightPixels;

    Log.d(TAG, "屏幕分辨率: " + screenWidth + "x" + screenHeight);
}
// 计算距离下一个 15 秒整点的时间

private void setImageReaderListener() {
    if (imageReader != null) {
        Handler handler = new Handler(Looper.getMainLooper());
        imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
            @Override
            public void onImageAvailable(ImageReader reader) {
                Image screenCopyImageRender = null;
                Bitmap PicBitmap = null;
                try {
                    screenCopyImageRender = reader.acquireLatestImage();
                    if (screenCopyImageRender != null) {

// Log.d(TAG,"新图像以推送"); // logListener.callBack("截图获取成功"); Image.Plane[] planes = screenCopyImageRender.getPlanes(); ByteBuffer buffer = planes[0].getBuffer(); int pixelStride = planes[0].getPixelStride(); int rowStride = planes[0].getRowStride(); int imageWidth = screenCopyImageRender.getWidth(); int imageHeight = screenCopyImageRender.getHeight();

                        // 计算包含填充的宽度
                        int bitmapWidth = rowStride / pixelStride;

                        // 确保缓冲区从头开始读取数据
                        buffer.position(0);
                        // 重新创建正确大小的 Bitmap
                        PicBitmap = Bitmap.createBitmap(bitmapWidth, imageHeight, Bitmap.Config.ARGB_8888);
                        buffer.position(0);
                        PicBitmap.copyPixelsFromBuffer(buffer);

// currentFullScreenImage = PicBitmap; commonPlay.updateCurrentFullScreenImage(PicBitmap); long currentMillis = System.currentTimeMillis(); int seconds = (int) ((currentMillis / 1000) % 60); // 当前时间的秒数 if (seconds % 15 == 0){ uploadLog(currentEmail,currentRoleName,"图像推送触发"); } } } catch (Exception e) { Log.e(TAG, "处理图像异常", e); } finally { if (screenCopyImageRender != null) { try { screenCopyImageRender.close(); } catch (Exception e) { Log.w(TAG, "Image 已关闭或关闭失败", e); } } }

            }
        }, handler);
    } else {
        Log.d(TAG,"镜像为空");
    }
}
private void refreshVirtualDisplay(){
    Log.d(TAG,"定时刷新 VirtualDisplay");
    uploadLog(currentEmail,currentRoleName,"定时刷新 VirtualDisplay");
    DelayedTaskExecutor refreshExecutor = new DelayedTaskExecutor();
    refreshExecutor.addTask(() -> {
        updateCaptureParametersForLandscape();
    }, 5*60*1000);
    refreshExecutor.setOnAllTasksCompletedListener(()->{
        refreshVirtualDisplay();
    });
    refreshExecutor.executeTasks();


}

private void updateCaptureParametersForLandscape() {
    // 1. 更新屏幕尺寸
    getScreenSize();
    Log.d(TAG, "更新后的屏幕分辨率: " + screenWidth + "x" + screenHeight);

    // 2. 创建一个新的 ImageReader ,尺寸为更新后的屏幕宽高
    ImageReader newImageReader = ImageReader.newInstance(screenWidth, screenHeight, PixelFormat.RGBA_8888, 3);

    // 3. 尝试通过反射调用 VirtualDisplay 的 resize 和 setSurface 方法更新参数
    if (virtualDisplay != null) {
        try {
            // 调用 resize(int width, int height, int densityDpi)
            Method resizeMethod = virtualDisplay.getClass().getMethod("resize", int.class, int.class, int.class);
            resizeMethod.invoke(virtualDisplay, screenWidth, screenHeight, getResources().getDisplayMetrics().densityDpi);
            Log.d(TAG, "VirtualDisplay 调整尺寸成功");

            // 调用 setSurface(Surface surface) 更新 Surface
            Method setSurfaceMethod = virtualDisplay.getClass().getMethod("setSurface", Surface.class);
            setSurfaceMethod.invoke(virtualDisplay, newImageReader.getSurface());
            Log.d(TAG, "VirtualDisplay Surface 更新成功");
        } catch (Exception e) {
            Log.e(TAG, "更新 VirtualDisplay 失败: " + e.getMessage());
            // 如调用失败,可考虑其他处理方式,比如提示用户或者重启录制
        }
    } else {
        // 如果 virtualDisplay 为空,则重新创建一个(但通常不建议这样做,以避免重复授权问题)
        virtualDisplay = mediaProjection.createVirtualDisplay("ScreenCapture", screenWidth, screenHeight, getResources().getDisplayMetrics().densityDpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, newImageReader.getSurface(), null, null);
        Log.d(TAG, "VirtualDisplay 已重新创建");
    }

    // 4. 关闭旧的 ImageReader 并更新引用
    if (imageReader != null) {
        imageReader.close();
    }
    imageReader = newImageReader;
    commonPlay = new CommonPlay(context, mediaProjection, mediaProjectionManager, imageReader);
    setImageReaderListener();
}

private void startScreenCapture(int resultCode, Intent data) {
    // 1️⃣ 获取 MediaProjection
    mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, data);
    getScreenSize();

    if (mediaProjection == null) {
        Log.e("ScreenCapture", "MediaProjection is null");
        return;
    }
    Log.d(TAG, "startScreenCapture: " + screenWidth + "x" + screenHeight);
    // 2️⃣ 创建 ImageReader ,用于接收屏幕数据
    imageReader = ImageReader.newInstance(screenWidth, screenHeight, PixelFormat.RGBA_8888, 3);

    // 注册回调
    mediaProjection.registerCallback(projectionCallback, new Handler(Looper.getMainLooper()));


    // 3️⃣ 创建 VirtualDisplay ,将屏幕内容映射到 ImageReader
    virtualDisplay = mediaProjection.createVirtualDisplay("ScreenCapture", screenWidth, screenHeight, getResources().getDisplayMetrics().densityDpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, imageReader.getSurface(), null, null);
    commonPlay = new CommonPlay(context, mediaProjection, mediaProjectionManager, imageReader);
    setImageReaderListener();
    refreshVirtualDisplay();

}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        CharSequence name = "My Channel";
        String description = "Channel for my foreground service";
        int importance = NotificationManager.IMPORTANCE_DEFAULT;
        NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
        channel.setDescription(description);

        // 注册通知渠道
        NotificationManager notificationManager = getSystemService(NotificationManager.class);
        notificationManager.createNotificationChannel(channel);
    }

    // 创建通知
    Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID).setContentTitle("My Service").setContentText("Service is running in the foreground").setSmallIcon(R.drawable.ic_launcher_background)  // 小图标
            .build();

    // 启动前台服务
    startForeground(1, notification);
    int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED);
    Intent data = intent.getParcelableExtra("data");

    if (resultCode == Activity.RESULT_OK && data != null) {
        startScreenCapture(resultCode, data);
    }
    return START_STICKY;
}
2094 次点击
所在节点    Android
4 条回复
sankemao
109 天前
如果屏幕上像素没有变化,拿不到截图的
flyqie
109 天前
话说...这怎么帖子排版全丢了。。。
fenglirookie
106 天前
@flyqie 不知道,,我粘贴进来就这样
fenglirookie
106 天前
@sankemao 像素怎么会变化呢?不是画面变化了就会推送吗?还说的 16 毫秒就会推送一次

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://ex.noerr.eu.org/t/1135458

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX