package info.guardianproject.iocipher.player; import java.io.IOException; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.Typeface; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.widget.MediaController; import android.widget.Toast; import android.widget.MediaController.MediaPlayerControl; public class MjpegView extends SurfaceView implements SurfaceHolder.Callback { private static final String TAG = "MjpegView"; 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 mRun = false; private boolean mIsPrepared = false; private boolean surfaceDone = false; private MediaController mMediaController; private boolean alreadyStarted = false; private Context mContext; private MjpegPlayer mPlayer; /* public class MjpegViewThread extends Thread { private SurfaceHolder mSurfaceHolder; private int frameCounter = 0; private long start, fpsstart; private long pause; private Bitmap ovl; private int ovlpostop = 5; 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 makeOverlay(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; } private void drawOverlay(Canvas c, Paint p, Bitmap overlay) { c.drawBitmap(overlay, 5, ovlpostop, p); ovlpostop += 5 + overlay.getHeight(); } public void run() { start = System.currentTimeMillis(); fpsstart = System.currentTimeMillis(); Log.v("MjpegView", "Start at " + start); PorterDuffXfermode mode = new PorterDuffXfermode(PorterDuff.Mode.DST_OVER); Bitmap bm; int left, top; Rect destRect = null; Canvas c = null; Paint p = new Paint(); String fps = ""; while (mRun) { if(surfaceDone) { try { c = mSurfaceHolder.lockCanvas(); synchronized (mSurfaceHolder) { try { ovlpostop = 5; //set start position (top) for overlay-table if (state == STATE_PLAY) { bm = mIn.readMjpegFrame(); destRect = destRect(bm.getWidth(),bm.getHeight()); c.drawColor(Color.BLACK); c.drawBitmap(bm, null, destRect, p); //* if(showFps) { //p.setXfermode(mode); if(ovl != null) { top = ((ovlPos & 1) == 1) ? destRect.top : destRect.bottom-ovl.getHeight(); left = ((ovlPos & 8) == 8) ? destRect.left : destRect.right -ovl.getWidth(); //c.drawBitmap(ovl, left, top, p); drawOverlay(c, p, ovl); } //p.setXfermode(null); frameCounter++; if((System.currentTimeMillis() - start) >= 1000) { fps = String.valueOf(frameCounter)+"fps"; Log.v(TAG, "FPS: " + fps); frameCounter = 0; fpsstart = System.currentTimeMillis(); ovl = makeOverlay(overlayPaint, fps); } } //* } else if (state == STATE_PAUSE){ String time = "T-" + (System.currentTimeMillis()-pause)/1000 + " sec"; Bitmap ovl1 = makeOverlay(overlayPaint, "PAUSED"); //c.drawBitmap(ovl1, 5, 5, p); Bitmap ovl2 = makeOverlay(overlayPaint, time); drawOverlay(c, p, ovl1); drawOverlay(c, p, ovl2); //c.drawBitmap(ovl1, 5, 5+2*ovl1.getHeight(), p); } setDuration(System.currentTimeMillis()-start); } catch (IOException e) {} } } finally { if (c != null) { mSurfaceHolder.unlockCanvasAndPost(c); } } } } synchronized(mSurfaceHolder) { c = mSurfaceHolder.lockCanvas(); c.drawColor(Color.BLACK); mSurfaceHolder.unlockCanvasAndPost(c); } } } */ private void init(Context context) { mContext = context; SurfaceHolder holder = getHolder(); holder.addCallback(this); //thread = new MjpegViewThread(holder, context); setFocusable(true); mPlayer = new MjpegPlayer(holder, mContext, mIn); mPlayer.setDisplay(getWidth(), getHeight(), MjpegView.SIZE_BEST_FIT); mIsPrepared = true; attachMediaController(); mPlayer.showFps(true); } public void startPlayback() { if (alreadyStarted) { Log.v(TAG, "Creating new MjpegPlayer (MjpegPlayer)"); //thread = new MjpegViewThread(holder, mContext); init(mContext); } if(mIn != null) { //mRun = true; Log.v(TAG, "Starting Playback:"); alreadyStarted = true; mPlayer.startPlayback(); //thread.start(); } } public void stopPlayback() { //mRun = false; mIsPrepared = false; mPlayer.stopPlayback(); /* 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) { mPlayer.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) { mPlayer.showFps(b); } public void setSource(MjpegInputStream source) { mIn = source; mPlayer.setSource(mIn); } /* 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 setMediaController(MediaController controller) { if (mMediaController != null) { mMediaController.hide(); } mMediaController = controller; attachMediaController(); //enable the MediaController. Without this the buttons will not work! (in the emulator...) } private View.OnClickListener next = new OnClickListener() { public void onClick(View v) { Log.v(TAG, "Clicked NEXT"); mPlayer.seekToLive(); } }; private View.OnClickListener prev = new OnClickListener() { public void onClick(View v) { Log.v(TAG, "Clicked PREV"); mPlayer.seekToBegin(); } }; private void attachMediaController() { if (mMediaController != null) { mMediaController.setMediaPlayer(mPlayer); View anchorView = this.getParent() instanceof View ? (View)this.getParent() : this; mMediaController.setAnchorView(anchorView); mMediaController.setEnabled(mIsPrepared); mMediaController.setPrevNextListeners(next, prev); } } @Override public boolean onTouchEvent(MotionEvent ev) { if (mIsPrepared && mMediaController != null) { toggleMediaControlsVisiblity(); } return false; } @Override public boolean onTrackballEvent(MotionEvent ev) { if (mIsPrepared && mMediaController != null) { toggleMediaControlsVisiblity(); } return false; } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (mIsPrepared && keyCode != KeyEvent.KEYCODE_BACK && keyCode != KeyEvent.KEYCODE_VOLUME_UP && keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_MENU && keyCode != KeyEvent.KEYCODE_CALL && keyCode != KeyEvent.KEYCODE_ENDCALL && //mMediaPlayer != null && mMediaController != null) { if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK) { if (mPlayer.isPlaying()) { mPlayer.pause(); mMediaController.show(); } else { start(); mMediaController.hide(); } return true; } else { toggleMediaControlsVisiblity(); } } return super.onKeyDown(keyCode, event); } private void toggleMediaControlsVisiblity() { if (mMediaController.isShowing()) { mMediaController.hide(); } else { mMediaController.show(); } } // public void pause() { // mPlayer.pause(); // // //this.thread.pause = System.currentTimeMillis(); // Log.v(TAG, "Pause Button pressed"); // /* // if (isPlaying() && state==STATE_PLAY) { // state = STATE_PAUSE; // Log.v(TAG, "new state: pause"); // } // else { // state = STATE_PLAY; // Log.v(TAG, "new state: play"); // } // */ // // } public void start() { //Toast.makeText(mContext, "START!", Toast.LENGTH_SHORT).show(); Log.v(TAG, "START!"); startPlayback(); } public boolean isPlaying() { return mPlayer.isPlaying(); } }