Ошибка памяти при использовании CGImage.ScreenImage и UIImagePickerController Mono Touch - PullRequest
1 голос
/ 08 ноября 2010

Я пытаюсь создать приложение для IP-камеры для iPhone, используя моно-тач. Чтобы получить изображение с камеры, я непрерывно вызываю метод CGImage.ScreenImage и преобразую полученный UIImage в байтовый массив, который затем передается в браузер. Подача камеры отображается с использованием класса UIImagePickerController путем установки

SourceType = UIImagePickerControllerSourceType.Camera;

Вот полный код класса ImageController:

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

Проблема, с которой я столкнулся, заключается в том, что я получаю предупреждение о памяти примерно через 20 секунд потоковой передачи, а второе - через 5 секунд, после чего происходит сбой приложения.

2010-11-08 13: 12: 56.457 MonoTouchCGImageScreenImageTest [2251: 307] Получено предупреждение о памяти. Уровень = 1

2010-11-08 13: 13: 11.059 MonoTouchCGImageScreenImageTest [2251: 307] Получено предупреждение о памяти. Уровень = 2

Все отображаемые изображения были удалены в операторе using, а переменная imageData также установлена ​​в null после ее передачи. Есть какой-то метод, который нужно вызвать или есть лучшее решение моей проблемы? Любая помощь будет оценена.

Спасибо

1 Ответ

4 голосов
/ 08 ноября 2010

Вы вызываете работника () в бесконечном цикле:

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

Это означает, что даже если вы утилизируете, вы находитесь в узком цикле распределения, который будет оказывать большое давление наGC.

Кроме того, вы используете UIImage.FromImage (), который возвращает автоматически освобожденный объект из среды выполнения obj-c, но, поскольку вы никогда не уступаете основному циклу, NSAutoreleasePool не может освободить этот объект.

...