I'm trying to create an IP Camera application for iPhone using mono touch. To get the camera feed, I call the CGImage.ScreenImage method continuously and convert the resulting UIImage into a byte array which is then transmitted across to the browser. The camera feed is displayed using a UIImagePickerController class by setting the
SourceType = UIImagePickerControllerSourceType.Camera;
Here are the complete code for the ImageController class:
public class ImageController : UIImagePickerController
{
private HttpListener listener;
public ImageController ()
{
SourceType = UIImagePickerControllerSourceType.Camera;
start();
}
void start()
{
listener = new HttpListener();
listener.Prefixes.Add( "http://+:8001/" );
listener.Prefixes.Add( "http://+:8001/current.jpg/" );
listener.Start();
listener.BeginGetContext( HandleRequest, listener );
}
public override void DidReceiveMemoryWarning ()
{
GC.Collect();
}
private void HandleRequest(IAsyncResult result)
{
HttpListenerContext context = listener.EndGetContext( result );
listener.BeginGetContext( HandleRequest, listener );
if ( context.Request.RawUrl.Contains( "current.jpg" ) )
{
context.Response.StatusCode = (int) HttpStatusCode.OK;
context.Response.ContentType = @"multipart/x-mixed-replace;boundary=--myboundary";
context.Response.KeepAlive = true;
byte [] imageData;
byte [] boundary;
while ( true )
{
imageData = worker();
boundary =
Encoding.UTF8.GetBytes(
"\r\n--myboundary\r\nContent-Type: image/jpeg\r\nContent-Length: " +
imageData.Length + "\r\n\r\n" );
context.Response.OutputStream.Write( boundary, 0, boundary.Length );
context.Response.OutputStream.Write( imageData, 0, imageData.Length );
imageData = null;
boundary = null;
}
}
else
{
string responseString = @"<html xmlns=""http://www.w3.org/1999/xhtml""> <body bgcolor=""#fffffff"">"+
@"<img name=""current"" src=""current.jpg"" border=""0"" id=""current"" /></body></html>";
byte [] responseByte = Encoding.UTF8.GetBytes( responseString );
context.Response.ContentType = "text/html";
context.Response.KeepAlive = true;
context.Response.StatusCode = (int) HttpStatusCode.OK;
context.Response.ContentLength64 = responseByte.Length;
context.Response.OutputStream.Write( responseByte, 0, responseByte.Length );
context.Response.OutputStream.Close();
}
}
private byte [] worker()
{
byte [] imageArray;
using ( var screenImage = CGImage.ScreenImage )
{
using ( var image = UIImage.FromImage(screenImage) )
{
using ( NSData imageData = image.AsJPEG())
{
imageArray = new byte[imageData.Length];
Marshal.Copy(imageData.Bytes, imageArray, 0, Convert.ToInt32(imageData.Length));
}
}
}
return imageArray;
}
}
}
The problem I'm having is that I receive a memory warning after about 20 seconds of streaming and a second one after 5 seconds, then the application crashes.
2010-11-08 13:12:56.457 MonoTouchCGImageScreenImageTest[2251:307] Received memory warning. Level=1
2010-11-08 13:13:11.059 MonoTouchCGImageScreenImageTest[2251:307] Received memory warning. Level=2
All of the images that were displayed have been disposed of within the using statement and the imageData variable is also been set to null once it is transmitted. Is there some method that needs to be called or is there a better solution to my problem? Any help would be appreciated.
Thanks