MjpegView中的内存泄漏

时间:2015-05-19 10:14:39

标签: android streaming mjpeg

我正在开发一个使用MjpegView(流媒体视频的自定义视图)的Android应用程序。当用户第一次进入应用流媒体时 效果很好,但是当用户开始转到其他屏幕,然后返回到流媒体屏幕时,应用程序变得比平常慢。

在阅读了几篇关于内存泄漏的文章后发现他们扔掉了eclipse,我试着查看我的应用程序并注意到每次当用户转到其他屏幕(流媒体屏幕除外)时,流媒体的线程仍然存在,是吗正常?

    public class MjpegView extends SurfaceView implements SurfaceHolder.Callback
{
    public final static int     POSITION_UPPER_LEFT     = 9;
    public final static int     POSITION_UPPER_RIGHT    = 3;
    public final static int     POSITION_LOWER_LEFT     = 12;
    public final static int     POSITION_LOWER_RIGHT    = 6;

    public final static int     SIZE_STANDARD           = 1;
    public final static int     SIZE_BEST_FIT           = 4;
    public final static int     SIZE_FULLSCREEN         = 8;

    private MjpegViewThread     thread;
    private MjpegInputStream    mIn                     = null;
    private boolean             showFps                 = true;
    private volatile boolean    mRun                    = false;    //volatile for fixing JIT unchanied all for thread => accures when opening and then closing drawer
    private boolean             surfaceDone             = false;
    private Paint               overlayPaint;
    private int                 overlayTextColor;
    private int                 overlayBackgroundColor;
    private int                 ovlPos;
    private int                 dispWidth;
    private int                 dispHeight;
    private int                 displayMode;
    private boolean             resume                  = false;

    private Context             context;
    private int                 streamWidth;
    private int                 streamHeight;

    public class MjpegViewThread extends Thread
    {
        private SurfaceHolder   mSurfaceHolder;
        private int             frameCounter    = 0;
        private long            start;
        private Bitmap          ovl;

        public MjpegViewThread(SurfaceHolder surfaceHolder, Context context)
        {
            mSurfaceHolder = surfaceHolder;
        }

        private Rect destRect(int bmw, int bmh)
        {
            int tempx;
            int tempy;
            if (displayMode == MjpegView.SIZE_STANDARD)
            {
                tempx = (dispWidth / 2) - (bmw / 2);
                tempy = (dispHeight / 2) - (bmh / 2);
                return new Rect(tempx, tempy, bmw + tempx, bmh + tempy);
            }
            if (displayMode == MjpegView.SIZE_BEST_FIT)
            {
                float bmasp = (float) bmw / (float) bmh;
                bmw = dispWidth;
                bmh = (int) (dispWidth / bmasp);
                if (bmh > dispHeight)
                {
                    bmh = dispHeight;
                    bmw = (int) (dispHeight * bmasp);
                }
                tempx = (dispWidth / 2) - (bmw / 2);
                tempy = (dispHeight / 2) - (bmh / 2);
                return new Rect(tempx, tempy, bmw + tempx, bmh + tempy);
            }
            if (displayMode == MjpegView.SIZE_FULLSCREEN) return new Rect(0, 0, dispWidth, dispHeight);
            return null;
        }

        public void setSurfaceSize(int width, int height)
        {
            synchronized (mSurfaceHolder)
            {
                dispWidth = width;
                dispHeight = height;
            }
        }

        private Bitmap makeFpsOverlay(Paint p, String text)
        {
            Rect b = new Rect();
            p.getTextBounds(text, 0, text.length(), b);
            int bwidth = b.width() + 2;
            int bheight = b.height() + 2;
            Bitmap bm = Bitmap.createBitmap(bwidth, bheight, Bitmap.Config.ARGB_8888);
            Canvas c = new Canvas(bm);
            p.setColor(overlayBackgroundColor);
            c.drawRect(0, 0, bwidth, bheight, p);
            p.setColor(overlayTextColor);
            c.drawText(text, -b.left + 1, (bheight / 2) - ((p.ascent() + p.descent()) / 2) + 1, p);
            return bm;
        }

        public void run()
        {
            start = System.currentTimeMillis();
            PorterDuffXfermode mode = new PorterDuffXfermode(PorterDuff.Mode.DST_OVER);
            int width;
            int height;
            Rect destRect;
            Canvas c = null;
            Paint p = new Paint();
            String fps = "";
            try
            {
                if (mIn != null && mRun)
                {
                    //clear the buffer when the user in other place except measurement screen
                    int availableBytes = mIn.available();
                    mIn.skipBytes(availableBytes);
                }
            }
            catch (IOException e1)
            {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
            while (mRun)
            {
                if (surfaceDone)
                {
                    try
                    {
                        c = mSurfaceHolder.lockCanvas();
                        synchronized (mSurfaceHolder)
                        {
                            try
                            {
                                if (mIn != null && c != null)
                                {
                                    Bitmap bm = mIn.readMjpegFrame();
                                    destRect = destRect(bm.getWidth(), bm.getHeight());

                                    if (streamHeight == -1 && streamWidth == -1)
                                    {
                                        streamWidth = bm.getWidth();
                                        streamHeight = bm.getHeight();
                                    }
                                    c.drawColor(Color.BLACK);
                                    c.drawBitmap(bm, null, destRect, p);
                                    if (showFps)
                                    {
                                        p.setXfermode(mode);
                                        if (ovl != null)
                                        {
                                            height = ((ovlPos & 1) == 1) ? destRect.top : destRect.bottom - ovl.getHeight();
                                            width = ((ovlPos & 8) == 8) ? destRect.left : destRect.right - ovl.getWidth();
                                            c.drawBitmap(ovl, width, height, null);
                                        }
                                        p.setXfermode(null);
                                        frameCounter++;
                                        if ((System.currentTimeMillis() - start) >= 1000)
                                        {
                                            fps = String.valueOf(frameCounter) + "fps";
                                            frameCounter = 0;
                                            start = System.currentTimeMillis();
                                            ovl = makeFpsOverlay(overlayPaint, fps);
                                        }
                                    }
                                }
                            }
                            catch (IOException e)
                            {
                            }
                            catch (IllegalArgumentException e1)
                            {
                                Log.d("anton", "IllegalArgumentException");
                            }
                        }
                    }
                    finally
                    {
                        if (c != null) mSurfaceHolder.unlockCanvasAndPost(c);
                    }
                }
            }
        }
    }

    public int getStreamWidth()
    {
        return streamWidth;
    }

    public int getStreamHeight()
    {
        return streamHeight;
    }

    private void init(Context context)
    {

        this.context = context;
        streamHeight = -1;
        streamWidth = -1;
        SurfaceHolder holder = getHolder();
        holder.addCallback(this);
        thread = new MjpegViewThread(holder, context);
        setFocusable(true);
        if (!resume)
        {
            resume = true;
            overlayPaint = new Paint();
            overlayPaint.setTextAlign(Paint.Align.LEFT);
            overlayPaint.setTextSize(12);
            overlayPaint.setTypeface(Typeface.DEFAULT);
            overlayTextColor = Color.WHITE;
            overlayBackgroundColor = Color.BLACK;
            ovlPos = MjpegView.POSITION_LOWER_RIGHT;
            displayMode = MjpegView.SIZE_STANDARD;
            dispWidth = getWidth();
            dispHeight = getHeight();
            Log.i("AppLog", "init");
        }
    }

    public void startPlayback()
    {
        if (mIn != null)
        {
            mRun = true;
            if (thread.getState() != Thread.State.TERMINATED)
            {
                thread.start();
            }
            else
            {
                resumePlayback();
            }
        }
    }

    public MjpegInputStream getStream()
    {
        return mIn;
    }

    public boolean isStreamingRunning()
    {
        return mRun;
    }

    public void resumePlayback()
    {
        mRun = true;
        init(context);
        Log.i("AppLog", "resume");
        thread.start();
    }

    public void stopPlayback()
    {
        streamHeight = -1;
        streamWidth = -1;
        mRun = false;
        boolean retry = true;
        while (retry)
        {
            try
            {
                thread.join();
                retry = false;
            }
            catch (InterruptedException e)
            {
            }
        }
    }

    public MjpegView(Context context, AttributeSet attrs)
    {
        super(context, attrs);
        init(context);
    }

    public void surfaceChanged(SurfaceHolder holder, int f, int w, int h)
    {
        thread.setSurfaceSize(w, h);
    }

    public void surfaceDestroyed(SurfaceHolder holder)
    {
        surfaceDone = false;
        stopPlayback();
    }

    public MjpegView(Context context)
    {
        super(context);
        init(context);
    }

    public void surfaceCreated(SurfaceHolder holder)
    {
        surfaceDone = true;
    }

    public void showFps(boolean b)
    {
        showFps = b;
    }

    public void setSource(MjpegInputStream source)
    {
        mIn = source;
        startPlayback();
    }

    //for swapping streams small/big mjpeg surfaces
    public void setStreamSource(MjpegInputStream source)
    {
        mIn = source;
    }

    public void setOverlayPaint(Paint p)
    {
        overlayPaint = p;
    }

    public void setOverlayTextColor(int c)
    {
        overlayTextColor = c;
    }

    public void setOverlayBackgroundColor(int c)
    {
        overlayBackgroundColor = c;
    }

    public void setOverlayPosition(int p)
    {
        ovlPos = p;
    }

    public void setDisplayMode(int s)
    {
        displayMode = s;
    }

    @Override
    public boolean performClick()
    {
        // TODO Auto-generated method stub
        return super.performClick();
    }

}

eclipse HPROF profiling screenshot

1 个答案:

答案 0 :(得分:0)

您必须记住活动/片段的stopPlayback()freeCameraMemory()方法中的onPause()onStop()