Pergunta

I have BufferedImage displayed in JFrame which I want to refresh periodically with raw R, G, B data I receive through Socket(byte[] buffer). Sequence of actions should look something like this:

  1. Receive byte[1280 * 480] array of pure RGB data(one byte per component) -> this part works flawless
  2. Iterate through byte array and call BufferedImage.setRgb(x, y, RGB) for every pixel

I have no problem with receiving and displaying one frame, but when I wrap code which does steps 1. and 2. I receive data regularly but not a single frame is ever shown. My guess was that receiving data is significantly faster than displaying images, in other words my received image gets somehow overwritten by new image etc. My next idea was to hand over buffer with image to another background thread and block main thread which does network communication until background thread has done 'displaying' image. Then I heard it can easily be done with SwingWorker here: Can a progress bar be used in a class outside main? but it does exactly the same thing as if I was still doing everything on one thread: no image was ever shown. Here is my code:

public class ConnectionManager {

public static final String serverIp = "192.168.1.10";
public static final int tcpPort = 7;
public static final int bufferSize = 1280;

private Socket client;
private BufferedInputStream networkReader;
private PrintStream printStream;

byte[] buffer;

public ConnectionManager(){}

public void connect() throws IOException{
    int dataRead;
    while(true){
        client = new Socket(serverIp, tcpPort);

        printStream = new PrintStream(client.getOutputStream());
        networkReader = new BufferedInputStream(client.getInputStream());

        dataRead = 0;
        buffer = new byte[1280 * 480];
        printStream.println(""); // CR is code to server to send data


        while(dataRead < (1280 * 480)){
            dataRead += networkReader.read(buffer, dataRead, (1280 * 480) - dataRead);
        }

        DrawBack d = new DrawBack();
        d.execute();
        try {
            d.get(); // here im trying to block main thread purposely
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        } 

    }
}

private class DrawBack extends SwingWorker<Void, Void>{

    @Override
    protected Void doInBackground() throws Exception {
        byte Y, U, V;
        int R, G, B, RGB, Yi, Ui, Vi;
        boolean alternate = false;
        for(int i = 0; i < 480; ++i){
            for(int j = 1; j < 1280; j += 2){
                if(alternate){
                    Y = buffer[i * 1280 + j];
                    V = buffer[i * 1280 + j -1];
                    U = buffer[i * 1280 + j -3];
                } else {
                    Y = buffer[i * 1280 + j];
                    U = buffer[i * 1280 + j -1];
                    V = buffer[i * 1280 + j +1];
                }
                Yi = Y & 0xFF;
                Ui = U & 0xFF;
                Vi = V & 0xFF;

                R = (int)(Yi + 1.402 * (Vi - 128));
                G = (int)(Yi - 0.34414 * (Ui - 128) - 0.71414 * (Vi - 128));
                B = (int)(Yi + 1.772 * (Ui - 128));

                RGB = R;
                RGB = (RGB << 8) + G;
                RGB = (RGB << 8) + B;

                alternate = !alternate;

                Masapp.window.getImage().setRGB(j/2, i, RGB);// reference to buffered image on JFrame

                if((i == 100) && (j == 479)){
                    System.out.println(Yi + " " + Ui + " " + Vi);
                }
            }
        }
        return null;
    }
}
}

I even tried to wait for completion with while:

DrawBack d = new DrawBack(); // DrawBack extends SwingWorker<Void, Void>
d.execute();
while(!d.isDone());

but it makes no improvement. I tried with calling BufferedImage.flush() and JFrame.invalidate() when I set all pixels.

My question basically is: How to refresh and display buffered image periodically?

Foi útil?

Solução

Your implementation is incorrectly synchronized in that it updates the GUI from the worker's background thread rather than the event dispatch thread. The resulting behavior is unpredictable. Instead, define a SwingWorker<BufferedImage, BufferedImage> and publish() the image for later rendering in your implementation of process(). For improved liveness, publish portions of the image as they are ready, e.g. publish() a BufferedImage containing one row at a time. Compare the example cited with this related example to see the approach.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top