这个项目是手机的摄像头作为硬件,采集视频流信息,把视频流推流到rtmp服务器,然后在本地使用vlc打开推流的视频,如果可以收到视频流,则证明推流成功

直播
采集端:
音视频采集,视频处理(美颜,水印) 音视频编码压缩  把音视频封装FLV  TS
常用框架
AVFoundation:数据
GPUImage:美颜
FFmpeg: 音频压缩
X264:   视频压缩
libremp:  推流

服务器流程:
数据分发CDN  鉴黄  截屏:展示主播画面  录制视频 实时转码

流媒体服务器
常用服务器  SNS BMS  nginx

播放端流程
从FLV TS 分离中音视频数据  音视频解码  播放  聊天互动

播放端 观众
ijkplayer :播放 
FFmpeg: 视频解码
VideoToolbox:视频硬解码
AudioToolbox:音频硬解码

github上有现成的开源实现,
推流、美颜、水印、弹幕、点赞动画、
滤镜、播放都有。技术其实不是很难,
而且现在很多云厂商都提供SDK,
七牛云、金山云、乐视云、腾讯云、百度云、
斗鱼直播伴侣推流端,功能几乎都是一样的,没啥亮点,
不同的是整个直播平台服务差异和接入的简易性。
后端现在 RTMP/HTTP-FLV 清一色,App挂个源站直接接入云厂商或CDN就OK。

1.先看效果图:

手机多种滤镜的运行效果:

因为代码实在太多,所以贴了一个项目地址,大概30M

项目地址:https://github.com/wrs13634194612/Rtmp-Video-Android.git

贴一下主要的核心代码:

1.清单文件申请权限:打开摄像头,麦克风采集声音信息,

<uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.CAMERA" /><uses-permission android:name="android.permission.RECORD_AUDIO" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.FLASHLIGHT" /><uses-feature android:name="android.hardware.camera.autofocus" /><uses-feature android:glEsVersion="0x00020000" android:required="true" />

2.主界面

package net.ossrs.yasea.demo;import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.hardware.Camera;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;import com.example.administrator.testz.R;
import com.github.faucamp.simplertmp.RtmpHandler;
import com.seu.magicfilter.utils.MagicFilterType;import net.ossrs.yasea.SrsCameraView;
import net.ossrs.yasea.SrsEncodeHandler;
import net.ossrs.yasea.SrsPublisher;
import net.ossrs.yasea.SrsRecordHandler;import java.io.IOException;
import java.net.SocketException;
import java.util.Random;public class MainActivity extends AppCompatActivity implements RtmpHandler.RtmpListener,SrsRecordHandler.SrsRecordListener, SrsEncodeHandler.SrsEncodeListener {private static final String TAG = "Yasea";private Button btnPublish;private Button btnSwitchCamera;private Button btnRecord;private Button btnSwitchEncoder;private Button btnPause;private SrsCameraView  mCameraView;private SharedPreferences sp;private String rtmpUrl = "rtmp://ossrs.net/" + getRandomAlphaString(3) + '/' + getRandomAlphaDigitString(5);private String recPath = Environment.getExternalStorageDirectory().getPath() + "/test.mp4";private SrsPublisher mPublisher;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);setContentView(R.layout.activity_main);// response screen rotation eventsetRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);// restore data.sp = getSharedPreferences("Yasea", MODE_PRIVATE);rtmpUrl = sp.getString("rtmpUrl", rtmpUrl);// initialize url.final EditText efu = (EditText) findViewById(R.id.url);efu.setText(rtmpUrl);btnPublish = (Button) findViewById(R.id.publish);btnSwitchCamera = (Button) findViewById(R.id.swCam);btnRecord = (Button) findViewById(R.id.record);btnSwitchEncoder = (Button) findViewById(R.id.swEnc);btnPause = (Button) findViewById(R.id.pause);btnPause.setEnabled(false);mCameraView = (SrsCameraView) findViewById(R.id.glsurfaceview_camera);mPublisher = new SrsPublisher(mCameraView);mPublisher.setEncodeHandler(new SrsEncodeHandler(this));mPublisher.setRtmpHandler(new RtmpHandler(this));mPublisher.setRecordHandler(new SrsRecordHandler(this));mPublisher.setPreviewResolution(640, 360);mPublisher.setOutputResolution(360, 640);mPublisher.setVideoHDMode();mPublisher.startCamera();mCameraView.setCameraCallbacksHandler(new SrsCameraView.CameraCallbacksHandler(){@Overridepublic void onCameraParameters(Camera.Parameters params) {//params.setFocusMode("custom-focus");                //params.setWhiteBalance("custom-balance");//etc...}});      btnPublish.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (btnPublish.getText().toString().contentEquals("publish")) {rtmpUrl = efu.getText().toString();SharedPreferences.Editor editor = sp.edit();editor.putString("rtmpUrl", rtmpUrl);editor.apply();//  mPublisher.startPublish(rtmpUrl);mPublisher.startPublish("please input your rtmp address");mPublisher.startCamera();if (btnSwitchEncoder.getText().toString().contentEquals("soft encoder")) {Toast.makeText(getApplicationContext(), "Use hard encoder", Toast.LENGTH_SHORT).show();} else {Toast.makeText(getApplicationContext(), "Use soft encoder", Toast.LENGTH_SHORT).show();}btnPublish.setText("stop");btnSwitchEncoder.setEnabled(false);btnPause.setEnabled(true);} else if (btnPublish.getText().toString().contentEquals("stop")) {mPublisher.stopPublish();mPublisher.stopRecord();btnPublish.setText("publish");btnRecord.setText("record");btnSwitchEncoder.setEnabled(true);btnPause.setEnabled(false);}}});btnPause.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {if(btnPause.getText().toString().equals("Pause")){mPublisher.pausePublish();btnPause.setText("resume");}else{mPublisher.resumePublish();btnPause.setText("Pause");}}});btnSwitchCamera.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {mPublisher.switchCameraFace((mPublisher.getCameraId() + 1) % Camera.getNumberOfCameras());}});btnRecord.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (btnRecord.getText().toString().contentEquals("record")) {if (mPublisher.startRecord(recPath)) {btnRecord.setText("pause");}} else if (btnRecord.getText().toString().contentEquals("pause")) {mPublisher.pauseRecord();btnRecord.setText("resume");} else if (btnRecord.getText().toString().contentEquals("resume")) {mPublisher.resumeRecord();btnRecord.setText("pause");}}});btnSwitchEncoder.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (btnSwitchEncoder.getText().toString().contentEquals("soft encoder")) {mPublisher.switchToSoftEncoder();btnSwitchEncoder.setText("hard encoder");} else if (btnSwitchEncoder.getText().toString().contentEquals("hard encoder")) {mPublisher.switchToHardEncoder();btnSwitchEncoder.setText("soft encoder");}}});}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.menu_main, menu);return true;}@Overridepublic boolean onOptionsItemSelected(MenuItem item) {// Handle action bar item clicks here. The action bar will// automatically handle clicks on the Home/Up button, so long// as you specify a parent activity in AndroidManifest.xml.int id = item.getItemId();//noinspection SimplifiableIfStatementif (id == R.id.action_settings) {return true;} else {switch (id) {case R.id.cool_filter:mPublisher.switchCameraFilter(MagicFilterType.COOL);break;case R.id.beauty_filter:mPublisher.switchCameraFilter(MagicFilterType.BEAUTY);break;case R.id.early_bird_filter:mPublisher.switchCameraFilter(MagicFilterType.EARLYBIRD);break;case R.id.evergreen_filter:mPublisher.switchCameraFilter(MagicFilterType.EVERGREEN);break;case R.id.n1977_filter:mPublisher.switchCameraFilter(MagicFilterType.N1977);break;case R.id.nostalgia_filter:mPublisher.switchCameraFilter(MagicFilterType.NOSTALGIA);break;case R.id.romance_filter:mPublisher.switchCameraFilter(MagicFilterType.ROMANCE);break;case R.id.sunrise_filter:mPublisher.switchCameraFilter(MagicFilterType.SUNRISE);break;case R.id.sunset_filter:mPublisher.switchCameraFilter(MagicFilterType.SUNSET);break;case R.id.tender_filter:mPublisher.switchCameraFilter(MagicFilterType.TENDER);break;case R.id.toast_filter:mPublisher.switchCameraFilter(MagicFilterType.TOASTER2);break;case R.id.valencia_filter:mPublisher.switchCameraFilter(MagicFilterType.VALENCIA);break;case R.id.walden_filter:mPublisher.switchCameraFilter(MagicFilterType.WALDEN);break;case R.id.warm_filter:mPublisher.switchCameraFilter(MagicFilterType.WARM);break;case R.id.original_filter:default:mPublisher.switchCameraFilter(MagicFilterType.NONE);break;}}setTitle(item.getTitle());return super.onOptionsItemSelected(item);}@Overrideprotected void onStart() {super.onStart();if(mPublisher.getCamera() == null){//if the camera was busy and available againmPublisher.startCamera();}}                           @Overrideprotected void onResume() {super.onResume();final Button btn = (Button) findViewById(R.id.publish);btn.setEnabled(true);mPublisher.resumeRecord();}@Overrideprotected void onPause() {super.onPause();mPublisher.pauseRecord();}@Overrideprotected void onDestroy() {super.onDestroy();mPublisher.stopPublish();mPublisher.stopRecord();}@Overridepublic void onConfigurationChanged(Configuration newConfig) {super.onConfigurationChanged(newConfig);mPublisher.stopEncode();mPublisher.stopRecord();btnRecord.setText("record");mPublisher.setScreenOrientation(newConfig.orientation);if (btnPublish.getText().toString().contentEquals("stop")) {mPublisher.startEncode();}mPublisher.startCamera();}private static String getRandomAlphaString(int length) {String base = "abcdefghijklmnopqrstuvwxyz";Random random = new Random();StringBuilder sb = new StringBuilder();for (int i = 0; i < length; i++) {int number = random.nextInt(base.length());sb.append(base.charAt(number));}return sb.toString();}private static String getRandomAlphaDigitString(int length) {String base = "abcdefghijklmnopqrstuvwxyz0123456789";Random random = new Random();StringBuilder sb = new StringBuilder();for (int i = 0; i < length; i++) {int number = random.nextInt(base.length());sb.append(base.charAt(number));}return sb.toString();}private void handleException(Exception e) {try {Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_SHORT).show();mPublisher.stopPublish();mPublisher.stopRecord();btnPublish.setText("publish");btnRecord.setText("record");btnSwitchEncoder.setEnabled(true);} catch (Exception e1) {//}}// Implementation of SrsRtmpListener.@Overridepublic void onRtmpConnecting(String msg) {Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();}@Overridepublic void onRtmpConnected(String msg) {Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();}@Overridepublic void onRtmpVideoStreaming() {}@Overridepublic void onRtmpAudioStreaming() {}@Overridepublic void onRtmpStopped() {Toast.makeText(getApplicationContext(), "Stopped", Toast.LENGTH_SHORT).show();}@Overridepublic void onRtmpDisconnected() {Toast.makeText(getApplicationContext(), "Disconnected", Toast.LENGTH_SHORT).show();}@Overridepublic void onRtmpVideoFpsChanged(double fps) {Log.i(TAG, String.format("Output Fps: %f", fps));}@Overridepublic void onRtmpVideoBitrateChanged(double bitrate) {int rate = (int) bitrate;if (rate / 1000 > 0) {Log.i(TAG, String.format("Video bitrate: %f kbps", bitrate / 1000));} else {Log.i(TAG, String.format("Video bitrate: %d bps", rate));}}@Overridepublic void onRtmpAudioBitrateChanged(double bitrate) {int rate = (int) bitrate;if (rate / 1000 > 0) {Log.i(TAG, String.format("Audio bitrate: %f kbps", bitrate / 1000));} else {Log.i(TAG, String.format("Audio bitrate: %d bps", rate));}}@Overridepublic void onRtmpSocketException(SocketException e) {handleException(e);}@Overridepublic void onRtmpIOException(IOException e) {handleException(e);}@Overridepublic void onRtmpIllegalArgumentException(IllegalArgumentException e) {handleException(e);}@Overridepublic void onRtmpIllegalStateException(IllegalStateException e) {handleException(e);}// Implementation of SrsRecordHandler.@Overridepublic void onRecordPause() {Toast.makeText(getApplicationContext(), "Record paused", Toast.LENGTH_SHORT).show();}@Overridepublic void onRecordResume() {Toast.makeText(getApplicationContext(), "Record resumed", Toast.LENGTH_SHORT).show();}@Overridepublic void onRecordStarted(String msg) {Toast.makeText(getApplicationContext(), "Recording file: " + msg, Toast.LENGTH_SHORT).show();}@Overridepublic void onRecordFinished(String msg) {Toast.makeText(getApplicationContext(), "MP4 file saved: " + msg, Toast.LENGTH_SHORT).show();}@Overridepublic void onRecordIOException(IOException e) {handleException(e);}@Overridepublic void onRecordIllegalArgumentException(IllegalArgumentException e) {handleException(e);}// Implementation of SrsEncodeHandler.@Overridepublic void onNetworkWeak() {Toast.makeText(getApplicationContext(), "Network weak", Toast.LENGTH_SHORT).show();}@Overridepublic void onNetworkResume() {Toast.makeText(getApplicationContext(), "Network resume", Toast.LENGTH_SHORT).show();}@Overridepublic void onEncodeIllegalArgumentException(IllegalArgumentException e) {handleException(e);}
}

布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="fill_parent"android:layout_height="fill_parent"tools:context="net.ossrs.yasea.demo.MainActivity"><net.ossrs.yasea.SrsCameraViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:id="@+id/glsurfaceview_camera"android:layout_alignParentBottom="true"android:layout_alignParentLeft="true"android:layout_alignParentStart="true"android:layout_alignParentTop="true"android:layout_alignParentRight="true"android:layout_alignParentEnd="true" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Pause"android:id="@+id/pause"android:layout_above="@+id/publish"android:layout_alignParentLeft="true"android:layout_alignParentStart="true" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="publish"android:id="@+id/publish"android:layout_alignParentBottom="true"android:layout_alignParentLeft="true"android:layout_alignParentStart="true" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="switch"android:id="@+id/swCam"android:layout_alignBottom="@+id/publish"android:layout_toRightOf="@+id/publish" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="record"android:id="@+id/record"android:layout_alignBottom="@+id/publish"android:layout_toRightOf="@id/swCam" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="soft encoder"android:id="@+id/swEnc"android:layout_alignBottom="@+id/publish"android:layout_toRightOf="@id/record"android:layout_alignParentRight="true"android:layout_alignParentEnd="true"/><EditTextandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="14dp"android:id="@+id/url"android:textColor="@color/accent_material_light" /></RelativeLayout>

说明:核心功能都在library里面,这个main只是调用一下方法,最后,启动,点击publish,开始推流,然后我们在vlc打开网络推流,就可以收到视频数据啦

vlc怎么使用,请看我上一篇博客,大疆无人机推流:https://blog.csdn.net/cf8833/article/details/92840672

android手机直播推流相关推荐

  1. Android手机直播(三)声音采集

    一.文章说明 开始写文章了,才知道写文章真心耗费心力,希望自己尽量做到快速更新,也希望这些文章真心能帮助到开发者们. 这篇文章主要讲述Android声音采集相关的知识,首先介绍声音的基础知识,然后介绍 ...

  2. Android手机直播

    http://www.jianshu.com/p/7ebbcc0c5df7 一.说明 近两年来直播行业越来越火,各个直播平台加一起差不多300多家.有些直播平台做秀场.综娱类的直播(来疯直播),有的做 ...

  3. android手机采集,Android手机直播之采集技术分析

    近两年来直播行业越来越火,图玩智能科技为企业提供直播平台二次开发服务以及各类app的开发,欢迎随时咨询www.toivan.com. 作为Android手机直播的研发,本着技术分享的精神,现在写一系列 ...

  4. Android手机直播(一)总览

    一.说明 近两年来直播行业越来越火,各个直播平台加一起差不多300多家.有些直播平台做秀场.综娱类的直播(来疯直播),有的做游戏直播(熊猫直播),有的做体育赛事的直播(乐视直播),分类也各种各样.下面 ...

  5. EasyPusher安卓Android手机直播推送之MediaCodec 硬编码H264格式

    EasyPusher安卓Android手机直播推送之MediaCodec 硬编码H264格式 最近在研究EasyDarwin的Push库EasyPusher,EasyPusher可以推送H264视频到 ...

  6. Android 手机直播聚合

    Kanzhibo 项目地址:xturbofan/Kanzhibo 简介:Android 手机直播聚合 虎牙的数据有点乱,因为需要兼容 YY 直播原先的数据接口(我猜的),所以还没搞完. 聚集了斗鱼,熊 ...

  7. android直播流渲染,Android手机直播之处理技术分析

    前一篇我为大家介绍了Android手机直播的采集技术,这一篇继续为大家介绍直播流程中对视频和音频的处理技术.图玩智能科技为企业提供直播平台的二次开发服务以及各类app的开发,欢迎随时咨询www.toi ...

  8. Android手机直播(二)摄像机

    一.文章说明 上周开始写直播相关的文章,写了一篇手机直播总览的文章,没想到得到大家很多赞和关注,在此感谢大家支持.这篇文章将会讲述Android摄像头相关的知识,希望能对大家有所帮助.文章开始会简单介 ...

  9. android直播视频编码,Android手机直播之视频编码技术

    今天我们继续给大家讲解Android手机直播流程中的编码技术,编码过程分为视频和音频解码,这篇文字先介绍视频编码的技术.图玩智能为企业提供直播平台的二次开发服务,为大家搭建更加完善的直播系统,欢迎随时 ...

最新文章

  1. golang导入git包_使用go module导入本地包的方法教程详解
  2. 【雷达对抗】频率测量与频谱分析-概述
  3. setup.s 分析—— Linux-0.11 学习笔记(二)
  4. PgSql备份pg_dump与还原手记pg_restore(转)
  5. 修改项目名称之后,访问不到项目的问题
  6. python怎么读取github_如何通过Python模拟登陆Github?
  7. win32开发(按键消息)
  8. docker部署在linux怎么代理,如何在linux 上部署docker
  9. C++ Exercises(十六)---Ethernet帧包结构解析
  10. Android 编码规范:(五)避免创建不必要的对象
  11. 开课吧课堂之如何创建自己的异常子类
  12. linux DNS 简单配置
  13. 【SQL Server】入门教程(总结篇)
  14. drools规则引擎源码解析
  15. MSTAR648方案遥控器配置
  16. 导航栏背景色、标题颜色以及返回键自定义
  17. 《2022年Java开发者生产力报告》出炉啦
  18. 关于DS12C887 以外部RAM方式访问
  19. (不定期更新)驯服Ubuntu指南
  20. 万能Ghost系统制作教程

热门文章

  1. Unity实用小工具或脚本—3D炫酷UI篇(一)
  2. 虚幻4引擎开发的手游_虚幻4引擎开发 《神佑》手游首次公开
  3. 俄罗斯方块、贪吃蛇、心形表白 | 好玩的C语言源码
  4. 【现代通信原理笔记】8 蜂窝系统
  5. 关于MacOS降系统版本的处理方法
  6. 电商客服售前售后话术培训资料合集(共150份)
  7. 【七夕特效】 -- 满屏爱心
  8. 《智能对话机器人开发实战20讲》--学习笔记--AIML基础功能拓展-与互联网的集成
  9. 02 - 语义网络,语义网,链接数据和知识图谱
  10. 扁平化easyUI default皮肤