2017-03-23 72 views
1

我在自定义纹理视图中播放视频。但宽度不适合。视频在播放视频时没有占满全宽

我的自定义纹理视图

public class TextureVideoView 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; 
    public 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; 

    // mCurrentState is a TextureVideoView object's current state. 
    // mTargetState is the state that a method caller intends to reach. 
    // For instance, regardless the TextureVideoView object's current state, 
    // calling pause() intends to bring the object to a target state 
    // of STATE_PAUSED. 
    private int mCurrentState = STATE_IDLE; 
    private int mTargetState = STATE_IDLE; 

    // All the stuff we need for playing and showing a video 
    private Surface  mSurface = null; 
    private MediaPlayer mMediaPlayer = null; 
    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 boolean  mCanPause; 
    private boolean  mCanSeekBack; 
    private boolean  mCanSeekForward; 
    private Context mContext; 

    private ScaleType mScaleType; 

    private boolean isMute; 


    public enum ScaleType { 
     CENTER_CROP, TOP, BOTTOM 
    } 

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

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

    public TextureVideoView(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 
     } 
     LogUtil.w("LOG_TAG", "Mesured Width -->" + width + "Mesured Height is -->" + height); 
     setMeasuredDimension(width, height); 
     // super.onMeasure(widthMeasureSpec,heightMeasureSpec); 
    } 

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

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

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

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

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


    public int getMediaState(){ 

     return mCurrentState; 
    } 

    /** 
    * @hide 
    */ 
    public void setVideoURI(Uri uri, Map<String, String> headers) { 
     LogUtil.e("LOG_TAG","TextureVideoView-->"+ uri); 
     mUri = uri; 
     mHeaders = headers; 
     mSeekWhenPrepared = 0; 
     openVideo(); 
     requestLayout(); 
     invalidate(); 
    } 

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

    public void stopPlayback() { 
     if (mMediaPlayer != null) { 
      mUri=null; 
      mMediaPlayer.stop(); 
      mMediaPlayer.release(); 
      mMediaPlayer = null; 
      mCurrentState = STATE_IDLE; 
      mTargetState = STATE_IDLE; 
     } 
    } 

    private void openVideo() { 
     if (mUri == null || mSurface == 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); 

     // we shouldn't clear the target state, because somebody might have 
     // called start() previously 
     release(false); 
     try { 
      mMediaPlayer = new MediaPlayer(); 

      if (mAudioSession != 0) { 
       mMediaPlayer.setAudioSessionId(mAudioSession); 
      } else { 
       mAudioSession = mMediaPlayer.getAudioSessionId(); 
      } 
      mMediaPlayer.setOnPreparedListener(mPreparedListener); 
      mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener); 
      mMediaPlayer.setOnCompletionListener(mCompletionListener); 
      mMediaPlayer.setOnErrorListener(mErrorListener); 
      mMediaPlayer.setOnInfoListener(mInfoListener); 
      mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener); 
      mCurrentBufferPercentage = 0; 
      mMediaPlayer.setDataSource(mContext, mUri, mHeaders); 
      mMediaPlayer.setSurface(mSurface); 
      mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); 
      mMediaPlayer.setScreenOnWhilePlaying(true); 
      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(); 
     } 
    } 

    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(); 

      LogUtil.w("LOG_TAG","Video Width is -->"+ mVideoWidth + "Video Height is -->"+ mVideoHeight); 

      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); 
       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 OnCompletionListener mCompletionListener = 
     new OnCompletionListener() { 
      public void onCompletion(MediaPlayer mp) { 
      if (mCurrentState == STATE_PLAYBACK_COMPLETED) { 
       // sprylab bugfix: on some devices onCompletion is called twice 
       return; 
      } 
       mCurrentState = STATE_PLAYBACK_COMPLETED; 
       mTargetState = STATE_PLAYBACK_COMPLETED; 
       if (mMediaController != null) { 
        mMediaController.hide(); 
       } 
       if (mOnCompletionListener != null) { 
        mOnCompletionListener.onCompletion(mMediaPlayer); 
       } 
      } 
     }; 

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

    private OnErrorListener mErrorListener = 
     new 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; 
        } 
       } 

      /* Otherwise, pop up an error dialog so the user knows that 
      * something bad has happened. Only try and pop up the dialog 
      * if we're attached to a window. When we're going away and no 
      * longer have a window, don't bother showing the user an error. 
      */ 
       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; 
    } 

    SurfaceTextureListener mSurfaceTextureListener = new SurfaceTextureListener() 
    { 
     @Override 
     public void onSurfaceTextureSizeChanged(final SurfaceTexture surface, final int width, final int height) { 
      mSurfaceWidth = width; 
      mSurfaceHeight = height; 
      boolean isValidState = (mTargetState == STATE_PLAYING); 
      boolean hasValidSize = (mVideoWidth == width && mVideoHeight == height); 
      if (mMediaPlayer != null && isValidState && hasValidSize) { 
       if (mSeekWhenPrepared != 0) { 
        seekTo(mSeekWhenPrepared); 
       } 
       start(); 
      } 
     } 

     @Override 
     public void onSurfaceTextureAvailable(final SurfaceTexture surface, final int width, final int height) { 
      mSurface = new Surface(surface); 
      openVideo(); 


     } 

     @Override 
     public boolean onSurfaceTextureDestroyed(final SurfaceTexture surface) { 
      // after we return from this we can't use the surface any more 
      if (mSurface != null) { 
       mSurface.release(); 
       mSurface = null; 
      } 
      if (mMediaController != null) mMediaController.hide(); 
      release(true); 
      return true; 
     } 
     @Override 
     public void onSurfaceTextureUpdated(final SurfaceTexture surface) { 
      // do nothing 
     } 
    }; 


    @Override 
    protected void onDetachedFromWindow() { 
     super.onDetachedFromWindow(); 

     if(mUri!=null){ 
      LogUtil.e("LOG_TAG","TextureVideo View is hidden-->"+ mUri.getPath()); 
      stopPlayback(); 
     } 

    } 

    /* 
     * 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(); 
       Constants.VIDEO_LENGTH = 0; 
       Constants.VIDEO_LENGTH = mMediaPlayer.getCurrentPosition(); 
       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; 
    } 
} 

使用这种纹理视图我收到视频这样 video

,我需要这样的Video image

请建议我应该怎么做才能补满后宽度

回答

0

更改此行:

mScaleType=ScaleType.BOTTOM; 

mScaleType=ScaleType.FIT_XY; 

如果你仍然有同样的问题,然后检查你的布局被设置为match_parent或not.and设置你的scaleType.FIT_XY在fnction其中视频开始播放。