七牛云直播SDK迭代快,但是官方文档跟不上迭代速度,导致快速开始这部分文档的还没更新,很多被废弃的类、方法还在文档中,本文是基于2.3.0版本进行的快速开发,由于是第一次接触直播,存在着许多不足欢迎批评指正。
添加相关权限并注册 Activity
添加 happy-dns 依赖(
compile 'com.qiniu:happy-dns:0.2.8'
)
实现自己的 Application
import android.app.Application;
import com.qiniu.pili.droid.streaming.StreamingEnv;
public class StreamingApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
/**
* init must be called before any other func
*/
StreamingEnv.init(getApplicationContext());
}
}
创建主界面
package com.live.demo.Activity;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import com.live.demo.R;
import com.live.demo.Util.Util;
import java.util.UUID;
public class MainActivity extends Activity implements View.OnClickListener{
private static final String TAG = "MainActivity";
private static final String GENERATE_STREAM_TEXT = "http://api-demo.qnsdk.com/v1/live/stream/";
private TextView tv_start;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
public void initView(){
tv_start = findViewById(R.id.tv_start);
tv_start.setOnClickListener(this);
}
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
final String tlpath = genPublishURL();
// video_Audio
Intent intent = new Intent(MainActivity.this, SWCameraStreamingActivity.class);
// 传推流地址
intent.putExtra("stream_publish_url", tlpath);
startActivity(intent);
}
}).start();
}
/**
* @author:
* @create at: 2018/11/13 13:01
* @Description: 获取推流地址
*/
private String genPublishURL() {
String publishUrl = Util.syncRequest(GENERATE_STREAM_TEXT + UUID.randomUUID());
return publishUrl;
}
}
主界面布局文件
创建推流界面
package com.live.demo.Activity;
import android.app.Activity;
import android.hardware.Camera;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import com.live.demo.R;
import com.live.demo.ui.CameraPreviewFrameView;
import com.qiniu.android.dns.DnsManager;
import com.qiniu.android.dns.IResolver;
import com.qiniu.android.dns.NetworkInfo;
import com.qiniu.android.dns.http.DnspodFree;
import com.qiniu.android.dns.local.AndroidDnsServer;
import com.qiniu.android.dns.local.Resolver;
import com.qiniu.pili.droid.streaming.CameraStreamingSetting;
import com.qiniu.pili.droid.streaming.MediaStreamingManager;
import com.qiniu.pili.droid.streaming.StreamStatusCallback;
import com.qiniu.pili.droid.streaming.StreamingProfile;
import com.qiniu.pili.droid.streaming.StreamingState;
import com.qiniu.pili.droid.streaming.StreamingStateChangedListener;
import java.io.IOException;
import java.net.InetAddress;
import java.net.URISyntaxException;
import static com.qiniu.pili.droid.streaming.AVCodecType.SW_VIDEO_WITH_SW_AUDIO_CODEC;
public class SWCameraStreamingActivity extends Activity implements StreamingStateChangedListener,
StreamStatusCallback {
private static final String TAG = "LiveAcivity";
private MediaStreamingManager mMediaStreamingManager;
private StreamingProfile mProfile;
private CameraPreviewFrameView cameraPreviewFrameView;
private TextView mStatView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_swcamera_streaming);
initView();
}
public void initView(){
cameraPreviewFrameView = findViewById(R.id.cameraPreview_surfaceView);
mStatView = findViewById(R.id.stream_status);
String publishURLFromServer = getIntent().getStringExtra("stream_publish_url");
Log.d(TAG, "initView: ===>"+publishURLFromServer);
mProfile = new StreamingProfile();
try {
mProfile.setVideoQuality(StreamingProfile.VIDEO_QUALITY_HIGH1)
.setAudioQuality(StreamingProfile.AUDIO_QUALITY_MEDIUM2)
.setQuicEnable(false)//RMPT or QUIC
.setVideoQuality(StreamingProfile.VIDEO_QUALITY_MEDIUM1)
.setEncodingOrientation(StreamingProfile.ENCODING_ORIENTATION.PORT )//横竖屏
.setEncodingSizeLevel(StreamingProfile.VIDEO_ENCODING_HEIGHT_480)
.setBitrateAdjustMode(StreamingProfile.BitrateAdjustMode.Auto)//自适应码率
.setEncoderRCMode(StreamingProfile.EncoderRCModes.QUALITY_PRIORITY)
.setDnsManager(getMyDnsManager())
.setStreamStatusConfig(new StreamingProfile.StreamStatusConfig(3))
.setSendingBufferProfile(new StreamingProfile.SendingBufferProfile(0.2f, 0.8f, 3.0f, 20 * 1000))
.setPublishUrl(publishURLFromServer);//设置推流地址
} catch (URISyntaxException e) {
e.printStackTrace();
}
CameraStreamingSetting setting = new CameraStreamingSetting();
setting.setCameraId(Camera.CameraInfo.CAMERA_FACING_FRONT) // 摄像头切换
.setContinuousFocusModeEnabled(true)
.setFaceBeautySetting(new CameraStreamingSetting.FaceBeautySetting(1.0f, 1.0f, 1.0f))//美颜 磨皮,美白,红润 取值范围为[0.0f, 1.0f]
.setVideoFilter(CameraStreamingSetting.VIDEO_FILTER_TYPE.VIDEO_FILTER_BEAUTY)
.setCameraPrvSizeLevel(CameraStreamingSetting.PREVIEW_SIZE_LEVEL.MEDIUM)
.setCameraPrvSizeRatio(CameraStreamingSetting.PREVIEW_SIZE_RATIO.RATIO_16_9);
mMediaStreamingManager = new MediaStreamingManager(this, cameraPreviewFrameView, SW_VIDEO_WITH_SW_AUDIO_CODEC);
mMediaStreamingManager.prepare(setting, mProfile);
mMediaStreamingManager.setStreamingStateListener(this);
}
@Override
public void onStateChanged(StreamingState streamingState, Object o) {
switch (streamingState) {
case PREPARING:
Log.d(TAG, "onStateChanged: ===>"+"准备");
break;
case READY:
startStreaming();
break;
case CONNECTING:
Log.d(TAG, "onStateChanged: ===>"+"连接");
break;
case STREAMING:
Log.d(TAG, "onStateChanged: ===>"+"已发送");
break;
case SHUTDOWN:
Log.d(TAG, "onStateChanged: ===>"+"推流结束");
break;
case IOERROR:
Log.d(TAG, "onStateChanged: ===>"+"IO异常");
break;
case SENDING_BUFFER_EMPTY:
break;
case SENDING_BUFFER_FULL:
break;
case AUDIO_RECORDING_FAIL:
break;
case OPEN_CAMERA_FAIL:
break;
case DISCONNECTED:
Log.d(TAG, "onStateChanged: ===>"+"断开连接");
break;
}
}
/**
* @author:
* @create at: 2018/11/14 15:32
* @Description: 开始推流
*/
protected void startStreaming() {
new Thread(new Runnable() {
@Override
public void run() {
mMediaStreamingManager.startStreaming();
Log.d(TAG, "run: ===>"+"推流");
}
}).start();
}
@Override
protected void onResume() {
super.onResume();
mMediaStreamingManager.resume();
}
@Override
protected void onPause() {
super.onPause();
mMediaStreamingManager.pause();
}
/**
* @author:
* @create at: 2018/11/14 10:57
* @Description: 防止 Dns 被劫持
*/
private static DnsManager getMyDnsManager() {
IResolver r0 = null;
IResolver r1 = new DnspodFree();
IResolver r2 = AndroidDnsServer.defaultResolver();
try {
r0 = new Resolver(InetAddress.getByName("119.29.29.29"));
} catch (IOException ex) {
ex.printStackTrace();
}
return new DnsManager(NetworkInfo.normal, new IResolver[]{r0, r1, r2});
}
@Override
public void notifyStreamStatusChanged(final StreamingProfile.StreamStatus streamStatus) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Log.d(TAG, "run:totalAVBitrate ===>"+streamStatus.totalAVBitrate);
Log.d(TAG, "run:audioFps ===>"+streamStatus.audioFps);
Log.d(TAG, "run:videoFps ===>"+streamStatus.videoFps);
mStatView.setText("bitrate:" + streamStatus.totalAVBitrate / 1024 + " kbps"
+ "\naudio:" + streamStatus.audioFps + " fps"
+ "\nvideo:" + streamStatus.videoFps + " fps");
}
});
}
}
推流界面布局
启动 APP 之后,当点击 开始推流,就可以开始推流了。
1.下载播放端的Demo运行输入推流地址 :https://github.com/pili-engineering/PLDroidPlayer
2.或者扫码下载播放app输入推流地址
推流地址获取方法
手机运行app,as打印推流地址