Month: October 2013

web socket example to stream screen to html 5 player

Here is a working example using web socket to stream screen to html 5 player. The server is in java, I use websockify.py to route the websocket to java socket.

package com.videotojpeg;

import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

import javax.imageio.ImageIO;

import org.apache.commons.codec.binary.Base64;

import com.github.sarxos.webcam.Webcam;

public class ClientServiceThread implements Runnable {
	Socket myClientSocket;
	Webcam webcam = Webcam.getDefault();

	public ClientServiceThread() {
		super();
	}

	ClientServiceThread(Socket s) {
		myClientSocket = s;
		webcam.setViewSize(new Dimension(480, 400));
		webcam.open();
	}

	public void run() {
		InputStream in = null;
		OutputStream out = null;
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		System.out.println("Accepted Client Address - " + myClientSocket.getInetAddress().getHostName());

		try {
			in = myClientSocket.getInputStream();
			out = myClientSocket.getOutputStream();

			int x = 1;
			while (true) {
				byte bytes2[] = new byte[1];
				for (int z = 0; z < 11; z++) {
					in.read(bytes2);
					System.out.print((char) bytes2[0]);
				}
				System.out.println();
				
				System.out.println("start cap");
				BufferedImage image = resize(new Robot().createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize())), 640, 480);
				//				BufferedImage image = new Robot().createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
				System.out.println("end cap");
				

				System.out.println("start encode");
				baos.reset();
				ImageIO.write(image, "jpg", baos);
				//				ImageIO.write(image, "png", new File("testing.png"));
				baos.flush();
				byte[] bytes = baos.toByteArray();
				baos.close();

				//				out.write("fssss".getBytes());

				byte header[] = (String.format("%09d", Base64.encodeBase64(bytes).length)).getBytes();
				System.out.println("end encode");

				System.out.println("start transmit");
				out.write(header);
				out.flush();

				out.write(Base64.encodeBase64(bytes));
				out.flush();
				System.out.println("end transmit");
				
				System.out.println("reply :" + bytes.length + "," + bytes + ", encoded len=" + Base64.encodeBase64(bytes).length);				x++;

			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				in.close();
				out.close();
				myClientSocket.close();
				System.out.println("...Stopped");
			} catch (IOException ioe) {
				ioe.printStackTrace();
			}
		}
	}

	public static BufferedImage resize(BufferedImage img, int newW, int newH) {
		int w = img.getWidth();
		int h = img.getHeight();
		BufferedImage dimg = new BufferedImage(newW, newH, img.getType());
		Graphics2D g = dimg.createGraphics();
		g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
		g.drawImage(img, 0, 0, newW, newH, 0, 0, w, h, null);
		g.dispose();
		return dimg;
	}
}

html 5 player

<html>
<title>Custom Draw</title>

<div id="output" style="display:none">output</div>
<canvas id="myCanvas" width="720" height="600" style="border:1px solid #000000;"></canvas>

<script type="text/javascript" src="jquery-2.0.3.min.js"></script>

<script>
        var width=720;
        var height=600;

        var c=document.getElementById("myCanvas");
        var ctx=c.getContext("2d");
        var imgData=ctx.createImageData(1440,900);
        var x=0;
        function draw(){
                for (var i=0;i<imgData.data.length;i+=4){
                        imgData.data[i+0]=Math.random()*255;
                        imgData.data[i+1]=Math.random()*255;
                        imgData.data[i+2]=Math.random()*255;
                        imgData.data[i+3]=255;
                }
                ctx.putImageData(imgData,0,0);
                $('#output').html(x);
                console.log(x);
                x++;
        }

        //setInterval(draw,10);


        ////////////////////////////////////////////////////////////////////////////////
        var blob;
        var readSize=0;
        var started=false;
        var imageSize=0;
        var image64="";

        websocket = new WebSocket("ws://192.168.163.121:8887", "binary");
        websocket.binaryType = "arraybuffer";
    websocket.onopen = function(evt) { onOpen(evt) };
    websocket.onclose = function(evt) { onClose(evt) };
    websocket.onmessage = function(evt) { onMessage(evt) };
    websocket.onerror = function(evt) { onError(evt) };

function onOpen(evt){
                websocket.send("hello peter");
        }

        function onClose(evt){
                //$('#output').html("close");
        }

        function onMessage(evt){
                blob=evt;
                var r=String.fromCharCode.apply(null, new Uint8Array(blob.data));
                

                if (started==false){
                        if (r==9){
                                imageSize=parseInt(r);
                        }else{
                                imageSize=parseInt(r.substring(0,9));
                                image64+=r.substring(9);
                                readSize+=parseInt(r.length-9);
                        }
                        console.log("imageSize="+imageSize);
                        started=true;
                }else{
                        //$('#output').html(r.length);
                        //console.log("r.length="+r.length);
                        image64+=r;
                        readSize+=parseInt(r.length);
                }
                console.log("readSize="+readSize+", r.length="+r.length);
                if (readSize==imageSize){
                        img=new Image();
                    img.onload=function(){
                        ctx.drawImage(img,0,0,img.width,img.height,0,0,width,height);
                        
                        websocket.send("hello peter");
                    }
                    console.log("loaded image, length="+image64.length);
                        img.src='data:image/jpg;base64,'+image64;

                        readSize=0;
                        started=false;
                        image64="";
                }
        }

function onerror(evt){
        }
</script>
</html>

read count : 2349

SwingUtilities.updateComponentTreeUI(this); will reset all custom UI

SwingUtilities.updateComponentTreeUI(this); will reset your own UI, if you call setUI() in constructor.

Example:

PeterCustomeTabbedPane —– extend ——> MaryCustomTabbedPane —-  extend ->   JTabbedPane (swing component)

Suppose PeterCustomeTabbedPane and MaryCustomTabbedPane have their own TabbedPaneUI, once you called SwingUtilities.updateComponentTreeUI(this); , PeterCustomeTabbedPane’s UI class will be reset to MaryCustomTabbedPane’s UI class.

Workaround:

!!! dont call setUI in PeterCustomeTabbedPane, override the setUI() method and set whatever you want to UI.

read count : 731

i may know why the gdb command “x” only request one byte each time

I am playing the gdbstub in qemu, i found a bug there http://peter.kingofcoders.com/?p=859 , if i invoke the function cpu_physical_memory_rw(0xffff0, mem_buf, 50, 0) , qemu crashes.

Then, i tested the gdb command “x /20bx 0xffff0” and use tcpflow to capture the gdb packet, i found out gdb send 20 command and each time request one byte only. GDB could already know this bug and try to avoid it by *not* request 20 bytes at once.

gdb x command
gdb x command

read count : 516

qemu 1.6.0 rc2 has bug

I found a bug in qemu, version 1.6.0 rc2. When i invoke:

cpu_physical_memory_rw(addr, mem_buf, noOfBytes, 0);

where addr=0xffff0 and noOfBytes=50, qemu will has segmentation fault. I called the cpu_physical_memory_rw right after the qemu is started (haven’t run yet) with gdb. The vm was in real mode, i am not sure it is crossing memory boundary problem. But i just failed for address 0xffff0. For address 0xfff and 0xfffff0 are ok.

Peter.

read count : 387