简体   繁体   中英

How can you stream M-JPEG from a Java HttpServer?

I am trying to stream M-JPEG content from a custom video source object but when reviewing the connection from wireshark no data is being returned from the server. Below are some relevant code segments that I used. Does anyone know how to get this code to function?

Segment:

            try {
                server = new HTTPServerWrapper(8099);                
                server.MJpegBindVideoSource(camera, "/test");
            } catch (IOException ex) {
                Logger.getLogger(Recorder.class.getName()).log(Level.SEVERE, null, ex);
            }

physics/server/HTTPServerWrapper.java:

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package physics.server;

import java.io.IOException;
import java.net.InetSocketAddress;
import physics.VideoSource;

/**
 *
 * @author rritoch
 */
public class HTTPServerWrapper  {

    com.sun.net.httpserver.HttpServer server;

    public HTTPServerWrapper(int port) throws IOException{        
       server = com.sun.net.httpserver.HttpServer.create(new InetSocketAddress(port), 0);                
    }

    public void MJpegBindVideoSource(VideoSource vs, String path) {        
        final VideoSource v = vs;        
        server.createContext(path,new MJpegHandler(vs)); 
    }    


}

physics/server/MJpegHandler.java:

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package physics.server;

import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import javax.imageio.ImageIO;
import physics.VideoSource;

/**
 *
 * @author rritoch
 */
public class MJpegHandler implements HttpHandler {

    VideoSource vs;

    public MJpegHandler(VideoSource videosource) {
        this.vs = videosource;
    }

    public void setVideoSource(VideoSource videosource) {
        this.vs = videosource;
    }

    public void handle(HttpExchange connection) throws IOException {
        byte[] data;

        System.err.println("Connect...");

        String boundary = "VNetPhysics";

        Headers responseHeaders = connection.getResponseHeaders();
        responseHeaders.add("Content-Type", String.format("multipart/x-mixed-replace; boundary=--%s", boundary));
        responseHeaders.add("Cache-Control", "no-cache, private");
        responseHeaders.add("Pragma", "no-cache");
        responseHeaders.add("Max-Age", "0");
        responseHeaders.add("Expires", "0");
        connection.sendResponseHeaders(200, 0);
        OutputStream responseBody = connection.getResponseBody();



        while (true) {

            BufferedImage bufferedImage = vs.getBufferedImage();

            ByteArrayOutputStream os = new ByteArrayOutputStream(8192 * 4);
            ImageIO.write(bufferedImage, "jpg", os);
            data = os.toByteArray();
            os.close();


            responseBody.write(("--" + boundary + "\r\n"
                    + "Content-type: image/jpg\r\n"
                    + "Content-Length: "
                    + data.length
                    + "\r\n\r\n").getBytes());

            responseBody.write(data);
            responseBody.flush();
        }

    }
};

Edit: After adding the connect message to stderr it seems that requests to http: // 192.168.2.7:8099/test are not being directed to this handler, with no handler I can see why it isn't functional. What am I missing to get this handler to process the request?

I see that 2 years passed since this question asked but I'll post my answer anyway in case people searched and found here... here is how I did;

import org.mortbay.util.MultiPartOutputStream;
import org.w3c.www.mime.MultipartInputStream;

//other stuff

public static int searchFor(byte[] array, byte[] subArray) {
    if (subArray.length > array.length)
        return -1;
    int p = (new String(array)).indexOf(new String(subArray));
    for (int i = 1; i < subArray.length; i++) {
        if (array[p + i] != subArray[i])
            return -1;
    }
    return p;
}

public static int searchFor(byte[] array, byte[] subArray, int off) {
    if (subArray.length > array.length)
        return -1;
    int p = (new String(array)).indexOf(new String(subArray), off);
    for (int i = 1; i < subArray.length; i++) {
        if (array[p + i] != subArray[i])
            return -1;
    }
    return p;
}

@GET
@Path("getcamlistfromip")
@Produces("multipart/image")
public Response getcamlist(@Context UriInfo info, @Context HttpServletResponse response){
    String host = "192.168.1.155:8080";
    String link = "mjpeg1";
    HttpURLConnection con = null;
    InputStream in = null;
    OutputStream outstream = null;
    final String fullURL = "http://" + host + "/" + link;

    try {

        outstream = response.getOutputStream();

        URL url = new URL(fullURL);
        con = (HttpURLConnection) url.openConnection();
        con.setConnectTimeout(35000);
        con.setReadTimeout(35000);
        int rc = con.getResponseCode();
        String ct = con.getHeaderField("Content-Type");
        int inbounds = ct.indexOf("boundary=--");
        String inbound = ct.substring(inbounds + "boundary=--".length());
        System.out.println("inbound: " + inbound);
        int cli = con.getContentLength();
        byte[] boundery = inbound.getBytes();
        byte[] buffer = new byte[1024]; // Adjust if you want
        int bytesRead;
        in = con.getInputStream();
        MultiPartOutputStream multiPartOutputStream = new MultiPartOutputStream(outstream);
        String bounderyS = multiPartOutputStream.getBoundary();
        response.addHeader("Transfer-Encoding", null);
        response.addHeader("Expires", "0");
        response.addHeader("Pragma", "no-cache");
        response.addHeader("Access-Control-Allow-Origin", "*");
        response.addHeader("Content-Type", "multipart/x-mixed-replace;boundary=--"+bounderyS);
        MultipartInputStream multipartInputStream = new MultipartInputStream(in, boundery);

        boolean boundstart = true;
        while (multipartInputStream.nextInputStream()) {

            boundstart = true;
            while ((bytesRead = multipartInputStream.read(buffer)) != -1)
            {
                if (boundstart) {
                    byte[] tmpba = new byte[1024];

                    String searchString = "Content-Length: ";
                    int clstart = searchFor(buffer, searchString.getBytes());
                    clstart += searchString.getBytes().length;
                    int clend = searchFor(buffer, "\r\n".getBytes(), clstart);
                    String conlen = new String(Arrays.copyOfRange(buffer, clstart, clend));
                    String[] headers = new String[2];
                    headers[0] = "Access-Control-Allow-Origin: *";
                    headers[1] = "Content-length: " + conlen;
                    multiPartOutputStream.startPart("image/jpeg", headers);
                    buffer = Arrays.copyOfRange(buffer, clend + "\r\n\r\n".getBytes().length, buffer.length);

                    bytesRead = buffer.length;
                }
                multiPartOutputStream.write(buffer, 0, bytesRead);
                boundstart = false;
                buffer = new byte[1024];
            }
            multiPartOutputStream.flush();

        }

    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        con.disconnect();
        try {
            outstream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    host = null;
    link = null;

    return Response.ok(outstream, MultiPartMediaTypes.MULTIPART_MIXED_TYPE).build();//it actually doesn't matter what you give here since code never reaches here.
}

others may have different aproaches, by maybe using other libraries that I don't know, aspecially multipartinputstream header handling part? Multipart class actually does automatically handles header part of each of its Bodypart but it is not suitable for streaming as far as can tell.

happy coding.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM