1. 程式人生 > >關於Android直播那些小事-推流1

關於Android直播那些小事-推流1

到年底了,閒暇之餘學了點熱門的東西,直播現在是很火的,所以我也玩玩直播,弄了個demo,準備玩一玩,這是第一篇,先說一下推流實現直播功能,陸續會有很多互動demo的功能,今天只是簡單的實現一下推流可以從攝像頭採集圖片到View上,這裡推流用的是Rtmp騰訊雲的工具。

1、今天只實現第一個功能直播推流效果是這樣的,按鈕下的功能會陸續實現

2、開發前的準備工作如圖


具體要用到的資源可以去騰訊雲下載的哦。。。。

3、開始裝逼

首先要在清單檔案中新增所需要的許可權:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission 
android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.CALL_PHONE"/> <uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_LOGS" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:name="android.hardware.Camera"
/> <uses-feature android:name="android.hardware.camera.autofocus" />

然後什麼佈局之類的就是輕車熟路了就不在這裡說了,

直接看關於fragment的佈局:

<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/root"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
>

    <com.tencent.rtmp.ui.TXCloudVideoView
android:id="@+id/video_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:visibility="gone"/>


    <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="10dp"
android:layout_gravity="bottom">
        <TextView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_weight="1"/>
        <Buttonandroid:id="@+id/btnPlay"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/play_start"/>
        <TextView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_weight="1"/>
        <Buttonandroid:id="@+id/btnCameraChange"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/camera_change"/>
        <TextView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_weight="1"/>
        <Buttonandroid:id="@+id/btnTouchFoucs"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/automatic"/>
        <TextView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_weight="1"/>
        <Buttonandroid:id="@+id/btnHWEncode"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/quick"/>
        <TextView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_weight="1"/>
        <Buttonandroid:id="@+id/btnFaceBeauty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/face_beauty"/>

        <TextView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_weight="1"/>
        <Buttonandroid:id="@+id/btnLog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/log_show"/>
        <TextView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_weight="1"/>
        <Buttonandroid:id="@+id/btnBitrate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/fix_bitrate"/>
        <TextView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_weight="1"/>
        <Buttonandroid:id="@+id/btnFlash"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/flash_on"/>
        <TextView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_weight="1"/>
    </LinearLayout>

    <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:id="@+id/layoutBitrate"
android:layout_marginBottom="0dp"
android:background="#FFFFFF"
android:visibility="gone"
android:clickable="true"
android:layout_gravity="bottom">
        <TextView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="位元速率自適應"
android:textSize="16sp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
android:layout_weight="1"/>
        <RadioGroup
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginBottom="25dp"
android:visibility="visible"
android:id="@+id/resolutionRadioGroup"
android:layout_gravity="center_horizontal"
android:orientation="horizontal">
            <RadioButton
style="@style/RadiobuttonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="720P"
android:tag="4"
android:id="@+id/radio_btn_fix_720p"
android:textColor="@color/resolution_radio_color"
android:background="@drawable/resolution_radio" />
            <RadioButton
style="@style/RadiobuttonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="540P"
android:tag="3"
android:id="@+id/radio_btn_fix_540p"
android:textColor="@color/resolution_radio_color"
android:background="@drawable/resolution_radio" />
            <RadioButton
style="@style/RadiobuttonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="360P"
android:tag="2"
android:id="@+id/radio_btn_fix_360p"
android:textColor="@color/resolution_radio_color"
android:background="@drawable/resolution_radio" />

            <RadioButton
style="@style/RadiobuttonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="360+"
android:tag="1"
android:id="@+id/radio_btn_auto"
android:textColor="@color/resolution_radio_color"
android:background="@drawable/resolution_radio" />
        </RadioGroup>
    </LinearLayout>

    <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="15dp"
android:minHeight="105dp"
android:orientation="vertical"
android:id="@+id/layoutFaceBeauty"
android:layout_marginBottom="0dp"
android:background="#FFFFFF"
android:visibility="gone"
android:clickable="true"
android:layout_gravity="bottom">

        <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:layout_marginBottom="10dp"
android:orientation="horizontal">

            <TextView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="美顏效果"
android:textSize="16sp" />
            <SeekBar
android:id="@+id/beauty_seekbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="15dp"
android:paddingRight="18dp"
android:maxHeight="4.0dip"
android:minHeight="4.0dip"
android:visibility="visible"
android:progressDrawable="@drawable/seekbar_progress_drawable"
android:thumb="@drawable/circle"
android:max="9"
android:indeterminate="false" />
        </LinearLayout>


        <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">

            <TextView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="美白效果"
android:textSize="16sp" />
            <SeekBar
android:id="@+id/whitening_seekbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="15dp"
android:paddingRight="18dp"
android:maxHeight="4.0dip"
android:minHeight="4.0dip"
android:visibility="visible"
android:progressDrawable="@drawable/seekbar_progress_drawable"
android:thumb="@drawable/circle"
android:max="3"
android:indeterminate="false" />
        </LinearLayout>

    </LinearLayout>
</FrameLayout>
然後就應該看我們的LivePushFragment
/**
 * 初始化
* @param view
*/
private void init(View view) {
    initData();
    initView(view);
    initListener();
}
/**
 * 初始化推流配置
*/
private void initData() {
    //1初始化推流配置
mLivePusher = new TXLivePusher(getActivity());
    mTxLivePushConfig = new TXLivePushConfig();
}

/**
 * 初始化控制元件
* @param view
*/
private void initView(View view) {
    //初始化播放view
mCaptureView = (TXCloudVideoView) view.findViewById(R.id.video_view);
    //初始化播放按鈕
mBtnPlay = (Button) view.findViewById(R.id.btnPlay);
    //初始化攝像頭
mBtnChangeCam = (Button) view.findViewById(R.id.btnCameraChange);
}
/**
 * 初始化監聽方法
*/
private void initListener() {
    //點選開始直播的按鈕
mBtnPlay.setOnClickListener(new View.OnClickListener() {
    @Override
public void onClick(View view) {
        if(mVideoPublish){
            stopPulishRtmp();
            mVideoPublish = false;
        }else{
            fixOrAdjustBitrate();
            mVideoPublish=startPublishRtmp();
        }
    }
});
}
//是否開始推流
private boolean mVideoPublish;
/**
 * 停止推流
*/
private void stopPulishRtmp() {
    //關閉攝像頭
mLivePusher.stopCameraPreview(true);
    //取消監聽
mLivePusher.setPushListener(null);
    //停止推送
mLivePusher.stopPusher();
    mCaptureView.setVisibility(View.GONE);
    mBtnPlay.setBackgroundResource(R.drawable.play_start);
}
/**
 * 設定位元速率:預設為自適應位元速率
*/
private void fixOrAdjustBitrate() {
    if(mLivePusher!=null){
       //設定顯示畫面
mTxLivePushConfig.setVideoResolution(TXLiveConstants.VIDEO_RESOLUTION_TYPE_360_640);
        //設定自適應位元速率
mTxLivePushConfig.setAutoAdjustBitrate(true);
        //設定最大位元速率
mTxLivePushConfig.setMaxVideoBitrate(1000);
        //設定最小位元速率
mTxLivePushConfig.setMinVideoBitrate(500);
        //設定常規位元速率
mTxLivePushConfig.setVideoBitrate(700);
        mLivePusher.setConfig(mTxLivePushConfig);

    }
}
/**
 * 開始推流
* @return
*/
private boolean startPublishRtmp() {
    //獲取推流地址:該地址為測試地址
String rtmpUrl = "rtmp://2000.livepush.myqcloud.com/live/2000_4eb4da7079af11e69776e435c87f075e?bizid=2000";
    if (TextUtils.isEmpty(rtmpUrl) || (!rtmpUrl.trim().toLowerCase().startsWith("rtmp://"))) {
        mVideoPublish = false;
        Toast.makeText(getActivity().getApplicationContext(), "推流地址不合法,目前支援rtmp推流!", Toast.LENGTH_SHORT).show();
        return false;
    }
    //設定顯示videoView
mCaptureView.setVisibility(View.VISIBLE);
    //帶測試,可去掉
int customModeType = 0;
    mTxLivePushConfig.setCustomModeType(customModeType);
    mLivePusher.setConfig(mTxLivePushConfig);
    //設定推流監聽
mLivePusher.setPushListener(this);
    //開啟攝像頭將獲取到的畫面放在videoViewmLivePusher.startCameraPreview(mCaptureView);
    //開始推流
mLivePusher.startPusher(rtmpUrl);
    mBtnPlay.setBackgroundResource(R.drawable.play_pause);
    return true;
}
最後看
PushListener
@Override
public void onPushEvent(int event, Bundle bundle) {
//斷網的情況下的判斷
 if(event==TXLiveConstants.PUSH_ERR_NET_DISCONNECT){
        stopPulishRtmp();
        mVideoPublish=false;
    }

}

@Override
public void onNetStatus(Bundle bundle) {

}
目前就是簡單的集成了推流功能,剩下的功能陸續上傳,敬請期待。