My application offers only Portrait mode. In a portrait activity I have a fullscreen VideoView. What I want to do is rotate the VideoView ( the actual video, videobuffer) 90 degrees at Landscape mode. Enabling activity to be on Lanscape mode is not an option. Extending VideoView and canvas rotate will not work as it is a SurfaceView not an actual view. Is there any way to achieve that with a videoView?
-
2Why is Landscape mode not an option, when this is what you want? – TouchBoarder Oct 14 '12 at 19:50
4 Answers
VideoView does not support rotation of video even if composition matrix is set correctly and rotation attribute is used.
What you can do is to use TextureView and set its attribute rotation="90" (for example). It then will rotate the frames but the aspect ratio is something that you need to handle your self. In order to do so you can use 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>
It should handle streamed video too. But please think of it as of an example rather than release ready code. I renamed some things and removed others, they don't have relation to the question and this might break something but in general this is workable example.
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);
}
}
}
Hope this helps. I was looking for this solution for quite long time. Tried almost everything and this seems to be the only way.

- 5,991
- 2
- 29
- 33
-
in two words, this is OpenGL texture surface, you can do with it whatever you like, stretch, mirror, etc. – Cynichniy Bandera Nov 26 '13 at 07:52
-
@Umka could you please tell me hw can we mirror the preview..any code example – Aswathy Jan 02 '14 at 09:22
-
1
-
This example would be nicer if you indicated how videoView and mediaPlayer are initialized. – Andrew Shepherd Jul 17 '14 at 01:31
-
Obviously videoView comes from @+id/playback_video. Media player init is pretty standard. Let me find it. – Cynichniy Bandera Jul 17 '14 at 06:43
-
Thanks all. This was tricky thing, I spent quite some time to find the answer. Fortunately, in iOS things are much simpler ) – Cynichniy Bandera Jul 17 '14 at 10:33
-
-
Its pretty standard thing... cannot say something more ) If you look at other examples of video playback they all use it. If you try a bit harder to explain what you really need to know I may tell more )) – Cynichniy Bandera Jan 11 '15 at 11:17
-
which class you implement in your activity that gives the above overriden methods which you implemented in your class? – Pradeep Sodhi Jan 16 '15 at 07:54
-
-
Note also loadMedia() which sets all the listeners to "this" instance, so that all those callbacks start working. – Cynichniy Bandera Jan 19 '15 at 15:44
-
Thanks! It was a good solution. I implemented it and now I am enjoying. But what is `BroadcastVideoOrientation` and `someVideoSource`. what are their libraries? I want to use them. – Bob Jan 28 '15 at 16:05
-
Its not related to the topic and 99% of normal life patterns this code may be used for ) Just ignore it. – Cynichniy Bandera Jan 29 '15 at 15:25
-
It worked great for me, but I have one question (just curiosity, really). Why does TextureView works with rotation and VideoView doesn't? I know that VideoView inherits from SurfaceView, so It's probably SurfaceView's fault. – Vinicius Melquiades Apr 04 '18 at 19:26
-
@ViniciusMelquiades I suspected it might be using opengl texture instead of whatever..., which allows it to be more flexible (stretching, mirroring, etc). – Cynichniy Bandera Apr 06 '18 at 07:05
VideoView does not support rotation
you can use
<com.warnyul.android.widget.FastVideoView
android:rotation="45"
android:layout_above="@+id/controller"
android:id="@+id/video2"
android:foregroundGravity="center"
android:layout_centerHorizontal="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
and must add bellow line to your dependencies in gradle
implementation 'com.warnyul.android.fast-video-view:fast-video-view:1.0.2'

- 182
- 1
- 10
-
-
Trying to get a landscape video on my portrait fragment, i rotate the fastvideoview 90* but i cannot get it to stretch to the full size of the fragment, the view stays the same size as it was before rotation – Steven B. Jul 22 '21 at 18:22
<TextureView
android:id="@+id/VideoViewfull"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:rotation="90"
/>
mMediaPlayer.setOnVideoSizeChangedListener(newMediaPlayer.OnVideoSizeChangedListener() {
@Override
public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
if (width < height) {
// orientation = "vertical";
mTextureView.setRotation(90f);
} else {
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int sHeight = displayMetrics.heightPixels;
int sntWidth = displayMetrics.widthPixels;
FrameLayout.LayoutParams parms =
new FrameLayout.LayoutParams(sHeight,sHeight);
mTextureView.setLayoutParams(parms);
}
}
});

- 31
- 5
-
can you please explain the answer, what this code will do? It will help other user referencing. – Suresh Karia Dec 04 '18 at 09:53
-
mTextureview setRotation 90 in portrait mode, video show only half view play in screen, so this code logically work landscape video play in screen without rotate screen – kishan Umretiya Dec 04 '18 at 12:41
-
You can set the oriantation individually of an activity in the manifest, so your video can be displayed in landscape (and portrait) while the rest of your application is in portrait. see my answer here for a solution on this.

- 1
- 1

- 6,422
- 2
- 52
- 60
-
This is a great idea, but won't work if you want to display the video in a Fragment, instead of full screen. – Guillaume Boudreau Nov 28 '13 at 19:07