到年底了,闲暇之余学了点热门的东西,直播现在是很火的,所以我也玩玩直播,弄了个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) { } 目前就是简单的集成了推流功能,剩下的功能陆续上传,敬请期待。