看著騰訊直播的官方指導(dǎo)接入SDK乡小,寫(xiě)了一個(gè)demo翅溺,有點(diǎn)簡(jiǎn)陋并且沒(méi)全部demo應(yīng)用,有空再更新吧诀黍,先做個(gè)筆記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;
//設(shè)置清晰度
private boolean mAutoBitrate;//畫(huà)質(zhì)優(yōu)先
private boolean mAutoResolution;//分辨率優(yōu)先
private int mVideoQuality = TXLiveConstants.VIDEO_QUALITY_HIGH_DEFINITION;//直播視頻質(zhì)量
//美顏
private int mBeautyStyle;//磨皮風(fēng)格: 0:光滑 1:自然 2:朦朧
private int mBeautyLevel;//磨皮等級(jí): 取值為 0-9.取值為 0 時(shí)代表關(guān)閉美顏效果.默認(rèn)值: 0,即關(guān)閉美顏效果.;
private int mWhiteningLevel;//美白等級(jí): 取值為 0-9.取值為 0 時(shí)代表關(guān)閉美白效果.默認(rèn)值: 0,即關(guān)閉美白效果.
private int mRuddyLevel;//紅潤(rùn)等級(jí): 取值為 0-9.取值為 0 時(shí)代表關(guān)閉美白效果.默認(rèn)值: 0,即關(guān)閉美白效果.
//濾鏡
private int filterIndex;//濾鏡圖片
private int filterDegree;//濾鏡程度
private float expouseCompensation;//曝光值
//攝像頭
private boolean mFlashTurnOn=true;//是否開(kāi)啟
private boolean mTouchFocus=false;//是否手動(dòng)(true)自動(dòng)對(duì)焦(false)袋坑,默認(rèn)手動(dòng)
//設(shè)置水印
private boolean isLogo=true;//true設(shè)置,false不設(shè)置
private boolean HWVideoCode =true;//是否開(kāi)啟軟(false眯勾,默認(rèn))硬件編碼(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);//是否自動(dòng)對(duì)焦
mLivePushConfig.setFrontCamera(true);//是否前置攝像頭
initLogo();//設(shè)置水印
initHardWareCode();//軟硬件編碼
setPasueBackImg();//后臺(tái)推流枣宫,設(shè)置主播暫停背景圖
//horizontalPushCustom();//調(diào)整觀眾端表現(xiàn)
//horizontalPushLiver();//調(diào)整主播端表現(xiàn)
initLiveType();//開(kāi)播類型
}
@Override
protected void onResume() {
super.onResume();
//10.4 切前臺(tái)處理
//mCaptureView.onResume(); // mCaptureView 是攝像頭的圖像渲染view
//mLivePusher.resumePusher(); // 通知 SDK 重回前臺(tái)推流
}
@Override
protected void onStop() {
super.onStop();
//10.3 切后臺(tái)處理
//mCaptureView.onPause(); // mCaptureView 是攝像頭的圖像渲染view
//mLivePusher.pausePusher(); // 通知 SDK 進(jìn)入“后臺(tái)推流模式”了
//10.4 后臺(tái)推攝像頭采集數(shù)據(jù)
//如果希望主播在切后臺(tái)或者跳轉(zhuǎn)其他界面還能看到攝像頭采集的畫(huà)面, 按照以下配置即可吃环。
//1镶柱、step 10.1 和 step 10.2 無(wú)需設(shè)置。
//2模叙、在 step 10.3 中歇拆,注釋 mLivePusher.pausePusher() 該方法。
//3范咨、在 step 10.4 中故觅,注釋 mLivePusher.resumePusher() 該方法。
}
@Override
protected void onDestroy() {
super.onDestroy();
stopRtmpPublish();//結(jié)束推流
}
//開(kāi)播類型
private void initLiveType() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("開(kāi)始純音頻直播還是音視頻直播");
builder.setIcon(R.mipmap.ic_launcher);
builder.setMessage("請(qǐng)選擇純音頻直播或是音視頻直播");
builder.setPositiveButton("音視頻直播", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
initStartLive();//開(kāi)始直播
}
});
builder.setNegativeButton("純音頻直播", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
initOnlyVoiceLive();
}
});
builder.show();
}
//純音頻直播
private void initOnlyVoiceLive() {
// 只有在推流啟動(dòng)前設(shè)置啟動(dòng)純音頻推流才會(huì)生效渠啊,推流過(guò)程中設(shè)置不會(huì)生效输吏。
mLivePushConfig.enablePureAudioPush(true); // true 為啟動(dòng)純音頻推流,而默認(rèn)值是 false替蛉;
mLivePusher.setConfig(mLivePushConfig); // 重新設(shè)置 config
String rtmpUrl = Constant.START_LIVE_URL;//開(kāi)始直播的推流地址
mLivePusher.startPusher(rtmpUrl);
}
//開(kāi)始直播
private void initStartLive() {
mLivePusher.setConfig(mLivePushConfig);
String rtmpUrl = Constant.START_LIVE_URL;//開(kāi)始直播的推流地址
mLivePusher.startPusher(rtmpUrl);
mCaptureView = (TXCloudVideoView) findViewById(R.id.video_view);
mLivePusher.startCameraPreview(mCaptureView);
}
//純音頻直播
public void voiceLive(View view) {
Log.e("uuuuuuuu :", "純音頻直播");
initOnlyVoiceLive();
}
//設(shè)置清晰度
public void setDifinition(View view) {
Log.e("uuuuuuuu :", "設(shè)置清晰度");
AlertDialog.Builder localBuilder = new AlertDialog.Builder(this);
final String[] arrayOfString = {"秀場(chǎng)直播", "手游直播", "連麥(主畫(huà)面)", "連麥(小畫(huà)面)", "視頻通話"};
localBuilder
.setTitle("設(shè)置清晰度")
.setIcon(R.mipmap.ic_launcher)
.setItems(arrayOfString, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface paramAnonymousDialogInterface, int paramAnonymousInt) {
switch (paramAnonymousInt) {
case 0://秀場(chǎng)直播
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://連麥(主畫(huà)面)
mAutoBitrate = true;
mAutoResolution = true;
mVideoQuality = TXLiveConstants.VIDEO_QUALITY_LINKMIC_MAIN_PUBLISHER;
mLivePusher.setVideoQuality(mVideoQuality, mAutoBitrate, mAutoResolution);
break;
case 3://連麥(小畫(huà)面)
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;
}
//暫時(shí)不知道什么用
if (mVideoQuality == TXLiveConstants.VIDEO_QUALITY_STANDARD_DEFINITION ||
mVideoQuality == TXLiveConstants.VIDEO_QUALITY_HIGH_DEFINITION ||
mVideoQuality == TXLiveConstants.VIDEO_QUALITY_SUPER_DEFINITION) {
mLivePushConfig.setVideoEncodeGop(5);
}
// 列表對(duì)話框不加這句贯溅,點(diǎn)擊選擇后也后不會(huì)消失
paramAnonymousDialogInterface.dismiss();
}
}).create().show();
}
//設(shè)置美顏
public void beatify(View view) {
Log.e("uuuuuuuu :", "美顏濾鏡");
//美顏濾鏡
mBeautyStyle = 0;//磨皮風(fēng)格: 0:光滑 1:自然 2:朦朧
mBeautyLevel = 0;//磨皮等級(jí): 取值為 0-9.取值為 0 時(shí)代表關(guān)閉美顏效果.默認(rèn)值: 0,即關(guān)閉美顏效果.;
mWhiteningLevel = 0;//美白等級(jí): 取值為 0-9.取值為 0 時(shí)代表關(guān)閉美白效果.默認(rèn)值: 0,即關(guān)閉美白效果.
mRuddyLevel = 0;//紅潤(rùn)等級(jí): 取值為 0-9.取值為 0 時(shí)代表關(guān)閉美白效果.默認(rèn)值: 0,即關(guān)閉美白效果.
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("設(shè)置美顏")
.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();
}
//設(shè)置濾鏡
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("設(shè)置濾鏡")
.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();
}
//設(shè)置曝光值
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("設(shè)置曝光值")
.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();
}
//設(shè)置攝像頭
public void setCameraHead(View view) {
Log.e("uuuuuuuu :", "設(shè)置攝像頭");
AlertDialog.Builder localBuilder = new AlertDialog.Builder(this);
View view_camera = getLayoutInflater().inflate(R.layout.camera, null);
initCameraView(view_camera);
localBuilder
.setTitle("設(shè)置曝光值")
.setIcon(R.mipmap.ic_launcher)
.setView(view_camera)
.setInverseBackgroundForced(false)
.setPositiveButton("確定", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface paramAnonymousDialogInterface, int paramAnonymousInt) {
}
})
.create()
.show();
}
//設(shè)置水印logo
public void setLogo(View view) {
Log.e("uuuuuuuu :", "設(shè)置水印logo");
if (isLogo){
Toast.makeText(this, "設(shè)置失敗拄氯,水印LOGO已經(jīng)設(shè)置了", Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(this, "設(shè)置失敗,需要在mLivePusher.setConfig(mLivePushConfig)之前調(diào)用!它浅,這里已經(jīng)做了译柏,只需修改isLogo的值即可", Toast.LENGTH_SHORT).show();
}
}
//開(kāi)始軟硬件編碼
public void hardwareCode(View view) {
Log.e("uuuuuuuu :", "開(kāi)始軟硬件編碼");
if (HWVideoCode){
Toast.makeText(this, "硬件加速失敗,原因:\n1姐霍、當(dāng)前手機(jī) API 級(jí)別過(guò)低(最低 18)\n" +
"2、需要在mLivePusher.setConfig(mLivePushConfig)之前調(diào)用!镊折,這里已經(jīng)做了,只需修改mTouchFocus的值即可", Toast.LENGTH_SHORT).show();
}
}
//本地錄制
public void nativeRecord(View view) {
Log.e("uuuuuuuu :", "本地錄制");
nativeRecord();
}
//后臺(tái)推流
public void backPush(View view) {
Log.e("uuuuuuuu :", "純音頻直播");
Toast.makeText(this, "查看代碼中的10.1、10.2、10.3、10.4", Toast.LENGTH_SHORT).show();
}
//網(wǎng)絡(luò)提示
public void networkTips(View view) {
Log.e("uuuuuuuu :", "網(wǎng)絡(luò)提示");
mLivePusher.setPushListener(new ITXLivePushListener() {
@Override
public void onPushEvent(int event, Bundle bundle) {
if (event==TXLiveConstants.PUSH_WARNING_NET_BUSY){
Toast.makeText(StartLiveActivity.this, "您當(dāng)前的網(wǎng)絡(luò)狀況不佳,推薦您離 WiFi 近一點(diǎn)勺阐,盡量不要讓 WiFi 穿墻", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onNetStatus(Bundle bundle) {
}
});
}
//橫屏推流
public void horizontalPush(View view) {
Log.e("uuuuuuuu :", "橫屏推流");
}
//設(shè)置背景混淆音
public void setBGM(View view) {
Log.e("uuuuuuuu :", "設(shè)置背景混淆音");
}
//發(fā)送消息
public void sendMessage(View view) {
Log.e("uuuuuuuu :", "發(fā)送消息");
//Android 示例代碼
//mLivePusher.sendMessage(questionInfo.getBytes("UTF-8"));
//mLivePusher.sendMessage(new byte[]);
byte[] bytes = new byte[]{};
mLivePusher.sendMessageEx(bytes);
}
//==================================設(shè)置濾鏡=======================
//初始化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;
}
});
}
//設(shè)置濾鏡
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;
}
//獲取資源圖片轉(zhuǎn)換
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);//自動(dòng)手動(dòng)對(duì)焦
TextView mMirrorTV = view_camera.findViewById(R.id.mMirrorTV);//鏡像效果
cameraTV.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 默認(rèn)是前置攝像頭
mLivePusher.switchCamera();
}
});
lampTV.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mLivePusher.turnOnFlashLight(mFlashTurnOn);
//mFlashTurnOn為true表示打開(kāi),否則表示關(guān)閉
if (!mLivePusher.turnOnFlashLight(mFlashTurnOn)) {
Toast.makeText(getApplicationContext(), "打開(kāi)閃光燈失敗:絕大部分手機(jī)不支持前置閃光燈!", Toast.LENGTH_SHORT).show();
}
mFlashTurnOn=!mFlashTurnOn;
}
});
mFocuseTV.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(), "設(shè)置手自動(dòng)對(duì)焦失敗:需要在mLivePusher.setConfig(mLivePushConfig)之前調(diào)用!矛双,這里已經(jīng)做了渊抽,只需修改mTouchFocus的值即可", Toast.LENGTH_SHORT).show();
}
});
mMirrorTV.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 需在 mLivePusher.setConfig(mLivePushConfig); 之后調(diào)用
mLivePusher.setMirror(true);
}
});
}
//=================================軟硬件編碼========================
private void initHardWareCode() {
if (HWVideoCode){
if (HWVideoCode){
if (mLivePushConfig != null) {
if(Build.VERSION.SDK_INT < 18){
Toast.makeText(getApplicationContext(), "硬件加速失敗,當(dāng)前手機(jī) API 級(jí)別過(guò)低(最低 18)",
Toast.LENGTH_SHORT).show();
HWVideoCode = false;
}
}
}
mLivePushConfig.setHardwareAcceleration(HWVideoCode ? TXLiveConstants.ENCODE_VIDEO_HARDWARE : TXLiveConstants.ENCODE_VIDEO_SOFTWARE);
// 如果你不清楚要何時(shí)開(kāi)啟硬件加速, 建議設(shè)置為 ENCODE_VIDEO_AUTO
// 默認(rèn)是啟用軟件編碼, 但手機(jī) CPU 使用率超過(guò) 80% 或者幀率 <= 10, SDK 內(nèi)部會(huì)自動(dòng)切換為硬件編碼
//ENCODE_VIDEO_HARDWARE 開(kāi)啟硬件加速
//ENCODE_VIDEO_SOFTWARE 禁用硬件加速议忽,默認(rèn)禁用硬件加速
//ENCODE_VIDEO_AUTO 自動(dòng)選擇是否啟用硬件加速
}
}
//=================================設(shè)置水印========================
private void initLogo() {
if (isLogo){
//設(shè)置視頻水印懒闷,后面兩個(gè)參數(shù)分別是水印位置的 X 軸坐標(biāo)和 Y 軸坐標(biāo)
mLivePushConfig.setWatermark(BitmapFactory.decodeResource(getResources(), R.drawable.watermark), 10, 10);
//設(shè)置視頻水印
//參數(shù)分別是水印圖片的 Bitmap、水印位置的 X 軸坐標(biāo)栈幸,水印位置的 Y 軸坐標(biāo)愤估,水印寬度。后面三個(gè)參數(shù)取值范圍是[0, 1]
//后面兩個(gè)參數(shù)分別是水印位置的X軸坐標(biāo)和 Y 軸坐標(biāo)
//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();
}
});
}
//=============================后臺(tái)推流============================
// 設(shè)置主播暫停背景圖
private void setPasueBackImg() {
mLivePushConfig.setPauseImg(300,5);
// 300 為后臺(tái)播放暫停圖片的最長(zhǎng)持續(xù)時(shí)間,單位是秒
// 10 為后臺(tái)播放暫停圖片的幀率,最小值為 5,最大值為 20
Bitmap bitmap = decodeResource(getResources(), R.drawable.pause_publish);
mLivePushConfig.setPauseImg(bitmap);
// 設(shè)置推流暫停時(shí),后臺(tái)播放的暫停圖片, 圖片最大尺寸不能超過(guò) 1920*1920.
//10.2 設(shè)置setPauseFlag
mLivePushConfig.setPauseFlag(PAUSE_FLAG_PAUSE_VIDEO|PAUSE_FLAG_PAUSE_AUDIO);//表示同時(shí)停止視頻和音頻采集速址,并且推送填充用的音視頻流玩焰;
//mLivePushConfig.setPauseFlag(PAUSE_FLAG_PAUSE_VIDEO);//表示停止攝像頭采集視頻畫(huà)面,但保持麥克風(fēng)繼續(xù)采集聲音芍锚,用于主播更衣等場(chǎng)景昔园;
}
//===============================橫屏推流===========================
//調(diào)整觀眾端表現(xiàn)
private void horizontalPushCustom() {
// 豎屏狀態(tài), 手機(jī) Home 鍵在正下方蔓榄。 旋轉(zhuǎn) 0 度
mLivePushConfig.setHomeOrientation(TXLiveConstants.VIDEO_ANGLE_HOME_DOWN);
// 橫屏狀態(tài),手機(jī) Home 鍵在右手方默刚。 旋轉(zhuǎn) 270 度
mLivePushConfig.setHomeOrientation(TXLiveConstants.VIDEO_ANGLE_HOME_RIGHT);
}
//調(diào)整主播端表現(xiàn)
private void horizontalPushLiver() {
// 豎屏狀態(tài)甥郑,本地渲染相對(duì)正方向的角度為0。
mLivePusher.setRenderRotation(0);
// 橫屏狀態(tài)羡棵,本地渲染相對(duì)正方向的角度為90壹若。
mLivePusher.setRenderRotation(90);
}
//Activity自旋轉(zhuǎn)
@Override
public void onConfigurationChanged(Configuration newConfig) {
// 自動(dòng)旋轉(zhuǎn)打開(kāi),Activity隨手機(jī)方向旋轉(zhuǎn)之后皂冰,只需要改變推流方向
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;
}
//通過(guò)設(shè)置config是設(shè)置生效(可以不用重新推流店展,騰訊云是少數(shù)支持直播中熱切換分辨率的云商之一)
mLivePusher.setRenderRotation(0);
mLivePushConfig.setHomeOrientation(pushRotation);
mLivePusher.setConfig(mLivePushConfig);
}
//===============================step 13:背景混音===========================
//SDK 1.6.1 開(kāi)始支持背景混音,支持主播帶耳機(jī)和不帶耳機(jī)兩種場(chǎng)景秃流,您可以通過(guò) TXLivePusher 中的如下這組接口實(shí)現(xiàn)背景混音功能:
//playBGM 通過(guò) path 傳入一首歌曲赂蕴,小直播 Demo中我們是從iOS的本地媒體庫(kù)中獲取音樂(lè)文件
//stopBGM 停止播放背景音樂(lè)
//pauseBGM 暫停播放背景音樂(lè)
//resumeBGM 繼續(xù)播放背景音樂(lè)
//setMicVolume 設(shè)置混音時(shí)麥克風(fēng)的音量大小,推薦在 UI 上實(shí)現(xiàn)相應(yīng)的一個(gè)滑動(dòng)條舶胀,由主播自己設(shè)置
//setBGMVolume 設(shè)置混音時(shí)背景音樂(lè)的音量大小概说,推薦在 UI 上實(shí)現(xiàn)相應(yīng)的一個(gè)滑動(dòng)條,由主播自己設(shè)置
//===============================step 14: 結(jié)束推流===========================
//結(jié)束推流嚣伐,注意做好清理工作
public void stopRtmpPublish() {
mLivePusher.stopCameraPreview(true); //停止攝像頭預(yù)覽
mLivePusher.stopPusher(); //停止推流
mLivePusher.setPushListener(null); //解綁 listener
mLivePusher.stopBGM();
mLivePusher.stopScreenCapture();
mCaptureView.setVisibility(View.GONE);
}
}
注:
①糖赔、直播碼獲取:https://console.cloud.tencent.com/live/livecodemanage
image.png
②轩端、接入文檔地址:
https://cloud.tencent.com/document/product/268/7685