Memory issue using CGImage.ScreenImage and UIImagePickerController Mono Touch

我的未来我决定 提交于 2019-12-23 03:43:05

问题


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


回答1:


You are calling worker() in a never ending loop:

        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;
        }

Which means that even tho you are disposing, you're in a tight allocation loop which will put a lot of pressure on the GC.

Additionally, you are using UIImage.FromImage() which returns an autoreleased object from the obj-c runtime, but since you never yield to the main loop, the NSAutoreleasePool cannot release this object.



来源:https://stackoverflow.com/questions/4121562/memory-issue-using-cgimage-screenimage-and-uiimagepickercontroller-mono-touch

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!