【问题标题】:Rotating an android VideoView旋转 android VideoView
【发布时间】:2012-01-25 01:41:30
【问题描述】:

我的应用程序仅提供纵向模式。在纵向活动中,我有一个全屏 VideoView。我想要做的是在横向模式下将 VideoView(实际视频、视频缓冲区)旋转 90 度。使活动处于 Lanscape 模式不是一种选择。 扩展 VideoView 和画布旋转将不起作用,因为它是 SurfaceView 而不是实际视图。 有没有办法通过 videoView 实现这一点?

【问题讨论】:

  • 为什么横向模式不是一个选项,当这是你想要的?

标签: android surfaceview android-videoview


【解决方案1】:

即使合成矩阵设置正确并使用了旋转属性,VideoView也不支持视频旋转。

你可以做的是使用TextureView并设置它的属性rotation="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>

它也应该处理流式视频。但请把它当作一个例子,而不是发布现成的代码。我重命名了一些内容并删除了其他内容,它们与问题无关,这可能会破坏某些内容,但总的来说这是一个可行的例子。

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);
        }
    }
}

希望这会有所帮助。我一直在寻找这个解决方案。几乎尝试了所有方法,这似乎是唯一的方法。

【讨论】:

  • 一句话,这是OpenGL纹理表面,你可以用它做任何你喜欢的事情,拉伸,镜像等等。
  • @Umka 你能告诉我我们可以镜像预览吗..任何代码示例
  • AFAIR 我使用 setScaleX() 和 setScaleY() 的值
  • 如果你说明了 videoView 和 mediaPlayer 是如何初始化的,这个例子会更好。
  • 显然videoView来自@+id/playback_video。媒体播放器初始化非常标准。让我找到它。
【解决方案2】:
 <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);
                    }
                }
            });

【讨论】:

  • 你能解释一下答案吗,这段代码会做什么?它将帮助其他用户参考。
  • mTextureview setRotation 90 在竖屏模式下,视频在屏幕上只显示半视图播放,所以这个代码逻辑上可以在屏幕上播放横向视频而不旋转屏幕
  • 其工作无需手机旋转全屏播放视频。
【解决方案3】:

VideoView 不支持旋转

你可以使用

<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"
        />

并且必须在 gradle 中的依赖项中添加以下行

implementation 'com.warnyul.android.fast-video-view:fast-video-view:1.0.2'

【讨论】:

  • 这真的很容易使用! tnx!!
  • 试图在我的纵向片段上获取横向视频,我将 fastvideoview 旋转 90* 但我无法将其拉伸到片段的完整大小,视图保持与以前相同的大小旋转
【解决方案4】:

您可以在清单中单独设置活动的方向,以便您的视频可以横向(和纵向)显示,而应用程序的其余部分则为纵向。请参阅我的回答 here 以获取解决方案。

【讨论】:

  • 这是个好主意,但如果您想在片段中显示视频而不是全屏显示,则无法使用。
猜你喜欢
  • 1970-01-01
  • 2017-10-23
  • 2011-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-10
  • 2012-01-09
  • 1970-01-01
相关资源
最近更新 更多