关于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"/>
        <Button
            android: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"/>
        <Button
            android: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"/>
        <Button
            android: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"/>
        <Button
            android: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"/>
        <Button
            android: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"/>
        <Button
            android: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"/>
        <Button
            android: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"/>
        <Button
            android: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);
    //开启摄像头将获取到的画面放在videoView    mLivePusher.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) {

}
目前就是简单的集成了推流功能,剩下的功能陆续上传,敬请期待。

一: 使用javacv来实现,最终也是用过ffmpeg来进行编码和推流,javacv实现到可以直接接收摄像头的帧数据 需要自己实现的代码只是打开摄像头,写一个SurfaceView进行预览,然后实现PreviewCallback将摄像头每一帧的数据交给javacv即可 javacv地址:https://github.com/bytedeco/javacv demo地址:https://github.com/beautifulSoup/RtmpRecoder/tree/master 二: 使用Android自带的编码工具,可实现硬编码,这里有一个国内大神开源的封装很完善的的库yasea,第一种方法需要实现的Camera采集部分也一起封装好了,进行一些简单配置就可以实现编码推流,并且yasea目前已经直接支持摄像头的热切换,和各种滤镜效果 yasea地址(内置demo):https://github.com/begeekmyfriend/yasea 服务器 流媒体服务器我用的是srs,项目地址:https://github.com/ossrs/srs 关于srs的编译、配置、部署、在官方wiki中已经写的很详细了,并且srs同样是国内开发人员开源的项目,有全中文的文档,看起来很方便 这里有最基本的简单编译部署过程 Android直播实现(二)srs流媒体服务器部署 播放器 android端的播放使用vitamio,还是国内的开源播放器,是不是感觉国内的前辈们越来越屌了^~^! vitamio支持几乎所有常见的的视频格式和流媒体协议 vitamio地址(内置demo):https://github.com/yixia/VitamioBundle 这里使用的是yaesa库,先介绍一下直播实现的流程:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值