Android 如何以编程方式管理自定义视频播放器的放大/缩小?
我们可以通过两种方式实现定制视频播放器:Android 如何以编程方式管理自定义视频播放器的放大/缩小?,android,video,android-video-player,Android,Video,Android Video Player,我们可以通过两种方式实现定制视频播放器: 视频视图 Surface查看并使用MediaPlayer执行此操作 我阅读了一篇有关定制视频播放器的教程,其中Surface查看并使用MediaPlayer来实现此功能-- 我需要什么: 如何使您的自定义视图像“当您触摸视频屏幕(如缩小/放大)时,视频视图变为全屏,在放大手势后变回固定大小什么较早” 有人能告诉我怎么做吗?我已经和大家分享了我的代码,我正在使用“纹理视图”使用两个手指进行放大/缩小(收缩缩放) package com.app.sample
定制视频播放器的教程,其中Surface查看并使用MediaPlayer来实现此功能--
我需要什么:
如何使您的自定义视图像“当您触摸视频屏幕(如缩小/放大)时,视频视图变为全屏,在放大手势后变回固定大小什么较早”
有人能告诉我怎么做吗?我已经和大家分享了我的代码,我正在使用“纹理视图”使用两个手指进行放大/缩小(收缩缩放)
package com.app.sampletextureview;
导入android.app.Activity;
导入android.content.Context;
导入android.content.res.AssetFileDescriptor;
导入android.graphics.Matrix;
导入android.graphics.PointF;
导入android.graphics.SurfaceTexture;
导入android.media.MediaActionSound;
导入android.media.MediaMetadataRetriever;
导入android.media.MediaPlayer;
导入android.support.v7.app.ActionBarActivity;
导入android.os.Bundle;
导入android.util.DisplayMetrics;
导入android.util.FloatMath;
导入android.util.Log;
导入android.view.Gravity;
导入android.view.Menu;
导入android.view.MenuItem;
导入android.view.MotionEvent;
导入android.view.scalegestruedetector;
导入android.view.Surface;
导入android.view.SurfaceHolder;
导入android.view.TextureView;
导入android.view.view;
导入android.view.ViewGroup;
导入android.widget.FrameLayout;
导入android.widget.RelativeLayout;
导入java.io.IOException;
公共类MainActivity extends活动实现TextureView.SurfacetTextRelistener、View.OnTouchListener{
私有静态最终字符串标记=MainActivity.class.getName();
私有静态最终字符串文件\u NAME=“Vid.mp4”;
私有媒体层;
私有纹理视图mTextureView;
私人相对人mrRelativeLayout;
私有浮动宽度;
私人浮动高度;
数据挖掘;
RelativeLayout.LayoutParams参数;
私人scalegestruedetector scalegestruedetector;
私有矩阵=新矩阵();
@抑制警告(“未使用”)
专用静态最终浮动最小缩放=1f,最大缩放=1f;
//这些矩阵将用于缩放图像的点
矩阵savedMatrix=新矩阵();
//用户试图执行的3个状态(事件)
静态最终int NONE=0;
静态最终整数阻力=1;
静态最终整数缩放=2;
int模式=无;
//这些PointF对象用于记录用户触摸的点
PointF start=新的PointF();
PointF mid=新的PointF();
浮动oldDist=1f;
私有浮动宽度;
私人浮动高度;
int viewWidth=0,viewHeight=0,xoff=0,yoff=0;;
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
calculateVideoSize();
initView();
}
私有void initView(){
mrRelativeLayout=(RelativeLayout)findViewById(R.id.rootView);
mTextureView=(TextureView)findViewById(R.id.TextureView);
mTextureView.setOnTouchListener(这个);
/*Log.d(“Height-WidthOnCreate”、“+mVideoHeight+”-“+mVideoWidth”);
mTextureView.setMinimumWidth((int)mvideWidth);
mTextureView.setMinimumHeight((int)mVideoHeight);
mTextureView.setSurfaceTextureListener(此);
}
@凌驾
受保护的空onDestroy(){
super.ondestory();
if(mmediplayer!=null){
mmediplayer.stop();
mmediplayer.release();
mmediplayer=null;
}
}
@凌驾
公共布尔onCreateOptions菜单(菜单){
//为菜单充气;这会将项目添加到操作栏(如果存在)。
getMenuInflater().充气(右菜单菜单菜单主菜单);
返回true;
}
@凌驾
公共布尔值onOptionsItemSelected(菜单项项){
//处理操作栏项目单击此处。操作栏将
//自动处理Home/Up按钮上的点击,只要
//在AndroidManifest.xml中指定父活动时。
int id=item.getItemId();
//noinspection SimplifiableIf语句
if(id==R.id.action\u设置){
返回true;
}
返回super.onOptionsItemSelected(项目);
}
@凌驾
SurfaceTexture上的公共空间可用(SurfaceTexture SurfaceTexture、int i、int i2){
表面=新表面(表面纹理);
试一试{
AssetFileDescriptor afd=getAssets().openFd(文件名);
mMediaPlayer=新媒体播放器();
mmediplayer.setDataSource(afd.getFileDescriptor(),afd.getStartOffset(),afd.getLength());
MMETIMIPLAYER.setSurface(表面);
mmediplayer.setLooping(true);
//在使用构造函数时,不要忘记调用MediaPlayer.prepareAsync()方法
//创建MediaPlayer
mMediaPlayer.prepareAsync();
调整AspectRatio((int)MVideWidth,(int)MVideHeight);
Log.d(“表面粗糙度”、“+MVideWidth+”+MVideHeight);
//当媒体源准备好播放时播放视频。
mMediaPlayer.setOnPreparedListener(新媒体播放
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);
}
}
}