Question

In my Android app, I have a custom video player that plays videos from a URL. When the video is taken in a portrait orientation, though, the video is rotated 90 degrees counterclockwise in the app.

Is there a way for me to get the orientation of the video and rotate the view accordingly? I need to detect the orientation dynamically because the app should still be able to play landscape videos (which it currently does without orientation issues).

Here is what I have for displaying the video:

// create the video controller
videoController = new MediaController(this);
videoControllerExists = true;
videoController.setAnchorView(mediaHolder);
videoController.setPadding(0, 0, 0, bottomButtonHeight);

s3Video = new VideoView(MediaPreview.this);
s3Video.setVideoURI(Uri.parse(mediaURL));
s3Video.setMediaController(videoController);
// do something here to determine if video is in portrait orientation
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
int h = displaymetrics.heightPixels;
int w = displaymetrics.widthPixels;

// add the video player to the view and play
mediaHolder.addView(s3Video);
s3Video.start();
s3Video.bringToFront();
videoController.requestFocus();

Here's a portrait video that you can test with if you're trying this out: https://dl.dropboxusercontent.com/u/1000620/portrait.mp4

Edit

After looking at some examples, I switched from a VideoView to a TextureView and was able to rotate the video. I still don't know how to detect the orientation of the video from a URL, though, so all videos are rotated right now.

How do I detect the orientation of a video from a URL?

Here's my updated code:

public class MediaPreview extends SherlockActivity implements YouTubePlayer.OnInitializedListener, TextureView.SurfaceTextureListener, OnBufferingUpdateListener, OnCompletionListener, OnPreparedListener,
OnVideoSizeChangedListener, MediaPlayerControl {

    private MediaPlayer s3VideoPlayer;
    private TextureView s3TextureView;
    private Surface s;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

    // set up textureview
        s3TextureView = (TextureView) findViewById(R.id.s3_video);
        s3TextureView.setSurfaceTextureListener(this);
    }

    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width,
            int height) {
        s = new Surface(surface);
        if(isFromVideo){
            playAmazonVideo(mediaHolder);
        }

    }

    private void playAmazonVideo(FrameLayout mediaHolder){

            // set up mediacontroller
            videoController = new MediaController(this);
            videoControllerExists = true;
            videoController.setAnchorView(mediaHolder);
            videoController.setPadding(0, 0, 0, bottomButtonHeight);

            // set scale for textureview
            DisplayMetrics displaymetrics = new DisplayMetrics();
            getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
            int h = displaymetrics.heightPixels;
            int w = displaymetrics.widthPixels;
            LayoutParams videoLayoutParams = new LayoutParams(h, w);
            videoLayoutParams.gravity = Gravity.CENTER;
            s3TextureView.setScaleX(h/w);
            s3TextureView.setLayoutParams(videoLayoutParams);

       // Setting up video view using Media Player
        try{
            s3VideoPlayer = MediaPlayer.create(this, Uri.parse(mediaURL));
            s3VideoPlayer.setSurface(s);
            s3VideoPlayer.setOnBufferingUpdateListener(this);
            s3VideoPlayer.setOnCompletionListener(this);
            s3VideoPlayer.setOnPreparedListener(this);
            s3VideoPlayer.setScreenOnWhilePlaying(true);
            s3VideoPlayer.setOnVideoSizeChangedListener(this);
            s3VideoPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            s3VideoPlayer.start();
    }

    @Override
    public void onPrepared(MediaPlayer mp) {
        if(isAmazon && mediaURL.length() > 0){
            mediaProgress.setVisibility(View.GONE);
            videoController.setMediaPlayer(this);
            videoController.setEnabled(true);
            videoController.show();     
        }    
    }

    @Override
    public boolean onTouchEvent(MotionEvent event){
        if(isAmazon){
            Log.d(TAG, "showing video controller");
            videoController.show();    
        }
        return false;
    }

 @Override
    public boolean canPause() {
        return true;
    }

    @Override
    public boolean canSeekBackward() {
        return true;
    }

    @Override
    public boolean canSeekForward() {
        return true;
    }

   @Override
    public int getCurrentPosition() {
        return s3VideoPlayer.getCurrentPosition();
    }

    @Override
    public int getDuration() {
        return s3VideoPlayer.getDuration();        
    }

    @Override
    public boolean isPlaying() {
        return s3VideoPlayer.isPlaying();
    }

 @Override
    public void pause() {
        s3VideoPlayer.pause();
    }

    @Override
    public void seekTo(int pos) {
        s3VideoPlayer.seekTo(pos);

    }

    @Override
    public void start() {
        s3VideoPlayer.start();

    }


    }

Edit #2

I've been looking into options for detecting video orientation and found http://wseemann.github.io/FFmpegMediaMetadataRetriever/

Unfortunately, this doesn't seem to be getting the video's rotation even though if I look at the exif for the video file, I can see that the orientation value is 90. So if anyone has any other solutions, please share!

Edit #3

Here is something else that I tried. I saw that you can set an OnVideoSizeChangedListener for a MediaPlayer to get the width and height of a video. But with the videos I'm using, the width is always greater than the height, and players know whether to rotate the video or not based on the rotation EXIF value. So I can't use this either...

Was it helpful?

Solution

I wasn't able to figure out the rotation issue, so I ended up just updating my Rails app to save the rotation of the video when it's updated. Then when I fetch videos from the website to the Android app, I also retrieve the rotation of the video and update the textureview rotation accordingly. It's really not an ideal way to do it, but I couldn't find any other solution.

This is what it looked like in the end:

        // set scale for textureview
        final Intent i = getIntent();
        videoRotation = i.getIntExtra("videoRotation", 0);
        Log.d(TAG, "setting video rotation...");
        DisplayMetrics displaymetrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
        int h = displaymetrics.heightPixels;
        int w = displaymetrics.widthPixels;
        Log.d(TAG, "hxw: " + h + w);
        LayoutParams videoLayoutParams = new LayoutParams(h, w);
        videoLayoutParams.gravity = Gravity.CENTER;
        s3TextureView.setScaleX(h/w);    
        s3TextureView.setRotation(Math.abs(360-videoRotation));
        s3TextureView.setLayoutParams(videoLayoutParams);
        Log.d(TAG, "done setting video rotation");

OTHER TIPS

Can the below code help?

activity.setRequestedOrientation(videoView.getWidth() < videoView.getHeight() ? ActivityInfo.SCREEN_ORIENTATION_PORTRAIT : ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

you can get width and height of video then you do a test for example if( width > 800) and (!isTablet) then forced the activity to be landscape.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top