本章节为您介绍了Android的输入外部视频流和音频流的接口示例。

输入外部视频流

注意 增加自定义视频输入时,建议您提前采集,RTC进入频道之前开始送入数据,避免看到摄像头数据。
  1. 注册外部视频接口回调。

    接口说明如下所示。

    /**
         * 注册原始数据回调接口
         * @param streamType 流类型
         * @return dataInterface 视频原始数据接口
         */
        public abstract ALI_RTC_INTERFACE.VideoRawDataInterface registerVideoRawDataInterface(ALI_RTC_INTERFACE.AliRawDataStreamType streamType);
    说明 streamType支持AliRTCSdk_Streame_Type_Capture(视频流)和AliRTCSdk_Streame_Type_Screen(屏幕流);SDK默认自动推拉流,例如:主动关闭将收不到对应回调。

    示例方法如下所示。

    //获取AliRtcEngine实例
    AliRtcEngine mAliRtcEngine = AliRtcEngine.getInstance(getApplicationContext());
    ALI_RTC_INTERFACE.VideoRawDataInterface videoRawDataInterface = mAliRtcEngine.registerVideoRawDataInterface(
                        ALI_RTC_INTERFACE.AliRawDataStreamType.AliRTCSdk_Streame_Type_Capture);
  2. 输入视频数据。

    接口说明如下所示。

    /**
             * 发送视频帧
             * @param frame AliRawDataFrame数据帧实体类
             * @param timeStamp 时间戳
             * @return
             */
            public abstract int deliverFrame(AliRawDataFrame frame, long timeStamp);

    参数说明,AliRawDataFrame必填项如下所示。

    参数 说明
    MediaStatesVideoFormat 数据类型,目前默认AndroidYUV数据返回NV21
    width 视频流宽
    height 视频流高
    rotation 视频流角度
    video_frame_length 数据buffer长度
    lineSize yuv数据数组,具体使用请参见下文示例
    frame buffer数据

    示例方法如下所示。

    private void decodeYUVRawData(ALI_RTC_INTERFACE.VideoRawDataInterface videoRawDataInterface) {
            String yuvPath = "<!-请输入yuv文件地址->";
            if (TextUtils.isEmpty(yuvPath)) {
                ToastUtils.LongToast("请先选择YUV文件!!!");
                return;
            }
            File yuvDataFile = new File(yuvPath);
            if (!yuvDataFile.exists()) {
                ToastUtils.LongToast(yuvPath + " 文件不存在!!!");
                return;
            }
            //此处仅为示例代码做法,请使用正确的流角度
            int rotation = 90;
            Log.d(TAG, "decodeYUVRawData: "+rotation+"__"+getVideoFormat());
            ToastUtils.LongToast("inputing yuv data");
            //此处仅为示例代码做法,请使用正确的流宽高
            int width = 480;
            int height = 640;
            //start push yuv
            new Thread() {
                @Override
                public void run() {
                    File yuvDataFile = new File(yuvPath);
                    RandomAccessFile raf = null;
                    try {
                        raf = new RandomAccessFile(yuvDataFile, "r");
                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                        return;
                    }
                    try {
                        byte[] buffer = new byte[width * height * 3 / 2];
                        while (videoRawDataInterface != null) {
                            int len = raf.read(buffer);
                            if (len == -1) {
                                raf.seek(0);
                            }
                            ALI_RTC_INTERFACE.AliRawDataFrame rawDataFrame
                                    = new ALI_RTC_INTERFACE.AliRawDataFrame();
                            rawDataFrame.format = MediaStatesVideoFormat.NV21;// 支持NV21和I420
                            rawDataFrame.frame = buffer;
                            rawDataFrame.width = width;
                            rawDataFrame.height = height;
                            rawDataFrame.lineSize[0] = width;
                            rawDataFrame.lineSize[1] = width / 2;
                            rawDataFrame.lineSize[2] = height / 2;
                            rawDataFrame.lineSize[3] = 0;
                            rawDataFrame.rotation = rotation;
                            rawDataFrame.video_frame_length = buffer.length;
                            if (videoRawDataInterface != null) {
                                    videoRawDataInterface.deliverFrame(rawDataFrame, System.nanoTime() / 1000);
                            }
                            //主动sleep发送一次
                            Thread.sleep(25);
                        }
                    } catch (IOException | InterruptedException ex) {
                        ex.printStackTrace();
                    } finally {
                        try {
                            raf.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }.start();
        }
  3. 反注册视频数据回调。

    接口方法如下所示。

    /**
         * 反注册原始数据回调接口
         * @param streamType 流类型
         */
        public abstract void unRegisterVideoRawDataInterface(ALI_RTC_INTERFACE.AliRawDataStreamType streamType);

    示例方法如下所示。

    mAliRtcEngine.unRegisterVideoRawDataInterface(
                        type);

输入外部音频流

  1. 打开外部音频输入开关。

    接口如下所示。

    /**
         * @brief 设置是否启用外部音频输入源
         * @param enable YES:开启,NO:关闭
         * @param sampleRate 采样率,16k、48k...
         * @param channels 外部音频源的通道数,可设置为1:单声道,2:双声道
         * @return 返回>=0表示成功, <0表示失败
         */
       public abstract  int setExternalAudioSource(boolean enable ,int sampleRate,int channels);
    
        /**
         * @brief 设置是否与麦克风采集音频混合
         * @param mixed YES:混音,NO:完全替换麦克风采集数据
         */
        public abstract int setMixedWithMic(boolean mixed);
    说明 目前仅支持PCM数据。

    示例方法如下所示。

    //获取mAliRtcEngine,
    AliRtcEngine  mAliRtcEngine = AliRtcEngine.getInstance(getApplicationContext());
    //设置开启外部音频输入源
    mAliRtcEngine.setExternalAudioSource(true,44100,1);
    //完全替代麦克风采集
    mAliRtcEngine.setMixedWithMic(false);
  2. 输入音频数据。

    接口方法如下所示。

    /**
         *  输入外部音频数据
         * @param samples 音频数据 不建议超过40ms数据
         * @param samplesLength 采样长度
         * @param timestamp 时间戳
         * @return return>=0 Success, return<0 Failure
         */
        public abstract  int pushExternalAudioFrameRawData(byte[] samples,int samplesLength,long timestamp);
    说明 如果返回值为17236225,代表当前buffer队列塞满,需要等待后再继续输送数据,建议您等待20ms。

    示例方法如下所示。

    private void decodePCMRawData(){
            String pcmPath = "/sdcard/123.pcm";
            if (TextUtils.isEmpty(pcmPath)) {
                ToastUtils.LongToast("请先选择PCM文件!!!");
                return;
            }
            File pcmDataFile = new File(pcmPath);
            if (!pcmDataFile.exists()) {
                ToastUtils.LongToast(pcmPath + " 文件不存在!!!");
                return;
            }
            ToastUtils.LongToast("inputing pcm data");
    
            new Thread() {
                @Override
                public void run() {
                    File pcmDataFile = new File(pcmPath);
                    RandomAccessFile raf = null;
                    try {
                        raf = new RandomAccessFile(pcmDataFile, "r");
                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                        return;
                    }
                    try {
                        byte[] buffer = new byte[(44100/100)*4*1];
                        while (true) {
                            int len = raf.read(buffer);
                            if (len == -1) {
                                raf.seek(0);
                            }
                            mAliRtcEngine.pushExternalAudioFrameRawData(buffer,buffer.length,0);
                            Thread.sleep(20);
                        }
                    } catch (IOException | InterruptedException ex) {
                        ex.printStackTrace();
                    } finally {
                        try {
                            raf.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }.start();
        }