MediaPlayer.OnVideoSizeChangedListener:视频宽高发生改变的时候会触发。当所设置的媒体资源没有视频图像、MediaPlayer没有设置展示的holder或者视频大小还没有被测量出来时,获取宽高得到的都是0.


Valid and invalid states

感觉用有效状态和无效状态来翻译不太合适,干脆直接就用官方上面所说的Valid and invalid states吧。它指出了MediaPlayer中常用公有方法在那些状态下可以使用,在那些状态下不可以使用。 
我们可以将所有的方法分为三类。 
- 在任何状态下都可以使用的。比如设置监听,以及其他MediaPlayer中与资源无关的方法。需要特别注意的是setDisplay和setSurface两个方法。 
- 在MediaPlayer状态机中除Error状态都可以使用的。比如获取视频宽高、获取当前位置等。 
- 对状态有诸多限制,需要严格遵循状态机流程的方法。 比如start、pause、stop等等方法。 
具体的在MediaPlayer官方说明中有对应的表。

1. 有声音没有图像 
视频播放有声音没图像也许是在使用MediaPlayer最容易出现的问题,几乎所有使用MediaPlayer的新手都会遇到。视频播放的图像呈现需要一个载体,需要利用MediaPlayer.setDisplay设置一个展示视频画面的SurfaceHolder,最终视频的每一帧图像是要绘制在Surface上面的。通常,设置给MediaPlayer的SurfaceHolder未被创建,视频播放就注定没有图像。 
* 比如你先调用了setDisplay,但是这个时候holder是没有被创建的。视频就没有图像了。 
* 或者你在setDisplay的时候holder确保了holder是被创建了,但是当因为一些原因holder被销毁了,视频也就没有图像了。 

* 再者,你没有给展示视频的view设置合适的大小,比如都设置wrap_content,或者都设置0,也会导致SurfaceHolder不能被创建,视频也就没有图像了。 

2. 视频图像变形 

Surface展示视频图像的时候,是不会去主动保证和呈现出来的图像和原始图像的宽高比例是一致的,所以我们需要自己去设置展示视频的View的宽高,以保证视频图像展示出来的时候不会变形。我认为比较合适的做法就是利用FrameLayout嵌套一个SurfaceView或者其他拥有Surface的View来作为视频图像播放的载体View,然后再OnVideoSizeChangeListener的监听回调中,对载体View的大小做更改。

3. 切入后台后声音还在继续播放 
这个问题只需要在onPause中暂停播放即可 

4. 切入后台再切回来,视频黑屏 
诸如此类的黑屏问题,多是因为surfaceholder被销毁了,再切回来时,需要重新给MediaPlayer设置holder。 
5. 播放时会有一小段时间的黑屏 
视频准备完成后,调用play进行播放视频,承载视频播放的View会是黑屏状态,我们只需要在播放前,给对应的Surface绘制一张图即可。 
6. 多个SurfaceView用来播放视频,滑动切换时会有上个视频的残影 
当视频切换出界面,设置surfaceView的visiable状态为Gone,界面切回来时再设置为visiable即可。



>>>黑屏,surfaceHolder问题,holder被创建的、且未被销毁

>>>应该在什么时机调用player.setDisplay(holder);

surfaceCreated (
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        if(display!=null&&holder==display.getHolder()){
            isSurfaceCreated=true;
            //此举保证以下操作下,不会黑屏。(或许还是会有手机黑屏)
            //暂停,然后切入后台,再切到前台,保持暂停状态
            if(player!=null){
                player.setDisplay(holder);
                //不加此句360f4不会黑屏、小米note1会黑屏,其他机型未测
                player.seekTo(player.getCurrentPosition());
            }
            log("surface被创建");
            playStart();
        }
    }
    )
player调用start方法之前( 
  private void playStart(){
        if(isVideoSizeMeasured&&isMediaPrepared&&isSurfaceCreated&&isUserWantToPlay&&isResumed){
            player.setDisplay(display.getHolder());
            player.start();
            log("视频开始播放");
            display.onStart(this);
            if(mPlayListener!=null){
                mPlayListener.onStart(this);
            }
        }
    }
     )

>>>应该在什么时候调整view大小

自动调用时,onVideoSizeChanged 视频宽高大于0的时候

手动调用时,视频宽高要大于0,

视频按照DisplayView的父布局大小显示。

设置是否裁剪视频,若裁剪,则视频按照DisplayView的父布局大小显示。

若不裁剪,视频居中于DisplayView的父布局显示

传入的DisplayView是surfaceView

//根据设置和视频尺寸,调整视频播放区域的大小

    private void tryResetSurfaceSize(final View view, int videoWidth, int videoHeight){


        ViewGroup parent= (ViewGroup) view.getParent();


        int width=parent.getWidth();


        int height=parent.getHeight();


        if(width>0&&height>0){


            final FrameLayout.LayoutParams params= (FrameLayout.LayoutParams) view.getLayoutParams();


            if(mIsCrop){


                float scaleVideo=videoWidth/(float)videoHeight;


                float scaleSurface=width/(float)height;


                if(scaleVideo<scaleSurface){


                    params.width=width;


                    params.height= (int) (width/scaleVideo);


                    params.setMargins(0,(height-params.height)/2,0,(height-params.height)/2);


                }else{


                    params.height=height;


                    params.width= (int) (height*scaleVideo);


                    params.setMargins((width-params.width)/2,0,(width-params.width)/2,0);


                }


            }else{


                if(videoWidth>width||videoHeight>height){


                    float scaleVideo=videoWidth/(float)videoHeight;


                    float scaleSurface=width/height;


                    if(scaleVideo>scaleSurface){


                        params.width=width;


                        params.height= (int) (width/scaleVideo);


                        params.setMargins(0,(height-params.height)/2,0,(height-params.height)/2);


                    }else{


                        params.height=height;


                        params.width= (int) (height*scaleVideo);


                        params.setMargins((width-params.width)/2,0,(width-params.width)/2,0);


                    }


                }


            }


            view.setLayoutParams(params);


        }


    }

>>>

video.getHolder().setFormat(PixelFormat.TRANSPARENT);
video.getHolder().setFormat(PixelFormat.OPAQUE);
video.setVideoURI(Uri.parse(temp));

surfaceview.setVisibility(View.GONE);


MediaPlayer + SurfaceView 来实现 视频播放SurfaceView + MediaPlayer 实现视频播放功能Android之SurfaceView实现视频播放