title: Android: streaming the camera as mjpeg
body: <p>After several days of searching SO and google I'm beginning to give up, so I thought I might as well post here.</p>
  
  <p>I'm creating an android app which should offer some kind of video chat. As this should be as close as possible to realtime, I read about various protocols and decided to try MJPEG for starters (not concerning with audio for now). </p>
  
  <p>Right now streaming the data is driving me nuts. The connection gets established, the app starts writing the camera preview frames to the stream, but neither VLC nor mplayer start playing video. Monitoring the connection reveals that the data is arriving.</p>
  
  <p><strong>Connecting</strong>
  This code is executed by an async task, a listener is notified on success:</p>
  
  <pre><code>try
      {
          ServerSocket server = new ServerSocket(8080);
  
          socket = server.accept();
  
          server.close();
  
          Log.i(TAG, "New connection to :" + socket.getInetAddress());
  
          stream = new DataOutputStream(socket.getOutputStream());
          prepared = true;
      }
      catch (IOException e)
      {
          Log.e(TAG, e.getMessage();
      }
  </code></pre>
  
  <p>On my PC I execute 'mplayer <code>http://tabletIP:8080</code>' and the tablet registers a connection (and thus starts my streamer and the camera preview). This also works with VLC.</p>
  
  <p><strong>Streaming</strong> This writes the header to the stream:</p>
  
  <pre><code>if (stream != null)
  {
      try
      {
          // send the header
          stream.write(("HTTP/1.0 200 OK\r\n" +
                        "Server: iRecon\r\n" +
                        "Connection: close\r\n" +
                        "Max-Age: 0\r\n" +
                        "Expires: 0\r\n" +
                        "Cache-Control: no-cache, private\r\n" + 
                        "Pragma: no-cache\r\n" + 
                        "Content-Type: multipart/x-mixed-replace; " +
                        "boundary=--" + boundary +
                        "\r\n\r\n").getBytes());
  
          stream.flush();
  
          streaming = true;
      }
      catch (IOException e)
      {
          notifyOnEncoderError(this, "Error while writing header: " + e.getMessage());
          stop();
      }
  }
  </code></pre>
  
  <p>Afterwards streaming is triggered through the Camera.onPreviewFrame() Callback:</p>
  
  <pre><code>@Override
  public void onPreviewFrame(byte[] data, Camera camera)
  {
      frame = data;
  
      if (streaming)
          mHandler.post(this);
  }
  
  @Override
  public void run()
  {
      // TODO: cache not filling?
      try
      {
                      // buffer is a ByteArrayOutputStream
          buffer.reset();
  
          switch (imageFormat)
          {
              case ImageFormat.JPEG:
                  // nothing to do, leave it that way
                  buffer.write(frame);
                  break;
  
              case ImageFormat.NV16:
              case ImageFormat.NV21:
              case ImageFormat.YUY2:
              case ImageFormat.YV12:
                  new YuvImage(frame, imageFormat, w, h, null).compressToJpeg(area, 100, buffer);
                  break;
  
              default:
                  throw new IOException("Error while encoding: unsupported image format");
          }
  
          buffer.flush();
  
          // write the content header
          stream.write(("--" + boundary + "\r\n" + 
                        "Content-type: image/jpg\r\n" + 
                        "Content-Length: " + buffer.size() + 
                        "\r\n\r\n").getBytes());
  
          // Should omit the array copy
          buffer.writeTo(stream);
  
          stream.write("\r\n\r\n".getBytes());
          stream.flush();
      }
      catch (IOException e)
      {
          stop();
          notifyOnEncoderError(this, e.getMessage());
      }
  }
  </code></pre>
  
  <p>There is no exception thrown. The mHandler runs in it's own HandlerThread. Just to be sure I tried using an AsyncTask, to no avail (btw, is this better?).</p>
  
  <p>The encoded frames are fine on the android side, I saved them to jpg files and could open them.</p>
  
  <p>My guess is that I have to cluster the data somehow or have to set some options for the socket or something, but....well, I'm stuck.</p>
  
  <p><strong>tl;dr:</strong> VLC not playing stream, mplayer says 'cache not filling', problem probably in last code segment, need help~ :)</p>
  
  <p>Thank you kindly!</p>