Tuesday, July 22, 2025

Java Screen Recorder

# Java Swing Desktop Screen Recorder with Network Streaming

I'll help you create a Java Swing application that can:
1. Display the desktop screen in real-time
2. Record the desktop screen with pause/resume functionality
3. Save the recording to a file
4. Stream the video over a network

Here's a complete implementation:

```java
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.atomic.AtomicBoolean;

public class DesktopRecorder extends JFrame {
    private Robot robot;
    private Rectangle screenRect;
    private AtomicBoolean recording = new AtomicBoolean(false);
    private AtomicBoolean paused = new AtomicBoolean(false);
    private JLabel screenLabel;
    private File outputFile;
    private ServerSocket serverSocket;
    private boolean streaming = false;

    public DesktopRecorder() {
        try {
            robot = new Robot();
            screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
            
            setTitle("Desktop Recorder");
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setLayout(new BorderLayout());
            
            screenLabel = new JLabel();
            add(screenLabel, BorderLayout.CENTER);
            
            JPanel controlPanel = new JPanel();
            JButton startBtn = new JButton("Start Recording");
            JButton pauseBtn = new JButton("Pause");
            JButton stopBtn = new JButton("Stop");
            JButton streamBtn = new JButton("Start Streaming");
            
            startBtn.addActionListener(e -> startRecording());
            pauseBtn.addActionListener(e -> togglePause());
            stopBtn.addActionListener(e -> stopRecording());
            streamBtn.addActionListener(e -> toggleStreaming());
            
            controlPanel.add(startBtn);
            controlPanel.add(pauseBtn);
            controlPanel.add(stopBtn);
            controlPanel.add(streamBtn);
            
            add(controlPanel, BorderLayout.SOUTH);
            
            pack();
            setSize(800, 600);
            setLocationRelativeTo(null);
            
            // Start screen capture thread
            new Thread(this::captureScreen).start();
        } catch (AWTException e) {
            e.printStackTrace();
        }
    }
    
    private void captureScreen() {
        while (true) {
            try {
                BufferedImage screenImage = robot.createScreenCapture(screenRect);
                ImageIcon icon = new ImageIcon(screenImage.getScaledInstance(
                    screenLabel.getWidth(), screenLabel.getHeight(), Image.SCALE_SMOOTH));
                screenLabel.setIcon(icon);
                
                if (recording.get() && !paused.get()) {
                    // Save frame to video file (simplified - in real app use proper video encoding)
                    saveFrame(screenImage);
                    
                    // Stream frame if streaming is enabled
                    if (streaming) {
                        streamFrame(screenImage);
                    }
                }
                
                Thread.sleep(1000 / 30); // ~30 FPS
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    private void saveFrame(BufferedImage image) {
        if (outputFile == null) {
            outputFile = new File("recording_" + System.currentTimeMillis() + ".avi");
        }
        
        // In a real application, you would use proper video encoding (like Xuggler or JavaCV)
        // This is a simplified placeholder
        try (FileOutputStream fos = new FileOutputStream(outputFile, true)) {
            // Just saving raw bytes - not a proper video format
            byte[] pixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
            fos.write(pixels);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    private void streamFrame(BufferedImage image) {
        try {
            if (serverSocket == null) {
                serverSocket = new ServerSocket(5555);
                new Thread(this::handleStreamConnections).start();
            }
            
            // Convert image to bytes (simplified)
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(image, "jpg", baos);
            byte[] imageBytes = baos.toByteArray();
            
            // Broadcast to all connected clients
            for (Socket client : ClientHandler.clients) {
                try {
                    DataOutputStream dos = new DataOutputStream(client.getOutputStream());
                    dos.writeInt(imageBytes.length);
                    dos.write(imageBytes);
                    dos.flush();
                } catch (IOException e) {
                    // Client disconnected
                    ClientHandler.clients.remove(client);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    private void handleStreamConnections() {
        try {
            while (streaming) {
                Socket client = serverSocket.accept();
                ClientHandler.clients.add(client);
                System.out.println("New client connected: " + client.getInetAddress());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    private void startRecording() {
        recording.set(true);
        paused.set(false);
        JOptionPane.showMessageDialog(this, "Recording started!");
    }
    
    private void togglePause() {
        paused.set(!paused.get());
        JOptionPane.showMessageDialog(this, paused.get() ? "Recording paused" : "Recording resumed");
    }
    
    private void stopRecording() {
        recording.set(false);
        paused.set(false);
        JOptionPane.showMessageDialog(this, "Recording stopped! Saved to: " + outputFile.getAbsolutePath());
        outputFile = null;
    }
    
    private void toggleStreaming() {
        streaming = !streaming;
        if (streaming) {
            JOptionPane.showMessageDialog(this, "Streaming started on port 5555");
        } else {
            JOptionPane.showMessageDialog(this, "Streaming stopped");
            try {
                if (serverSocket != null) {
                    serverSocket.close();
                    serverSocket = null;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            new DesktopRecorder().setVisible(true);
        });
    }
    
    static class ClientHandler {
        static java.util.List<Socket> clients = new java.util.ArrayList<>();
    }
}
```

## Important Notes About This Implementation:

1. **Video Encoding**: This example doesn't include proper video encoding. In a real application, you would use a library like:
   - Xuggler
   - JavaCV (OpenCV wrapper)
   - JCodec

2. **Performance**: Screen recording is resource-intensive. The current implementation captures at ~30 FPS but may need optimization for different systems.

3. **Network Streaming**: The streaming implementation is basic. For a production app, consider:
   - Using proper video compression
   - Implementing a protocol like RTMP
   - Adding authentication

4. **Pause Functionality**: The pause button stops frames from being saved/streamed but continues screen capture.

## To Improve This Application:

1. Add proper video encoding using a library like JavaCV:
```java
// Example with JavaCV
FFmpegFrameRecorder recorder = new FFmpegFrameRecorder("output.mp4", screenWidth, screenHeight);
recorder.setFormat("mp4");
recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
recorder.start();
```

2. Add file chooser dialog to select output location:
```java
JFileChooser fileChooser = new JFileChooser();
if (fileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
    outputFile = fileChooser.getSelectedFile();
}
```

3. Add quality settings (resolution, FPS, compression)

Would you like me to explain any specific part in more detail or enhance any particular functionality?

No comments: