全屏视频查看而不拉伸视频
Posted
技术标签:
【中文标题】全屏视频查看而不拉伸视频【英文标题】:Full screen videoview without stretching the video 【发布时间】:2012-08-31 08:44:31 【问题描述】:我想知道我是否可以通过 videoview 全屏播放视频?
我搜索了很多,尝试了很多方法,例如:
在清单中应用主题:
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
但这并不强制视频全屏显示。
在活动本身中应用:
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
也不强制视频全屏显示。
强制视频全屏的唯一方法是:
<VideoView android:id="@+id/myvideoview"
android:layout_
android:layout_alignParentRight="true"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_>
</VideoView>
这样会产生全屏视频,但会拉伸视频本身(拉长视频),
我没有将这个不正确的解决方案应用于我的视频视图,那么有什么方法可以在不拉伸视频的情况下做到这一点?
视频类:
public class Video extends Activity
private VideoView myvid;
@Override
public void onCreate(Bundle icicle)
super.onCreate(icicle);
setContentView(R.layout.main);
myvid = (VideoView) findViewById(R.id.myvideoview);
myvid.setVideoURI(Uri.parse("android.resource://" + getPackageName()
+"/"+R.raw.video_1));
myvid.setMediaController(new MediaController(this));
myvid.requestFocus();
myvid.start();
main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
android:orientation="vertical" >
<VideoView
android:id="@+id/myvideoview"
android:layout_
android:layout_ />
</LinearLayout>
【问题讨论】:
只需在布局 xml 文件中删除 4 android:layout_alignXXX 即可让您的 VideoView 使用尽可能多的屏幕空间,同时保持视频的宽高比。这就是 API 的设计方式和工作方式。 @yorkw 我知道,通常它需要 1/3 的屏幕才能显示正常的视频,我也没有将带有 4 android:layout_alignXXX 的 xml 应用到我的应用程序,这是我发现强制执行的不正确的解决方案全屏,我想要任何适当的方法来强制它全屏但(不拉伸), 我认为这是预期的结果。如果您在纵向模式下播放,视频通常会占据全宽,但会在顶部和底部留出很大空间,如果以横向模式播放,视频通常会占据全高但会在侧面留出一些空间。 @yorkw android 默认播放器和许多自定义播放器全屏播放任何视频,没有间距,因此必须有一个技巧或代码破解来做到这一点,这就是我正在寻找的亲爱的 它们仍然保持纵横比吗?我不信。有许多设备具有不同的屏幕尺寸。以三星 Galaxy S2 为例,屏幕尺寸为 480 x 800,横向模式下为 5:3,可见不是 4:3 或 16:9 那样的正常纵横比。 【参考方案1】:这样你可以自己设置视频的属性。
使用 SurfaceView(让您对视图有更多控制权),将其设置为 fill_parent 以匹配整个屏幕
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_
android:layout_>
<SurfaceView
android:id="@+id/surfaceViewFrame"
android:layout_
android:layout_
android:layout_gravity="center" >
</SurfaceView>
</Linearlayout>
然后在您的 java 代码中获取表面视图并将您的媒体播放器添加到其中
surfaceViewFrame = (SurfaceView) findViewById(R.id.surfaceViewFrame);
player = new MediaPlayer();
player.setDisplay(holder);
在您的媒体播放器上设置一个 onPreparedListener 并手动计算所需的视频大小,以所需的比例填充屏幕,避免拉伸视频!
player.setOnPreparedListener(new OnPreparedListener()
@Override
public void onPrepared(MediaPlayer mp)
// Adjust the size of the video
// so it fits on the screen
int videoWidth = player.getVideoWidth();
int videoHeight = player.getVideoHeight();
float videoProportion = (float) videoWidth / (float) videoHeight;
int screenWidth = getWindowManager().getDefaultDisplay().getWidth();
int screenHeight = getWindowManager().getDefaultDisplay().getHeight();
float screenProportion = (float) screenWidth / (float) screenHeight;
android.view.ViewGroup.LayoutParams lp = surfaceViewFrame.getLayoutParams();
if (videoProportion > screenProportion)
lp.width = screenWidth;
lp.height = (int) ((float) screenWidth / videoProportion);
else
lp.width = (int) (videoProportion * (float) screenHeight);
lp.height = screenHeight;
surfaceViewFrame.setLayoutParams(lp);
if (!player.isPlaying())
player.start();
);
我从前段时间关注的视频流教程修改了这个,现在找不到它来引用它,如果有人这样做,请添加答案的链接!
希望对你有帮助!
编辑
好的,因此,如果您希望视频占据整个屏幕并且不希望它拉伸,那么最终会在两侧出现黑色条纹。在我发布的代码中,我们正在找出更大的视频或手机屏幕,并以最佳方式对其进行调整。
你有我的完整活动,从链接流式传输视频。它是 100% 功能性的。我不能告诉你如何从你自己的设备上播放视频,因为我不知道。我相信您会在文档here 或here 中找到它。
public class VideoPlayer extends Activity implements Callback, OnPreparedListener, OnCompletionListener,
OnClickListener
private SurfaceView surfaceViewFrame;
private static final String TAG = "VideoPlayer";
private SurfaceHolder holder;
private ProgressBar progressBarWait;
private ImageView pause;
private MediaPlayer player;
private Timer updateTimer;
String video_uri = "http://daily3gp.com/vids/familyguy_has_own_orbit.3gp";
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.videosample);
pause = (ImageView) findViewById(R.id.imageViewPauseIndicator);
pause.setVisibility(View.GONE);
if (player != null)
if (!player.isPlaying())
pause.setVisibility(View.VISIBLE);
surfaceViewFrame = (SurfaceView) findViewById(R.id.surfaceViewFrame);
surfaceViewFrame.setOnClickListener(this);
surfaceViewFrame.setClickable(false);
progressBarWait = (ProgressBar) findViewById(R.id.progressBarWait);
holder = surfaceViewFrame.getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
player = new MediaPlayer();
player.setOnPreparedListener(this);
player.setOnCompletionListener(this);
player.setScreenOnWhilePlaying(true);
player.setDisplay(holder);
private void playVideo()
new Thread(new Runnable()
public void run()
try
player.setDataSource(video_uri);
player.prepare();
catch (Exception e) // I can split the exceptions to get which error i need.
showToast("Error while playing video");
Log.i(TAG, "Error");
e.printStackTrace();
).start();
private void showToast(final String string)
runOnUiThread(new Runnable()
public void run()
Toast.makeText(VideoPlayer.this, string, Toast.LENGTH_LONG).show();
finish();
);
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
// TODO Auto-generated method stub
public void surfaceCreated(SurfaceHolder holder)
playVideo();
public void surfaceDestroyed(SurfaceHolder holder)
// TODO Auto-generated method stub
//prepare the video
public void onPrepared(MediaPlayer mp)
progressBarWait.setVisibility(View.GONE);
// Adjust the size of the video
// so it fits on the screen
int videoWidth = player.getVideoWidth();
int videoHeight = player.getVideoHeight();
float videoProportion = (float) videoWidth / (float) videoHeight;
int screenWidth = getWindowManager().getDefaultDisplay().getWidth();
int screenHeight = getWindowManager().getDefaultDisplay().getHeight();
float screenProportion = (float) screenWidth / (float) screenHeight;
android.view.ViewGroup.LayoutParams lp = surfaceViewFrame.getLayoutParams();
if (videoProportion > screenProportion)
lp.width = screenWidth;
lp.height = (int) ((float) screenWidth / videoProportion);
else
lp.width = (int) (videoProportion * (float) screenHeight);
lp.height = screenHeight;
surfaceViewFrame.setLayoutParams(lp);
if (!player.isPlaying())
player.start();
surfaceViewFrame.setClickable(true);
// callback when the video is over
public void onCompletion(MediaPlayer mp)
mp.stop();
if (updateTimer != null)
updateTimer.cancel();
finish();
//pause and resume
public void onClick(View v)
if (v.getId() == R.id.surfaceViewFrame)
if (player != null)
if (player.isPlaying())
player.pause();
pause.setVisibility(View.VISIBLE);
else
player.start();
pause.setVisibility(View.GONE);
【讨论】:
首先感谢您的回答,请您写完整的代码,因为这是我第一次使用videoview,从不使用surfaceview或MediaPlayer,我不是android专家,我也无法理解这个(手动计算所需的视频大小,以所需的比例填充屏幕),我也希望最终在任何手机上播放我的视频时占据全屏而不失真或拉伸,这个问题将是大项目的一部分所以我的应用会有很多不同长度和大小的视频,非常感谢 我还添加了这条线:final MediaPlayer player = MediaPlayer.create(this,R.raw.video_1);然后它只播放视频的音频而不是它自己的视频,谢谢 如果答案是您想要的,请不要忘记接受它!我很高兴能帮上忙! 此代码将调整视频大小但不会拉伸它。如果您希望视频全屏显示,我想您需要多种分辨率,并且您需要选择一种与您的手机匹配的分辨率,但请记住,我不是媒体播放方面的专家。您可以跟踪异常并查看问题所在。我的第一个猜测是 URI 中有一些断开的链接或输入错误! 顺便说一句,我认为没有任何理由经历所有 SurfaceView 的疯狂。您可以像往常一样使用 VideoView,但在 onPrepared 回调中将该尺寸调整代码应用于其 LayoutParameters。【参考方案2】: @Override
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
videoView1 = (VideoView) findViewById(R.id.videoview);
String SrcPath = "/mnt/sdcard/final.mp4";
videoView1.setVideoPath(SrcPath);
videoView1.setMediaController(new MediaController(this));
videoView1.requestFocus();
videoView1.start();
<VideoView
android:id="@+id/videoview"
android:layout_
android:layout_
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true" >
</VideoView>
试试这个对我有用
【讨论】:
如果布局为fill_parent,是否需要所有对齐属性?听起来像重复。 是的,要将视频视图设置为全屏,我们需要所有对齐, 此代码使 videoview 全屏显示,但如果视频不完全适合,它会拉伸视频。此代码不保持纵横比。【参考方案3】:当前赞成的解决方案有效,但对于原始问题可能有更简单的解决方案。一位评论者正确地指出,您可以使用相同的方法调整 VideoView 的大小,而无需将所有内容都转换为 SurfaceView。我在我的一个应用程序中对此进行了测试,它似乎有效。只需在 OnPreparedListener 回调中将计算好的布局参数添加到 VideoView 中即可:
mInspirationalVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() @覆盖 公共无效onPrepared(MediaPlayer mp) // mMediaPlayer = mp;
mp.setOnSeekCompleteListener(new MediaPlayer.OnSeekCompleteListener()
@Override
public void onSeekComplete(MediaPlayer mp)
if(isPlaying = true)
stopPosition = 0;
mp.start();
mVideoProgressTask = new VideoProgress();
mVideoProgressTask.execute();
);
// so it fits on the screen
int videoWidth = mp.getVideoWidth();
int videoHeight = mp.getVideoHeight();
float videoProportion = (float) videoWidth / (float) videoHeight;
DisplayMetrics mDisplayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(mDisplayMetrics);
float screenWidth = mDisplayMetrics.widthPixels;
float screenHeight = mDisplayMetrics.heightPixels;
float screenProportion = (float) screenWidth / (float) screenHeight;
android.view.ViewGroup.LayoutParams lp = mInspirationalVideoView.getLayoutParams();
if (videoProportion > screenProportion)
lp.width = screenWidth;
lp.height = (int) ((float) screenWidth / videoProportion);
else
lp.width = (int) (videoProportion * (float) screenHeight);
lp.height = screenHeight;
mInspirationalVideoView.setLayoutParams(lp);
...
);
【讨论】:
这对我很有用,谢谢。但是 getwidth() 和 getheight() 方法被贬低了,还有其他选择吗???【参考方案4】:这是我的函数,它适用于全屏视频而不拉伸它。它会自动裁剪视频的两侧。它适用于纵向和横向模式。
实际上取自answer。
public void onPrepared(MediaPlayer mp)
int videoWidth = mediaPlayer.getVideoWidth();
int videoHeight = mediaPlayer.getVideoHeight();
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int screenWidth = displayMetrics.widthPixels;
int screenHeight = displayMetrics.heightPixels;
float scaleY = 1.0f;
float scaleX = (videoWidth * screenHeight / videoHeight) / screenWidth;
int pivotPointX = (int) (screenWidth / 2);
int pivotPointY = (int) (screenHeight / 2);
surfaceView.setScaleX(scaleX);
surfaceView.setScaleY(scaleY);
surfaceView.setPivotX(pivotPointX);
surfaceView.setPivotY(pivotPointY);
mediaPlayer.setLooping(true);
mediaPlayer.start();
【讨论】:
【参考方案5】:您是否尝试过调整底层表面支架尺寸?试试下面的代码,它应该将表面支架调整为与屏幕尺寸相同的宽度和高度。您仍然应该让您的活动全屏显示而没有标题栏。
public class Video extends Activity
private VideoView myvid;
@Override
public void onCreate(Bundle icicle)
super.onCreate(icicle);
setContentView(R.layout.main);
myvid = (VideoView) findViewById(R.id.myvideoview);
myvid.setVideoURI(Uri.parse("android.resource://" + getPackageName()
+"/"+R.raw.video_1));
myvid.setMediaController(new MediaController(this));
myvid.requestFocus();
//Set the surface holder height to the screen dimensions
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
myvid.getHolder().setFixedSize(size.x, size.y);
myvid.start();
【讨论】:
它在 word 下给了我红色错误:getSize in this line : display.getSize(size);【参考方案6】:嗯,希望对FullscreenVideoView有帮助
它处理所有关于表面视图和全屏视图的无聊代码,让你只关注 UI 按钮。
如果您不想构建自定义按钮,可以使用 FullscreenVideoLayout。
【讨论】:
【参考方案7】:SurfaceView 为您提供优化的绘图表面
public class YourMovieActivity extends Activity implements SurfaceHolder.Callback
private MediaPlayer media = null;
//...
@Override
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
media = new MediaPlayer();
mSurfaceView = (SurfaceView) findViewById(R.id.surface);
//...
MediaPlayer 调用应包含在 try 中。
@Override
public void surfaceCreated(SurfaceHolder holder)
media.setDataSource("android.resource://" + getPackageName()
+"/"+R.raw.video_);
media.prepare();
int videoWidth = mp.getVideoWidth();
int videoHeight = mp.getVideoHeight();
int screenWidth = getWindowManager().getDefaultDisplay().getWidth();
android.view.
ViewGroup.LayoutParams layout = mSurfaceView.getLayoutParams();
layout.width = screenWidth;
layout.height = (int) (((float)videoHeight / (float)videoWidth) * (float)screenWidth);
mSurfaceView.setLayoutParams(layout);
mp.start();
【讨论】:
android.widget.VideoView implementation 比您的实现更健壮、更智能。它可以处理视频太高或太宽的两种情况,所以请使用 VideoView。 但是当你使用视图时,你可以动态放置我认为你瞄准的视频的参数 @Yorkw:SurfaceView 充当容器。所以你可以在其中添加 videoView。所以你的健壮性仍然占上风。 不,您不要将 VideoView 包装在 SurfaceView 中,因为 VideoView 本身就是 SurfaceViewpublic class VideoView extends SurfaceView implements MediaPlayerControl ...
。这正是 API 提供 VideoView 的原因,让您的生活更轻松,因为 VideoView 足以满足大多数常见用例。【参考方案8】:
我已经通过Custom VideoView解决了这个问题:
我以两种方式从 xml 和以编程方式将 VideoView 添加到 ParentView。
为以 FullScreenVideoView.java 命名的 VideoView 添加自定义类:
import android.content.Context;
import android.util.AttributeSet;
import android.widget.VideoView;
public class FullScreenVideoView extends VideoView
public FullScreenVideoView(Context context)
super(context);
public FullScreenVideoView(Context context, AttributeSet attrs)
super(context, attrs);
public FullScreenVideoView(Context context, AttributeSet attrs, int defStyle)
super(context, attrs, defStyle);
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
如何绑定与xml:
<FrameLayout
android:id="@+id/secondMedia"
android:layout_
android:layout_>
<com.my.package.customview.FullScreenVideoView
android:layout_
android:layout_
android:id="@+id/fullScreenVideoView"/>
</FrameLayout>
或
如何以编程方式将 VideoView 添加到 ParentView:
FullScreenVideoView videoView = new FullScreenVideoView(getActivity());
parentLayout.addView(videoView, new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
希望这会对你有所帮助。
【讨论】:
这会拉伸视频 @MartyMiller,如果视频分辨率小的话会拉伸视频,你可以使用高清视频以上是关于全屏视频查看而不拉伸视频的主要内容,如果未能解决你的问题,请参考以下文章