Android 如何以编程方式管理自定义视频播放器的放大/缩小?

Android 如何以编程方式管理自定义视频播放器的放大/缩小?,android,video,android-video-player,Android,Video,Android Video Player,我们可以通过两种方式实现定制视频播放器: 视频视图 Surface查看并使用MediaPlayer执行此操作 我阅读了一篇有关定制视频播放器的教程,其中Surface查看并使用MediaPlayer来实现此功能-- 我需要什么: 如何使您的自定义视图像“当您触摸视频屏幕(如缩小/放大)时,视频视图变为全屏,在放大手势后变回固定大小什么较早” 有人能告诉我怎么做吗?我已经和大家分享了我的代码,我正在使用“纹理视图”使用两个手指进行放大/缩小(收缩缩放) package com.app.sample

我们可以通过两种方式实现定制视频播放器:

  • 视频视图

  • Surface查看并使用MediaPlayer执行此操作

  • 我阅读了一篇有关
    定制视频播放器的教程,其中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);
        }
    
    }
        }