package com.theta.view; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.util.AttributeSet; import android.view.SurfaceHolder; import android.view.SurfaceView; import java.io.IOException; import jp.agentec.abook.abv.bl.common.log.Logger; /** * Motion JPEG view */ public class MJpegView extends SurfaceView implements SurfaceHolder.Callback { private static final String TAG = "MJpegView"; private MJpegViewThread mMJpegViewThread = null; private MJpegInputStream mMJpegInputStream = null; private boolean existSurface = false; private int mDisplayWidth; private int mDisplayHeight; private MJpegView.LiveCameraListener mListener; public interface LiveCameraListener { void liveCameraPlayFail(); } public void setLiveCameraListenerListener(MJpegView.LiveCameraListener listener) { this.mListener = listener; } /** * Constructor * @param context */ public MJpegView(Context context) { super(context); init(); } /** * Constructor * @param context * @param attrs */ public MJpegView(Context context, AttributeSet attrs) { super(context, attrs); init(); } /** * Constructor * @param context * @param attrs * @param defStyleAttr */ public MJpegView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } /** * Initialization process */ private void init() { SurfaceHolder holder = getHolder(); holder.addCallback(this); setFocusable(true); mDisplayWidth = getWidth(); mDisplayHeight = getHeight(); } /** * Start playback */ public void play() { if (mMJpegViewThread != null) { stopPlay(); } if(mMJpegInputStream != null) { if (mMJpegViewThread != null) { if (mMJpegViewThread.getState() == Thread.State.NEW) { mMJpegViewThread.start(); } } else { mMJpegViewThread = new MJpegViewThread(getHolder()); mMJpegViewThread.start(); } } } /** * Stop playback */ public void stopPlay() { if (mMJpegViewThread != null) { mMJpegViewThread.cancel(); boolean retry = true; while (retry) { try { mMJpegViewThread.join(); retry = false; mMJpegViewThread = null; } catch (InterruptedException e) { e.getStackTrace(); } } } } /** * Set source stream for receiving motion JPEG * @param source Source stream */ public void setSource(MJpegInputStream source) { if (source == null) { //mMJpegInputStreamのクローズ作業のため、現在スレッドをストップする。 stopPlay(); } else { mMJpegInputStream = source; play(); } } /** * Get source stream for receiving motion JPEG * @return Source stream */ public MJpegInputStream getSource() { return mMJpegInputStream; } @Override public void surfaceCreated(SurfaceHolder holder) { existSurface = true; } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { synchronized(holder) { mDisplayWidth = width; mDisplayHeight = height; } } @Override public void surfaceDestroyed(SurfaceHolder holder) { existSurface = false; stopPlay(); } /** * Thread class for receiving motion JPEG */ private class MJpegViewThread extends Thread { private final SurfaceHolder mSurfaceHolder; private boolean keepRunning = true; /** * Constructor * @param surfaceHolder */ public MJpegViewThread(SurfaceHolder surfaceHolder) { mSurfaceHolder = surfaceHolder; } /** * Acquire image size according to display area<p> * Calculates the size that fits the display area while maintaining the aspect ratio of the motion JPEG. * @param bitmapWidth Width of motion JPEG * @param bitmapHeight Height of motion JPEG * @return Image size */ private Rect getImageRect(int bitmapWidth, int bitmapHeight) { float bitmapAspectRatio = (float) bitmapWidth / (float) bitmapHeight; bitmapWidth = mDisplayWidth; bitmapHeight = (int) (mDisplayWidth / bitmapAspectRatio); if (bitmapHeight > mDisplayHeight) { bitmapHeight = mDisplayHeight; bitmapWidth = (int) (mDisplayHeight * bitmapAspectRatio); } int bitmapX = (mDisplayWidth / 2) - (bitmapWidth / 2); int bitmapY = (mDisplayHeight / 2) - (bitmapHeight / 2); return new Rect(0, bitmapY, mDisplayWidth, bitmapHeight + bitmapY); } /** * Abort thread */ public void cancel() { keepRunning = false; } @Override public void run() { Bitmap bitmap; Rect bitmapRect; Canvas bitmapCanvas = null; while (keepRunning) { if (existSurface) { try { bitmapCanvas = mSurfaceHolder.lockCanvas(); synchronized (mSurfaceHolder) { try { if ((mMJpegInputStream != null) && (bitmapCanvas != null)) { bitmap = mMJpegInputStream.readMJpegFrame(); bitmapRect = getImageRect(bitmap.getWidth(), bitmap.getHeight()); bitmapCanvas.drawColor(Color.BLACK); bitmapCanvas.drawBitmap(bitmap, null, bitmapRect, new Paint()); bitmap.recycle(); } } catch (IOException e) { e.getStackTrace(); Logger.e(TAG, "MJpegView IOException = " + e.toString()); keepRunning = false; mListener.liveCameraPlayFail(); } } } finally { if (bitmapCanvas != null) { mSurfaceHolder.unlockCanvasAndPost(bitmapCanvas); } } } } bitmapCanvas = mSurfaceHolder.lockCanvas(); synchronized (mSurfaceHolder) { if (bitmapCanvas != null) { bitmapCanvas.drawColor(Color.BLACK); } } if (bitmapCanvas != null) { mSurfaceHolder.unlockCanvasAndPost(bitmapCanvas); } if (mMJpegInputStream != null) { try { mMJpegInputStream.close(); mMJpegInputStream = null; } catch (IOException e) { e.printStackTrace(); Logger.e(TAG, "mMJpegInputStream IOException = " + e.toString()); } } } } }