旋转一个Android VideoView
我的应用程序只提供肖像模式。 在肖像活动中,我有一个全屏的VideoView。 我想要做的是在风景模式下旋转VideoView(实际的video,videobuffer)90度。 启用活动在Lanscape模式不是一个选项。 扩展VideoView和canvas旋转将无法正常工作,因为它是一个SurfaceView而不是实际的视图。 有没有办法用videoView来实现这一点?
即使合成matrix设置正确并使用旋转属性,VideoView也不支持旋转video。
你可以做的是使用TextureView并设置其属性旋转=“90”(例如)。 然后它会旋转框架,但纵横比是你需要处理自己的东西。 为了做到这一点,你可以使用textureView.setScaleX((screenHeight * 1.0f)/ screenWidth)
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <TextureView android:id="@+id/playback_video" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_centerInParent="true" android:rotation="90" /> </RelativeLayout>
它也应该处理stream式video。 但是请把它看作是一个例子而不是发布现成的代码。 我重命名了一些东西,删除了其他东西,他们与这个问题没有关系,这可能会破坏一些东西,但总的来说这是可行的例子。
public class PlaybackActivity extends Activity implements MediaPlayer.OnErrorListener, OnPreparedListener, OnCompletionListener, OnVideoSizeChangedListener, OnBufferingUpdateListener, OnInfoListener, SurfaceTextureListener { private MediaPlayer mediaPlayer; private TextureView videoView; private boolean startedPlayback = false; private boolean playerReady = false; public static final int MEDIA_INFO_NETWORK_BANDWIDTH = 703; private void createMediaPlayer() { mediaPlayer = new MediaPlayer(); } private void releaseMediaPlayer() { if (mediaPlayer != null) { mediaPlayer.setSurface(null); mediaPlayer.release(); mediaPlayer = null; } } public void onCompletion(MediaPlayer mp) { Log.w(TAG, "Video playback finished"); } @Override public boolean onError(MediaPlayer player, int what, int extra) { if (what == MediaPlayer.MEDIA_ERROR_UNKNOWN) { /* * Restart play back in case we did not start anything yet. This may * be the case when we tried to tune in in very first secs of the * broadcast when there is no data yet. */ if (liveBroadcast && mediaPlayer != null && !mediaPlayer.isPlaying() && !startedPlayback) { if (checkCount-- > 0) { mediaPlayer.reset(); checkBroadcast(); } else { Log.w(TAG, "Broadcast finished"); } } else { Log.w(TAG, "No media in stream"); } } else if (what == MediaPlayer.MEDIA_ERROR_SERVER_DIED) { Log.w(TAG, "Media service died unexpectedly"); } else { Log.w(TAG, "Unknown media error"); } return true; } @Override public boolean onInfo(MediaPlayer mp, int what, int extra) { switch (what) { case MediaPlayer.MEDIA_INFO_VIDEO_TRACK_LAGGING: Log.w(TAG, "Media is too complex to decode it fast enough."); startedPlayback = true; break; case MEDIA_INFO_NETWORK_BANDWIDTH: Log.w(TAG, "Bandwith in recent past."); break; case MediaPlayer.MEDIA_INFO_BUFFERING_START: Log.w(TAG, "Start of media bufferring."); startedPlayback = true; break; case MediaPlayer.MEDIA_INFO_BUFFERING_END: Log.w(TAG, "End of media bufferring."); startedPlayback = true; break; case MediaPlayer.MEDIA_INFO_BAD_INTERLEAVING: Log.w(TAG, "Media is not properly interleaved."); break; case MediaPlayer.MEDIA_INFO_NOT_SEEKABLE: Log.w(TAG, "Stream is not seekable."); break; case MediaPlayer.MEDIA_INFO_METADATA_UPDATE: Log.w(TAG, "New set of metadata is available."); break; case MediaPlayer.MEDIA_INFO_UNKNOWN: default: Log.w(TAG, "Unknown playback info (" + what + ":" + extra + ")."); break; } return true; } private void startPlayback() { if (mediaPlayer != null) { onLoaded(mediaPlayer); mediaPlayer.start(); } } private void pausePlayback() { if (mediaPlayer != null && mediaPlayer.isPlaying()) mediaPlayer.pause(); } private void resumePlayback() { if (mediaPlayer != null && mediaPlayer.isPlaying()) mediaPlayer.start(); } private void onLoaded(MediaPlayer mp) { } public void onPrepared(MediaPlayer mp) { playerReady = true; startPlayback(); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); setContentView(R.layout.playback); videoView = (TextureView) findViewById(R.id.playback_video); videoView.setOnClickListener(videoViewClickHandler); videoView.setSurfaceTextureListener(this); createMediaPlayer(); } @Override protected void onDestroy() { releaseMediaPlayer(); if (surface != null) { surface.release(); surface = null; } super.onDestroy(); } @Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { this.surface = new Surface(surface); loadMedia(someurl); } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { if (this.surface != null) { releaseMediaPlayer(); this.surface.release(); this.surface = null; } return true; } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { } @Override public void onSurfaceTextureUpdated(SurfaceTexture surface) { } @Override public void onVideoSizeChanged(MediaPlayer mp, int w, int h) { if (w > 0 && h > 0 && !videoSizeSetupDone) { Log.w(TAG, "Video size changed: " + w + "x" + h); changeVideoSize(w, h); } } private boolean videoSizeSetupDone = false; private void changeVideoSize(int width, int height) { DisplayMetrics metrics = new DisplayMetrics(); RelativeLayout.LayoutParams params; Utils.getScreenMetrics(this, metrics); VideoOrientation orientation = someVideoSource.getVideoOrientation(); if (orientation == LANDSCAPE) { params = new RelativeLayout.LayoutParams(metrics.widthPixels, metrics.heightPixels); } else { float rotation = orientation == BroadcastVideoOrientation.BroadcastVideoFrontCamera ? -90.0f : 90.0f; params = new RelativeLayout.LayoutParams(metrics.heightPixels, metrics.widthPixels); float scale = (width * 1.0f) / (height * 1.0f); videoView.setRotation(rotation); videoView.setScaleX(scale); } params.addRule(RelativeLayout.CENTER_IN_PARENT, -1); videoView.setLayoutParams(params); videoSizeSetupDone = true; } private void loadMedia(String url) { if (surface == null) return; Log.d(App.TAG, "Loading url: " + url); startedPlayback = false; try { mediaPlayer.reset(); mediaPlayer.setSurface(surface); mediaPlayer.setDataSource(url); mediaPlayer.setOnPreparedListener(this); mediaPlayer.setOnCompletionListener(this); mediaPlayer.setOnErrorListener(this); mediaPlayer.setOnVideoSizeChangedListener(this); mediaPlayer.setScreenOnWhilePlaying(true); mediaPlayer.setOnBufferingUpdateListener(this); mediaPlayer.setOnInfoListener(this); mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mediaPlayer.prepareAsync(); } catch (Exception e) { Log.w(TAG, "Media load failed"); Utils.alert(this, "Playback Error", e.getMessage(), finishHandler); } } }
希望这可以帮助。 我正在寻找这个解决scheme很长一段时间。 几乎所有的尝试,这似乎是唯一的方法。
您可以在清单中单独设置某个活动的Oriant,因此您的video可以横向(和纵向)显示,而其他应用程序则是纵向显示。 看到我的答案在这里find一个解决scheme。