Question

I'm trying to use my phone as a realtime MJPEG video source. So far, capturing frames and converting them into JPEGs is no big deal. My real issue is sending the multipart response properly. There's tons of documentation about sending multipart responses out there, but the issue with them is that they all expect that all of the images are available at the time the HTTP request comes in (such as would be used for a multi-image upload). In order to stream in realtime, of course, I need to be able to begin to send the multipart response while continually adding jpegs in the body. I'm by no means a HTTP buff, so it's not desirable for me be required to roll my own HTTP response and write directly to a socket. Is there a library out there that supports this kind of behavior? I've scoured the internet for solutions, but I really don't see anything useful out there.

Any ideas? Worst case scenario, I'd be willing to look at human-readable documentation of how to write a multipart response by hand, but I'd really just rather use a library if that's possible.

Thanks in advance.

edit: got it working using the orielly servlet library as per sigmavirus' suggestion. Note that the MJPEG stream is more or less implicitly inferred from the fact that I'm sending a multipart/x-mixed-replace that only has image/jpeg's in it. Check out the comment in my code for a tutorial that shows what jetty libraries you'll need to get this running. Of course, you'll additionally need cos.jar, the Orielly servlet library. The code follows:

package edu.stevens.arpac.webclient;

import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Collections;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.apache.http.conn.util.InetAddressUtils;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.Request;

import com.oreilly.servlet.MultipartResponse;
import com.oreilly.servlet.ServletUtils;


import android.os.Environment;
import android.util.Log;
// holla at http://puregeekjoy.blogspot.com/2011/06/running-embedded-jetty-in-android-app.html
public class JettyServer extends Thread 
{
private static final String TAG = "JettyServer";
private Server webServer;
private Boolean isStarted = false;

public JettyServer()
{
    super();
    Log.i(TAG, "Initializing server to port 8080");
    webServer = new Server(8080);

    Handler handler = new AbstractHandler() {
        public void handle(String target, Request request, HttpServletRequest servletRequest,
                HttpServletResponse servletResponse) throws IOException, ServletException {

            ServletOutputStream out = servletResponse.getOutputStream();

             MultipartResponse multi = new MultipartResponse(servletResponse);


             Boolean go = true;
             while( go )
             {

                 try
                 {
                     multi.startResponse("image/jpeg");
                     ServletUtils.returnFile(Environment.getExternalStorageDirectory().getPath() + "/ARPac/twi.jpg", out);
                     multi.endResponse();
                 }
                 catch(IOException ex)
                 {
                    go = false;
                    Log.i(TAG, "IO Failed with exception " + ex.getMessage());
                 }
             }
             request.setHandled(true);
        }
    };
    webServer.setHandler(handler);

    try {
        webServer.start();
        Log.d(TAG, "started Web server @ " + getIPAddress());
        isStarted = true;

    }
    catch (Exception e) {
        Log.d(TAG, "unexpected exception starting Web server: " + e);
    }
}

/**
 * Get IP address from first non-localhost interface
 * @return  address or empty string
 */
private String getIPAddress() 
{
    try 
    {
        List<NetworkInterface> interfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
        for (NetworkInterface intf : interfaces) 
        {
            List<InetAddress> addrs = Collections.list(intf.getInetAddresses());
            for (InetAddress addr : addrs) 
            {
                if (!addr.isLoopbackAddress())
                {
                    String sAddr = addr.getHostAddress().toUpperCase(); 
                    if (InetAddressUtils.isIPv4Address(sAddr))
                    {
                        //Log.d(TAG, "IP address is: " + sAddr);
                        return sAddr;
                    } 
                }
            }
        }
    } 
    catch (Exception ex) 
    { 
        Log.e(TAG, "could not get IP address: " + ex.getMessage());
    } // for now eat exceptions
    Log.e(TAG, "Could not find a non-loopback IPv4 address!");
    return "";
}

public void teardown()
{
    if( isStarted )
    {
        try {
            webServer.stop();
            isStarted = false;
        } catch (Exception e) {
            Log.e(TAG, "Couldn't stop server. Probably was called when server already stopped.");
        }
    }
}

public void run() 
 {

 }

}

Was it helpful?

Solution

Have you seen this? http://www.servlets.com/cos/javadoc/com/oreilly/servlet/MultipartResponse.html It looks like the example sends each part individually and waits a specified time limit before sending the next or receiving an interrupt.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top