Android音视频之Rtmp推流到B站(手机直播demo)

学习目标:

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);
    }

其他的代码就不贴了,可以下载项目链接
项目链接

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值