近几天的主要问题在于播放器。原来采用的方案最终发现存在问题无法实施,只好临时替换。想起最开始就曾经想用的android提供的VideoView和MediaPlayer组件,开始替换,然后就是一堆问题。网上查到的大部分资料都没有解决问题,无意中搜到这篇文章,感觉还不错的问题总结,希望能帮我解决问题吧,也希望对正在学习的人能有所帮助。
主要内容来自于(原文网址):http://www.boyunjian.com/do/article/snapshot.do?uid=3453185252600635258,原文标题:视频播放器之遇到问题篇 ,转载请注明。(不知道是否本身就是被转载,已经找不到作者的名字了)
内容如下:
视频播放器之遇到问题篇
---------------------------------------------------------------------------------------------------------------------------
遇到问题1:
当播放公司服务器视频,在模拟器2.1系统下无问题播放,但在模拟器2.2系统下当执行到MediaPlayer.prepaer();这个方法时会抛出IOException异常?
解决思路:
首先去查看了Android里面MediaPlayer.prepaer();的源代码,看看在什么情况在会抛出IO异常,但是它的MediaPlayer.里的prepaer()方法是 native的,看MeidaPlayer.cpp也没具体看明白.后来查看Android Supported Media Formats发现其支持视频编码是Baseline Profile (BP),��后来连接手机调试,使用MOTO Defy 2.2无法播放,但放到HTCG7 2.2及平板电脑上可正常播放,据此推断,可能是由于厂家定制底层和内核的时候,根据需求增减了一部分支持的视频编码。
---------------------------------------------------------------------------------------------------------------------------
遇到问题2
正常情况下如果视频处于started状态直接调用MediaPlayer.seekTo()跳转指定时间没有问题,但是如果处于paused状态调用MediaPlayer.seekTo()方法后,此时开始调用start()方法会出现error,,onError(MediaPlayer mp, int what, int extra)中返回的是
07-1916:05:29.499: INFO/System.out(7763): whatis 100 extra 0
extra 0没搞懂是什么,后来查看自带的播放器也存在这个问题,视频暂停,然后拖动进度条,在开始会发生错误。 解决办法: 尝试方法1: 1在拖动进度条监听器的onStopTrackingTouch()方法中首先检测视频是否正在播放(mMediaPlayer.isPlaying()==true), 2如果拖动前是暂停状态的话,就先start进入started状态, 3然后在调用seekTo()方法,测试后还是会问题,错误如下 07-1916:54:05.569: ERROR/ProfileVideoFrameDrops(8984): PVMediaOutputNodePort 1Frames dropped at 1 07-1916:54:05.960: ERROR/TI_Video_Decoder(8984): 2273 VIDDEC_HandleCommandFlush DSPflushed without processing SPS/PPS. saving first buffer 07-1916:54:05.983: ERROR/MediaPlayer(8959): internal/external state mismatchcorrected onError(MediaPlayermp, int what, int extra)中返回的是 07-1916:54:05.983: INFO/System.out(8959): what is 100 extra 0 然后进入了OnCompletionListener中的onCompletion方法 然后onError r(MediaPlayer mp, int what, intextra)继续返回 07-1916:54:06.092: INFO/System.out(8959): what is -38 extra 0 说明此方法行不通。 尝试方法2: 1 和第一步一样,看是否在播放中 2 如果处于paused状态,调用reset()方法, 3然后重新调用prepare()方法准备 4开始seekTo();或者先start(),然后seekTo(); 出现的问题是: onError(MediaPlayer mp, int what, intextra)中返回的是 07-19 17:10:17.749:INFO/System.out(9472): what is -38 extra 0 尝试方法3: 1 和第一步一样,看是否在播放中 2如果处于paused状态,调用stop()方法, 3然后重新调用prepare()方法准备 4开始seekTo(); 这种方法是我暂时尝试到了能行得通的方法,但是有个小瑕疵,就是seekTo()后自动播放了,这时调用pause()也停不了,或者先start(),然后pause()也不行。不知道是什么原因,查看log发现当跳动时的错误 07-1920:17:20.108: ERROR/TI_LCML(11015): 507 :: Exiting Init_DSPSubSystem 07-1920:17:20.881: ERROR/ProfileVideoFrameDrops(11015): PVMediaOutputNodePort 5Frames dropped at 6 --------------------------------------------------------------------------------------------------------------------------- 遇到问题3 获取PopupWindow上的按钮ID 例如ImageButton playButton = (ImageButton)findViewById(R.id.play);一直出现空指针异常。 解决办法: 这时候findViewById(R.id.play)是当前View的,而不是PopupWindow里的,应该修改成为 ImageButtonplayButton = (ImageButton) vPopupWindow.findViewById(R.id.play); --------------------------------------------------------------------------------------------------------------------------- 遇到问题4 在实验PopupWindow时,把seekBar和开始按钮放到PopupWindow上,但是弹出PopupWindow后,点击PopupWindow外部其他控件时,PopupWindow无法消失,焦点一直在PopupWindow上. 解决办法: 网上查看相关资料后。发现是因为没有给PopupWindow设置背景图片,使用下面这个方法 popup.setBackgroundDrawable(getResources().getDrawable(R.drawable.videoplayer_bg)); 后问题解决。 --------------------------------------------------------------------------------------------------------------------------- 遇到问题5 想在视频播放中使用OnGestureListener识别用户手势,来做到不使用控制台快捷控制一些常用的例如快进倒退调声等,但是实验时无法进入android.view.GestureDetector.OnGestureListener里的public boolean onFling()函数.因此没法检测手势 解决办法: 把默认生成的onDown方法返回值改成 return true ; public boolean onDown(MotionEvent e) { // TODO Auto-generatedmethod stub return true ; } ---------------------------------------------------------------------------------- 遇到问题6 使用更新时间线程和打开控制台一定时间后自动隐藏控制台线程时,如果处于线程延时时间内横竖屏转换时,转变后会发生错误导致崩溃.错误如下:07-2017:13:13.780: WARN/dalvikvm(12151): threadid=1: thread exiting with uncaughtexception (group=0x400208b0) 07-2017:13:13.803: ERROR/AndroidRuntime(12151): java.lang.IllegalArgumentException:View not attached to window manager 解决办法 原因估计是在横竖屏转换时Activity重载时没有注销线程里的Runnable 隐藏控制台线程在run()方法结尾执行注销线程里的runnable dismissHandler.removeCallbacks(dismissRunnable); 在Activity里的onDestroy()方法里 执行 if (updateHandle!= null ) { updateHandle .removeCallbacks(updateRunnable); releaseMediaPlayer(); } if (dismissHandler!= null ) { dismissHandler.removeCallbacks(dismissRunnable); } --------------------------------------------------------------------------------------------------------------------------- 遇到问题7 播放视频中,如果中途返回桌面,处理完外部事件在回到播放器,会出现无法继续退出前的时间点继续播放。错误是播放器线程死亡。 解决办法: 首先在activity的onPause()方法里保存时间断点,这里我用一个static int userPauseTime来保存。 protected void onPause() { userPauseTime =mMediaPlayer.getCurrentPosition(); mMediaPlayer.pause(); System. out .println("onPause"); super .onPause(); } 当用户处理完其他事件重新进入activity,程序执行流程根据我的跟踪是这样的, onResume()->surfaceCreated()->initMedia(media初始化)->onPrepared() 如果在onResume()直接seekTo()是不行的,因为这个时候貌似mediaplayer已经挂掉了,所以在surfaceCreated()里需要重新如下面这样new一个 mediaplayer,然后重新初始化 if (mMediaPlayer != null ) { mMediaPlayer.reset(); mMediaPlayer.release(); mMediaPlayer = null ; } // 对mMedia进行相关准备工作 try { mMediaPlayer = new MediaPlayer(); mMediaPlayer.setDataSource(path); mMediaPlayer.setDisplay(holder); mMediaPlayer.setAudioStreamType(AudioManager. STREAM_MUSIC ); mMediaPlayer.prepareAsync(); } catch (Exception e) { // TODO : handleexception System. out .println("e"+e); } initMediaAllListener(); mMediaPlayer.setAudioStreamType(AudioManager. STREAM_MUSIC ); 然后在onPrepared()方法中,判断是否用户之前有中断的时间,如果没有的话,应该属于第一次启动本视频,如果有的话 就调用 seekTo()跳转到之前的时间 public void onPrepared(MediaPlayer mediaplayer) { Log. d ( TAG , "onPreparedcalled"); mIsVideoReadyToBePlayed = true ; if (mIsVideoReadyToBePlayed && mIsVideoSizeKnown) { // startVideoPlayback(); } if ( userPauseTime ==0) { startVideoPlayback(); System. out .println("startVideoPlayback();"); } else { mMediaPlayer.seekTo( userPauseTime ); mMediaPlayer.start(); startProgressUpdate(); userPauseTime =0; System. out .println("userPauseTime!=0"); } } --------------------------------------------------------------------------------------------------------------------------- 遇到问题8 不清楚onInfo和onError里打印出来的 what 和 extra 代表什么意思,因此无法辨别mediaplayer出了什么错误. 解决办法: 总结如下 1.onInfo里 what= 1extra=44 时,代表着可以连接本地视频文件或者连接目标服务器流文件成功。 2.OnInfo里 what= 1extra=26 时, 代表无法找到连接本地视频文件或者连接目标服务器。接着会 onError 里会打印出 INFO/System.out(5514): what is 1 extra -4,然后继续打印出 onError INFO/System.out(5514):what is -38 extra 0 只要mediaplayer出了错误 最后都是onError 打印出 what is -38 extra 0 但是API文档中并未找到详细说明或给出对应的错误列表... 经过研究和网上资料的收集,暂总结如下: 在这个网站下可以查到如下内容 http://android.git.kernel.org/?p=platform/external/opencore.git;a=blob;f=pvmi/pvmf/include/pvmf_return_codes.h;h=ed5a2539ca85ae60425229be41646b6bd7d9389c;hb=HEAD /* *DRM clock is not available or cannot be read */ const PVMFStatus PVMFErrDrmClockError = (-38); /* *Return code for pending completion */ const PVMFStatus PVMFPending = 0; DRM指的是内容 。 由于数字化信息的特点决定了必须有另一种独特的技术,来加强保护这些数字化的音视频节目内容的版权。 3播放正在缓冲时,无线网络断开 07-2510:25:16.647: ERROR/MediaPlayer(8789): error (1, -17)既 what is 1, extra is -17 07-25 10:55:17.436: INFO/System.out(12355): whatis 1extra 31 07-27 10:23:42.040: INFO/System.out(14344):onInfo is 1 extra is28 --------------------------------------------------------------------------------------------------------------------------------------------- 遇到问题9 横竖屏速度慢,而且会重新开始播放视频。如何能加快转换速度,并且不间断播放? 解决办法: 转换速度慢并且重新播放是由于横竖屏转换时调用了activity里的onCreate()方法导致重新加载了,如果不想自动转换时调用onCreate()则在AndroidMaifest.xml中相应的activity下加入如下语句: --------------------------------------------------------------------------------------------------------------------------------------------- 遇到问题10 调整音量时,会显示出系统自带的音量调整UI ,可能会遮挡住视频,如何才能不显示自带的音量UI? 解决办法: 在调整音量时,是使用下面这条语句: audioManager.adjustStreamVolume(AudioManager. STREAM_MUSIC , AudioManager. ADJUST_LOWER ,AudioManager. FLAG_SHOW_UI ); 最后一个参数指的就是需不需要显示出音量UI,如果设置为0 ,就不会显示了。 --------------------------------------------------------------------------------------------------------------------------------------------- 遇到问题11 在播放网络流媒体时,如果网速太慢,根据缓冲进度来给用户正在缓冲的提示? 解决办法: 第一种,在onBufferingUpdate()里面跟踪视频正在播放时间,如果与上一次时间相同,则弹出缓冲提示如下 int CurrentTime =mMediaPlayer.getCurrentPosition(); if(lastBufferTime==CurrentTime) { if(bufferAlertDialog.isShowing()==false) { bufferAlertDialog.show(); System.out.println("bufferAlertDialog.show();"); } } else { if(bufferAlertDialog.isShowing()==true) { bufferAlertDialog.dismiss(); bufferAlertDialog=null; System.out.println("bufferAlertDialog.dismiss();"); } } if (mMediaPlayer!= null ) { if (mMediaPlayer.isPlaying()== true ) { lastBufferTime=CurrentTime;//正在播放才更新上一次缓冲时间 防止用户暂停时也更新 } } 但是这样有些瑕疵 ,首先是每次先是画面停顿后2秒-3秒左右后才弹出缓冲中,这是由于onBuffer自己调用的时间是2s左右。 其次是可以播放,但是播放起来很卡,这种方法暂时不能给出任何提示。 --------------------------------------------------------------------------------------------------------------------------------------------- 遇到问题12 使用ProgressDialog进行缓冲提示时,第一次ProgressDialog上的进度条会旋转,但在播放中进度条不会旋转。 解决办法: 在每次onBuffer里面重新生成 ProgressDialog, if (bufferAlertDialog== null ) { initBuffering(); } 然后在每次dismiss后赋值null, if (bufferAlertDialog.isShowing()== true ) { bufferAlertDialog.dismiss(); bufferAlertDialog= null ; } 注意: 这里不能使用 dismiss()不能改成dialog.hide()方法,经过测试,hide方法后 isShowing()返回的一直是 true ,虽然在手机上看不见了,但是依然是 isShowing --------------------------------------------------------------------------------------------------------------------------------------------- 遇到问题13 如何在屏幕双击后自动切换播放视频原始尺寸或全屏显示? 解决办法: 可以通过设置SurfaceView的参数来调整显示大小,如下 public void setVideoScale( int width, int height) { LayoutParams lp = mPreview.getLayoutParams(); lp.height = height; lp.width = width; mPreview.setLayoutParams(lp); } width和height 如果是视频默认尺寸的话就是 int videoWidth = mMediaPlayer.getVideoWidth(); int videoHeight = mMediaPlayer.getVideoHeight(); 全屏显示时就是 Display display =getWindowManager().getDefaultDisplay(); screenHeight = display.getHeight(); screenWidth = display.getWidth(); 最后在双击的监听器中 @Override public boolean onDoubleTap(MotionEvent e) { System. out .println("onDoubleTap"); if (isFullScreen) { setVideoScale( SCREEN_DEFAULT ); } else { setVideoScale( SCREEN_FULL ); } isFullScreen = !isFullScreen; return true ; } --------------------------------------------------------------------------------------------------------------------------------------------- 遇到问题14 横竖屏转换时,竖屏全屏播放转换成横屏时,只能显示在左边而且显示一半. 解决办法: 显示在左边是xml中的布局问题,在其修改成
来源: http://www.bubuko.com/infodetail-1870103.html