第一部分:问题的出现

需求:页面有很多布局,其中有一块区域播放视频,当我单击这块区域的时候,全屏播放。

我使用MediaPlayer +

SurfaceView,当全屏时,改变SurfaceView的大小,然后MediaPlayer.setHolder(mSurfaceViewHolder),但是

,只有SurfaceView改变了,但是视频大小仍然没有改变。而且在不设置surfaceHolder的情况下,视频仍以奇特的方式播放,具体方法可以参看我之前的例子,链接是:。大家可以尝试,我在后面会进行一些测试来一步一步来排除问题。

第二部分:转换思路,解决问题

解决问题优先,换了一种思路解决问题,使用Android框架封装好的VideoView解决,很快实现。

思路:当需要全屏时,gone掉无关紧要的其他布局。让VideoView的父组件(的父组件)FILL_PARENT。当要回到默认的显示布局时,将之前保存的原始尺寸设置回来,原来gone掉的布局显示出来即可。

关键代码如下:

publicvoidonClick(View v) {

switch(v.getId()) {

caseR.id.videoView:

if(!isFullScreen) {

toFullScreen();

} else{

toDefaultScreen();

}

break;

}

}

privatevoidtoFullScreen() {

// TODO Auto-generated method stub

mVideoBarDefaultWidth = mVideoView.getWidth();

mVideoBarDefaultHeight = mVideoView.getHeight();

mTitleBar.setVisibility(View.GONE);

mAppBar.setVisibility(View.GONE);

mCategoryBar.setVisibility(View.GONE);

mIndicatorBar.setVisibility(View.GONE);

mContentLayout.setLayoutParams(newLinearLayout.LayoutParams(

LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));

mVideoViewLayout.setLayoutParams(newLinearLayout.LayoutParams(

LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));

mVideoView.setLayoutParams(newLinearLayout.LayoutParams(

LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));

isFullScreen = true;

}

privatevoidtoDefaultScreen() {

// TODO Auto-generated method stub

mTitleBar.setVisibility(View.VISIBLE);

mAppBar.setVisibility(View.VISIBLE);

mCategoryBar.setVisibility(View.VISIBLE);

mIndicatorBar.setVisibility(View.VISIBLE);

mContentLayout.setLayoutParams(newLinearLayout.LayoutParams(

LayoutParams.FILL_PARENT, mVideoBarDefaultHeight));

mVideoViewLayout.setLayoutParams(newLinearLayout.LayoutParams(

mVideoBarDefaultWidth, mVideoBarDefaultHeight));

mVideoView.setLayoutParams(newLinearLayout.LayoutParams(

mVideoBarDefaultWidth, mVideoBarDefaultHeight));

isFullScreen = false;

}

第三部分:原因+设计测试

VideoView本身是SurfaceView的子类,既然VideoView没有问题,显然问题出在我对SurfaceView的处理上。因为出现了上面提到的不设置SurfaceViewHolder,MediaPlayer也能播放的问题。So,

第一个问题:MediaPlayer播放视频的依赖条件是什么?

查找到android的视频播放框架,见下图(双击图片可以放大)。

显然,视频播放需要通过:

(1) JAVA Framework(即Android Framework),通过VideoView,经过Surface,

(2) 再到Native Framework,

(3) 最后到达Driver.

在这里要重申一句:我们的问题是,为什么

SurfaceView没能实现全屏? 那么go on !!!

我们只需要关注到Android

Framework之间的关联关系即可。显然,VideoView的父类是SurfaceView,最终通过其与Surface产生关联。

即VideoView?----------------SurfaceView?----------------------Surface

SurfaceView和Surface:

分析:文档

首先,SurfaceView的父类是View,最终父类是Object,但是Surface的父类是Object。类的层级见下图所示(双击可放大)。

所以两者是对等的关系,那么这两个是如何产生关系的。

SurfaceView的Class Overview见下图(双击图片可放大):

蓝色选中部分为关键内容:SurfaceView在它的Window上凿出一个洞,以便让Surface层的内容显示出来。本身它只提供一个显示Surface的窗口。

在此贴出来供参考:

SurfaceView是视图(View)的继承类,这个视图里内嵌了一个专门用于绘制的Surface。你可以控制这个Surface的格式和尺寸。Surfaceview控制这个Surface的绘制位置。 surface是纵深排序(Z-ordered)的,这表明它总在自己所在窗口的后面。surfaceview提供了一个可见区域,只有在这个可见区域内

的surface部分内容才可见,可见区域外的部分不可见。surface的排版显示受到视图层级关系的影响,它的兄弟视图结点会在顶端显示。这意味者

surface的内容会被它的兄弟视图遮挡,这一特性可以用来放置遮盖物(overlays)(例如,文本和按钮等控件)。注意,如果surface上面

有透明控件,那么它的每次变化都会引起框架重新计算它和顶层控件的透明效果,这会影响性能。 你可以通过SurfaceHolder接口访问这个surface,getHolder()方法可以得到这个接口。 surfaceview变得可见时,surface被创建;surfaceview隐藏前,surface被销毁。这样能节省资源。如果你要查看

surface被创建和销毁的时机,可以重载surfaceCreated(SurfaceHolder)和

surfaceDestroyed(SurfaceHolder)。 surfaceview的核心在于提供了两个线程:UI线程和渲染线程。这里应注意: 1>

所有SurfaceView和SurfaceHolder.Callback的方法都应该在UI线程里调用,一般来说就是应用程序主线程。渲染线程所要访问的各种变量应该作同步处理。 2>

由于surface可能被销毁,它只在SurfaceHolder.Callback.surfaceCreated()和

SurfaceHolder.Callback.surfaceDestroyed()之间有效,所以要确保渲染线程访问的是合法有效的surface。

第一个问题已经解决: Android的视频播放必须通过SurfaceView(或其封装类VideoView)实现。

第二个问题:视频播放中,可以切换到不同的SurfaceView上吗?

测试。

测试之前有必要上一张图,就是MediaPlayer的状态机(State-Machine),状态时刻指导代码。见下图。(双击图片可放大)。

建立测试Demo,如下图所示(双击图片可以放大):

Test1:指定初始SurfaceView的大小(demo中有左小右大两个SurfaceView),播放视频

显然,MediaPlayer和显示是独立的两个部分,为简化起见,MediaPlayer直接准备好。代码如下,

publicvoidonClick(View v) {

switch(v.getId()) {

caseR.id.buttonToSmall:

Log.d("testSurfaceView","onClick buttonToSmall");

try{

if(mMediaPlayer.isPlaying()) {

mMediaPlayer.release();

mMediaPlayer.setDataSource(mPath);

mMediaPlayer.prepare();

}

mMediaPlayer.setDisplay(mSurfaceView1.getHolder());

mMediaPlayer.start();

} catch(IllegalArgumentExceptione) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch(IllegalStateException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch(IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

break;

caseR.id.buttonToBig:

Log.d("testSurfaceView","onClick buttonToBig");

try{

if(mMediaPlayer.isPlaying()) {

mMediaPlayer.release();

mMediaPlayer.setDataSource(mPath);

mMediaPlayer.prepare();

}

mMediaPlayer.setDisplay(mSurfaceView2.getHolder());

mMediaPlayer.start();

} catch(IllegalArgumentExceptione) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch(IllegalStateException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch(IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

break;

测试结果:初始的surfaceview将决定视频的播放大小。系统会自动适配SurfaceView和Video的大小比例,使之恰当,但是在实际的显示效果并不佳,所以最好能通过运算计算一下。

Test2:既然两个SurfaceView都能单独播放,那么能否从一个切换到另一个上呢?

MediaPlayer通过SurfaceView显示出来,而SurfaceView由SurfaceViewHolder控制。MediaPlayer通过方法setDisplay(SurfaceViewHolder sh)实现。

参看SurfaceHolder的文档,见下图(双击图片可放大)。

参看setDisplay()方法的文档,见下图(双击图片可放大):

要点:在非播放状况下,使用此方法。

2-2-1代码如下:

publicvoidonClick(View v) {

switch(v.getId()) {

caseR.id.buttonToSmall:

Log.d("testSurfaceView","onClick buttonToSmall");

mMediaPlayer.setDisplay(mSurfaceView1.getHolder());

mMediaPlayer.start();

break;

caseR.id.buttonToBig:

Log.d("testSurfaceView","onClick buttonToBig");

mMediaPlayer.pause();

mMediaPlayer.setDisplay(mSurfaceView2.getHolder());

mMediaPlayer.start();

break;

测试结果:根本没变,还是在原来的Surface上显示。

2-2-2参考之前写的代码,做联想,如果重新Prepare,是否可以播放?

代码如下:

publicvoidstart() {

// TODO Auto-generated method stub

mMediaPlayer.start();

}

publicvoidonClick(View v) {

switch(v.getId()) {

caseR.id.buttonToSmall:

Log.d("testSurfaceView","onClick buttonToSmall");

mMediaPlayer.setDisplay(mSurfaceView1.getHolder());

mMediaPlayer.start();

break;

caseR.id.buttonToBig:

Log.d("testSurfaceView","onClick buttonToBig");

try{

mMediaPlayer.stop();

mMediaPlayer.setDisplay(mSurfaceView2.getHolder());

mMediaPlayer.prepare();

mMediaPlayer.start();

} catch(IllegalStateException e1) {

// TODO Auto-generated catch block

e1.printStackTrace();

} catch(IOException e1) {

// TODO Auto-generated catch block

e1.printStackTrace();

}

break;

测试结果:不能切换,有一个暂停,即是停止和重新做准备的所得。

结论:第一次设置holder之后,似乎就绑定了,无法切换到其他holder所控制的SurfaceView对应的display

surface。

More:为什么setDisplay()方法不能使得显示视频的SurfaceView进行切换,查找源码:如下图所示:

因为我暂时对Native

Framework不是很了解,所以只提到这里。原因就在:_setVideoSurface();

updateSurfaceScreenOn();

这两个方法中,可以去查找相关内容。

Test3:既然不能再两个SurfaceView之间切换,那么更改其中一个大小,可以变化吗?

点击Enlarge1按钮,gone掉Big SurfaceView,增大small SurfaceView

代码如下:

publicvoidonClick(View v) {

switch(v.getId()) {

caseR.id.buttonToSmall:

Log.d("testSurfaceView","onClick buttonToSmall");

try{

mMediaPlayer.setDisplay(mSurfaceView1.getHolder());

mMediaPlayer.prepare();

mMediaPlayer.start();

} catch(IllegalStateException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch(IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

break;

caseR.id.buttonToBig:

Log.d("testSurfaceView","onClick buttonToBig");

Log.d("testSurfaceView","has finished buttonToBig");

break;

caseR.id.buttonEnlarge1:

Log.d("testSurfaceView","onClick buttonEnlarge1");

try{

mMediaPlayer.pause();

mSurfaceView2.setVisibility(View.GONE);

mSurfaceView1.setLayoutParams(newLinearLayout.LayoutParams(500,500));

mSurfaceView1.getHolder().setFixedSize(500,500);

mMediaPlayer.setDisplay(mSurfaceView1.getHolder());

mMediaPlayer.start();

} catch(IllegalStateException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch(IllegalArgumentExceptione) {

// TODO Auto-generated catch block

e.printStackTrace();

}

break;

}

}

测试结果:我靠!居然ok了。再写此篇博文的时候,这个问题并没有解决。我是准备按照我的思路一步一步测试。

原因分析:很简单的道理。真正显示的是surface,通过SurfaceView.getHolder()获得SurfaceView对应下的Surface的控制器SurfaceHolder,获得SurfaceView的初始大小,但是,SurfaceHolder并未与SurfaceView动态关联(即虽然凿出的洞很大,但是真正播放的大小仍然是初始大小)。我们需要使用方法SurfaceHolder让真正播放的大小与凿的洞的大小相适应。这样视频才会大。

解决了MediaPlayer +SurafaceView 全屏的问题。

android surfaceview 大小,MediaPlayer + SurfaceView(视频大小和surfaceview大小)相关推荐

  1. Android之使用MediaPlayer和SurfaceView组件播放一个简单的视频

    1.MediaPlayer除了可以播放音乐外,还可以播放视频,但是使用MediaPlayer播放音乐时,没有提供图像输出界面,可以使用SurfaceView组件来显示视频画面,首先,必须在布局文件ac ...

  2. Android开发使用SurfaceView和Mediaplayer播放网络视频(功能齐全)

    本篇播客主要说明如何使用SurfaceView和Mediaplayer来播放网络视频. 支持视频格式:实测支持的有mp3.mp4.rmvb.avi.3gp.flv--. 带有功能:播放.暂停.视频拖动 ...

  3. 播放视频android学习笔记---44_在线视频播放器,网络视频解析器,SurfaceView 控件使用方法...

    最近用使开辟的过程中涌现了一个小题问,顺便录记一下因原和法方--播放视频 44_在线视频播放器 ------------------------- 1.注意这里,在模拟器中,android2.2和an ...

  4. Android音视频开发(二)SurfaceView

    简介 官方API文档介绍:SurfaceView是View的子类,它内嵌了一个专门用于绘制的Surface,你可以控制这个Surface的格式和尺寸,Surfaceview控制这个Surface的绘制 ...

  5. Android中使用自定义的VideoController和MediaPlayer实现视频的窗口和全屏播放

    基于MediaPlayer的能窗口和全屏切换的视屏播放器 之前在一个项目中做了一个能窗口化和全屏切换的播放器,做之前在网上也看了很多的demo,今天为了记录下自己的学习成果,特意将它写下来供自己以后参 ...

  6. android缓冲机制,Android自定义View之双缓冲机制和SurfaceView

    Android自定义View系列 双缓冲机制 问题的由来 CPU访问内存的速度要远远快于访问屏幕的速度.如果需要绘制大量复杂的图像时,每次都一个个从内存中读取图形然后绘制到屏幕就会造成多次地访问屏幕, ...

  7. Android 视频播放器 (二):使用MediaPlayer播放视频

    在 Android 视频播放器 (一):使用VideoView播放视频 我们讲了一下如何使用VideoView播放视频,了解了基本的播放器的一些知识和内容.也知道VideoView内部封装的就是Med ...

  8. android mediaplayer 播放 视频 【转】

    留着,当时,对这个 没有搞清楚的... 这两天在android上面捣弄它的mediaplayer,结果发现它果然挑食无比,非常的难伺候,其成熟程度跟iphone完全不在同一个level的.放在http ...

  9. TextureView/SurfaceView/GLSurfaceView/VideoView渲染视频(点播播放器)

    OpenGL实现视频的剪裁.旋转.水印.滤镜?? 将 ffmpeg 库移植到 Android 平台?   在播放网络上的视频流时,Android原生的MediaPlayer支持两种协议,HTTP和RT ...

最新文章

  1. 神经网络中,设计loss function有哪些技巧?
  2. RDKit相关文章汇总
  3. mpVue配置sass全局变量
  4. 如何导入pytorch包_PyTorch 目前的运行途径
  5. Hadoop学习笔记(8) ——实战 做个倒排索引
  6. Python Generators(生成器)——yield关键字
  7. 数据库SQL语言从入门到精通--Part 3--SQL语言基础知识
  8. 程序员容易不能生育?
  9. AS3.0中的显示编程(末篇)-- 滤镜(下)
  10. python machinelearning下载_Python与机器学习系列1:Anaconda的下载与安装
  11. 搞深度学习如何快速读懂开源代码?
  12. 最通俗易懂的讲解工厂模式
  13. 解决GUT GUI中文乱码问题
  14. 按键精灵助手之按钮响应事件
  15. JAVA线程中的sleep()、wait()、yield()、join()作用
  16. 上传图片报Invalid filename错误
  17. 《皮囊》——蔡崇达,读后感
  18. MySQL数据库 -- 库和表的操作
  19. FSL处理DTI数据详细流程(本人亲身经历的流程)
  20. python运行excel宏_从python运行excel宏

热门文章

  1. CN-EN-Translation-BERT
  2. Idea 解决SVN冲突
  3. 坚持 540 天,我有怎样的感受?
  4. Oracle 的安装和配置
  5. 从一个页面请求开始(二)
  6. 图解2017双十一背后的阿里云技术
  7. Maven基本面试题问答
  8. 理解gluPerspective和gluLookAt的关系
  9. 如果需要你来测试淘宝的购物车,你会如何设计测试用例,需要从哪些方面来考虑。
  10. The least populated class in y has only 1 member, which is too few. The minimum number of groups for