Vitamio 视频直播播放端
- MediaPlayer:https://www.vitamio.org/docs/API/2013/0508/10.html
- VideoView:https://www.vitamio.org/docs/API/2013/0508/9.html
- 依赖module—vitamio (注意raw文件夹)
权限配置
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- 添加<activity />
<activity
android:name="io.vov.vitamio.activity.InitActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation"
android:launchMode="singleTop"
android:theme="@android:style/Theme.NoTitleBar"
android:windowSoftInputMode="stateAlwaysHidden" />
- 在操作的activity中加入
<category android:name="android.intent.category.DEFAULT" />
- 在MyApplication里面初始化
Vitamio.initialize(this);
- 两种方式 MainActivity.java
- ①使用MediaPlayer(用于播放rtmp)
public class MainActivity extends AppCompatActivity { String url = "rtmp://live.hkstv.hk.lxdns.com/live/hks"; SurfaceView surfaceView; MediaPlayer mediaPlayer; //vitamio下的类 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); surfaceView = (SurfaceView) findViewById(sv); surfaceView.getHolder().addCallback(callback); surfaceView.getHolder().setFormat(PixelFormat.RGBA_8888); //画质(必加) surfaceView.setOnClickListener(onClickListener); } SurfaceHolder.Callback callback = new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder holder) { try { mediaPlayer = new MediaPlayer(getBaseContext()); mediaPlayer.setDataSource(url); mediaPlayer.setDisplay(holder); mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { mediaPlayer.start(); } }); mediaPlayer.prepareAsync(); mediaPlayer.setBufferSize(1024 * 1024 * 2); //设置缓存大小 } catch (IOException e) { e.printStackTrace(); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { if (mediaPlayer != null) { if (mediaPlayer.isPlaying()) { mediaPlayer.stop(); } mediaPlayer.release(); mediaPlayer = null; } } }; //点击画面暂停或者播放 View.OnClickListener onClickListener = new View.OnClickListener() { @Override public void onClick(View v) { if (mediaPlayer != null) { if (mediaPlayer.isPlaying()) { mediaPlayer.pause(); Toast.makeText(MainActivity.this, "已暂停", Toast.LENGTH_SHORT).show(); } else { mediaPlayer.start(); Toast.makeText(MainActivity.this, "继续播放", Toast.LENGTH_SHORT).show(); } } } }; }
- ②使用VideoView(用于播放flv)
public class FlvActivity extends AppCompatActivity { VideoView videoView; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_flv); videoView = (VideoView) findViewById(R.id.vv); MediaController controller = new MediaController(this); videoView.setMediaController(controller); videoView.setVideoPath("http://pull99.a8.com/live/1482127743567166.flv"); videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { mp.start(); } }); } }
百度云直播(视频录制端)
https://cloud.baidu.com/doc/LSS/Android-Capture-SDK.html#.E5.BC.80.E5.A7.8B.E6.8E.A8.E6.B5.81
/**
* Session:开会,会议;(法庭的)开庭;会期,学期;(进行某活动连续的)一段时间
*/
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
LiveSession liveSession;
SurfaceView surfaceView;
Button btnFlash;
Button btnBegin;
Button btnSwitchCamera;
boolean isPrepare;
boolean isError = false; //是否出错
boolean isPlaying = false; //是否播放
boolean isOpenFlash = false;//是否开启闪光灯
int cameraState = 0; //前置或后置摄像头
public static final int[] STATE = {LiveConfig.CAMERA_FACING_BACK, LiveConfig.CAMERA_FACING_FRONT}; //0后置 1前置
String url = "rtmp://zhibo1.whunf.com.cn/xykj/push";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initLiveSession();
surfaceView = (SurfaceView) findViewById(R.id.sv);
btnBegin = (Button) findViewById(R.id.btn_begin);
btnFlash = (Button) findViewById(R.id.btn_flash);
btnSwitchCamera = (Button) findViewById(R.id.btn_switchCamera);
btnBegin.setOnClickListener(this);
btnFlash.setOnClickListener(this);
btnSwitchCamera.setOnClickListener(this);
}
private void initLiveSession() { //初始化 LiveSession
LiveConfig liveConfig = new LiveConfig.Builder()
.setCameraId(LiveConfig.CAMERA_FACING_FRONT) // 选择摄像头为前置摄像头
.setCameraOrientation(LiveConfig.CAMERA_FACING_BACK) // 设置摄像头为竖向
.setVideoWidth(1280) // 设置推流视频宽度, 需传入长的一边
.setVideoHeight(720) // 设置推流视频高度,需传入短的一边
.setVideoFPS(30) // 设置视频帧率
.setInitVideoBitrate(1200) // 设置视频码率,单位为bit per seconds
.setAudioBitrate(64 * 1000) // 设置音频码率,单位为bit per seconds
.setAudioSampleRate(LiveConfig.AUDIO_SAMPLE_RATE_44100) // 设置音频采样率
.setGopLengthInSeconds(2) // 设置I帧间隔,单位为秒
.setQosEnabled(true) // 开启码率自适应,默认为true,即默认开启
.setMinVideoBitrate(200 * 1000) // 码率自适应,最低码率
.setMaxVideoBitrate(1024 * 1000) // 码率自适应,最高码率
.setQosSensitivity(5) // 码率自适应,调整的灵敏度,单位为秒,可接受[5, 10]之间的整数值
.build();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { //版本大于或等于4.3
liveSession = new LiveSessionHW(this, liveConfig);
} else {
liveSession = new LiveSessionSW(this, liveConfig);
}
liveSession.setStateListener(sessionStateListener); //liveSession状态监听
liveSession.bindPreviewDisplay(surfaceView.getHolder()); //初始化成功后,必须为LiveSession对象设置预览View,否则无法启动相机
liveSession.prepareSessionAsync(); //在开始推流前,需要启动音视频采集设备(即相机和 MIC)
}
SessionStateListener sessionStateListener = new SessionStateListener() {
@Override
public void onSessionPrepared(int i) { //已准备好
isPrepare = true;
}
@Override
public void onSessionStarted(int i) { //开始
}
@Override
public void onSessionStopped(int i) { //停止
}
@Override
public void onSessionError(int i) { //出错
isError = true;
switch (i) {
case ERROR_CODE_OF_OPEN_MIC_FAILED:
Toast.makeText(MainActivity.this, "MIC设备无法打开", Toast.LENGTH_SHORT).show();
break;
case ERROR_CODE_OF_OPEN_CAMERA_FAILED:
Toast.makeText(MainActivity.this, "相机设备无法打开", Toast.LENGTH_SHORT).show();
break;
case ERROR_CODE_OF_PREPARE_SESSION_FAILED:
Toast.makeText(MainActivity.this, "接口调用失败,原因只能是 MIC 或相机打开失败", Toast.LENGTH_SHORT).show();
break;
case ERROR_CODE_OF_CONNECT_TO_SERVER_FAILED:
Toast.makeText(MainActivity.this, "原因通常为连接不上推流服务器", Toast.LENGTH_SHORT).show();
break;
case ERROR_CODE_OF_DISCONNECT_FROM_SERVER_FAILED:
Toast.makeText(MainActivity.this, "网路异常", Toast.LENGTH_SHORT).show();
break;
}
}
};
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_begin: //播放/暂停
if (isPrepare && !isError) { //若已准备好且没有出错
if (isPlaying) { //如果正在播放
liveSession.startRtmpSession(url); //开始url
btnBegin.setText("停止");
} else {
liveSession.stopRtmpSession(); //如果没有播放,则停止url
btnBegin.setText("开始");
}
} else if (isError) {
Toast.makeText(MainActivity.this, "推流出错", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainActivity.this, "正在准备推流", Toast.LENGTH_SHORT).show();
}
break;
case R.id.btn_flash:
// if (STATE[cameraState % 2] == 1) {
// btnFlash.setEnabled(false);
// } else {
// btnFlash.setEnabled(true);
// }
isOpenFlash = !isOpenFlash;
liveSession.toggleFlash(isOpenFlash); //开启闪光灯
break;
case R.id.btn_switchCamera:
if (liveSession.canSwitchCamera()) {
cameraState++;
liveSession.switchCamera(STATE[cameraState % 2]); //0则后置,1则前置
// if (isOpenFlash && (cameraState % 2 == 1)) { //当开了闪光灯,且前置的时候
// isOpenFlash = false;
// }
}
break;
}
}
@Override
public void onBackPressed() { //退出时候,关闭session
super.onBackPressed();
liveSession.stopRtmpSession();
}
}