V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
fenglirookie
V2EX  ›  Android

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

  •  
  •   fenglirookie · 6 天前 · 939 次点击

    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;
    }
    
    4 条回复    2025-06-02 20:30:35 +08:00
    sankemao
        1
    sankemao  
       6 天前
    如果屏幕上像素没有变化,拿不到截图的
    flyqie
        2
    flyqie  
       6 天前 via Android
    话说...这怎么帖子排版全丢了。。。
    fenglirookie
        3
    fenglirookie  
    OP
       3 天前 via Android
    @flyqie 不知道,,我粘贴进来就这样
    fenglirookie
        4
    fenglirookie  
    OP
       3 天前 via Android
    @sankemao 像素怎么会变化呢?不是画面变化了就会推送吗?还说的 16 毫秒就会推送一次
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3918 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 19ms · UTC 05:18 · PVG 13:18 · LAX 22:18 · JFK 01:18
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.