Android 使用PLDroidPlayer播放网络视频 根据视频角度自动旋转

最近因为项目需求 ,需要播放网络视频 ,于是乎 研究了一番 ,说说我遇到的那些坑

现在市面上有几个比较主流好用的第三方框架

当然还有很多别的视频播放框架 因为我只找到这几个= =!

因为项目比较急,所以我用的比较简单的 PLDroidPlayer

首先把需要的jar包和jni文件拷到你的项目中

这个里面有很多控件,你们可以根据自己的需求来用指定的控件,我用的是PLVideoTextureView

<com.pili.pldroid.player.widget.PLVideoTextureView
        android:id="@+id/video"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerInParent="true" />
... prompt‘‘‘

然后findviewbyid找到它

public class PLVideoTextureActivity extends AppCompatActivity {

    private MediaController mMediaController;
    private PLVideoTextureView mVideoView;
    private Toast mToast = null;
    private String mVideoPath = null;
    private int mRotation = 0;
    private int mDisplayAspectRatio = PLVideoTextureView.ASPECT_RATIO_FIT_PARENT; //default

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        setContentView(R.layout.activity_pl_video_texture);
        mVideoView = (PLVideoTextureView) findViewById(R.id.VideoView);

        View loadingView = findViewById(R.id.LoadingView);
        mVideoView.setBufferingIndicator(loadingView);

        mVideoPath = getIntent().getStringExtra("videoPath");

        // If you want to fix display orientation such as landscape, you can use the code show as follow
        //
        // if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
        //     mVideoView.setPreviewOrientation(0);
        // }
        // else if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
        //     mVideoView.setPreviewOrientation(270);
        // }

        mVideoPath = getIntent().getStringExtra("videoPath");

        AVOptions options = new AVOptions();

        int isLiveStreaming = getIntent().getIntExtra("liveStreaming", 1);
        // the unit of timeout is ms
        options.setInteger(AVOptions.KEY_PREPARE_TIMEOUT, 10 * 1000);
        options.setInteger(AVOptions.KEY_GET_AV_FRAME_TIMEOUT, 10 * 1000);
        // Some optimization with buffering mechanism when be set to 1
        options.setInteger(AVOptions.KEY_LIVE_STREAMING, isLiveStreaming);
        if (isLiveStreaming == 1) {
            options.setInteger(AVOptions.KEY_DELAY_OPTIMIZATION, 1);
        }

        // 1 -> hw codec enable, 0 -> disable [recommended]
        int codec = getIntent().getIntExtra("mediaCodec", 0);
        options.setInteger(AVOptions.KEY_MEDIACODEC, codec);

        // whether start play automatically after prepared, default value is 1
        options.setInteger(AVOptions.KEY_START_ON_PREPARED, 0);

        mVideoView.setAVOptions(options);

        // You can mirror the display
        // mVideoView.setMirror(true);

        // You can also use a custom `MediaController` widget
        mMediaController = new MediaController(this, false, isLiveStreaming == 1);
        mVideoView.setMediaController(mMediaController);

        mVideoView.setOnInfoListener(mOnInfoListener);
//        mVideoView.setOnVideoSizeChangedListener(mOnVideoSizeChangedListener);
        mVideoView.setOnBufferingUpdateListener(mOnBufferingUpdateListener);
        mVideoView.setOnCompletionListener(mOnCompletionListener);
        mVideoView.setOnSeekCompleteListener(mOnSeekCompleteListener);
        mVideoView.setOnErrorListener(mOnErrorListener);
        mVideoView.setVideoPath(mVideoPath);
        mVideoView.setDisplayAspectRatio(PLVideoView.ASPECT_RATIO_PAVED_PARENT);
        mVideoView.setOnPreparedListener(mOnPreparedListener);
        mVideoView.setOnVideoSizeChangedListener(new PLMediaPlayer.OnVideoSizeChangedListener() {
            @Override
            public void onVideoSizeChanged(PLMediaPlayer plMediaPlayer, int width, int height) {
                Logger.i("width:" + width + "---heightL:" + height);
                if (width > height) {
                    //视频是横屏 旋转方向
                   setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
                }

            }
        });

        mVideoView.setVideoPath(mVideoPath);
        mVideoView.start();
    }

    @Override
    protected void onPause() {
        super.onPause();
        mToast = null;
        mVideoView.pause();
    }

    @Override
    protected void onResume() {
        super.onResume();
        mVideoView.start();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mVideoView.stopPlayback();
    }

    public void onClickRotate(View v) {
        mRotation = (mRotation + 90) % 360;
        mVideoView.setDisplayOrientation(mRotation);
    }

    public void onClickSwitchScreen(View v) {
        mDisplayAspectRatio = (mDisplayAspectRatio + 1) % 5;
        mVideoView.setDisplayAspectRatio(mDisplayAspectRatio);
        switch (mVideoView.getDisplayAspectRatio()) {
            case PLVideoTextureView.ASPECT_RATIO_ORIGIN:
                showToastTips("Origin mode");
                break;
            case PLVideoTextureView.ASPECT_RATIO_FIT_PARENT:
                showToastTips("Fit parent !");
                break;
            case PLVideoTextureView.ASPECT_RATIO_PAVED_PARENT:
                showToastTips("Paved parent !");
                break;
            case PLVideoTextureView.ASPECT_RATIO_16_9:
                showToastTips("16 : 9 !");
                break;
            case PLVideoTextureView.ASPECT_RATIO_4_3:
                showToastTips("4 : 3 !");
                break;
            default:
                break;
        }
    }

    private PLMediaPlayer.OnErrorListener mOnErrorListener = new PLMediaPlayer.OnErrorListener() {
        @Override
        public boolean onError(PLMediaPlayer mp, int errorCode) {
            switch (errorCode) {
                case PLMediaPlayer.ERROR_CODE_INVALID_URI:
                    showToastTips("Invalid URL !");
                    break;
                case PLMediaPlayer.ERROR_CODE_404_NOT_FOUND:
                    showToastTips("404 resource not found !");
                    break;
                case PLMediaPlayer.ERROR_CODE_CONNECTION_REFUSED:
                    showToastTips("Connection refused !");
                    break;
                case PLMediaPlayer.ERROR_CODE_CONNECTION_TIMEOUT:
                    showToastTips("Connection timeout !");
                    break;
                case PLMediaPlayer.ERROR_CODE_EMPTY_PLAYLIST:
                    showToastTips("Empty playlist !");
                    break;
                case PLMediaPlayer.ERROR_CODE_STREAM_DISCONNECTED:
                    showToastTips("Stream disconnected !");
                    break;
                case PLMediaPlayer.ERROR_CODE_IO_ERROR:
                    showToastTips("Network IO Error !");
                    break;
                case PLMediaPlayer.ERROR_CODE_UNAUTHORIZED:
                    showToastTips("Unauthorized Error !");
                    break;
                case PLMediaPlayer.ERROR_CODE_PREPARE_TIMEOUT:
                    showToastTips("Prepare timeout !");
                    break;
                case PLMediaPlayer.ERROR_CODE_READ_FRAME_TIMEOUT:
                    showToastTips("Read frame timeout !");
                    break;
                case PLMediaPlayer.MEDIA_ERROR_UNKNOWN:
                default:
                    showToastTips("unknown error !");
                    break;
            }
            // Todo pls handle the error status here, retry or call finish()
            finish();
            // If you want to retry, do like this:
            // mVideoView.setVideoPath(mVideoPath);
            // mVideoView.start();
            // Return true means the error has been handled
            // If return false, then `onCompletion` will be called
            return true;
        }
    };

     private PLMediaPlayer.OnCompletionListener mOnCompletionListener = new PLMediaPlayer.OnCompletionListener() {
        @Override
        public void onCompletion(PLMediaPlayer plMediaPlayer) {
//            finish();
            showToast("视频播放完成");
        }
    };

    private PLMediaPlayer.OnBufferingUpdateListener mOnBufferingUpdateListener = new PLMediaPlayer.OnBufferingUpdateListener() {
        @Override
        public void onBufferingUpdate(PLMediaPlayer plMediaPlayer, int precent) {
        }
    };

    private PLMediaPlayer.OnSeekCompleteListener mOnSeekCompleteListener = new PLMediaPlayer.OnSeekCompleteListener() {
        @Override
        public void onSeekComplete(PLMediaPlayer plMediaPlayer) {
            Logger.d("onSeekComplete !");
        }

    };

    private PLMediaPlayer.OnPreparedListener mOnPreparedListener = new PLMediaPlayer.OnPreparedListener() {
        @Override
        public void onPrepared(PLMediaPlayer plMediaPlayer) {

        }
    };
    private PLMediaPlayer.OnInfoListener mOnInfoListener = new PLMediaPlayer.OnInfoListener() {
        @Override
        public boolean onInfo(PLMediaPlayer plMediaPlayer, int what, int extra) {
            switch (what) {
                case PLMediaPlayer.MEDIA_INFO_BUFFERING_START:
                    Logger.i("正在缓冲----");
                    //开始缓存,暂停播放
                    if (isPlaying()) {
//                        stopPlayer();
                        if (mVideoView != null) {
                            mVideoView.pause();
                        }
                        needResume = true;
                    }
                    rl_loading.setVisibility(View.VISIBLE);
                    break;
                case PLMediaPlayer.MEDIA_INFO_BUFFERING_END:
                case PLMediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START:
                    Logger.i("缓冲完成----");
                    //缓存完成,继续播放
                    if (needResume)
//                        startPlayer();
                        if (mVideoView != null) {
                            mVideoView.start();
                        }
                    rl_loading.setVisibility(View.GONE);
                    break;
                case PLMediaPlayer.MEDIA_INFO_BUFFERING_BYTES_UPDATE:
                    //显示 下载速度
                    Logger.e("download rate:" + extra);
                    //mListener.onDownloadRateChanged(arg2);
                    break;
            }
            Logger.i("onInfo:" + what + "___" + extra);
            return false;
        }
    };
}

这样就完成了普通视频的播放和旋转视频播放

看似简单 其实隐藏着大问题 ,也就是我所说的大坑

现在我是这样判断角度的 当视频的宽度大于高度的 我就认为这是一个横屏的视频 ,也就是说假如这个视频是1330X720(我随便说的尺寸,只为举例)现在宽度大于高度了 那么这就是一个横屏的视频,但是我只要播放手机拍摄的视频就会发现视频被放大了 ,但是其实我录制视频的时候是竖着排的 ,可视播放的时候却给我横着过来了,然后我就去看这个手机拍摄视频的尺寸 现在一般录制视频最低都是1280X720 ,恰好符合我判断的逻辑 ,难道他真是横着的? 然后我就用系统自带的播放器打开 ,居然没有横过来 ,而是竖着播放的 ,可它是怎么知道这个方向呢?于是我在百度搜 ,确实可以获取到本地视频的角度,但是好像低版本好像不兼容,然后根据角度去判断 是否需要旋转,可是我这个是网络视频啊 ,网络视频怎么获取到视频角度啊 ? 我第一反应是 上传视频的时候把宽高角度传到服务器 ,然后获取的时候根据这个角度旋转 ,但是别人播放网络视频的时候也没有传角度过去啊 - - 然后我就在github上面问那个作者 ,结果他说

“onInfo: 10001, 90”, 收到这个消息后,使用 PLVideoTextureView 的 setDisplayOrientation 旋转显示的方向,后面会补充这个回调的接口和文档。

我晕 ,你这不说 谁知道啊 坑死啊 - -

然后我就修改了下代码

 /**
     * 视频的方向
     */
private int mVideoRotation;
    private boolean needResume;
    private PLMediaPlayer.OnInfoListener mOnInfoListener = new PLMediaPlayer.OnInfoListener() {
        @Override
        public boolean onInfo(PLMediaPlayer plMediaPlayer, int what, int extra) {
            switch (what) {
                case PLMediaPlayer.MEDIA_INFO_BUFFERING_START:
                    Logger.i("正在缓冲----");
                    //开始缓存,暂停播放
                    if (isPlaying()) {
//                        stopPlayer();
                        if (mVideoView != null) {
                            mVideoView.pause();
                        }
                        needResume = true;
                    }
                    rl_loading.setVisibility(View.VISIBLE);
                    break;
                case PLMediaPlayer.MEDIA_INFO_BUFFERING_END:
                case PLMediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START:
                    Logger.i("缓冲完成----");
                    //缓存完成,继续播放
                    if (needResume)
//                        startPlayer();
                        if (mVideoView != null) {
                            mVideoView.start();
                        }
                    rl_loading.setVisibility(View.GONE);
                    break;
                case PLMediaPlayer.MEDIA_INFO_BUFFERING_BYTES_UPDATE:
                    //显示 下载速度
                    Logger.e("download rate:" + extra);
                    //mListener.onDownloadRateChanged(arg2);
                    break;
                case 10001:
                    //保存视频角度
                    mVideoRotation=extra;

                    break;
            }
            Logger.i("onInfo:" + what + "___" + extra);
            return false;
        }
    };

然后在onVideoSizeChanged的回调里这样

 mVideoView.setOnVideoSizeChangedListener(new PLMediaPlayer.OnVideoSizeChangedListener() {
            @Override
            public void onVideoSizeChanged(PLMediaPlayer plMediaPlayer, int width, int height) {
                Logger.i("width:" + width + "---heightL:" + height);
                if (width > height&&mVideoRotation==0) {
                    //旋转方向
                    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
                }
                //如果视频角度是90度
                if(mVideoRotation==90)
                {
                   //旋转视频
                    mVideoView.setDisplayOrientation(270);
                }

            }
        });

这样 不管是什么视频 播放终于正常了 - -

转载请注明出处

时间: 2024-11-05 12:21:02

Android 使用PLDroidPlayer播放网络视频 根据视频角度自动旋转的相关文章

Android 使用PLDroidPlayer播放网络视频 依据视频角度自己主动旋转

近期由于项目需求 .须要播放网络视频 .于是乎 研究了一番 ,说说我遇到的那些坑 如今市面上有几个比較主流好用的第三方框架 Vitamio ( 体积比較大,有商业化风险 github:https://github.com/yixia/VitamioBundle/) ijkplayer(B站下开源的框架 体积大 配置环境比較麻烦 github:https://github.com/Bilibili/ijkplayer ) PLDroidPlayer(七牛依据ijkplayer二次开发的 定制简单

Android使用VideoView播放网络视频

Android支持播放网络上的视频.在播放网络上的视频时,牵涉到视频流的传输,往往有两种协议,一种是HTTP,一种是RTSP.这 两种协议最大的不同是,HTTP协议,不支持实时流媒体的播放,而RTSP协议就支持. Android中自带的播放器,以及VideoView等都支持上述两种协议,因此,可以直接播放网络上的视频,唯一不同的就是URI. 代码如下: package demo.camera; import android.app.Activity; import android.net.Uri

网络摄像机IPCamera RTSP直播播放网络/权限/音视频数据/花屏问题检测与分析助手EasyRTSPClient

前言 最近在项目中遇到一个奇怪的问题,同样的SDK调用,访问海康摄像机的RTSP流,发保活OPTIONS命令保活,一个正常,而另一个一发就会被IPC断开,先看现场截图: 图1:发OPTIONS,摄像机立马断流 图2:但在另一个程序中发OPTIONS保活包又不断流 在大部分的摄像机上,都没什么问题,单单在海康的这一款摄像机中出现了这种问题,不仔细对比命令行中的输出,根本无法确定问题点,图2中的OPTIONS报文中携带了Authorization的头字段,将认证信息都带入了进来,而图1中只是简单将用

Android Multimedia框架总结(二)MediaPlayer框架及播放网络视频案例

前言:前面一篇我们介绍MediaPlayer相关方法,有人说,没有实际例子,看得不是很明白,今天在分析MediaPlayer时,顺带一个播放网络视频例子.可以自行试试.今天分析的都是下几篇介绍各个模块进行铺垫. Android中的MediaPlayer框架 MediaPlayer播放视频主要模块 播放主要模块对应组件 MediaPlayer方法对应有效状态及无效状态 案例:Mediaplayer播放网络视频 Android中的MediaPlayer框架 MediaPlayer播放视频主要模块 播

播放网络视频

播放网络视频: PlayInternetVideoActivity.java package com.example.videoplaydemo; import android.app.Activity; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import java.io.File; import android.app.Activity; import android.o

Android使用TextureView播放视频

1.引言 如果你想显示一段在线视频或者任意的数据流比如视频或者OpenGL 场景,你可以用android中的TextureView做到. 1).TextureView的兄弟SurfaceView 应用程序的视频或者opengl内容往往是显示在一个特别的UI控件中:SurfaceView.SurfaceView的工作方式是创建一个置于应用窗口之后的新窗口.这种 方式的效率非常高,因为SurfaceView窗口刷新的时候不需要重绘应用程序的窗口(android普通窗口的视图绘制机制是一层一层的,任何

Android VideoView简单播放视频

给Android VideoView一个文件目录,就可以直接播放智能设备中的视频文件,现在以播放事先用手机拍好并重命名的视频文件test.mp4为例.(1) 需要在布局文件中写一个ViedoView: 1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 and

ios网络学习------9 播放网络视频

IOS提供了叫做MPMoviePlayerController  MPMoviePlayerViewController两个类,可以轻松用来实现视频播放.MPMoviePlayerViewController只能全屏播放视频. #import "MainViewController.h" #import <MediaPlayer/MediaPlayer.h> @interface MainViewController () //视频播放器 @property (strong

Android 打开/播放电脑的音频/视频文件

今天早上一到办公室,照常打开博客园看文章,看到有一片文章是用  http://www.cnblogs.com/wdfrog/p/3738180.html 看到这哥们实现的方法好复杂,又是配置电脑端,又是配置手机端,还又是转码啥的,倒腾时间长不说,而且还很麻烦,这里介绍下我是如何用手机直接播放电脑上的文件的. 之所以播放电脑上的文件,主要原因是视频文件都很大,清晰度高的一部电影都1GB左右了,对于手机来说,虽然能够装得下,但是看完就得删了,没法长时间储存在手机上, 来回往手机上拷视频文件,就这文件