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

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

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

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

首先把需要的jar包和jni文件拷到你的项目中
这个里面有很多控件,你们可以根据自己的需求来用指定的控件,我用的是PLVideoTextureView

1
2
3
4
5
6
<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找到它

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
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 旋转显示的方向,后面会补充这个回调的接口和文档。

我晕 ,你这不说 谁知道啊 坑死啊 - -
然后我就修改了下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/**
* 视频的方向
*/
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的回调里这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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);
}
}
});

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

转载请注明出处 http://blog.csdn.net/yewei02538/article/details/51882933

Demo下载地址: http://download.csdn.net/detail/yewei02538/9602032