学习目标:
Android音视频之Rtmp推流到B站学习内容:
rtmp推流实现
通过rtmpdump的方式实现rtmp推流,选择以android结尾的下载,即(librtmp)
rtmpdump下载地址
录屏功能的实现
通过线程的方式实现不断的读取录屏数据,并且利用rtmpdump实现推流。
public class VideoCodec extends Thread {
private ScreenLive screenLive;
//MediaCodec是Android提供的用于对音视频进行编解码的类,
// 它通过访问底层的codec来实现编解码的功能。
// 是Android media基础框架的一部分,
// 通常和 MediaExtractor, MediaSync, MediaMuxer, MediaCrypto, MediaDrm, Image, Surface和AudioTrack 一起使用。
private MediaCodec mediaCodec;
private VirtualDisplay virtualDisplay;
private boolean isLiving;
private long timeStamp;
private long startTime;
private MediaProjection mediaProjection;
public VideoCodec(ScreenLive screenLive) {
this.screenLive = screenLive;
}
@Override
public void run() {
isLiving = true;
mediaCodec.start();
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
while (isLiving) {
if (timeStamp != 0) {
//2000毫秒后 mediacodec虽然设置了关键帧间隔,但是没用 需要手动强制请求
if (System.currentTimeMillis() - timeStamp >= 2000) {
Bundle params = new Bundle();
//立即刷新 让下一帧是关键帧
params.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0);
mediaCodec.setParameters(params);
timeStamp = System.currentTimeMillis();
}
} else {
timeStamp = System.currentTimeMillis();
}
int index = mediaCodec.dequeueOutputBuffer(bufferInfo, 10);
if (index >= 0) {
ByteBuffer buffer = mediaCodec.getOutputBuffer(index);
byte[] outData = new byte[bufferInfo.size];
buffer.get(outData);
//这样也能拿到 sps pps
// ByteBuffer sps = mediaCodec.getOutputFormat().getByteBuffer
// ("csd-0");
// ByteBuffer pps = mediaCodec.getOutputFormat().getByteBuffer
// ("csd-1");
if (startTime == 0) {
// 微妙转为毫秒
startTime = bufferInfo.presentationTimeUs / 1000;
}
RTMPPackage rtmpPackage = new RTMPPackage();
rtmpPackage.setBuffer(outData);
rtmpPackage.setType(RTMPPackage.RTMP_PACKET_TYPE_VIDEO);
long tms = (bufferInfo.presentationTimeUs / 1000) - startTime;
rtmpPackage.setTms(tms);
screenLive.addPackage(rtmpPackage);
mediaCodec.releaseOutputBuffer(index, false);
}
}
isLiving = false;
startTime = 0;
mediaCodec.stop();
mediaCodec.release();
mediaCodec = null;
virtualDisplay.release();
virtualDisplay = null;
mediaProjection.stop();
mediaProjection = null;
}
//开始直播,采集数据
public void startLive(MediaProjection mediaProjection) {
this.mediaProjection = mediaProjection;
// 配置编码参数,媒体格式,长,宽参数,
// 创建一个Format用来设置Codec的格式
MediaFormat format = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, 640,
480);
format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
//码流
format.setInteger(MediaFormat.KEY_BIT_RATE, 500_000);
//帧数
format.setInteger(MediaFormat.KEY_FRAME_RATE, 20);
//关键帧
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 2);
try {
// 创建编码器
mediaCodec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC);
mediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
// 从编码器创建一个画布, 画布上的图像会被编码器自动编码
Surface surface = mediaCodec.createInputSurface();
//创建视频采集,创建一个虚拟显示器-----创建当前图像到虚拟显示器
virtualDisplay = mediaProjection.createVirtualDisplay(
//虚拟显示器名字
"virtual-screen",
//宽,高
640, 480, 1,
DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC,
surface, null, null);
} catch (IOException e) {
e.printStackTrace();
}
start();
}
public void stopLive() {
isLiving = false;
try {
//阻塞上一线程,让线程按顺序进行
join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//开始直播
public void startLive(View view) {
//推流地址
String url="rtmp://live-push.bilivideo.com/live-bvc/?streamname=live_64489196_1713195&key=b21119d21ac4a4a6a238a63dde3a769b&schedule=rtmp&pflag=1";
mScreenLive = new ScreenLive();
mScreenLive.startLive(this, url);
}
其他的代码就不贴了,可以下载项目链接
项目链接