Может ли VideoView отсоединяться и повторно подключаться без остановки потока?

Я создаю приложение, в котором пользователь нажимает кнопку, чтобы показать полноэкранное видео. Первоначально видео прикрепляется к представлению внутри ViewPager. Чтобы показать его в полноэкранном режиме, я отсоединяю его от родителя и привязываю его к корневому представлению. Это отлично работает, за исключением случаев, когда во время воспроизведения видео переключается на полноэкранный режим. Когда я отсоединяю проигрыватель VideoView, он просто останавливается, и мне нужно его перезапустить. Это неприемлемо, так как видео начинает буферизацию перед возобновлением. Здесь часть кода, в котором выполняется отрыв:

    final ViewGroup parent = (ViewGroup) findViewById(R.id.parent);

    final ViewGroup root = (ViewGroup) findViewById(R.id.root);

    Button b = (Button) findViewById(R.id.button);
    b.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            parent.removeView(mVideoView);

            LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
            root.addView(mVideoView, lp);
        }
    });

В зависимости от устройства у меня другая ошибка журнала. Вероятно, потому, что фактический видеопроигрыватель предоставляется изготовителем, а не Android SDK. Вот журналы ошибок для Nexus 7:

10-30 20:26:18.618: D/NvOsDebugPrintf(124): NvMMDecTVMRDestroyParser Begin 
10-30 20:26:18.618: D/NvOsDebugPrintf(124): --------- Closing TVMR Frame Delivery Thread -------------
10-30 20:26:18.678: D/NvOsDebugPrintf(124): ------- NvAvpClose -------
10-30 20:26:18.678: D/NvOsDebugPrintf(124): NvMMDecTVMRDestroyParser Done 
10-30 20:26:18.678: D/NvOsDebugPrintf(124): NvMMLiteTVMRDecPrivateClose Done 

Я не смог отсоединить видео, не останавливая его. Я пробовал использовать SurfaceView или TextureView без успеха.

Я также попытался найти стороннего видеоплеера. Я нашел коммерческий (http://www.vitamio.org/), который я действительно не могу использовать по соображениям бизнеса. Я нашел открытый исходный код, который не обновлялся в прошлом году (https://code.google.com/p/dolphin-player/).

В настоящее время я нацелен на Android 4.2 или лучше только на планшет.


Обратите внимание, что ViewPager не является полноэкранным. Поэтому я не могу использовать LayoutParams для создания полноэкранного видео. Мне нужно удалить VideoView из родителя в ViewPager и добавить его в корневой вид, чтобы показать его в полноэкранном режиме.

URL, с которым я тестирую: http://bellvps1.cpl.delvenetworks.com/media/e1b3e24ecb944abd8f4ed823a0b76ddc/68f78d35296243bfb46d2418f03f2fd0/bande-annonce---the-secret-life-of-walter-mitty-1-9efcc5c6e52ac07a3edf84a1b21967995b7796a2.m3u8

Ответ 1

Этот эффект может быть достигнут с помощью TextureView. По существу, вы создаете экземпляр MediaPlayer, prepare() it и start(), вы можете использовать метод MediaPlayer.setSurface() для любого TextureView для изменения поверхности при воспроизведении видео без каких-либо изменений в MediaPlayer состояние объекта, как указано в документах android для метода setSurface():

This method can be called in any state and calling it does not change the object state.

Обратите внимание, что эта реализация предназначена для демонстрации, вы должны, вероятно, использовать mediaplayer.prepareAsync() и дождаться обратного вызова с помощью onPreparedListener(), вам также нужно будет установить правильные размеры для второго TextureView в соответствии с вашим видео размер, изменения ориентации рукоятки и, конечно, обрабатывать исключения, когда это необходимо.

activity_main.xml:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v4.view.ViewPager
        android:id="@+id/pager"
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:layout_gravity="center"
        android:background="#ff0000" />

    <Button
        android:id="@+id/btn"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:layout_gravity="bottom|center_horizontal"
        android:text="Switch to second surface" />

    <TextureView
        android:id="@+id/tv_full"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</FrameLayout>

MainActivity.java

public class MainActivity extends Activity {
    private static final String VIDEO_URI = "http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4";

    private TextureView tvFull;
    private MediaPlayer mp;

    @Override protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mp = new MediaPlayer();
        try {
            mp.setDataSource(this, Uri.parse(VIDEO_URI));
            mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
            mp.prepare();
        } catch (IOException e) {
            e.printStackTrace();
        }

        ((ViewPager) findViewById(R.id.pager)).setAdapter(new PagerAdapter() {
            @Override public int getCount() {
                return 1;
            }

            @Override public boolean isViewFromObject(View view, Object o) {
                return view == o;
            }

            @Override public Object instantiateItem(ViewGroup container, int position) {
                final TextureView tv = new TextureView(MainActivity.this);

                tv.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
                    @Override public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i2) {
                        tv.setSurfaceTextureListener(null);
                        mp.setSurface(new Surface(surfaceTexture));
                        mp.start();
                    }

                    @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i2) {}

                    @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
                        return false;
                    }

                    @Override public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {}
                });

                if (tv.isAvailable()) {
                    tv.getSurfaceTextureListener().onSurfaceTextureAvailable(tv.getSurfaceTexture(),
                            tv.getWidth(), tv.getHeight());
                }

                container.addView(tv, 0);
                return tv;
            }

            @Override public void destroyItem(ViewGroup container, int position, Object object) {
                container.removeView((View) object);
            }
        });

        tvFull = (TextureView) findViewById(R.id.tv_full);

        findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
            @Override public void onClick(View view) {
                tvFull.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
                    @Override public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i2) {
                        tvFull.setSurfaceTextureListener(null);
                        mp.setSurface(new Surface(surfaceTexture));
                    }

                    @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i2) {

                    }

                    @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
                        return false;
                    }

                    @Override public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {

                    }
                });

                if (tvFull.isAvailable()) {
                    tvFull.getSurfaceTextureListener().onSurfaceTextureAvailable(tvFull.getSurfaceTexture(),
                            tvFull.getWidth(), tvFull.getHeight());
                }
            }
        });
    }

    @Override protected void onDestroy() {
        mp.reset();
        mp.release();

        super.onDestroy();
    }
}

Ответ 2

Я не знаю подробностей о том, как работает проигрыватель, но я подозреваю, что вам нужно:

Override onSaveInstanceState to save the place in the video (maybe a timestamp?)

Override onRestoreInstanceState to reload the video and seek to the point saved in step 1

Ответ 3

Я не пробовал это, но надеюсь, что это может вам помочь,

        final ViewGroup parent = (ViewGroup) findViewById(R.id.parent);

    final ViewGroup root = (ViewGroup) findViewById(R.id.root);//assuming this full screen

    Button b = (Button) findViewById(R.id.button);
    b.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            // parent.removeView(mVideoView);
            LayoutParams parentParam = parent.getLayoutParams();
            parentParam.height = root.getLayoutParams().height;
            parentParam.width = root.getLayoutParams().width;
            parent.setLayoutParams(parentParam);
            LayoutParams lp = new FrameLayout.LayoutParams(
                    LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
            root.addView(mVideoView, lp);
        }
    });

Спасибо.

Ответ 4

используйте текстуру с этой модификацией:

@Override 
            public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {

                if (mediaPlayer != null) {
                    mediaPlayer.setSurface(new Surface (surfaceTexture));}
            }

Обновление: и полный код: player2.java:

public class player2 extends TextureView
    implements MediaPlayerControl {
    private String TAG = "TextureVideoView";
    // settable by the client
    private Uri         mUri;
    private Map<String, String> mHeaders;

    // all possible internal states
    private static final int STATE_ERROR              = -1;
    private static final int STATE_IDLE               = 0;
    private static final int STATE_PREPARING          = 1;
    private static final int STATE_PREPARED           = 2;
    private static final int STATE_PLAYING            = 3;
    private static final int STATE_PAUSED             = 4;
    private static final int STATE_PLAYBACK_COMPLETED = 5;

    private static int mCurrentState;
    private static int mTargetState;


    // All the stuff we need for playing and showing a video
    static public SurfaceTexture sf;
    static public MediaPlayer mMediaPlayer;
    private int         mAudioSession;
    private int         mVideoWidth;
    private int         mVideoHeight;
    private int         mSurfaceWidth;
    private int         mSurfaceHeight;
    private  MediaController mMediaController;
    private OnCompletionListener mOnCompletionListener;
    private MediaPlayer.OnPreparedListener mOnPreparedListener;
    private int         mCurrentBufferPercentage;
    private OnErrorListener mOnErrorListener;
    private OnInfoListener  mOnInfoListener;
    private int         mSeekWhenPrepared;  // recording the seek position while preparing
    private static boolean     mCanPause;
    private static boolean     mCanSeekBack;
    private static boolean     mCanSeekForward;
    private Context mContext;

    public player2(Context context) {
        super(context);
       initVideoView();
    }

    public player2(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
        initVideoView();
    }

    public player2(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initVideoView();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //Log.i("@@@@", "onMeasure(" + MeasureSpec.toString(widthMeasureSpec) + ", "
        //        + MeasureSpec.toString(heightMeasureSpec) + ")");

        int width = getDefaultSize(mVideoWidth, widthMeasureSpec);
        int height = getDefaultSize(mVideoHeight, heightMeasureSpec);
        if (mVideoWidth > 0 && mVideoHeight > 0) {

            int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
            int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
            int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
            int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);

            if (widthSpecMode == MeasureSpec.EXACTLY && heightSpecMode == MeasureSpec.EXACTLY) {
                // the size is fixed
                width = widthSpecSize;
                height = heightSpecSize;

                // for compatibility, we adjust size based on aspect ratio
                if ( mVideoWidth * height  < width * mVideoHeight ) {
                    //Log.i("@@@", "image too wide, correcting");
                    width = height * mVideoWidth / mVideoHeight;
                } else if ( mVideoWidth * height  > width * mVideoHeight ) {
                    //Log.i("@@@", "image too tall, correcting");
                    height = width * mVideoHeight / mVideoWidth;
                }
            } else if (widthSpecMode == MeasureSpec.EXACTLY) {
                // only the width is fixed, adjust the height to match aspect ratio if possible
                width = widthSpecSize;
                height = width * mVideoHeight / mVideoWidth;
                if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) {
                    // couldn't match aspect ratio within the constraints
                    height = heightSpecSize;
                }
            } else if (heightSpecMode == MeasureSpec.EXACTLY) {
                // only the height is fixed, adjust the width to match aspect ratio if possible
                height = heightSpecSize;
                width = height * mVideoWidth / mVideoHeight;
                if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) {
                    // couldn't match aspect ratio within the constraints
                    width = widthSpecSize;
                }
            } else {
                // neither the width nor the height are fixed, try to use actual video size
                width = mVideoWidth;
                height = mVideoHeight;
                if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) {
                    // too tall, decrease both width and height
                    height = heightSpecSize;
                    width = height * mVideoWidth / mVideoHeight;
                }
                if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) {
                    // too wide, decrease both width and height
                    width = widthSpecSize;
                    height = width * mVideoHeight / mVideoWidth;
                }
            }
        } else {
            // no size yet, just adopt the given spec sizes
        }
        setMeasuredDimension(width, height);
    }

    @Override
    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
        super.onInitializeAccessibilityEvent(event);
        event.setClassName(player2.class.getName());
    }

    @Override
    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
        super.onInitializeAccessibilityNodeInfo(info);
        info.setClassName(player2.class.getName());
    }

    public int resolveAdjustedSize(int desiredSize, int measureSpec) {
        return getDefaultSize(desiredSize, measureSpec);
    }

    private void initVideoView() {
        mContext = getContext();
        mVideoWidth = 0;
        mVideoHeight = 0;
        setSurfaceTextureListener(mSurfaceTextureListener);
        setFocusable(true);
        setFocusableInTouchMode(true);
        requestFocus();
        mPendingSubtitleTracks = new Vector<Pair<InputStream, MediaFormat>>();
        if (mMediaPlayer==null)  {
        mCurrentState = STATE_IDLE;
        mTargetState  = STATE_IDLE;}
    }

    public void setVideoPath(String path) {
        setVideoURI(Uri.parse(path));
    }

    public void setVideoURI(Uri uri) {
        setVideoURI(uri, null);
    }

    /**
     * @hide
     */
    private void setVideoURI(Uri uri, Map<String, String> headers) {
        mUri = uri;
        mHeaders = headers;
        mSeekWhenPrepared = 0;
        requestLayout();
        invalidate();
    }

    private Vector<Pair<InputStream, MediaFormat>> mPendingSubtitleTracks;

    public void stopPlayback() {
        if (mMediaPlayer != null) {
            mMediaPlayer.stop();
            mMediaPlayer.release();
            mMediaPlayer = null;
            mCurrentState = STATE_IDLE;
            mTargetState  = STATE_IDLE;
        }
    }
    private void setListeners() {
        mMediaPlayer.setOnPreparedListener(mPreparedListener);
        mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
        mMediaPlayer.setOnCompletionListener(mCompletionListener);
        mMediaPlayer.setOnErrorListener(mErrorListener);
        mMediaPlayer.setOnInfoListener(mInfoListener);
        mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
        mCurrentBufferPercentage = 0;
        mMediaPlayer.setScreenOnWhilePlaying(true);
    }
    private void openVideo() {
        if (mUri == null || sf == null) {
            // not ready for playback just yet, will try again later
            return;
        }
        // Tell the music playback service to pause
        // TODO: these constants need to be published somewhere in the framework.
       /* Intent i = new Intent("com.android.music.musicservicecommand");
        i.putExtra("command", "pause");
        mContext.sendBroadcast(i);*/
        if (mMediaPlayer==null) {
        try {
            mMediaPlayer = new MediaPlayer();

            if (mAudioSession != 0) {
                mMediaPlayer.setAudioSessionId(mAudioSession);
            } else {
                mAudioSession = mMediaPlayer.getAudioSessionId();
            }
            setListeners();

            mMediaPlayer.setSurface(new Surface (sf));
            mMediaPlayer.setDataSource(mContext, mUri, mHeaders);
            mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            mMediaPlayer.prepareAsync();
            // we don't set the target state here either, but preserve the
            // target state that was there before.
            mCurrentState = STATE_PREPARING;
            attachMediaController();
        } catch (IOException ex) {
            Log.w(TAG, "Unable to open content: " + mUri, ex);
            mCurrentState = STATE_ERROR;
            mTargetState = STATE_ERROR;
            mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
            return;
        } catch (IllegalArgumentException ex) {
            Log.w(TAG, "Unable to open content: " + mUri, ex);
            mCurrentState = STATE_ERROR;
            mTargetState = STATE_ERROR;
            mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
            return;
        } finally {
            mPendingSubtitleTracks.clear();
        }} else {
            setListeners();
        }
    }

    public void setMediaController(MediaController controller) {
        if (mMediaController != null) {
            mMediaController.hide();
        }
        mMediaController = controller;
        attachMediaController();
    }

    private void attachMediaController() {
        if (mMediaPlayer != null && mMediaController != null) {
            mMediaController.setMediaPlayer(this);
            View anchorView = this.getParent() instanceof View ?
                (View)this.getParent() : this;
            mMediaController.setAnchorView(anchorView);
            mMediaController.setEnabled(isInPlaybackState());
        }
    }

    MediaPlayer.OnVideoSizeChangedListener mSizeChangedListener =
        new MediaPlayer.OnVideoSizeChangedListener() {
            public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
                mVideoWidth = mp.getVideoWidth();
                mVideoHeight = mp.getVideoHeight();
                if (mVideoWidth != 0 && mVideoHeight != 0) {
                    getSurfaceTexture().setDefaultBufferSize(mVideoWidth, mVideoHeight);
                    requestLayout();
                }
            }
        };

    MediaPlayer.OnPreparedListener mPreparedListener = new MediaPlayer.OnPreparedListener() {
        public void onPrepared(MediaPlayer mp) {
            mCurrentState = STATE_PREPARED;

            mCanPause = mCanSeekBack = mCanSeekForward = true;

            if (mOnPreparedListener != null) {
                mOnPreparedListener.onPrepared(mMediaPlayer);
            }
            if (mMediaController != null) {
                mMediaController.setEnabled(true);
            }
            mVideoWidth = mp.getVideoWidth();
            mVideoHeight = mp.getVideoHeight();

            int seekToPosition = mSeekWhenPrepared;  // mSeekWhenPrepared may be changed after seekTo() call
            if (seekToPosition != 0) {
                seekTo(seekToPosition);
            }
            if (mVideoWidth != 0 && mVideoHeight != 0) {
                //Log.i("@@@@", "video size: " + mVideoWidth +"/"+ mVideoHeight);
                getSurfaceTexture().setDefaultBufferSize(mVideoWidth, mVideoHeight);
                requestLayout();
                if (mSurfaceWidth == mVideoWidth && mSurfaceHeight == mVideoHeight) {
                    // We didn't actually change the size (it was already at the size
                    // we need), so we won't get a "surface changed" callback, so
                    // start the video here instead of in the callback.
                    if (mTargetState == STATE_PLAYING) {
                        start();
                        if (mMediaController != null) {
                            mMediaController.show();
                        }
                    } else if (!isPlaying() &&
                        (seekToPosition != 0 || getCurrentPosition() > 0)) {
                        if (mMediaController != null) {
                            // Show the media controls when we're paused into a video and make 'em stick.
                            mMediaController.show(0);
                        }
                    }
                }
            } else {
                // We don't know the video size yet, but should start anyway.
                // The video size might be reported to us later.
                if (mTargetState == STATE_PLAYING) {
                    start();
                }
            }
        }
    };

    private MediaPlayer.OnCompletionListener mCompletionListener =
        new MediaPlayer.OnCompletionListener() {
            public void onCompletion(MediaPlayer mp) {
            if (mCurrentState == STATE_PLAYBACK_COMPLETED) {
                return;
            }
                mCurrentState = STATE_PLAYBACK_COMPLETED;
                mTargetState = STATE_PLAYBACK_COMPLETED;
                if (mMediaController != null) {
                    mMediaController.hide();
                }
                if (mOnCompletionListener != null) {
                    mOnCompletionListener.onCompletion(mMediaPlayer);
                }
            }
        };

    private MediaPlayer.OnInfoListener mInfoListener =
        new MediaPlayer.OnInfoListener() {
            public  boolean onInfo(MediaPlayer mp, int arg1, int arg2) {
                if (mOnInfoListener != null) {
                    mOnInfoListener.onInfo(mp, arg1, arg2);
                }
                return true;
            }
        };

    private MediaPlayer.OnErrorListener mErrorListener =
        new MediaPlayer.OnErrorListener() {
            public boolean onError(MediaPlayer mp, int framework_err, int impl_err) {
                Log.d(TAG, "Error: " + framework_err + "," + impl_err);
                mCurrentState = STATE_ERROR;
                mTargetState = STATE_ERROR;
                if (mMediaController != null) {
                    mMediaController.hide();
                }

            /* If an error handler has been supplied, use it and finish. */
                if (mOnErrorListener != null) {
                    if (mOnErrorListener.onError(mMediaPlayer, framework_err, impl_err)) {
                        return true;
                    }
                }
                if (getWindowToken() != null) {
                   // Resources r = mContext.getResources();
                    int messageId;

                    if (framework_err == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) {
                        messageId = R.string.VideoView_error_text_invalid_progressive_playback;
                    } else {
                        messageId = R.string.VideoView_error_text_unknown;
                    }

                    new AlertDialog.Builder(mContext)
                        .setMessage(messageId)
                        .setPositiveButton(R.string.VideoView_error_button,
                            new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog, int whichButton) {
                                        /* If we get here, there is no onError listener, so
                                         * at least inform them that the video is over.
                                         */
                                    if (mOnCompletionListener != null) {
                                        mOnCompletionListener.onCompletion(mMediaPlayer);
                                    }
                                }
                            })
                        .setCancelable(false)
                        .show();
                }
                return true;
            }
        };

    private MediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener =
        new MediaPlayer.OnBufferingUpdateListener() {
            public void onBufferingUpdate(MediaPlayer mp, int percent) {
                mCurrentBufferPercentage = percent;
            }
        };

    /**
     * Register a callback to be invoked when the media file
     * is loaded and ready to go.
     *
     * @param l The callback that will be run
     */
    public void setOnPreparedListener(MediaPlayer.OnPreparedListener l)
    {
        mOnPreparedListener = l;
    }

    /**
     * Register a callback to be invoked when the end of a media file
     * has been reached during playback.
     *
     * @param l The callback that will be run
     */
    public void setOnCompletionListener(OnCompletionListener l)
    {
        mOnCompletionListener = l;
    }

    /**
     * Register a callback to be invoked when an error occurs
     * during playback or setup.  If no listener is specified,
     * or if the listener returned false, TextureVideoView will inform
     * the user of any errors.
     *
     * @param l The callback that will be run
     */
    public void setOnErrorListener(OnErrorListener l)
    {
        mOnErrorListener = l;
    }

    /**
     * Register a callback to be invoked when an informational event
     * occurs during playback or setup.
     *
     * @param l The callback that will be run
     */
    public void setOnInfoListener(OnInfoListener l) {
        mOnInfoListener = l;
    }

    TextureView.SurfaceTextureListener mSurfaceTextureListener = new SurfaceTextureListener()
    {
        @Override
        public void onSurfaceTextureSizeChanged(final SurfaceTexture surface, final int width, final int height) {
            if (mMediaPlayer!=null) {
                mVideoWidth = mMediaPlayer.getVideoWidth();
                mVideoHeight = mMediaPlayer.getVideoHeight();
                if (mVideoWidth != 0 && mVideoHeight != 0) {
                    surface.setDefaultBufferSize(mVideoWidth, mVideoHeight);
                    requestLayout();
                }}
        }

        @Override
        public void onSurfaceTextureAvailable(final SurfaceTexture surface, final int width, final int height) {
           sf=surface;
           mSurfaceWidth = width;
           mSurfaceHeight = height;
            if (mMediaPlayer!=null) { mMediaPlayer.setSurface(new Surface (surface));
          } 
            openVideo();
        }


        @Override
        public boolean onSurfaceTextureDestroyed(final SurfaceTexture surface) {
            return false;
        }
        @Override
        public void onSurfaceTextureUpdated(final SurfaceTexture surface) {}
    };

    /*
     * release the media player in any state
     */
    private void release(boolean cleartargetstate) {
        if (mMediaPlayer != null) {
            mMediaPlayer.reset();
            mMediaPlayer.release();
            mMediaPlayer = null;
            mPendingSubtitleTracks.clear();
            mCurrentState = STATE_IDLE;
            if (cleartargetstate) {
                mTargetState  = STATE_IDLE;
            }
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        if (isInPlaybackState() && mMediaController != null) {
            toggleMediaControlsVisiblity();
        }
        return false;
    }

    @Override
    public boolean onTrackballEvent(MotionEvent ev) {
        if (isInPlaybackState() && mMediaController != null) {
            toggleMediaControlsVisiblity();
        }
        return false;
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event)
    {
        boolean isKeyCodeSupported = keyCode != KeyEvent.KEYCODE_BACK &&
            keyCode != KeyEvent.KEYCODE_VOLUME_UP &&
            keyCode != KeyEvent.KEYCODE_VOLUME_DOWN &&
            keyCode != KeyEvent.KEYCODE_VOLUME_MUTE &&
            keyCode != KeyEvent.KEYCODE_MENU &&
            keyCode != KeyEvent.KEYCODE_CALL &&
            keyCode != KeyEvent.KEYCODE_ENDCALL;
        if (isInPlaybackState() && isKeyCodeSupported && mMediaController != null) {
            if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK ||
                keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) {
                if (mMediaPlayer.isPlaying()) {
                    pause();
                    mMediaController.show();
                } else {
                    start();
                    mMediaController.hide();
                }
                return true;
            } else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) {
                if (!mMediaPlayer.isPlaying()) {
                    start();
                    mMediaController.hide();
                }
                return true;
            } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP
                || keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) {
                if (mMediaPlayer.isPlaying()) {
                    pause();
                    mMediaController.show();
                }
                return true;
            } else {
                toggleMediaControlsVisiblity();
            }
        }

        return super.onKeyDown(keyCode, event);
    }

    private void toggleMediaControlsVisiblity() {
        if (mMediaController.isShowing()) {
            mMediaController.hide();
        } else {
            mMediaController.show();
        }
    }

    @Override
    public void start() {
        if (isInPlaybackState()) {
            mMediaPlayer.start();
            mCurrentState = STATE_PLAYING;
        }
        mTargetState = STATE_PLAYING;
    }

    @Override
    public void pause() {
        if (isInPlaybackState()) {
            if (mMediaPlayer.isPlaying()) {
                mMediaPlayer.pause();
                mCurrentState = STATE_PAUSED;
            }
        }
        mTargetState = STATE_PAUSED;
    }

    public void suspend() {
        release(false);
    }

    public void resume() {
        openVideo();
    }

    @Override
    public int getDuration() {
        if (isInPlaybackState()) {
            return mMediaPlayer.getDuration();
        }

        return -1;
    }

    @Override
    public int getCurrentPosition() {
        if (isInPlaybackState()) {
            return mMediaPlayer.getCurrentPosition();
        }
        return 0;
    }

    @Override
    public void seekTo(int msec) {
        if (isInPlaybackState()) {
            mMediaPlayer.seekTo(msec);
            mSeekWhenPrepared = 0;
        } else {
            mSeekWhenPrepared = msec;
        }
    }

    @Override
    public boolean isPlaying() {
        return isInPlaybackState() && mMediaPlayer.isPlaying();
    }

    @Override
    public int getBufferPercentage() {
        if (mMediaPlayer != null) {
            return mCurrentBufferPercentage;
        }
        return 0;
    }

    private boolean isInPlaybackState() {
        return (mMediaPlayer != null &&
            mCurrentState != STATE_ERROR &&
            mCurrentState != STATE_IDLE &&
            mCurrentState != STATE_PREPARING);
    }

    @Override
    public boolean canPause() {
        return mCanPause;
    }

    @Override
    public boolean canSeekBackward() {
        return mCanSeekBack;
    }

    @Override
    public boolean canSeekForward() {
        return mCanSeekForward;
    }

    public int getAudioSessionId() {
        if (mAudioSession == 0) {
            MediaPlayer foo = new MediaPlayer();
            mAudioSession = foo.getAudioSessionId();
            foo.release();
        }
        return mAudioSession;
    }

}

И некоторый код MainActivity:

   public class MainActivity extends Activity {
        static View frame1;
        static player2 textureView;
        static boolean pause=false;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
...
        }
        @Override
        protected void onDestroy() {
            pause=false;
            super.onDestroy();
        }
        @Override
        public void onPause() {
            pause=true;
            super.onPause();
        }
        @Override
        public void onResume() {
            if ((player2.sf!=null)&&(pause==true)&&(textureView.getSurfaceTexture()==null)) {
                textureView.setSurfaceTexture(player2.sf);}
            super.onResume();
        }
        public static class PlaceholderFragment extends Fragment  {


            public PlaceholderFragment() {}

            @Override
            public View onCreateView(LayoutInflater inflater, ViewGroup container,
                    Bundle savedInstanceState) {
                View rootView = inflater.inflate(R.layout.fragment_main, container,
                        false);
                frame1=rootView.findViewById(R.id.frame1);


                textureView = (player2)rootView.findViewById(R.id.textureView1);
                textureView.setVideoPath("http://master255.org/res/Клипы/S/SKRILLEX/Skrillex - Summit (feat. Ellie Goulding) [Video by Pilerats].mp4");
                textureView.setMediaController(new mediac(getActivity(), frame1));
                if (player2.sf != null) {
                    if ((pause==false)&&(textureView.getSurfaceTexture()==null)) {
                        textureView.setSurfaceTexture(player2.sf);}
                }

                textureView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                    @Override
                    public void onPrepared(final MediaPlayer mp) {
                        textureView.start();
                    }
                });
                return rootView;
            }
            public class mediac extends MediaController
            {

                public mediac(Context context, View anchor)
                {
                    super(context);
                    super.setAnchorView(anchor);
                }

                @Override
                public void setAnchorView(View view)
                {}

            }
        }

    }