使用 CGImage.ScreenImage 和 UIImagePickerController Mono Touch 的内存问题
我正在尝试使用单点触控为 iPhone 创建 IP 摄像头应用程序。要获取相机源,我调用 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] 收到内存警告。 Level=1
2010-11-08 13:13:11.059 MonoTouchCGImageScreenImageTest[2251:307] 收到内存警告。 Level=2
所有显示的图像都已在 using 语句中处理掉,并且 imageData 变量在传输后也被设置为 null。 是否需要调用某些方法或者是否有更好的解决方案来解决我的问题?任何帮助将不胜感激。
谢谢
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
你在一个永无休止的循环中调用worker():
这意味着即使你正在处置,你仍然处于一个紧密的分配循环中,这会给GC带来很大的压力。
此外,您使用 UIImage.FromImage() 从 obj-c 运行时返回一个自动释放的对象,但由于您永远不会屈服于主循环,因此 NSAutoreleasePool 无法释放该对象。
You are calling worker() in a never ending loop:
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.