我们可以通过两种方式实现CUSTOM视频播放器:
VideoView
SurfaceView并使用MediaPlayer执行此操作。
我阅读了一篇与Custom Video Player
相关的教程,其中使用了SurfaceView并使用MediaPlayer来实现此功能 - link here
我的需求是什么:
如何制作自定义视图,例如"When you touch on the video screen such as zoom out/zoom in, video view goes to the full screen and after zoom in gesture back to fix size what earlier "
?
有人可以建议我怎么做这件事吗?
答案 0 :(得分:0)
我与你分享我的代码我正在使用纹理视图使用两个手指放大/缩小(捏缩放)
package com.app.sampletextureview;
import android.app.Activity;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.SurfaceTexture;
import android.media.MediaActionSound;
import android.media.MediaMetadataRetriever;
import android.media.MediaPlayer;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.FloatMath;
import android.util.Log;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.TextureView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
import java.io.IOException;
public class MainActivity extends Activity implements TextureView.SurfaceTextureListener,View.OnTouchListener {
private static final String TAG = MainActivity.class.getName();
private static final String FILE_NAME = "Vid.mp4";
private MediaPlayer mMediaPlayer;
private TextureView mTextureView;
private RelativeLayout mrRelativeLayout;
private float mVideoWidth;
private float mVideoHeight;
DisplayMetrics dm;
RelativeLayout.LayoutParams params;
private ScaleGestureDetector scaleGestureDetector;
private Matrix matrix = new Matrix();
@SuppressWarnings("unused")
private static final float MIN_ZOOM = 1f,MAX_ZOOM = 1f;
// These matrices will be used to scale points of the image
Matrix savedMatrix = new Matrix();
// The 3 states (events) which the user is trying to perform
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
// these PointF objects are used to record the point(s) the user is touching
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
private float mVideoWidth;
private float mVideoHeight;
int viewWidth=0,viewHeight=0,xoff=0,yoff=0;;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
calculateVideoSize();
initView();
}
private void initView() {
mrRelativeLayout= (RelativeLayout) findViewById(R.id.rootView);
mTextureView = (TextureView) findViewById(R.id.textureView);
mTextureView.setOnTouchListener(this);
/*Log.d("Height-WidthOnCreate",""+mVideoHeight+"-"+mVideoWidth);
mTextureView.setMinimumWidth((int)mVideoWidth);
mTextureView.setMinimumHeight((int)mVideoHeight);
mTextureView.setSurfaceTextureListener(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mMediaPlayer != null) {
mMediaPlayer.stop();
mMediaPlayer.release();
mMediaPlayer = null;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i2) {
Surface surface = new Surface(surfaceTexture);
try {
AssetFileDescriptor afd = getAssets().openFd(FILE_NAME);
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
mMediaPlayer.setSurface(surface);
mMediaPlayer.setLooping(true);
// don't forget to call MediaPlayer.prepareAsync() method when you use constructor for
// creating MediaPlayer
mMediaPlayer.prepareAsync();
adjustAspectRatio((int) mVideoWidth, (int)mVideoHeight);
Log.d("SurfaceCreate",""+mVideoWidth+""+mVideoHeight);
// Play video when the media source is ready for playback.
mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mediaPlayer) {
mediaPlayer.start();
}
});
} catch (IllegalArgumentException e) {
Log.d(TAG, e.getMessage());
} catch (SecurityException e) {
Log.d(TAG, e.getMessage());
} catch (IllegalStateException e) {
Log.d(TAG, e.getMessage());
} catch (IOException e) {
Log.d(TAG, e.getMessage());
}
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i2) {
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
}
private void calculateVideoSize() {
try {
AssetFileDescriptor afd = getAssets().openFd(FILE_NAME);
MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever();
metaRetriever.setDataSource(
afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
String height = metaRetriever
.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
String width = metaRetriever
.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH);
mVideoHeight = Float.parseFloat(height);
mVideoWidth = Float.parseFloat(width);
Log.d("Height-Width",""+mVideoHeight+"-"+mVideoWidth);
} catch (IOException e) {
Log.d(TAG, e.getMessage());
} catch (NumberFormatException e) {
Log.d(TAG, e.getMessage());
}
}
private void updateTextureViewSize(int viewWidth, int viewHeight) {
float scaleX = 1.0f;
float scaleY = 1.0f;
if (mVideoWidth > viewWidth && mVideoHeight > viewHeight) {
scaleX = mVideoWidth / viewWidth;
scaleY = mVideoHeight / viewHeight;
} else if (mVideoWidth < viewWidth && mVideoHeight < viewHeight) {
scaleY = viewWidth / mVideoWidth;
scaleX = viewHeight / mVideoHeight;
} else if (viewWidth > mVideoWidth) {
scaleY = (viewWidth / mVideoWidth) / (viewHeight / mVideoHeight);
} else if (viewHeight > mVideoHeight) {
scaleX = (viewHeight / mVideoHeight) / (viewWidth / mVideoWidth);
}
// Calculate pivot points, in our case crop from center
int pivotPointX = viewWidth / 2;
int pivotPointY = viewHeight / 2;
Matrix matrix = new Matrix();
matrix.setScale(scaleX, scaleY, pivotPointX, pivotPointY);
mTextureView.setTransform(matrix);
}
private void adjustAspectRatio(int videoWidth, int videoHeight) {
int viewWidth = mTextureView.getWidth();
int viewHeight = mTextureView.getHeight();
double aspectRatio = (double) videoHeight / videoWidth;
int newWidth, newHeight;
if (viewHeight > (int) (viewWidth * aspectRatio)) {
// limited by narrow width; restrict height
newWidth = viewWidth;
newHeight = (int) (viewWidth * aspectRatio);
} else {
// limited by short height; restrict width
newWidth = (int) (viewHeight / aspectRatio);
newHeight = viewHeight;
}
int xoff = (viewWidth - newWidth) / 2;
int yoff = (viewHeight - newHeight) / 2;
Log.v(TAG, "video=" + videoWidth + "x" + videoHeight +
" view=" + viewWidth + "x" + viewHeight +
" newView=" + newWidth + "x" + newHeight +
" off=" + xoff + "," + yoff);
Matrix txform = new Matrix();
mTextureView.getTransform(txform);
txform.setScale((float) newWidth / viewWidth, (float) newHeight / viewHeight);
//txform.postRotate(10); // just for fun
txform.postTranslate(xoff, yoff);
mTextureView.setTransform(txform);
}
/* @Override
public boolean onTouchEvent(MotionEvent ev) {
// scaleGestureDetector.onTouchEvent(ev);
return true;
}
*/
private class ScaleListener extends ScaleGestureDetector.
SimpleOnScaleGestureListener {
@Override
public boolean onScale(ScaleGestureDetector detector) {
float scaleFactor = detector.getScaleFactor();
scaleFactor = Math.max(0.1f, Math.min(scaleFactor, 5.0f));
matrix.setScale(scaleFactor, scaleFactor);
Log.d("Matrix", "" + scaleFactor);
mTextureView.setTransform(matrix);
return true;
}
}
@Override
public boolean onTouch(View v, MotionEvent event)
{
dumpEvent(event);
// Handle touch events here...
switch (event.getAction() & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_DOWN: // first finger down only
if (!istouch) {
istouch=true;
ll_bottombar.setVisibility(View.VISIBLE);
ll_topheader.setVisibility(View.VISIBLE);
hideSystemUI(getWindow());
}else{
String tag = btnLock.getTag().toString();
if (tag.equals("false")) {
istouch = false;
ll_bottombar.setVisibility(View.GONE);
ll_topheader.setVisibility(View.GONE);
hideSystemUI(getWindow());
}
}
break;
case MotionEvent.ACTION_UP: // first finger lifted
mode = NONE;
Log.d(TAG, "mode=NONE");
break;
case MotionEvent.ACTION_POINTER_UP: // second finger lifted
mode = NONE;
Log.d(TAG, "mode=NONE");
break;
case MotionEvent.ACTION_POINTER_DOWN: // first and second finger down
//case MotionEvent.ACTION_POINTER_2_DOWN:
oldDist = spacing(event);
Log.d(TAG, "oldDist=" + oldDist);
if (oldDist > 5f) {
savedMatrix.set(matrix);
midPoint(mid, event);
// matrix.setScale( mid.y,(float) newWidth / viewWidth,mid.x, (float) newHeight / viewHeight);
// matrix.setScale(mid.x,mid.y);
if(event.getPointerCount() >= 2) {
event.setAction(MotionEvent.ACTION_MOVE);
mode = ZOOM;
Log.d(TAG, "mode=ZOOM");
}
}
break;
case MotionEvent.ACTION_MOVE:
if (mode == NONE)
{
mode = NONE;
Log.d(TAG, "mode=NONE");
}
if (event.getPointerCount() >= 2) {
/* if (mode == DRAG)
{
// matrix.set(savedMatrix);
// matrix.postTranslate(event.getX() - start.x, event.getY() - start.y); // create the transformation in the matrix of points
}else if (mode == NONE)
{
mode = NONE;
Log.d(TAG, "mode=NONE");
}*/
if (mode == ZOOM) {
// pinch zooming
float newDist = spacing(event);
Log.d(TAG, "newDist=" + newDist);
if (newDist > 5f) {
matrix.set(savedMatrix);
Log.d(TAG, "NEW="+newDist+"--"+oldDist);
Log.d(TAG, "NEW Mid Point="+mid.x+"--"+mid.y);
scale = newDist / oldDist;
// matrix.setScale();
// matrix.setScale(scale,scale);
matrix.postScale(scale,scale,mid.x, mid.y);
Log.d(TAG,"New Hight Width"+mTextureView.getWidth()+"--"+mTextureView.getHeight());
}
}
mTextureView.setTransform(matrix);
}
break;
}
// display the transformation on screen
return true; // indicate event was handled
}
/* * --------------------------------------------------------------------------
* Method: spacing Parameters: MotionEvent Returns: float Description:
* checks the spacing between the two fingers on touch
* ----------------------------------------------------
*/
private float spacing(MotionEvent event)
{
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return (float)Math.sqrt(x * x + y * y);
}
/* * --------------------------------------------------------------------------
* Method: midPoint Parameters: PointF object, MotionEvent Returns: void
* Description: calculates the midpoint between the two fingers
* ------------------------------------------------------------
private void midPoint(PointF point, MotionEvent event)
{
float x = mrRelativeLayout.getX()+mrRelativeLayout.getWidth();
float y = mrRelativeLayout.getY()+mrRelativeLayout.getHeight();
point.set(x / 2, y / 2);
}
private void dumpEvent(MotionEvent event)
{
String names[] = { "DOWN", "UP", "MOVE", "CANCEL", "OUTSIDE","POINTER_DOWN", "POINTER_UP", "7?", "8?", "9?" };
StringBuilder sb = new StringBuilder();
int action = event.getAction();
int actionCode = action & MotionEvent.ACTION_MASK;
sb.append("event ACTION_").append(names[actionCode]);
if (actionCode == MotionEvent.ACTION_POINTER_DOWN || actionCode == MotionEvent.ACTION_POINTER_UP)
{
sb.append("(pid ").append(action >> MotionEvent.ACTION_POINTER_ID_SHIFT);
sb.append(")");
}
sb.append("[");
for (int i = 0; i < event.getPointerCount(); i++)
{
sb.append("#").append(i);
sb.append("(pid ").append(event.getPointerId(i));
sb.append(")=").append((int) event.getX(i));
sb.append(",").append((int) event.getY(i));
if (i + 1 < event.getPointerCount())
sb.append(";");
}
sb.append("]");
}
private void adjustAspectRatio(int videoWidth, int videoHeight) {
viewWidth = mTextureView.getWidth();
viewHeight = mTextureView.getHeight();
double aspectRatio = (double) videoHeight / videoWidth;
if (viewHeight > (int) (viewWidth * aspectRatio)) {
// limited by narrow width; restrict height
newWidth = viewWidth;
newHeight = (int) (viewWidth * aspectRatio);
} else {
// limited by short height; restrict width
newWidth = (int) (viewHeight / aspectRatio);
newHeight = viewHeight;
}
xoff = (viewWidth - newWidth) / 2;
yoff = (viewHeight - newHeight) / 2;
Log.d(TAG, "video=" + videoWidth + "x" + videoHeight +
" view=" + viewWidth + "x" + viewHeight +
" newView=" + newWidth + "x" + newHeight +
" off=" + xoff + "," + yoff);
Log.d(TAG, "video="+mTextureView.getHeight()+"--"+mTextureView.getWidth());
Log.d(TAG, "video="+newHeight+"--"+newWidth);
mTextureView.setMinimumWidth(newWidth);
mTextureView.setMinimumHeight(newHeight);
// Matrix txform = new Matrix();
mTextureView.getTransform(matrix);
matrix.setScale((float) newWidth / viewWidth, (float) newHeight / viewHeight);
//txform.postRotate(10); // just for fun
matrix.postTranslate(xoff, yoff);
mTextureView.setTransform(matrix);
}
} }