我们经常用直播,但是直播怎么做呢?前面的文章已经搭建好了推流服务器,现在就让我们先从采集数据开始吧,然后压缩数据,然后推流数据等等,一步步来,一定会成个大胖纸的。加油!

Activity.java

public class MainActivity extends Activity {static final String URL = "rtmp://112.74.96.116/live/jason";private LivePusher live;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);SurfaceView surfaceView = (SurfaceView) findViewById(R.id.surface);//相机图像的预览live = new LivePusher(surfaceView.getHolder());}/*** 开始直播* @param btn*/public void mStartLive(View view) {Button btn = (Button)view;if(btn.getText().equals("开始直播")){live.startPush(URL);btn.setText("停止直播");}else{live.stopPush();btn.setText("开始直播");}}/*** 切换摄像头* @param btn*/public void mSwitchCamera(View btn) {live.switchCamera();}}

Push业务

定义接口Pusher.java

public abstract class Pusher {public abstract void startPush();public abstract void stopPush();public abstract void release();
}

视频Push
VideoPusher.java

public class VideoPusher extends Pusher implements Callback, PreviewCallback{private SurfaceHolder surfaceHolder;private Camera mCamera;private VideoParam videoParams;private byte[] buffers;private boolean isPushing = false;private PushNative pushNative;public VideoPusher(SurfaceHolder surfaceHolder, VideoParam videoParams, PushNative pushNative) {this.surfaceHolder = surfaceHolder;this.videoParams = videoParams;this.pushNative = pushNative;surfaceHolder.addCallback(this);}@Overridepublic void startPush() {isPushing = true;}@Overridepublic void stopPush() {isPushing = false;}@Overridepublic void surfaceCreated(SurfaceHolder holder) {startPreview();}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {}@Overridepublic void release() {stopPreview();}/*** 切换摄像头*/public void switchCamera() {if(videoParams.getCameraId() == CameraInfo.CAMERA_FACING_BACK){videoParams.setCameraId(CameraInfo.CAMERA_FACING_FRONT);}else{videoParams.setCameraId(CameraInfo.CAMERA_FACING_BACK);}//重新预览stopPreview();startPreview();}/*** 开始预览*/private void startPreview() {try {//SurfaceView初始化完成,开始相机预览mCamera = Camera.open(videoParams.getCameraId());mCamera.setPreviewDisplay(surfaceHolder);//获取预览图像数据buffers = new byte[videoParams.getWidth() * videoParams.getHeight() * 4];mCamera.addCallbackBuffer(buffers);mCamera.setPreviewCallbackWithBuffer(this);mCamera.startPreview();} catch (IOException e) {e.printStackTrace();}}/*** 停止预览*/private void stopPreview() {if(mCamera != null){            mCamera.stopPreview();mCamera.release();mCamera = null;}}@Overridepublic void onPreviewFrame(byte[] data, Camera camera) {if(mCamera != null){mCamera.addCallbackBuffer(buffers);}if(isPushing){//回调函数中获取图像数据,然后给Native代码编码pushNative.fireVideo(data);}}
}

音频AudioPusher.java

public class AudioPusher extends Pusher{private AudioParam audioParam;private AudioRecord audioRecord;private boolean isPushing = false;private int minBufferSize;private PushNative pushNative;public AudioPusher(AudioParam audioParam, PushNative pushNative) {this.audioParam = audioParam;this.pushNative = pushNative;int channelConfig = audioParam.getChannel() == 1 ? AudioFormat.CHANNEL_IN_MONO : AudioFormat.CHANNEL_IN_STEREO; //最小缓冲区大小minBufferSize = AudioRecord.getMinBufferSize(audioParam.getSampleRateInHz(), channelConfig, AudioFormat.ENCODING_PCM_16BIT);audioRecord = new AudioRecord(AudioSource.MIC, audioParam.getSampleRateInHz(), channelConfig, AudioFormat.ENCODING_PCM_16BIT, minBufferSize);}@Overridepublic void startPush() {isPushing = true;//启动一个录音子线程new Thread(new AudioRecordTask()).start();}@Overridepublic void stopPush() {isPushing = false;audioRecord.stop();}@Overridepublic void release() {if(audioRecord != null){audioRecord.release();audioRecord = null;}}class AudioRecordTask implements Runnable{@Overridepublic void run() {//开始录音audioRecord.startRecording();while(isPushing){//通过AudioRecord不断读取音频数据byte[] buffer = new byte[minBufferSize];int len = audioRecord.read(buffer, 0, buffer.length);if(len > 0){//传给Native代码,进行音频编码pushNative.fireAudio(buffer, len);}}}}
}

push总类,音频视频同时push


public class LivePusher implements Callback {private SurfaceHolder surfaceHolder;private VideoPusher videoPusher;private AudioPusher audioPusher;private PushNative pushNative;public LivePusher(SurfaceHolder surfaceHolder) {this.surfaceHolder = surfaceHolder;surfaceHolder.addCallback(this);prepare();}/*** 预览准备*/private void prepare() {pushNative = new PushNative();//实例化视频推流器VideoParam videoParam = new VideoParam(480, 320, CameraInfo.CAMERA_FACING_BACK);videoPusher = new VideoPusher(surfaceHolder,videoParam,pushNative);//实例化音频推流器AudioParam audioParam = new AudioParam();audioPusher = new AudioPusher(audioParam,pushNative);}/*** 切换摄像头*/public void switchCamera() {videoPusher.switchCamera();}/*** 开始推流*/public void startPush(String url) {videoPusher.startPush();audioPusher.startPush();pushNative.startPush(url);}/*** 停止推流*/public void stopPush() {videoPusher.stopPush();audioPusher.stopPush();pushNative.stopPush();}/*** 释放资源*/private void release() {videoPusher.release();audioPusher.release();pushNative.release();}@Overridepublic void surfaceCreated(SurfaceHolder holder) {}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {stopPush();release();}
}

参数的设置:


public class LivePusher implements Callback {private SurfaceHolder surfaceHolder;private VideoPusher videoPusher;private AudioPusher audioPusher;private PushNative pushNative;public LivePusher(SurfaceHolder surfaceHolder) {this.surfaceHolder = surfaceHolder;surfaceHolder.addCallback(this);prepare();}/*** 预览准备*/private void prepare() {pushNative = new PushNative();//实例化视频推流器VideoParam videoParam = new VideoParam(480, 320, CameraInfo.CAMERA_FACING_BACK);videoPusher = new VideoPusher(surfaceHolder,videoParam,pushNative);//实例化音频推流器AudioParam audioParam = new AudioParam();audioPusher = new AudioPusher(audioParam,pushNative);}/*** 切换摄像头*/public void switchCamera() {videoPusher.switchCamera();}/*** 开始推流*/public void startPush(String url) {videoPusher.startPush();audioPusher.startPush();pushNative.startPush(url);}/*** 停止推流*/public void stopPush() {videoPusher.stopPush();audioPusher.stopPush();pushNative.stopPush();}/*** 释放资源*/private void release() {videoPusher.release();audioPusher.release();pushNative.release();}@Overridepublic void surfaceCreated(SurfaceHolder holder) {}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {stopPush();release();}}
package com.dongnaoedu.live.params;/*** 视频数据参数*/
public class VideoParam {private int width;private int height;private int cameraId;public VideoParam(int width, int height, int cameraId) {super();this.width = width;this.height = height;this.cameraId = cameraId;}public int getWidth() {return width;}public void setWidth(int width) {this.width = width;}public int getHeight() {return height;}public void setHeight(int height) {this.height = height;}public int getCameraId() {return cameraId;}public void setCameraId(int cameraId) {this.cameraId = cameraId;}}

当然数据有了,我们必须通过C++代码完成操作,所以如下:


/*** 调用C代码进行编码与推流*/
public class PushNative {public native void startPush(String url);public native void stopPush();public native void release();/*** 设置视频参数* @param width* @param height* @param bitrate* @param fps*/public native void setVideoOptions(int width, int height, int bitrate, int fps);/*** 设置音频参数* @param sampleRateInHz* @param channel*/public native void setAudioOptions(int sampleRateInHz, int channel);/*** 发送视频数据* @param data*/public native void fireVideo(byte[] data);/*** 发送音频数据* @param data* @param len*/public native void fireAudio(byte[] data, int len);static{System.loadLibrary("dn_live");}
}

上面是第一节操作,我们后面的文章将慢慢介绍C++的实现,牵扯到jni的使用,可能会单独有一篇文章进行介绍,小朋友记得加关注哦。

java代码视频数据和音频数据的采集相关推荐

  1. Java提取视频中的音频

    话不多说,上代码 Scanner scanner = new Scanner(System.in);System.out.println("请输入被提取音频的视频:");Strin ...

  2. Java Mp3转化WAV/PCM音频数据,解码详细解析,提取每一帧数据集合/比特流/播放,一行代码!

    导言 大家好!我是原子君 1.因为Java本身只支持,wav,缺少mp3的解码器,所以Java自带的无法对mp3进行处理,这种MPEG-*音频有损压缩标准编码,更不要说使用Java的音频格式和音频流就 ...

  3. python音频 降噪_从视频中提取音频数据,然后应用傅里叶对音频降噪(python)...

    视频准备 QQ有热键 然后随便打开一个视频网站进行录屏 我选择B站 从视频中提取音频 需要安装包moviepy pip install moviepy 提取代码 from moviepy.editor ...

  4. 从视频中提取音频数据,然后应用傅里叶对音频降噪(python)

    视频准备 QQ有热键 然后随便打开一个视频网站进行录屏 我选择B站 从视频中提取音频 需要安装包moviepy pip install moviepy 提取代码 from moviepy.editor ...

  5. 解决POI事件驱动模式读取不到Java代码创建的Excel表格数据问题

    场景 使用POI官网上的事件驱动模式的示例方法,读取单sheet单次创建的Excel表格文件(.xlsx),Microsoft Excel和WPS Excel创建的表格文件可以正常读取数据,但是jav ...

  6. java如何向数据库中插入数据_如何控制Java代码向数据库中插入数据

    慕哥6287543 Java程序向数据库中插入数据,代码如下:123456789101112131415161718192021222324252627282930313233343536373839 ...

  7. MongoDB最简单的入门教程之三 使用Java代码往MongoDB里插入数据

    前两篇教程我们介绍了如何搭建MongoDB的本地环境. 这篇教程我们会介绍如何使用Java代码来连接MongoDB. 如果您是基于Maven进行依赖管理的Java项目,只需要在您的pom.xml里加入 ...

  8. 使用FFMPEG库封装264视频和acc音频数据到MP4文件中

    准备 ffmepeg 4.4 一段H264的视频文件 一段acc格式的音频文件 封装流程 1.使用avformat_open_input分别打开视频和音频文件,初始化其AVFormatContext, ...

  9. 笨鸟先飞java代码,笨鸟先飞之Java--MySql中文数据乱码为哪般???

    图一:在drp的分销商模块,每次修改区域虽然返回修改成功,但是每次读取到的中文数据都是"???"的字符串,但数字和字母的数据却不受影响. 图二:不管是drp还是hibernate项 ...

最新文章

  1. java static 作用详解
  2. 回顾2020,我国无人机经历了四大新变化
  3. Blocking/Non-Blocking VS Sync/Async VS Overlapped
  4. matlab mandrill,MATLAB】MATLAB的自带数据及可生成数据的函数
  5. js中执行到一个if就停止的代码_Node 中如何引入一个模块及其细节
  6. CSS3的边框(二)
  7. OBS鉴权实现的宝典秘籍,速拿!
  8. 微博:坚决打击在政务、媒体官微下刷量控评的行为
  9. kcf算法中cos_window是什么意思_知网/维普查重系统算法介绍(史上最详细)
  10. 强化学习 ---baselines项目之 Atari游戏的网络结构解析
  11. 微信小程序 人脸识别登陆模块
  12. mac系统修改idea运行内存
  13. java 中subtract_Java.math.BigDecimal.subtract()方法实例详解
  14. 赛格威航空T15评测骑行测试
  15. c语言三角分解法解方程,用直接三角分解法解线性方程组.ppt
  16. 2020诺贝尔文学奖得主,死亡的诗歌
  17. 中国人工智能大赛机器阅读理解任务冠军方案出炉~
  18. n2n内网穿透及代理服务
  19. Visual Studio 2017 设置语言以及下载语言包
  20. sbt 使用国内镜像 sbt 下载很慢 (尝试了几乎全网所有办法,依然无效。最后解决!!!)

热门文章

  1. PAL和NTSC有什么区别
  2. 公共服务领域英文译写规范
  3. Python函数式编程:map/reduce
  4. 华为4.0系统怎么没ROOT激活xposed框架的经验
  5. 五:Dubbo中Provider参数配置及源码讲解
  6. 软件测试面试中的一些奇葩问题
  7. 走进就职演说幕后:大有深意的用词
  8. Vue v-if和-vshow的差异比较
  9. 小程序FMP优化实录,已拿offer附真题解析
  10. 马斯克认错:裁掉他们是我最大的错误,但黑粉们却没能笑太久...