如何从Java HttpServer流式传输M-JPEG?

时间:2013-04-26 03:08:55

标签: java http mjpeg

我正在尝试从自定义视频源对象流式传输M-JPEG内容,但在查看wireshark的连接时,没有从服务器返回任何数据。以下是我使用的一些相关代码段。有谁知道如何使这个代码起作用?

段:

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

物理/服务器/ 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)); 
    }    


}

物理/服务器/ 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();
        }

    }
};

编辑:将连接消息添加到stderr之后,似乎没有将对http:// 192.168.2.7:8099/test的请求定向到此处理程序,没有处理程序我可以看到它为什么不起作用。我有什么办法让这个处理程序来处理请求?

1 个答案:

答案 0 :(得分:2)

我看到这个问题已经过去了2年,但我还是会发布我的答案,以防人们在这里搜索并发现......这就是我的做法;

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

//其他东西

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.
}
其他人可能有不同的方法,可能使用其他我不知道的库,特别是multipartinputstream标题处理部分? Multipart类实际上会自动处理每个Bodypart的标题部分,但它不适合流式传输。

快乐的编码。