看着腾讯直播的官方指导接入SDK,写了一个demo,有点简陋并且没全部demo应用,有空再更新吧,先做个笔记Mark先
demo地址
import android.content.DialogInterface;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.util.TypedValue;
import android.view.Surface;
import android.view.View;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import com.tencent.rtmp.ITXLivePushListener;
import com.tencent.rtmp.TXLiveConstants;
import com.tencent.rtmp.TXLivePushConfig;
import com.tencent.rtmp.TXLivePusher;
import com.tencent.rtmp.ui.TXCloudVideoView;
import com.tencent.ugc.TXRecordCommon;
import static com.tencent.rtmp.TXLiveConstants.PAUSE_FLAG_PAUSE_AUDIO;
import static com.tencent.rtmp.TXLiveConstants.PAUSE_FLAG_PAUSE_VIDEO;
public class StartLiveActivity extends AppCompatActivity{
private TXLivePushConfig mLivePushConfig;
private TXCloudVideoView mCaptureView;
private TXLivePusher mLivePusher;
//设置清晰度
private boolean mAutoBitrate;//画质优先
private boolean mAutoResolution;//分辨率优先
private int mVideoQuality = TXLiveConstants.VIDEO_QUALITY_HIGH_DEFINITION;//直播视频质量
//美颜
private int mBeautyStyle;//磨皮风格: 0:光滑 1:自然 2:朦胧
private int mBeautyLevel;//磨皮等级: 取值为 0-9.取值为 0 时代表关闭美颜效果.默认值: 0,即关闭美颜效果.;
private int mWhiteningLevel;//美白等级: 取值为 0-9.取值为 0 时代表关闭美白效果.默认值: 0,即关闭美白效果.
private int mRuddyLevel;//红润等级: 取值为 0-9.取值为 0 时代表关闭美白效果.默认值: 0,即关闭美白效果.
//滤镜
private int filterIndex;//滤镜图片
private int filterDegree;//滤镜程度
private float expouseCompensation;//曝光值
//摄像头
private boolean mFlashTurnOn=true;//是否开启
private boolean mTouchFocus=false;//是否手动(true)自动对焦(false),默认手动
//设置水印
private boolean isLogo=true;//true设置,false不设置
private boolean HWVideoCode =true;//是否开启软(false,默认)硬件编码(true)
//本地录制
private TextView recordTv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_live);
recordTv=findViewById(R.id.recordTv);
mLivePusher = new TXLivePusher(this);
mLivePushConfig = new TXLivePushConfig();
mLivePushConfig.setTouchFocus(mTouchFocus);//是否自动对焦
mLivePushConfig.setFrontCamera(true);//是否前置摄像头
initLogo();//设置水印
initHardWareCode();//软硬件编码
setPasueBackImg();//后台推流,设置主播暂停背景图
//horizontalPushCustom();//调整观众端表现
//horizontalPushLiver();//调整主播端表现
initLiveType();//开播类型
}
@Override
protected void onResume() {
super.onResume();
//10.4 切前台处理
//mCaptureView.onResume(); // mCaptureView 是摄像头的图像渲染view
//mLivePusher.resumePusher(); // 通知 SDK 重回前台推流
}
@Override
protected void onStop() {
super.onStop();
//10.3 切后台处理
//mCaptureView.onPause(); // mCaptureView 是摄像头的图像渲染view
//mLivePusher.pausePusher(); // 通知 SDK 进入“后台推流模式”了
//10.4 后台推摄像头采集数据
//如果希望主播在切后台或者跳转其他界面还能看到摄像头采集的画面, 按照以下配置即可。
//1、step 10.1 和 step 10.2 无需设置。
//2、在 step 10.3 中,注释 mLivePusher.pausePusher() 该方法。
//3、在 step 10.4 中,注释 mLivePusher.resumePusher() 该方法。
}
@Override
protected void onDestroy() {
super.onDestroy();
stopRtmpPublish();//结束推流
}
//开播类型
private void initLiveType() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("开始纯音频直播还是音视频直播");
builder.setIcon(R.mipmap.ic_launcher);
builder.setMessage("请选择纯音频直播或是音视频直播");
builder.setPositiveButton("音视频直播", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
initStartLive();//开始直播
}
});
builder.setNegativeButton("纯音频直播", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
initOnlyVoiceLive();
}
});
builder.show();
}
//纯音频直播
private void initOnlyVoiceLive() {
// 只有在推流启动前设置启动纯音频推流才会生效,推流过程中设置不会生效。
mLivePushConfig.enablePureAudioPush(true); // true 为启动纯音频推流,而默认值是 false;
mLivePusher.setConfig(mLivePushConfig); // 重新设置 config
String rtmpUrl = Constant.START_LIVE_URL;//开始直播的推流地址
mLivePusher.startPusher(rtmpUrl);
}
//开始直播
private void initStartLive() {
mLivePusher.setConfig(mLivePushConfig);
String rtmpUrl = Constant.START_LIVE_URL;//开始直播的推流地址
mLivePusher.startPusher(rtmpUrl);
mCaptureView = (TXCloudVideoView) findViewById(R.id.video_view);
mLivePusher.startCameraPreview(mCaptureView);
}
//纯音频直播
public void voiceLive(View view) {
Log.e("uuuuuuuu :", "纯音频直播");
initOnlyVoiceLive();
}
//设置清晰度
public void setDifinition(View view) {
Log.e("uuuuuuuu :", "设置清晰度");
AlertDialog.Builder localBuilder = new AlertDialog.Builder(this);
final String[] arrayOfString = {"秀场直播", "手游直播", "连麦(主画面)", "连麦(小画面)", "视频通话"};
localBuilder
.setTitle("设置清晰度")
.setIcon(R.mipmap.ic_launcher)
.setItems(arrayOfString, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface paramAnonymousDialogInterface, int paramAnonymousInt) {
switch (paramAnonymousInt) {
case 0://秀场直播
mAutoBitrate = false;
mAutoResolution = false;
//VIDEO_QUALITY_SUPER_DEFINITION
mVideoQuality = TXLiveConstants.VIDEO_QUALITY_HIGH_DEFINITION;
mLivePusher.setVideoQuality(mVideoQuality, mAutoBitrate, mAutoResolution);
break;
case 1://手游直播
mAutoBitrate = true;
mAutoResolution = true;
mVideoQuality = TXLiveConstants.VIDEO_QUALITY_SUPER_DEFINITION;
mLivePusher.setVideoQuality(mVideoQuality, mAutoBitrate, mAutoResolution);
break;
case 2://连麦(主画面)
mAutoBitrate = true;
mAutoResolution = true;
mVideoQuality = TXLiveConstants.VIDEO_QUALITY_LINKMIC_MAIN_PUBLISHER;
mLivePusher.setVideoQuality(mVideoQuality, mAutoBitrate, mAutoResolution);
break;
case 3://连麦(小画面)
mAutoBitrate = false;
mAutoResolution = false;
mVideoQuality = TXLiveConstants.VIDEO_QUALITY_LINKMIC_SUB_PUBLISHER;
mLivePusher.setVideoQuality(mVideoQuality, mAutoBitrate, mAutoResolution);
break;
case 4://视频通话
mAutoBitrate = true;
mAutoResolution = true;
mVideoQuality = TXLiveConstants.VIDEO_QUALITY_REALTIEM_VIDEOCHAT;
mLivePusher.setVideoQuality(mVideoQuality, mAutoBitrate, mAutoResolution);
break;
}
//暂时不知道什么用
if (mVideoQuality == TXLiveConstants.VIDEO_QUALITY_STANDARD_DEFINITION ||
mVideoQuality == TXLiveConstants.VIDEO_QUALITY_HIGH_DEFINITION ||
mVideoQuality == TXLiveConstants.VIDEO_QUALITY_SUPER_DEFINITION) {
mLivePushConfig.setVideoEncodeGop(5);
}
// 列表对话框不加这句,点击选择后也后不会消失
paramAnonymousDialogInterface.dismiss();
}
}).create().show();
}
//设置美颜
public void beatify(View view) {
Log.e("uuuuuuuu :", "美颜滤镜");
//美颜滤镜
mBeautyStyle = 0;//磨皮风格: 0:光滑 1:自然 2:朦胧
mBeautyLevel = 0;//磨皮等级: 取值为 0-9.取值为 0 时代表关闭美颜效果.默认值: 0,即关闭美颜效果.;
mWhiteningLevel = 0;//美白等级: 取值为 0-9.取值为 0 时代表关闭美白效果.默认值: 0,即关闭美白效果.
mRuddyLevel = 0;//红润等级: 取值为 0-9.取值为 0 时代表关闭美白效果.默认值: 0,即关闭美白效果.
AlertDialog.Builder localBuilder = new AlertDialog.Builder(this);
View view_beaty = getLayoutInflater().inflate(R.layout.beaty, null);
SeekBar mStyleSeekBar = view_beaty.findViewById(R.id.mStyleSeekBar);
final TextView mStyleTV = view_beaty.findViewById(R.id.mStyleTV);
mStyleSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
mStyleTV.setText(progress + "");
mBeautyStyle = progress;
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
SeekBar mLevelSeekBar = view_beaty.findViewById(R.id.mLevelSeekBar);
final TextView mLevelTV = view_beaty.findViewById(R.id.mLevelTV);
mLevelSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
mLevelTV.setText(progress + "");
mBeautyLevel = progress;
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
SeekBar whiteningLevelSeekbar = view_beaty.findViewById(R.id.whiteningLevelSeekbar);
final TextView whiteningLevelTV = view_beaty.findViewById(R.id.whiteningLevelTV);
whiteningLevelSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
whiteningLevelTV.setText(progress + "");
mWhiteningLevel = progress;
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
SeekBar ruddyLevelSeekbar = view_beaty.findViewById(R.id.ruddyLevelSeekbar);
final TextView ruddyLevelTV = view_beaty.findViewById(R.id.ruddyLevelTV);
ruddyLevelSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
ruddyLevelTV.setText(progress + "");
mRuddyLevel = progress;
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
localBuilder
.setTitle("设置美颜")
.setIcon(R.mipmap.ic_launcher)
.setView(view_beaty)
.setPositiveButton("确定美颜", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface paramAnonymousDialogInterface, int paramAnonymousInt) {
mLivePusher.setBeautyFilter(mBeautyStyle, mBeautyLevel, mWhiteningLevel, mRuddyLevel);
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface paramAnonymousDialogInterface, int paramAnonymousInt) {
}
})
.create()
.show();
}
//设置滤镜
public void filter(View view) {
AlertDialog.Builder localBuilder = new AlertDialog.Builder(this);
View view_filter = getLayoutInflater().inflate(R.layout.filter, null);
initFilterType(view_filter);
localBuilder
.setTitle("设置滤镜")
.setIcon(R.mipmap.ic_launcher)
.setView(view_filter)
.setPositiveButton("确定滤镜程度", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface paramAnonymousDialogInterface, int paramAnonymousInt) {
mLivePusher.setSpecialRatio(filterDegree / 10.f);//滤镜程度
}
})
.setNegativeButton("确定滤镜图片", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface paramAnonymousDialogInterface, int paramAnonymousInt) {
setFilter(filterIndex);//滤镜图片
}
})
.create()
.show();
}
//设置曝光值
public void exposure(View view) {
AlertDialog.Builder localBuilder = new AlertDialog.Builder(this);
View view_expouse = getLayoutInflater().inflate(R.layout.expouse, null);
initExpouseView(view_expouse);
localBuilder
.setTitle("设置曝光值")
.setIcon(R.mipmap.ic_launcher)
.setView(view_expouse)
.setPositiveButton("确定曝光值", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface paramAnonymousDialogInterface, int paramAnonymousInt) {
mLivePusher.setExposureCompensation(expouseCompensation);
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface paramAnonymousDialogInterface, int paramAnonymousInt) {
}
})
.create()
.show();
}
//设置摄像头
public void setCameraHead(View view) {
Log.e("uuuuuuuu :", "设置摄像头");
AlertDialog.Builder localBuilder = new AlertDialog.Builder(this);
View view_camera = getLayoutInflater().inflate(R.layout.camera, null);
initCameraView(view_camera);
localBuilder
.setTitle("设置曝光值")
.setIcon(R.mipmap.ic_launcher)
.setView(view_camera)
.setInverseBackgroundForced(false)
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface paramAnonymousDialogInterface, int paramAnonymousInt) {
}
})
.create()
.show();
}
//设置水印logo
public void setLogo(View view) {
Log.e("uuuuuuuu :", "设置水印logo");
if (isLogo){
Toast.makeText(this, "设置失败,水印LOGO已经设置了", Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(this, "设置失败,需要在mLivePusher.setConfig(mLivePushConfig)之前调用!,这里已经做了,只需修改isLogo的值即可", Toast.LENGTH_SHORT).show();
}
}
//开始软硬件编码
public void hardwareCode(View view) {
Log.e("uuuuuuuu :", "开始软硬件编码");
if (HWVideoCode){
Toast.makeText(this, "硬件加速失败,原因:\n1、当前手机 API 级别过低(最低 18)\n" +
"2、需要在mLivePusher.setConfig(mLivePushConfig)之前调用!,这里已经做了,只需修改mTouchFocus的值即可", Toast.LENGTH_SHORT).show();
}
}
//本地录制
public void nativeRecord(View view) {
Log.e("uuuuuuuu :", "本地录制");
nativeRecord();
}
//后台推流
public void backPush(View view) {
Log.e("uuuuuuuu :", "纯音频直播");
Toast.makeText(this, "查看代码中的10.1、10.2、10.3、10.4", Toast.LENGTH_SHORT).show();
}
//网络提示
public void networkTips(View view) {
Log.e("uuuuuuuu :", "网络提示");
mLivePusher.setPushListener(new ITXLivePushListener() {
@Override
public void onPushEvent(int event, Bundle bundle) {
if (event==TXLiveConstants.PUSH_WARNING_NET_BUSY){
Toast.makeText(StartLiveActivity.this, "您当前的网络状况不佳,推荐您离 WiFi 近一点,尽量不要让 WiFi 穿墙", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onNetStatus(Bundle bundle) {
}
});
}
//横屏推流
public void horizontalPush(View view) {
Log.e("uuuuuuuu :", "横屏推流");
}
//设置背景混淆音
public void setBGM(View view) {
Log.e("uuuuuuuu :", "设置背景混淆音");
}
//发送消息
public void sendMessage(View view) {
Log.e("uuuuuuuu :", "发送消息");
//Android 示例代码
//mLivePusher.sendMessage(questionInfo.getBytes("UTF-8"));
//mLivePusher.sendMessage(new byte[]);
byte[] bytes = new byte[]{};
mLivePusher.sendMessageEx(bytes);
}
//==================================设置滤镜=======================
//初始化Dialog的空件
private void initFilterType(final View view_filter) {
filterDegree = 0;
final TextView mFilterTV = view_filter.findViewById(R.id.mFilterTV);
SeekBar mFilterSeekBar = view_filter.findViewById(R.id.mFilterSeekBar);
mFilterSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
filterDegree = progress;
mFilterTV.setText("" + filterDegree);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
view_filter.findViewById(R.id.bailan).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
filterIndex = 5;
}
});
view_filter.findViewById(R.id.biaozhun).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
filterIndex = 1;
}
});
view_filter.findViewById(R.id.chaotuo).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
filterIndex = 7;
}
});
view_filter.findViewById(R.id.chunzhen).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
filterIndex = 4;
}
});
view_filter.findViewById(R.id.fennen).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
filterIndex = 13;
}
});
view_filter.findViewById(R.id.huaijiu).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
filterIndex = 14;
}
});
view_filter.findViewById(R.id.landiao).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
filterIndex = 15;
}
});
view_filter.findViewById(R.id.langman).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
filterIndex = 10;
}
});
view_filter.findViewById(R.id.qingliang).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
filterIndex = 16;
}
});
view_filter.findViewById(R.id.qinxi).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
filterIndex = 11;
}
});
view_filter.findViewById(R.id.rixi).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
filterIndex = 17;
}
});
view_filter.findViewById(R.id.weimei).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
filterIndex = 12;
}
});
view_filter.findViewById(R.id.white).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
filterIndex = 9;
}
});
view_filter.findViewById(R.id.xiangfen).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
filterIndex = 8;
}
});
view_filter.findViewById(R.id.yinghong).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
filterIndex = 2;
}
});
view_filter.findViewById(R.id.yuanqi).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
filterIndex = 6;
}
});
view_filter.findViewById(R.id.yunshang).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
filterIndex = 3;
}
});
}
//设置滤镜
private void setFilter(int index) {
Bitmap bmp = getFilterBitmapByIndex(index);
if (mLivePusher != null) {
mLivePusher.setFilter(bmp);
}
}
//获取图片资源
public Bitmap getFilterBitmapByIndex(int index) {
Bitmap bmp = null;
switch (index) {
case 1:
bmp = decodeResource(getResources(), R.drawable.filter_biaozhun);
break;
case 2:
bmp = decodeResource(getResources(), R.drawable.filter_yinghong);
break;
case 3:
bmp = decodeResource(getResources(), R.drawable.filter_yunshang);
break;
case 4:
bmp = decodeResource(getResources(), R.drawable.filter_chunzhen);
break;
case 5:
bmp = decodeResource(getResources(), R.drawable.filter_bailan);
break;
case 6:
bmp = decodeResource(getResources(), R.drawable.filter_yuanqi);
break;
case 7:
bmp = decodeResource(getResources(), R.drawable.filter_chaotuo);
break;
case 8:
bmp = decodeResource(getResources(), R.drawable.filter_xiangfen);
break;
case 9:
bmp = decodeResource(getResources(), R.drawable.filter_white);
break;
case 10:
bmp = decodeResource(getResources(), R.drawable.filter_langman);
break;
case 11:
bmp = decodeResource(getResources(), R.drawable.filter_qingxin);
break;
case 12:
bmp = decodeResource(getResources(), R.drawable.filter_weimei);
break;
case 13:
bmp = decodeResource(getResources(), R.drawable.filter_fennen);
break;
case 14:
bmp = decodeResource(getResources(), R.drawable.filter_huaijiu);
break;
case 15:
bmp = decodeResource(getResources(), R.drawable.filter_landiao);
break;
case 16:
bmp = decodeResource(getResources(), R.drawable.filter_qingliang);
break;
case 17:
bmp = decodeResource(getResources(), R.drawable.filter_rixi);
break;
default:
bmp = null;
break;
}
return bmp;
}
//获取资源图片转换
private Bitmap decodeResource(Resources resources, int id) {
TypedValue value = new TypedValue();
resources.openRawResource(id, value);
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inTargetDensity = value.density;
return BitmapFactory.decodeResource(resources, id, opts);
}
//======================================曝光值======================
//初始化曝光值控件
private void initExpouseView(View view_expouse) {
SeekBar mExpuseSeekBar = view_expouse.findViewById(R.id.mExpuseSeekBar);
final TextView mExpuseTV = view_expouse.findViewById(R.id.mExpuseTV);
mExpuseSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
float p=(progress-10)/10.0f;
expouseCompensation=p;
mExpuseTV.setText("曝光值为:"+p);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
}
//===================================控制摄像头======================
private void initCameraView(View view_camera) {
TextView cameraTV = view_camera.findViewById(R.id.cameraTV);//前后摄像头
TextView lampTV = view_camera.findViewById(R.id.lampTV);//闪光灯
TextView mFocuseTV = view_camera.findViewById(R.id.mFocuseTV);//自动手动对焦
TextView mMirrorTV = view_camera.findViewById(R.id.mMirrorTV);//镜像效果
cameraTV.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 默认是前置摄像头
mLivePusher.switchCamera();
}
});
lampTV.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mLivePusher.turnOnFlashLight(mFlashTurnOn);
//mFlashTurnOn为true表示打开,否则表示关闭
if (!mLivePusher.turnOnFlashLight(mFlashTurnOn)) {
Toast.makeText(getApplicationContext(), "打开闪光灯失败:绝大部分手机不支持前置闪光灯!", Toast.LENGTH_SHORT).show();
}
mFlashTurnOn=!mFlashTurnOn;
}
});
mFocuseTV.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(), "设置手自动对焦失败:需要在mLivePusher.setConfig(mLivePushConfig)之前调用!,这里已经做了,只需修改mTouchFocus的值即可", Toast.LENGTH_SHORT).show();
}
});
mMirrorTV.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 需在 mLivePusher.setConfig(mLivePushConfig); 之后调用
mLivePusher.setMirror(true);
}
});
}
//=================================软硬件编码========================
private void initHardWareCode() {
if (HWVideoCode){
if (HWVideoCode){
if (mLivePushConfig != null) {
if(Build.VERSION.SDK_INT < 18){
Toast.makeText(getApplicationContext(), "硬件加速失败,当前手机 API 级别过低(最低 18)",
Toast.LENGTH_SHORT).show();
HWVideoCode = false;
}
}
}
mLivePushConfig.setHardwareAcceleration(HWVideoCode ? TXLiveConstants.ENCODE_VIDEO_HARDWARE : TXLiveConstants.ENCODE_VIDEO_SOFTWARE);
// 如果你不清楚要何时开启硬件加速, 建议设置为 ENCODE_VIDEO_AUTO
// 默认是启用软件编码, 但手机 CPU 使用率超过 80% 或者帧率 <= 10, SDK 内部会自动切换为硬件编码
//ENCODE_VIDEO_HARDWARE 开启硬件加速
//ENCODE_VIDEO_SOFTWARE 禁用硬件加速,默认禁用硬件加速
//ENCODE_VIDEO_AUTO 自动选择是否启用硬件加速
}
}
//=================================设置水印========================
private void initLogo() {
if (isLogo){
//设置视频水印,后面两个参数分别是水印位置的 X 轴坐标和 Y 轴坐标
mLivePushConfig.setWatermark(BitmapFactory.decodeResource(getResources(), R.drawable.watermark), 10, 10);
//设置视频水印
//参数分别是水印图片的 Bitmap、水印位置的 X 轴坐标,水印位置的 Y 轴坐标,水印宽度。后面三个参数取值范围是[0, 1]
//后面两个参数分别是水印位置的X轴坐标和 Y 轴坐标
//mLivePushConfig.setWatermark(mBitmap, 0.02f, 0.05f, 0.2f);
}
}
//=================================本地录制========================
private void nativeRecord(){
String externalFilesDir = getExternalFilesDir(Environment.DIRECTORY_MOVIES).toString()+".mp4";
mLivePusher.startRecord(externalFilesDir);
mLivePusher.setVideoRecordListener(new TXRecordCommon.ITXVideoRecordListener() {
@Override
public void onRecordEvent(int event, Bundle bundle) {
Log.e("本地录制==","完成"+event);
}
@Override
public void onRecordProgress(long milliSecond) {
recordTv.setText(String.format("%02d:%02d",milliSecond/1000/60, milliSecond/1000%60));
}
@Override
public void onRecordComplete(TXRecordCommon.TXRecordResult txRecordResult) {
Log.e("本地录制==","完成"+txRecordResult.videoPath+" "+txRecordResult.coverPath);
}
});
recordTv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mLivePusher.stopRecord();
}
});
}
//=============================后台推流============================
// 设置主播暂停背景图
private void setPasueBackImg() {
mLivePushConfig.setPauseImg(300,5);
// 300 为后台播放暂停图片的最长持续时间,单位是秒
// 10 为后台播放暂停图片的帧率,最小值为 5,最大值为 20
Bitmap bitmap = decodeResource(getResources(), R.drawable.pause_publish);
mLivePushConfig.setPauseImg(bitmap);
// 设置推流暂停时,后台播放的暂停图片, 图片最大尺寸不能超过 1920*1920.
//10.2 设置setPauseFlag
mLivePushConfig.setPauseFlag(PAUSE_FLAG_PAUSE_VIDEO|PAUSE_FLAG_PAUSE_AUDIO);//表示同时停止视频和音频采集,并且推送填充用的音视频流;
//mLivePushConfig.setPauseFlag(PAUSE_FLAG_PAUSE_VIDEO);//表示停止摄像头采集视频画面,但保持麦克风继续采集声音,用于主播更衣等场景;
}
//===============================横屏推流===========================
//调整观众端表现
private void horizontalPushCustom() {
// 竖屏状态, 手机 Home 键在正下方。 旋转 0 度
mLivePushConfig.setHomeOrientation(TXLiveConstants.VIDEO_ANGLE_HOME_DOWN);
// 横屏状态,手机 Home 键在右手方。 旋转 270 度
mLivePushConfig.setHomeOrientation(TXLiveConstants.VIDEO_ANGLE_HOME_RIGHT);
}
//调整主播端表现
private void horizontalPushLiver() {
// 竖屏状态,本地渲染相对正方向的角度为0。
mLivePusher.setRenderRotation(0);
// 横屏状态,本地渲染相对正方向的角度为90。
mLivePusher.setRenderRotation(90);
}
//Activity自旋转
@Override
public void onConfigurationChanged(Configuration newConfig) {
// 自动旋转打开,Activity随手机方向旋转之后,只需要改变推流方向
int mobileRotation = getWindowManager().getDefaultDisplay().getRotation();
int pushRotation = TXLiveConstants.VIDEO_ANGLE_HOME_DOWN;
switch (mobileRotation) {
case Surface.ROTATION_0:
pushRotation = TXLiveConstants.VIDEO_ANGLE_HOME_DOWN;
break;
case Surface.ROTATION_90:
pushRotation = TXLiveConstants.VIDEO_ANGLE_HOME_RIGHT;
break;
case Surface.ROTATION_270:
pushRotation = TXLiveConstants.VIDEO_ANGLE_HOME_LEFT;
break;
default:
break;
}
//通过设置config是设置生效(可以不用重新推流,腾讯云是少数支持直播中热切换分辨率的云商之一)
mLivePusher.setRenderRotation(0);
mLivePushConfig.setHomeOrientation(pushRotation);
mLivePusher.setConfig(mLivePushConfig);
}
//===============================step 13:背景混音===========================
//SDK 1.6.1 开始支持背景混音,支持主播带耳机和不带耳机两种场景,您可以通过 TXLivePusher 中的如下这组接口实现背景混音功能:
//playBGM 通过 path 传入一首歌曲,小直播 Demo中我们是从iOS的本地媒体库中获取音乐文件
//stopBGM 停止播放背景音乐
//pauseBGM 暂停播放背景音乐
//resumeBGM 继续播放背景音乐
//setMicVolume 设置混音时麦克风的音量大小,推荐在 UI 上实现相应的一个滑动条,由主播自己设置
//setBGMVolume 设置混音时背景音乐的音量大小,推荐在 UI 上实现相应的一个滑动条,由主播自己设置
//===============================step 14: 结束推流===========================
//结束推流,注意做好清理工作
public void stopRtmpPublish() {
mLivePusher.stopCameraPreview(true); //停止摄像头预览
mLivePusher.stopPusher(); //停止推流
mLivePusher.setPushListener(null); //解绑 listener
mLivePusher.stopBGM();
mLivePusher.stopScreenCapture();
mCaptureView.setVisibility(View.GONE);
}
}
注:
①、直播码获取:https://console.cloud.tencent.com/live/livecodemanage
②、接入文档地址:
https://cloud.tencent.com/document/product/268/7685