Windows平台RTMP直播推送集成简要说明

好多开发者在集成大牛直播SDK (官方)的Windows平台RTMP推送模块时吓一跳,怎么这么多接口?本文做个简单的拆分:

初始化

初始化之前,如需设置日志路径,调用NTSmartLog.NT_SL_SetPath(log_path); 设置日志存放路径。

设置过后,调用NT_PB_Init()接口,完成SDK初始化动作,注意,哪怕多实例推送,Init()接口也仅需调一次,同理,UnInit()接口也是。

然后,代码会判断系统是不是支持WR模式采集窗口,WR这种只有Win10高版本的才支持,如果不需要用到采集窗口,这个接口可忽略。

        /*
		 * 检查是否支持WR方式采集窗口
         * is_supported: 输出参数, 输出1表示支持, 0表示不支持
         * 注意:这个需要win10较高版本才支持
         * 成功返回 NT_ERC_OK
		 */
        [DllImport(@"SmartPublisherSDK.dll")]
		public static extern UInt32 NT_PB_IsWRCaptureWindowSupported(ref Int32 is_supported);

再往下,是遍历系统支持的硬解、摄像头等信息,比如LoadHWVideoEncoderInfos():

        private void LoadHWVideoEncoderInfos()
        {            
	        hw_video_encoder_infos_.Clear();

	        Int32 count = 0;
            UInt32 ret = NTSmartPublisherSDK.NT_PB_GetHWVideoEncoderInfoCount(ref count);
	        
            if (NTBaseCodeDefine.NT_ERC_OK == ret && count > 0)
	        {
                IntPtr ptr_hw_video_encoder_infos = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(NT_PB_HWVideoEncoderInfo)) * count);
                
                Int32 out_count = 0;

                ret = NTSmartPublisherSDK.NT_PB_GetHWVideoEncoderInfos(ptr_hw_video_encoder_infos, count, ref out_count);

                if (ret != NTBaseCodeDefine.NT_ERC_OK || out_count < 1)
                {
                    hw_video_encoder_infos_.Clear();
                }
                else
                {
                    for (int i = 0; i < out_count; i++)
                    {
                        NT_PB_HWVideoEncoderInfo hw_video_encoder_info = (NT_PB_HWVideoEncoderInfo)Marshal.PtrToStructure(ptr_hw_video_encoder_infos + i * Marshal.SizeOf(typeof(NT_PB_HWVideoEncoderInfo)), typeof(NT_PB_HWVideoEncoderInfo));
                        
                        hw_video_encoder_infos_.Add(hw_video_encoder_info);
                    }
                }

               Marshal.FreeHGlobal(ptr_hw_video_encoder_infos);
	        }
        }

            if (hw_video_encoder_infos_.Count > 0)
            {
                EnableHWVideoEncoderControls(true);
                FillVideoEncodersControl((uint)NTCommonMediaDefine.NT_MEDIA_CODEC_ID.NT_MEDIA_CODEC_ID_H264);
            }

紧接着是Audio和camera相关:

            int auido_devices = 0;

            if (NTBaseCodeDefine.NT_ERC_OK == NTSmartPublisherSDK.NT_PB_GetAuidoInputDeviceNumber(ref auido_devices))
            {
                if (auido_devices > 0)
                {
                    btn_check_auido_mic_input_.Enabled = true;

                    for (int i = 0; i < auido_devices; ++i)
                    {
                        byte[] deviceNameBuffer = new byte[512];

                        string name = "";

                        if (NTBaseCodeDefine.NT_ERC_OK == NTSmartPublisherSDK.NT_PB_GetAuidoInputDeviceName((uint)i, deviceNameBuffer, 512))
                        {
                            int count = 0;
                            for (int j = 0; j < deviceNameBuffer.Length; ++j )
                            {
                                if ( deviceNameBuffer[j] != 0 )
                                {
                                    count++;
                                }
                                else
                                {
                                    break;
                                }
                            }

                            if ( count > 0 )
                            {
                                name = Encoding.UTF8.GetString(deviceNameBuffer, 0, count);
                            }                    
                        }

                        var audio_name = "";

                        if (name.Length == 0)
                        {
                            audio_name = "音频采集设备-";
                        }
                        else
                        {
                            audio_name = name + "-";
                        }

                        audio_name = audio_name + (i + 1);

                        combox_auido_input_devices_.Items.Add(name);
                    }
                    combox_auido_input_devices_.SelectedIndex = 0;
                }
            }

            publisher_handle_ = new IntPtr();

            region_choose_tool_handle_ = new IntPtr();

            win_form_wnd_ = GetForegroundWindow();

            cameras_ = new List<CameraInfo>();

            btn_check_video_bitrate_.CheckState = CheckState.Checked;

            if (IsCanCaptureSpeaker())
            {
                btn_check_auido_speaker_input_.Enabled = true;
            }
            else
            {
                btn_check_auido_speaker_input_.Enabled = false;
            }

            if (btn_check_auido_mic_input_.Checked
                  || btn_check_auido_speaker_input_.Checked)
            {
                btn_check_speex_encoder_.Enabled = true;
                edit_speex_quality_.Enabled = true;
                btn_check_noise_suppression_.Enabled = true;
                btn_check_agc_.Enabled = true;
                btn_check_vad_.Enabled = true;
            }

            if ( btn_check_auido_mic_input_.Checked
                && btn_check_auido_speaker_input_.Checked)
            {
                btn_check_echo_cancel_.Enabled = false;
                edit_echo_delay_.Enabled = false;
            }

            edit_audio_input_volume_.Text = "1.0";
            edit_audio_speaker_input_volume_.Text = "1.0";

            FillCameraInfo();
            InitCameraControl();

OpenPublisherHandle()

OpenPublisherHandle()主要是确认选择数据源类型,然后获取推送句柄,等待做下一步的操作。

选择video option和 audio option

            // 视频
            UInt32 video_option = (UInt32)NTSmartPublisherDefine.NT_PB_E_VIDEO_OPTION.NT_PB_E_VIDEO_OPTION_NO_VIDEO;

            if (btn_desktop_camera_switch.Checked
                || btn_camera_overlay_to_desktop.Checked
                || btn_desktop_overlay_to_camera.Checked)
            {
                // 使用叠加模式
                video_option = (UInt32)NTSmartPublisherDefine.NT_PB_E_VIDEO_OPTION.NT_PB_E_VIDEO_OPTION_LAYER;
            }
            else if (btn_check_window_input_.Checked)
            {
                video_option = (UInt32)NTSmartPublisherDefine.NT_PB_E_VIDEO_OPTION.NT_PB_E_VIDEO_OPTION_WINDOW;
            }
            else if (btn_check_desktop_input_.Checked && btn_check_scale_desktop_.Checked)
            {
                // 使用叠加模式来实现缩放
                video_option = (UInt32)NTSmartPublisherDefine.NT_PB_E_VIDEO_OPTION.NT_PB_E_VIDEO_OPTION_LAYER;
            }
            else if (btn_check_desktop_input_.Checked && !btn_check_scale_desktop_.Checked)
            {
                //屏幕模式
                video_option = (UInt32)NTSmartPublisherDefine.NT_PB_E_VIDEO_OPTION.NT_PB_E_VIDEO_OPTION_SCREEN;
            }
            else if (btn_check_camera_input_.Checked)
            {
                //摄像头模式
                video_option = (UInt32)NTSmartPublisherDefine.NT_PB_E_VIDEO_OPTION.NT_PB_E_VIDEO_OPTION_CAMERA;
            }

            // 音频
            UInt32 audio_option = (UInt32)NTSmartPublisherDefine.NT_PB_E_AUDIO_OPTION.NT_PB_E_AUDIO_OPTION_NO_AUDIO;

            if (btn_check_auido_mic_input_.Checked
                && btn_check_auido_speaker_input_.Checked)
            {
                audio_option = (UInt32)NTSmartPublisherDefine.NT_PB_E_AUDIO_OPTION.NT_PB_E_AUDIO_OPTION_CAPTURE_MIC_SPEAKER_MIXER;
            }
            else if (btn_check_auido_mic_input_.Checked)
            {
                //麦克风模式
                audio_option = (UInt32)NTSmartPublisherDefine.NT_PB_E_AUDIO_OPTION.NT_PB_E_AUDIO_OPTION_CAPTURE_MIC;
            }
            else if (btn_check_auido_speaker_input_.Checked)
            {
                //扬声器模式
                audio_option = (UInt32)NTSmartPublisherDefine.NT_PB_E_AUDIO_OPTION.NT_PB_E_AUDIO_OPTION_CAPTURE_SPEAKER;
            }

调用Open接口获取publisher handle,然设置event callback

            if (NTBaseCodeDefine.NT_ERC_OK != NTSmartPublisherSDK.NT_PB_Open(out publisher_handle_,
                video_option, audio_option, 0, IntPtr.Zero))
            {
                MessageBox.Show("Call open failed!");
                return false;
            }

            if (publisher_handle_ != IntPtr.Zero)
            {
                pb_event_call_back_ = new NT_PB_SDKEventCallBack(PbSDKEventCallBack);

                NTSmartPublisherSDK.NT_PB_SetEventCallBack(publisher_handle_, win_form_wnd_, pb_event_call_back_);
                return true;
            }
            else
            {
                return false;
            }

event callback相关ID

        /*事件ID*/
        public enum NT_PB_E_EVENT_ID : uint
        {
            NT_PB_E_EVENT_ID_BASE = NTBaseCodeDefine.NT_EVENT_ID_SMART_PUBLISHER_SDK,

	        NT_PB_E_EVENT_ID_CONNECTING			= NT_PB_E_EVENT_ID_BASE | 0x2,	/*连接中, param5表示推送URL */
	        NT_PB_E_EVENT_ID_CONNECTION_FAILED	= NT_PB_E_EVENT_ID_BASE | 0x3,	/*连接失败, param5表示推送URL*/
	        NT_PB_E_EVENT_ID_CONNECTED			= NT_PB_E_EVENT_ID_BASE | 0x4,	/*已连接, param5表示推送URL*/
	        NT_PB_E_EVENT_ID_DISCONNECTED		= NT_PB_E_EVENT_ID_BASE | 0x5,	/*断开连接, param5表示推送URL*/
	
	        NT_PB_E_EVENT_ID_RECORDER_START_NEW_FILE    = NT_PB_E_EVENT_ID_BASE | 0x7,	/*录像写入新文件, param5表示录像文件名*/
	        NT_PB_E_EVENT_ID_ONE_RECORDER_FILE_FINISHED = NT_PB_E_EVENT_ID_BASE | 0x8,	/*一个录像文件完成, param5表示录像文件名*/

            NT_PB_E_EVENT_ID_CAPTURE_WINDOW_INVALID = NT_PB_E_EVENT_ID_BASE | 0xd, /*捕获窗口时,如果窗口句柄无效则通知用户, param1为窗口句柄*/

            NT_PB_E_EVENT_ID_RTSP_URL = NT_PB_E_EVENT_ID_BASE | 0xe, /* 通知rtsp url, param1表示rtsp server handle, param5 表示rtsp url */
            NT_PB_E_EVENT_ID_PUSH_RTSP_SERVER_RESPONSE_STATUS_CODE = NT_PB_E_EVENT_ID_BASE | 0xf,  /* 推送rtsp时服务端相应的status code上报,目前只上报401, param1表示status code,  param5表示推送URL */
            NT_PB_E_EVENT_ID_PUSH_RTSP_SERVER_NOT_SUPPORT = NT_PB_E_EVENT_ID_BASE | 0x10,  /* 推送rtsp时服务器不支持rtsp推送,  param5表示推送URL */
        }

SetCommonOptionToPublisherSDK()

SetCommonOptionToPublisherSDK()主要是指定具体采集的音视频数据类型,比如摄像头数据、屏幕数据、摄像头和屏幕叠加后的数据(以层级模式实现)、窗口等,这块比较复杂,好在作为SDK调用者,你只要搞清楚你需要采集的类型,直接移植就可以了。

           // 视频相关设置
            if (btn_desktop_camera_switch.Checked
                || btn_camera_overlay_to_desktop.Checked
                || btn_desktop_overlay_to_camera.Checked
                || btn_check_desktop_input_.Checked
                || btn_check_window_input_.Checked
                || btn_check_camera_input_.Checked)
            {
                if (btn_desktop_camera_switch.Checked)
                {
                    //摄像头和屏幕相互切换
                    int left = Int32.Parse(edit_clip_left_.Text);
                    int top = Int32.Parse(edit_clip_top_.Text);
                    int w = Int32.Parse(edit_clip_width_.Text);
                    int h = Int32.Parse(edit_clip_height_.Text);

                    // 有一个是0, 就使用全屏
                    if (w == 0 || h == 0)
                    {
                        left = 0;
                        top = 0;
                        w = screenArea_.Width;
                        h = screenArea_.Height;
                    }
                    else
                    {
                        // 保证4字节对齐
                        w = NT_ByteAlign(w, 4);
                        h = NT_ByteAlign(h, 4);
                    }


                    NTSmartPublisherSDK.NT_PB_ClearLayersConfig(publisher_handle_, 0,
                                    0, IntPtr.Zero);

                    // 第0层填充RGBA矩形, 目的是保证帧率, 颜色就填充全黑
                    int red = 0;
                    int green = 0;
                    int blue = 0;
                    int alpha = 255;

                    NT_PB_RGBARectangleLayerConfig rgba_layer_c0 = new NT_PB_RGBARectangleLayerConfig();

                    rgba_layer_c0.base_.type_ = (Int32)NTSmartPublisherDefine.NT_PB_E_LAYER_TYPE.NT_PB_E_LAYER_TYPE_RGBA_RECTANGLE;
                    rgba_layer_c0.base_.index_ = 0;
                    rgba_layer_c0.base_.enable_ = 1;
                    rgba_layer_c0.base_.region_.x_ = left;
                    rgba_layer_c0.base_.region_.y_ = top;
                    rgba_layer_c0.base_.region_.width_ = w;
                    rgba_layer_c0.base_.region_.height_ = h;

                    rgba_layer_c0.base_.offset_ = Marshal.OffsetOf(rgba_layer_c0.GetType(), "base_").ToInt32();
                    rgba_layer_c0.base_.cb_size_ = (uint)Marshal.SizeOf(rgba_layer_c0);

                    rgba_layer_c0.red_ = System.BitConverter.GetBytes(red)[0];
                    rgba_layer_c0.green_ = System.BitConverter.GetBytes(green)[0];
                    rgba_layer_c0.blue_ = System.BitConverter.GetBytes(blue)[0];
                    rgba_layer_c0.alpha_ = System.BitConverter.GetBytes(alpha)[0];

                    IntPtr rgba_conf = Marshal.AllocHGlobal(Marshal.SizeOf(rgba_layer_c0));

                    Marshal.StructureToPtr(rgba_layer_c0, rgba_conf, true);

                    UInt32 rgba_r = NTSmartPublisherSDK.NT_PB_AddLayerConfig(publisher_handle_, 0,
                                    rgba_conf, (int)NTSmartPublisherDefine.NT_PB_E_LAYER_TYPE.NT_PB_E_LAYER_TYPE_RGBA_RECTANGLE,
                                    0, IntPtr.Zero);

                    Console.WriteLine("[摄像头和屏幕相互切换] NT_PB_AddLayerConfig, rgba: " + rgba_r + Environment.NewLine);

                    Marshal.FreeHGlobal(rgba_conf);

                    //第一层:摄像头
                    NT_PB_CameraLayerConfigV2 camera_layer_c1 = new NT_PB_CameraLayerConfigV2();

                    CameraInfo camera = cameras_[cur_sel_camera_index_];
                    NT_PB_VideoCaptureCapability cap = camera.capabilities_[cur_sel_camera_resolutions_index_];

                    camera_layer_c1.device_unique_id_utf8_ = camera.id_;

                    camera_layer_c1.base_.type_ = (Int32)NTSmartPublisherDefine.NT_PB_E_LAYER_TYPE.NT_PB_E_LAYER_TYPE_CAMERA;
                    camera_layer_c1.base_.index_ = 1;
                    camera_layer_index_ = camera_layer_c1.base_.index_;
                    camera_layer_c1.base_.enable_ = 1;
                    camera_layer_c1.base_.region_.x_ = left;
                    camera_layer_c1.base_.region_.y_ = top;
                    camera_layer_c1.base_.region_.width_ = w;
                    camera_layer_c1.base_.region_.height_ = h;

                    if (btn_check_flip_horizontal_camera_.Checked)
                    {
                        camera_layer_c1.is_flip_horizontal_ = 1;
                    }
                    else
                    {
                        camera_layer_c1.is_flip_horizontal_ = 0;
                    }

                    if (btn_check_flip_vertical_camera_.Checked)
                    {
                        camera_layer_c1.is_flip_vertical_ = 1;
                    }
                    else
                    {
                        camera_layer_c1.is_flip_vertical_ = 0;
                    }

                    // 这种叠加模式下不要旋转,否则变形厉害, 要么就定好一个角度,调整宽高,但不要动态旋转
                    camera_layer_c1.rotate_degress_ = 0;

                    camera_layer_c1.base_.offset_ = Marshal.OffsetOf(camera_layer_c1.GetType(), "base_").ToInt32(); //offsetof(T, base_);
                    camera_layer_c1.base_.cb_size_ = (uint)Marshal.SizeOf(camera_layer_c1);

                    IntPtr cmr_conf = Marshal.AllocHGlobal(Marshal.SizeOf(camera_layer_c1));

                    Marshal.StructureToPtr(camera_layer_c1, cmr_conf, true);

                    UInt32 c_r = NTSmartPublisherSDK.NT_PB_AddLayerConfig(publisher_handle_, 0,
                                cmr_conf, (int)NTSmartPublisherDefine.NT_PB_E_LAYER_TYPE.NT_PB_E_LAYER_TYPE_CAMERA,
                                0, IntPtr.Zero);

                    Marshal.FreeHGlobal(cmr_conf);

                    //第二层
                    NT_PB_ScreenLayerConfig screen_layer_c2 = new NT_PB_ScreenLayerConfig();

                    screen_layer_c2.base_.type_ = (Int32)NTSmartPublisherDefine.NT_PB_E_LAYER_TYPE.NT_PB_E_LAYER_TYPE_SCREEN;
                    screen_layer_c2.base_.index_ = 2;
                    screen_layer_index_ = screen_layer_c2.base_.index_;
                    screen_layer_c2.base_.enable_ = 1;
                    screen_layer_c2.base_.region_.x_ = left;
                    screen_layer_c2.base_.region_.y_ = top;
                    screen_layer_c2.base_.region_.width_ = w;
                    screen_layer_c2.base_.region_.height_ = h;

                    screen_layer_c2.base_.offset_ = Marshal.OffsetOf(screen_layer_c2.GetType(), "base_").ToInt32(); //offsetof(T, base_);
                    screen_layer_c2.base_.cb_size_ = (uint)Marshal.SizeOf(screen_layer_c2);

                    screen_layer_c2.clip_region_.x_ = left;
                    screen_layer_c2.clip_region_.y_ = top;
                    screen_layer_c2.clip_region_.width_ = w;
                    screen_layer_c2.clip_region_.height_ = h;

                    screen_layer_c2.reserve_ = IntPtr.Zero;

                    IntPtr scr_conf = Marshal.AllocHGlobal(Marshal.SizeOf(screen_layer_c2));

                    Marshal.StructureToPtr(screen_layer_c2, scr_conf, true);

                    UInt32 s_r = NTSmartPublisherSDK.NT_PB_AddLayerConfig(publisher_handle_, 0,
                                scr_conf, (int)NTSmartPublisherDefine.NT_PB_E_LAYER_TYPE.NT_PB_E_LAYER_TYPE_SCREEN,
                                0, IntPtr.Zero);

                    Marshal.FreeHGlobal(scr_conf);

                    // 第三层填充RGBA矩形, 目的是保证帧率, 颜色就填充全黑
                    red = Int32.Parse(edit_rgba_rect_layer_red_.Text);
                    red = ClipIntValue(red, 0, 255);

                    green = Int32.Parse(edit_rgba_rect_layer_green_.Text);
                    green = ClipIntValue(green, 0, 255);

                    blue = Int32.Parse(edit_rgba_rect_layer_blue_.Text);
                    blue = ClipIntValue(blue, 0, 255);

                    alpha = Int32.Parse(edit_rgba_rect_layer_alpha_.Text);
                    alpha = ClipIntValue(alpha, 0, 255);

                    NT_PB_RGBARectangleLayerConfig rgba_layer_c3 = new NT_PB_RGBARectangleLayerConfig();

                    rgba_layer_c3.base_.type_ = (Int32)NTSmartPublisherDefine.NT_PB_E_LAYER_TYPE.NT_PB_E_LAYER_TYPE_RGBA_RECTANGLE;
                    rgba_layer_c3.base_.index_ = 3;
                    rgba_layer_index_ = rgba_layer_c3.base_.index_;
                    rgba_layer_c3.base_.enable_ = 1;
                    rgba_layer_c3.base_.region_.x_ = left;     //这个只是demo演示,实际以需要遮盖位置为准
                    rgba_layer_c3.base_.region_.y_ = top;
                    rgba_layer_c3.base_.region_.width_ = 160;
                    rgba_layer_c3.base_.region_.height_ = 160;

                    rgba_layer_c3.base_.offset_ = Marshal.OffsetOf(rgba_layer_c3.GetType(), "base_").ToInt32();
                    rgba_layer_c3.base_.cb_size_ = (uint)Marshal.SizeOf(rgba_layer_c3);

                    rgba_layer_c3.red_ = System.BitConverter.GetBytes(red)[0];
                    rgba_layer_c3.green_ = System.BitConverter.GetBytes(green)[0];
                    rgba_layer_c3.blue_ = System.BitConverter.GetBytes(blue)[0];
                    rgba_layer_c3.alpha_ = System.BitConverter.GetBytes(alpha)[0];

                    IntPtr rgba_conf_3 = Marshal.AllocHGlobal(Marshal.SizeOf(rgba_layer_c3));

                    Marshal.StructureToPtr(rgba_layer_c3, rgba_conf_3, true);

                    UInt32 rgba_r_3 = NTSmartPublisherSDK.NT_PB_AddLayerConfig(publisher_handle_, 0,
                                    rgba_conf_3, (int)NTSmartPublisherDefine.NT_PB_E_LAYER_TYPE.NT_PB_E_LAYER_TYPE_RGBA_RECTANGLE,
                                    0, IntPtr.Zero);

                    Console.WriteLine("NT_PB_AddLayerConfig, rgba: " + rgba_r_3 + Environment.NewLine);

                    Marshal.FreeHGlobal(rgba_conf_3);
                    
                    // 第四层填充png水印(注意,实时开启、关闭水印,是根据图层的index来的,如此demo,png水印的index为4)
                    // 如果有图片,增加图片层
                    if (!String.IsNullOrEmpty(image_layer_file_name_utf8_)
                        && image_layer_width_ > 0
                        && image_layer_height_ > 0)
                    {
                        NT_PB_ImageLayerConfig image_layer_c4 = new NT_PB_ImageLayerConfig();

                        image_layer_c4.base_.type_ = (Int32)NTSmartPublisherDefine.NT_PB_E_LAYER_TYPE.NT_PB_E_LAYER_TYPE_IMAGE;
                        image_layer_c4.base_.index_ = 4;
                        image_layer_index_ = image_layer_c4.base_.index_;
                        image_layer_c4.base_.enable_ = 1;
                        image_layer_c4.base_.region_.x_ = image_layer_left_;
                        image_layer_c4.base_.region_.y_ = image_layer_top_;
                        image_layer_c4.base_.region_.width_ = image_layer_width_;
                        image_layer_c4.base_.region_.height_ = image_layer_height_;

                        image_layer_c4.base_.offset_ = Marshal.OffsetOf(image_layer_c4.GetType(), "base_").ToInt32();
                        image_layer_c4.base_.cb_size_ = (uint)Marshal.SizeOf(image_layer_c4);

                        byte[] buffer1 = Encoding.Default.GetBytes(image_layer_file_name_utf8_);
                        byte[] buffer2 = Encoding.Convert(Encoding.UTF8, Encoding.Default, buffer1, 0, buffer1.Length);
                        string strBuffer = Encoding.Default.GetString(buffer2, 0, buffer2.Length);

                        image_layer_c4.file_name_utf8_ = strBuffer;

                        image_layer_c4.is_setting_background_ = 0;
                        image_layer_c4.bk_red_ = 0;
                        image_layer_c4.bk_green_ = 0;
                        image_layer_c4.bk_blue_ = 0;
                        image_layer_c4.reserve_ = 0;

                        IntPtr image_conf = Marshal.AllocHGlobal(Marshal.SizeOf(image_layer_c4));

                        Marshal.StructureToPtr(image_layer_c4, image_conf, true);

                        UInt32 image_r = NTSmartPublisherSDK.NT_PB_AddLayerConfig(publisher_handle_, 0,
                                        image_conf, (int)NTSmartPublisherDefine.NT_PB_E_LAYER_TYPE.NT_PB_E_LAYER_TYPE_IMAGE,
                                        0, IntPtr.Zero);

                        Console.WriteLine("NT_PB_AddLayerConfig, image: " + image_r + Environment.NewLine);

                        Marshal.FreeHGlobal(image_conf);

                        NTSmartPublisherSDK.NT_PB_SetFrameRate(publisher_handle_, UInt32.Parse(edit_frame_rate_.Text));
                    }
                }
                else if (btn_camera_overlay_to_desktop.Checked)
                {
                    //摄像头overlay到桌面
                    int left = Int32.Parse(edit_clip_left_.Text);
                    int top = Int32.Parse(edit_clip_top_.Text);
                    int w = Int32.Parse(edit_clip_width_.Text);
                    int h = Int32.Parse(edit_clip_height_.Text);

			        // 有一个是0, 就使用全屏
			        if ( w == 0 || h == 0 )
			        {
				        left = 0;
				        top = 0;
                        w = screenArea_.Width;
                        h = screenArea_.Height;
			        }
			        else
			        {
				        // 保证4字节对齐
                        w = NT_ByteAlign(w, 4);
                        h = NT_ByteAlign(h, 4);
			        }

                    //第一层:屏幕
                    NT_PB_ScreenLayerConfig screen_layer_c0 = new NT_PB_ScreenLayerConfig();

                    screen_layer_c0.base_.type_ = (Int32)NTSmartPublisherDefine.NT_PB_E_LAYER_TYPE.NT_PB_E_LAYER_TYPE_SCREEN;
                    screen_layer_c0.base_.index_ = 0;
                    screen_layer_index_ = screen_layer_c0.base_.index_;
                    screen_layer_c0.base_.enable_ = 1;
                    screen_layer_c0.base_.region_.x_ = left;
                    screen_layer_c0.base_.region_.y_ = top;
                    screen_layer_c0.base_.region_.width_ = w;
                    screen_layer_c0.base_.region_.height_ = h;

                    screen_layer_c0.base_.offset_ = Marshal.OffsetOf(screen_layer_c0.GetType(), "base_").ToInt32(); //offsetof(T, base_);
                    screen_layer_c0.base_.cb_size_ = (uint)Marshal.SizeOf(screen_layer_c0);

                    screen_layer_c0.clip_region_.x_ = left;
                    screen_layer_c0.clip_region_.y_ = top;
                    screen_layer_c0.clip_region_.width_ = w;
                    screen_layer_c0.clip_region_.height_ = h;

                    screen_layer_c0.reserve_ = IntPtr.Zero;

                    NTSmartPublisherSDK.NT_PB_ClearLayersConfig(publisher_handle_, 0,
                            0, IntPtr.Zero);
                    
                    IntPtr scr_conf = Marshal.AllocHGlobal(Marshal.SizeOf(screen_layer_c0));

                    Marshal.StructureToPtr(screen_layer_c0, scr_conf, true);

                    UInt32 s_r = NTSmartPublisherSDK.NT_PB_AddLayerConfig(publisher_handle_, 0,
                                scr_conf, (int)NTSmartPublisherDefine.NT_PB_E_LAYER_TYPE.NT_PB_E_LAYER_TYPE_SCREEN,
                                0, IntPtr.Zero);

                    Marshal.FreeHGlobal(scr_conf);

                    //第二层:摄像头
                    if (-1 != cur_sel_camera_index_)
                    {
                        int c_l = Int32.Parse(edit_camera_overlay_left_.Text);
                        int c_t = Int32.Parse(edit_camera_overlay_top_.Text);

                        int c_w = Int32.Parse(edit_camera_overlay_width_.Text);
                        int c_h = Int32.Parse(edit_camera_overlay_height_.Text);

                        if (c_w == 0)
                        {
                            c_w = w / 2;
                        }

                        if (c_h == 0)
                        {
                            c_h = h / 2;
                        }

                        ctos_camera_layer_c1_ = new NT_PB_CameraLayerConfigV2();

                        CameraInfo camera = cameras_[cur_sel_camera_index_];
                        NT_PB_VideoCaptureCapability cap = camera.capabilities_[cur_sel_camera_resolutions_index_];

                        ctos_camera_layer_c1_.device_unique_id_utf8_ = camera.id_;

                        ctos_camera_layer_c1_.base_.type_ = (Int32)NTSmartPublisherDefine.NT_PB_E_LAYER_TYPE.NT_PB_E_LAYER_TYPE_CAMERA;
                        ctos_camera_layer_c1_.base_.index_ = 1;
                        camera_layer_index_ = ctos_camera_layer_c1_.base_.index_;
                        ctos_camera_layer_c1_.base_.enable_ = 1;
                        ctos_camera_layer_c1_.base_.region_.x_ = c_l;
                        ctos_camera_layer_c1_.base_.region_.y_ = c_t;
                        ctos_camera_layer_c1_.base_.region_.width_ = c_w;
                        ctos_camera_layer_c1_.base_.region_.height_ = c_h;

                        if (btn_check_flip_horizontal_camera_.Checked)
                        {
                            ctos_camera_layer_c1_.is_flip_horizontal_ = 1;
                        }
                        else
                        {
                            ctos_camera_layer_c1_.is_flip_horizontal_ = 0;
                        }

                        if (btn_check_flip_vertical_camera_.Checked)
                        {
                            ctos_camera_layer_c1_.is_flip_vertical_ = 1;
                        }
                        else
                        {
                            ctos_camera_layer_c1_.is_flip_vertical_ = 0;
                        }

                        ctos_camera_layer_c1_.rotate_degress_ = GetCameraRotateDegress();

                        ctos_camera_layer_c1_.base_.offset_ = Marshal.OffsetOf(ctos_camera_layer_c1_.GetType(), "base_").ToInt32(); //offsetof(T, base_);
                        ctos_camera_layer_c1_.base_.cb_size_ = (uint)Marshal.SizeOf(ctos_camera_layer_c1_);

                        IntPtr cmr_conf = Marshal.AllocHGlobal(Marshal.SizeOf(ctos_camera_layer_c1_));

                        Marshal.StructureToPtr(ctos_camera_layer_c1_, cmr_conf, true);

                        UInt32 c_r = NTSmartPublisherSDK.NT_PB_AddLayerConfig(publisher_handle_, 0,
                                    cmr_conf, (int)NTSmartPublisherDefine.NT_PB_E_LAYER_TYPE.NT_PB_E_LAYER_TYPE_CAMERA,
                                    0, IntPtr.Zero);

                        Marshal.FreeHGlobal(cmr_conf);
                    }
                   
                    NTSmartPublisherSDK.NT_PB_SetFrameRate(publisher_handle_, UInt32.Parse(edit_frame_rate_.Text));
                }
                else if (btn_desktop_overlay_to_camera.Checked)
                {
                    //桌面overlay到摄像头

                    //第一层:摄像头
                    if (-1 != cur_sel_camera_index_
                           && -1 != cur_sel_camera_resolutions_index_
                           && -1 != cur_sel_camera_frame_rate_index_)
                    {
                        NT_PB_CameraLayerConfigV2 camera_layer_c0 = new NT_PB_CameraLayerConfigV2();

                        CameraInfo camera = cameras_[cur_sel_camera_index_];
                        NT_PB_VideoCaptureCapability cap = camera.capabilities_[cur_sel_camera_resolutions_index_];

                        camera_layer_c0.device_unique_id_utf8_ = camera.id_;

                        camera_layer_c0.base_.type_ = (Int32)NTSmartPublisherDefine.NT_PB_E_LAYER_TYPE.NT_PB_E_LAYER_TYPE_CAMERA;
                        camera_layer_c0.base_.index_ = 0;
                        camera_layer_index_ = camera_layer_c0.base_.index_;
                        camera_layer_c0.base_.enable_ = 1;
                        camera_layer_c0.base_.region_.x_ = 0;
                        camera_layer_c0.base_.region_.y_ = 0;
                        camera_layer_c0.base_.region_.width_ = cap.width_;
                        camera_layer_c0.base_.region_.height_ = cap.height_;

                        if (btn_check_flip_horizontal_camera_.Checked)
                        {
                            camera_layer_c0.is_flip_horizontal_ = 1;
                        }
                        else
                        {
                            camera_layer_c0.is_flip_horizontal_ = 0;
                        }

                        if (btn_check_flip_vertical_camera_.Checked)
                        {
                            camera_layer_c0.is_flip_vertical_ = 1;
                        }
                        else
                        {
                            camera_layer_c0.is_flip_vertical_ = 0;
                        }

                        // 这种叠加模式下不要旋转,否则变形厉害, 要么就定好一个角度,调整宽高,但不要动态旋转
                        camera_layer_c0.rotate_degress_ = 0;

                        camera_layer_c0.base_.offset_ = Marshal.OffsetOf(camera_layer_c0.GetType(), "base_").ToInt32(); //offsetof(T, base_);
                        camera_layer_c0.base_.cb_size_ = (uint)Marshal.SizeOf(camera_layer_c0);

                        NTSmartPublisherSDK.NT_PB_ClearLayersConfig(publisher_handle_, 0,
                                        0, IntPtr.Zero);

                        IntPtr cmr_conf = Marshal.AllocHGlobal(Marshal.SizeOf(camera_layer_c0));

                        Marshal.StructureToPtr(camera_layer_c0, cmr_conf, true);

                        UInt32 r = NTSmartPublisherSDK.NT_PB_AddLayerConfig(publisher_handle_, 0,
                                    cmr_conf, (int)NTSmartPublisherDefine.NT_PB_E_LAYER_TYPE.NT_PB_E_LAYER_TYPE_CAMERA,
                                    0, IntPtr.Zero);

                        Marshal.FreeHGlobal(cmr_conf);

                        //第二层:屏幕
                        NT_PB_ScreenLayerConfig screen_layer_c1 = new NT_PB_ScreenLayerConfig();

                        screen_layer_c1.base_.type_ = (Int32)NTSmartPublisherDefine.NT_PB_E_LAYER_TYPE.NT_PB_E_LAYER_TYPE_SCREEN;
                        screen_layer_c1.base_.index_ = 1;
                        screen_layer_index_ = screen_layer_c1.base_.index_;
                        screen_layer_c1.base_.enable_ = 1;
                        screen_layer_c1.base_.region_.x_ = 0;
                        screen_layer_c1.base_.region_.y_ = 0;
                        screen_layer_c1.base_.region_.width_ = cap.width_ / 2;
                        screen_layer_c1.base_.region_.height_ = cap.height_ / 2;

                        screen_layer_c1.base_.offset_ = Marshal.OffsetOf(screen_layer_c1.GetType(), "base_").ToInt32(); //offsetof(T, base_);
                        screen_layer_c1.base_.cb_size_ = (uint)Marshal.SizeOf(screen_layer_c1);

                        screen_layer_c1.clip_region_.x_ = 0;
                        screen_layer_c1.clip_region_.y_ = 0;
                        screen_layer_c1.clip_region_.width_ = cap.width_ / 2;
                        screen_layer_c1.clip_region_.height_ = cap.height_ / 2;

                        screen_layer_c1.reserve_ = IntPtr.Zero;

                        IntPtr scr_conf = Marshal.AllocHGlobal(Marshal.SizeOf(screen_layer_c1));

                        Marshal.StructureToPtr(screen_layer_c1, scr_conf, true);

                        UInt32 s_r = NTSmartPublisherSDK.NT_PB_AddLayerConfig(publisher_handle_, 0,
                                    scr_conf, (int)NTSmartPublisherDefine.NT_PB_E_LAYER_TYPE.NT_PB_E_LAYER_TYPE_SCREEN,
                                    0, IntPtr.Zero);

                        Marshal.FreeHGlobal(scr_conf);
                    }

                    NTSmartPublisherSDK.NT_PB_SetFrameRate(publisher_handle_, (uint)(cur_sel_camera_frame_rate_index_ + 1));
                }
                else if (btn_check_desktop_input_.Checked && btn_check_scale_desktop_.Checked)
                {
                    int left = 0;
                    int top = 0;
                    int w = 0;
                    int h = 0;
                    int scale_w = 0;
                    int scale_h = 0;

                    GetScreenScaleConfigInfo(ref left, ref top, ref w, ref h, ref scale_w, ref scale_h);

                    NTSmartPublisherSDK.NT_PB_ClearLayersConfig(publisher_handle_, 0,
                    0, IntPtr.Zero);

                    // 第0层填充RGBA矩形, 目的是保证帧率, 颜色就填充全黑
                    int red = 0;
                    int green = 0;
                    int blue = 0;   
                    int alpha = 255;

                    NT_PB_RGBARectangleLayerConfig rgba_layer_c0 = new NT_PB_RGBARectangleLayerConfig();

                    rgba_layer_c0.base_.type_ = (Int32)NTSmartPublisherDefine.NT_PB_E_LAYER_TYPE.NT_PB_E_LAYER_TYPE_RGBA_RECTANGLE;
                    rgba_layer_c0.base_.index_ = 0;
                    rgba_layer_index_ = rgba_layer_c0.base_.index_;
                    rgba_layer_c0.base_.enable_ = 1;
                    rgba_layer_c0.base_.region_.x_ = 0;
                    rgba_layer_c0.base_.region_.y_ = 0;
                    rgba_layer_c0.base_.region_.width_ = scale_w;
                    rgba_layer_c0.base_.region_.height_ = scale_h;

                    rgba_layer_c0.base_.offset_ = Marshal.OffsetOf(rgba_layer_c0.GetType(), "base_").ToInt32();
                    rgba_layer_c0.base_.cb_size_ = (uint)Marshal.SizeOf(rgba_layer_c0);

                    rgba_layer_c0.red_   = 0;
                    rgba_layer_c0.green_ = 0;
                    rgba_layer_c0.blue_  = 0;
                    rgba_layer_c0.alpha_ = 255;

                    IntPtr rgba_conf_0 = Marshal.AllocHGlobal(Marshal.SizeOf(rgba_layer_c0));

                    Marshal.StructureToPtr(rgba_layer_c0, rgba_conf_0, true);

                    UInt32 rgba_r_0 = NTSmartPublisherSDK.NT_PB_AddLayerConfig(publisher_handle_, 0,
                                    rgba_conf_0, (int)NTSmartPublisherDefine.NT_PB_E_LAYER_TYPE.NT_PB_E_LAYER_TYPE_RGBA_RECTANGLE,
                                    0, IntPtr.Zero);

                    Console.WriteLine("NT_PB_AddLayerConfig, rgba: " + rgba_r_0 + Environment.NewLine);

                    Marshal.FreeHGlobal(rgba_conf_0);

                    //第1层
                    NT_PB_ScreenLayerConfigV2 screen_layer_c1 = new NT_PB_ScreenLayerConfigV2();

                    screen_layer_c1.base_.type_ = (Int32)NTSmartPublisherDefine.NT_PB_E_LAYER_TYPE.NT_PB_E_LAYER_TYPE_SCREEN;
                    screen_layer_c1.base_.index_ = 1;
                    screen_layer_index_ = screen_layer_c1.base_.index_;
                    screen_layer_c1.base_.enable_ = checkbox_black_screen_.Checked?0:1;
                    screen_layer_c1.base_.region_.x_ = left;
                    screen_layer_c1.base_.region_.y_ = top;
                    screen_layer_c1.base_.region_.width_ = scale_w;
                    screen_layer_c1.base_.region_.height_ = scale_h;

                    screen_layer_c1.base_.offset_ = Marshal.OffsetOf(screen_layer_c1.GetType(), "base_").ToInt32(); //offsetof(T, base_);
                    screen_layer_c1.base_.cb_size_ = (uint)Marshal.SizeOf(screen_layer_c1);

                    screen_layer_c1.clip_region_.x_ = left;
                    screen_layer_c1.clip_region_.y_ = top;
                    screen_layer_c1.clip_region_.width_ = w;
                    screen_layer_c1.clip_region_.height_ = h;

                    screen_layer_c1.reserve1_ = IntPtr.Zero;
                    screen_layer_c1.reserve2_ = 0;
                    screen_layer_c1.scale_filter_mode_ = 3;
                    
                    IntPtr scr_conf = Marshal.AllocHGlobal(Marshal.SizeOf(screen_layer_c1));

                    Marshal.StructureToPtr(screen_layer_c1, scr_conf, true);

                    UInt32 s_r = NTSmartPublisherSDK.NT_PB_AddLayerConfig(publisher_handle_, 0,
                                scr_conf, (int)NTSmartPublisherDefine.NT_PB_E_LAYER_TYPE.NT_PB_E_LAYER_TYPE_SCREEN,
                                0, IntPtr.Zero);

                    Marshal.FreeHGlobal(scr_conf);

                    NTSmartPublisherSDK.NT_PB_SetSleepMode(publisher_handle_, checkbox_black_screen_.Checked ? 1 : 0, 0);

                    NTSmartPublisherSDK.NT_PB_SetFrameRate(publisher_handle_, UInt32.Parse(edit_frame_rate_.Text));
                }
                else if (btn_check_desktop_input_.Checked && !btn_check_scale_desktop_.Checked)
                {
                    //桌面
                    NTSmartPublisherSDK.NT_PB_SetScreenClip(publisher_handle_,
                    UInt32.Parse(edit_clip_left_.Text),
                    UInt32.Parse(edit_clip_top_.Text),
                    UInt32.Parse(edit_clip_width_.Text),
                    UInt32.Parse(edit_clip_height_.Text));

                    NTSmartPublisherSDK.NT_PB_SetFrameRate(publisher_handle_, UInt32.Parse(edit_frame_rate_.Text));
                }
                else if (btn_check_window_input_.Checked)
                {
                    if (IntPtr.Zero != cur_sel_capture_window_)
                    {
                        NTSmartPublisherSDK.NT_PB_SetCaptureWindow(publisher_handle_, cur_sel_capture_window_);

                        NTSmartPublisherSDK.NT_PB_SetFrameRate(publisher_handle_, UInt32.Parse(edit_frame_rate_.Text));

                        NTSmartPublisherSDK.NT_PB_ClearLayersConfig(publisher_handle_, 0, 0, IntPtr.Zero);
                    }
                }
                else if (btn_check_camera_input_.Checked)
                {
                    //摄像头
                    if (-1 != cur_sel_camera_index_
                        && -1 != cur_sel_camera_resolutions_index_
                        && -1 != cur_sel_camera_frame_rate_index_)
                    {
                        CameraInfo camera = cameras_[cur_sel_camera_index_];
                        NT_PB_VideoCaptureCapability cap = camera.capabilities_[cur_sel_camera_resolutions_index_];

                        NTSmartPublisherSDK.NT_PB_SetVideoCaptureDeviceBaseParameter(publisher_handle_,
                            camera.id_.ToString(), (UInt32)cap.width_, (UInt32)cap.height_);

                        NTSmartPublisherSDK.NT_PB_SetFrameRate(publisher_handle_, (UInt32)(cur_sel_camera_frame_rate_index_ + 1));

                        if (btn_check_flip_vertical_camera_.Checked)
                        {
                            NTSmartPublisherSDK.NT_PB_FlipVerticalCamera(publisher_handle_, 1);
                        }
                        else
                        {
                            NTSmartPublisherSDK.NT_PB_FlipVerticalCamera(publisher_handle_, 0);
                        }

                        if (btn_check_flip_horizontal_camera_.Checked)
                        {
                            NTSmartPublisherSDK.NT_PB_FlipHorizontalCamera(publisher_handle_, 1);
                        }
                        else
                        {
                            NTSmartPublisherSDK.NT_PB_FlipHorizontalCamera(publisher_handle_, 0);
                        }

                        Int32 degress = GetCameraRotateDegress();
                        NTSmartPublisherSDK.NT_PB_RotateCamera(publisher_handle_, degress);
                    }
                }

音视频参数设定

其他音视频相关接口参数设定,比是否启用DXGI, Aero模式,软硬编码模式,帧率关键帧间隔码率等设定。

                if (btn_check_dxgi_screen_capturer_.Checked)
                {
                    NTSmartPublisherSDK.NT_PB_EnableDXGIScreenCapturer(publisher_handle_, 1);
                }
                else
                {
                    NTSmartPublisherSDK.NT_PB_EnableDXGIScreenCapturer(publisher_handle_, 0);
                }

                if (check_capture_layered_window_.Checked)
                {
                    NTSmartPublisherSDK.NT_PB_EnableScreenCaptureLayeredWindow(publisher_handle_, 1);
                }
                else
                {
                    NTSmartPublisherSDK.NT_PB_EnableScreenCaptureLayeredWindow(publisher_handle_, 0);
                }

                if (btn_check_capturer_disable_aero_.Checked)
                {
                    NTSmartPublisherSDK.NT_PB_DisableAeroScreenCapturer(publisher_handle_, 1);
                }
                else
                {
                    NTSmartPublisherSDK.NT_PB_DisableAeroScreenCapturer(publisher_handle_, 0);
                }

                if (btn_check_wr_way_capture_window_.Checked)
                {
                    NTSmartPublisherSDK.NT_PB_SetCaptureWindowWay(publisher_handle_, 2);
                }
                else
                {
                    NTSmartPublisherSDK.NT_PB_SetCaptureWindowWay(publisher_handle_, 1);
                }

                int cur_video_codec_id = (int)NTCommonMediaDefine.NT_MEDIA_CODEC_ID.NT_MEDIA_CODEC_ID_H264;

                if (btn_check_h265_encoder_.Checked)
                {
                    cur_video_codec_id = (int)NTCommonMediaDefine.NT_MEDIA_CODEC_ID.NT_MEDIA_CODEC_ID_H265;
                }

                bool is_hw_encoder = false;

                if ( btn_check_video_hardware_encoder_.Checked)
                {
                    is_hw_encoder = true;
                }

                Int32 cur_sel_encoder_id = 0;
                Int32 cur_sel_gpu = 0;


                if (is_hw_encoder)
                {
                    int cur_sel_hw = combobox_video_encoders_.SelectedIndex;
                    if (cur_sel_hw >= 0)
                    {
                        cur_sel_encoder_id = Convert.ToInt32(combobox_video_encoders_.SelectedValue);
                        cur_sel_gpu = -1;

                        int cur_sel_hw_dev = combobox_video_hardware_encoder_devices_.SelectedIndex;
                        if (cur_sel_hw_dev >= 0)
                        {
                            cur_sel_gpu = Convert.ToInt32(combobox_video_hardware_encoder_devices_.SelectedValue);
                        }
                    }
                    else
                    {
                        is_hw_encoder = false;
                    }
                }

                if (!is_hw_encoder)
                {
                    if ((int)NTCommonMediaDefine.NT_MEDIA_CODEC_ID.NT_MEDIA_CODEC_ID_H264 == cur_video_codec_id)
                    {
                        cur_sel_encoder_id = btn_check_openh264_encoder_.Checked ? 1 : 0;
                    }
                }

                NTSmartPublisherSDK.NT_PB_SetVideoEncoder(publisher_handle_, (int)(is_hw_encoder ? 1 : 0), (int)cur_sel_encoder_id, (uint)cur_video_codec_id, (int)cur_sel_gpu);

                if (!btn_check_window_input_.Checked)
                {
                    NTSmartPublisherSDK.NT_PB_SetVideoBitRate(publisher_handle_, Int32.Parse(edit_bit_rate_.Text));
                }
                else
                {
                    // 窗口的分辨率会变, 所以设置一组码率下去
                    Int32 frame_rate = Int32.Parse(edit_bit_rate_.Text);
                    SetBitrateGroup(publisher_handle_, frame_rate);
                }

                NTSmartPublisherSDK.NT_PB_SetVideoQualityV2(publisher_handle_, Int32.Parse(edit_video_quality_.Text));

                NTSmartPublisherSDK.NT_PB_SetVideoMaxBitRate(publisher_handle_, Int32.Parse(edit_video_max_bitrate_.Text));

                NTSmartPublisherSDK.NT_PB_SetVideoKeyFrameInterval(publisher_handle_, Int32.Parse(edit_key_frame_.Text));

                if (cur_video_codec_id == (int)NTCommonMediaDefine.NT_MEDIA_CODEC_ID.NT_MEDIA_CODEC_ID_H264)
                {
                    int profile_sel = combox_h264_profile_.SelectedIndex;

                    if (profile_sel != -1)
                    {
                        NTSmartPublisherSDK.NT_PB_SetVideoEncoderProfile(publisher_handle_, profile_sel + 1);
                    }
                }

                NTSmartPublisherSDK.NT_PB_SetVideoEncoderSpeed(publisher_handle_, Int32.Parse(edit_video_encode_speed_.Text));

                // 清除编码器所有的特定的参数
                NTSmartPublisherSDK.NT_PB_ClearVideoEncoderSpecialOptions(publisher_handle_);

                if (cur_sel_encoder_id == 1)
                {
                    // qp_max 和 qp_min 当前只对openh264有效, 这里也就只在openh264使用的场景下设置配置值
                    NTSmartPublisherSDK.NT_PB_SetVideoEncoderQPMax(publisher_handle_, Int32.Parse(edit_qp_max_.Text));
                    NTSmartPublisherSDK.NT_PB_SetVideoEncoderQPMin(publisher_handle_, Int32.Parse(edit_qp_min_.Text));

                    // openh264 配置特定参数
                    NTSmartPublisherSDK.NT_PB_SetVideoEncoderSpecialInt32Option(publisher_handle_, "usage_type", btn_check_openh264_ppt_usage_type_.Checked ? 1 : 0);
                    NTSmartPublisherSDK.NT_PB_SetVideoEncoderSpecialInt32Option(publisher_handle_, "rc_mode", btn_check_openh264_rc_bitrate_mode_.Checked ? 1 : 0);
                    NTSmartPublisherSDK.NT_PB_SetVideoEncoderSpecialInt32Option(publisher_handle_, "enable_frame_skip", btn_check_openh264_frame_skip_.Checked ? 1 : 0);
                }
                else
                {
                    NTSmartPublisherSDK.NT_PB_SetVideoEncoderQPMax(publisher_handle_, -1);
                    NTSmartPublisherSDK.NT_PB_SetVideoEncoderQPMin(publisher_handle_, -1);
                }

                // 音频相关设置
                if (btn_check_auido_mic_input_.Checked)
                {
                    int count = combox_auido_input_devices_.Items.Count;
                    if (count != -1 && count > 0)
                    {
                        int cur_sel = combox_auido_input_devices_.SelectedIndex;
                        if (cur_sel != -1)
                        {
                            NTSmartPublisherSDK.NT_PB_SetAuidoInputDeviceId(publisher_handle_, (uint)cur_sel);
                        }
                    }
                }

                // 只采集扬声器时做静音补偿
                if (!btn_check_auido_mic_input_.Checked
                    && btn_check_auido_speaker_input_.Checked)
                {
                    NTSmartPublisherSDK.NT_PB_SetCaptureSpeakerCompensateMute(publisher_handle_, 1);
                }

                if (btn_check_speex_encoder_.Checked)
                {
                    NTSmartPublisherSDK.NT_PB_SetPublisherAudioCodecType(publisher_handle_, 2);

                    NTSmartPublisherSDK.NT_PB_SetPublisherSpeexEncoderQuality(publisher_handle_, Int32.Parse(edit_speex_quality_.Text));
                }
                else
                {
                    NTSmartPublisherSDK.NT_PB_SetPublisherAudioCodecType(publisher_handle_, 1);
                }

                if (btn_check_auido_mic_input_.Checked
                    || btn_check_auido_speaker_input_.Checked)
                {
                    if (btn_check_set_mute_.Checked)
                    {
                        NTSmartPublisherSDK.NT_PB_SetMute(publisher_handle_, 1);
                    }
                }

                if (btn_check_echo_cancel_.Checked)
                {
                    NTSmartPublisherSDK.NT_PB_SetEchoCancellation(publisher_handle_, 1, Int32.Parse(edit_echo_delay_.Text));
                }
                else
                {
                    NTSmartPublisherSDK.NT_PB_SetEchoCancellation(publisher_handle_, 0, 0);
                }

                if (btn_check_noise_suppression_.Checked)
                {
                    NTSmartPublisherSDK.NT_PB_SetNoiseSuppression(publisher_handle_, 1);
                }
                else
                {
                    NTSmartPublisherSDK.NT_PB_SetNoiseSuppression(publisher_handle_, 0);
                }

                if (btn_check_agc_.Checked)
                {
                    NTSmartPublisherSDK.NT_PB_SetAGC(publisher_handle_, 1);
                }
                else
                {
                    NTSmartPublisherSDK.NT_PB_SetAGC(publisher_handle_, 0);
                }

                if (btn_check_vad_.Checked)
                {
                    NTSmartPublisherSDK.NT_PB_SetVAD(publisher_handle_, 1);
                }
                else
                {
                    NTSmartPublisherSDK.NT_PB_SetVAD(publisher_handle_, 0);
                }

                if (btn_check_auido_mic_input_.Checked
                    && btn_check_auido_speaker_input_.Checked)
                {
                    NTSmartPublisherSDK.NT_PB_SetInputAudioVolume(publisher_handle_, 0, Convert.ToSingle(edit_audio_input_volume_.Text));
                    NTSmartPublisherSDK.NT_PB_SetInputAudioVolume(publisher_handle_, 1, Convert.ToSingle(edit_audio_speaker_input_volume_.Text));
                }
                else if (btn_check_auido_mic_input_.Checked)
                {
                    NTSmartPublisherSDK.NT_PB_SetInputAudioVolume(publisher_handle_, 0, Convert.ToSingle(edit_audio_input_volume_.Text));
                }
                else if (btn_check_auido_speaker_input_.Checked)
                {
                    NTSmartPublisherSDK.NT_PB_SetInputAudioVolume(publisher_handle_, 0, Convert.ToSingle(edit_audio_speaker_input_volume_.Text));
                }

获取视频码率默认值,不是每个开发者都有音视频开发背景,如果不想自行设置码率等一些参数,可参考我们的码率设定。

       private void FillBitrateControlDefValue()
        {
            int w = 640, h = 480;
            int frame_rate = 5;
            bool is_var_bitrate = false;

            GetVideoConfigInfo(ref w, ref h, ref frame_rate, ref is_var_bitrate);

            if (btn_check_openh264_encoder_.Checked)
            {
                is_var_bitrate = false;
            }

            int kbit_rate = CalBitRate(frame_rate, w, h);
            int max_kbit_rate = CalMaxKBitRate(frame_rate, w, h, is_var_bitrate);

            if (is_var_bitrate)
            {
                btn_check_video_bitrate_.CheckState = CheckState.Unchecked;
            }
            else
            {
                btn_check_video_bitrate_.CheckState = CheckState.Checked;
            }

            if (is_var_bitrate)
            {
                edit_bit_rate_.Enabled = false;
                edit_video_quality_.Enabled = true;
            }
            else
            {
                edit_bit_rate_.Enabled = true;
                edit_video_quality_.Enabled = false;
            }

            if (btn_check_video_bitrate_.Checked)
            {
                edit_bit_rate_.Text = kbit_rate.ToString();
                edit_video_max_bitrate_.Text = max_kbit_rate.ToString();
            }
            else
            {
                edit_bit_rate_.Text = "0";
                edit_video_max_bitrate_.Text = max_kbit_rate.ToString();
            }

            bool is_h264 = false;

            if (btn_check_h265_encoder_.Checked)
            {
                is_h264 = false;
            }
            else
            {
                is_h264 = true;
            }

            edit_video_quality_.Text = CalVideoQuality(w, h, is_h264).ToString();

            combox_h264_profile_.SelectedIndex = 2;

            edit_video_encode_speed_.Text = CalVideoEncoderSpeed(w, h, is_h264).ToString();

            // 默认关键帧间隔设置为帧率的2倍
            edit_key_frame_.Text = (frame_rate * 2).ToString();
        }

开始推送

设置推送URL后,调用StartPublisher接口开始推流,如需发送扩展SEI用户数据,推送之前设置下数据发送对接大小。

            if (publisher_handle_ == IntPtr.Zero)
            {
                MessageBox.Show("[publish] handle with null");
            }
            if (!String.IsNullOrEmpty(url))
	        {
                NTSmartPublisherSDK.NT_PB_SetURL(publisher_handle_, url, IntPtr.Zero);
	        }

            //设置用户数据发送队列大小
            NTSmartPublisherSDK.NT_PB_SetPostUserDataQueueMaxSize(publisher_handle_, 3, 0);

            if (NTBaseCodeDefine.NT_ERC_OK != NTSmartPublisherSDK.NT_PB_StartPublisher(publisher_handle_, IntPtr.Zero))
            {
                if (0 == publisher_handle_count_)
                {
                    NTSmartPublisherSDK.NT_PB_Close(publisher_handle_);
                    publisher_handle_ = IntPtr.Zero;
                }

                is_publishing_ = false;

                MessageBox.Show("调用推流接口失败");

                return;
            }

停止推送

调用NT_PB_StopPublisher()即可,停止推送后,如果没有录像等,可调用NT_PB_Close()接口,关掉实例,并把handle置 IntPtr.Zero。

        private void btn_stop_publish_Click(object sender, EventArgs e)
        {
            publisher_handle_count_--;
            NTSmartPublisherSDK.NT_PB_StopPublisher(publisher_handle_);

            rtmp_play_urls_.Clear();
            UpdateDisplayURLs();

            if (0 == publisher_handle_count_)
            {
                NTSmartPublisherSDK.NT_PB_Close(publisher_handle_);
                publisher_handle_ = IntPtr.Zero;
            }

            btn_publish.Enabled = true;
            btn_stop_publish.Enabled = false;

            is_publishing_ = false;

            if (0 == publisher_handle_count_)
            {
                if (btn_check_desktop_input_.Checked)
                {
                    btn_choose_screen_region_.Text = "选择屏幕区域";
                }

                btn_check_dxgi_screen_capturer_.Enabled = true;
                check_capture_layered_window_.Enabled = true;

                btn_check_wr_way_capture_window_.Enabled = true;

                btn_desktop_camera_switch_.Text = "切换到摄像头";
                btn_disable_image_watermark_.Text = "停止水印";
                btn_disable_camera_overlay_.Text = "停止叠加摄像头";
                btn_disable_desktop_overlay_.Text = "停止叠加屏幕";

                btn_desktop_camera_switch.Enabled = true;
                btn_camera_overlay_to_desktop.Enabled = true;
                btn_desktop_overlay_to_camera.Enabled = true;
                btn_desktop_camera_switch.Enabled = true;

                btn_check_desktop_input_.Enabled = true;
                btn_check_scale_desktop_.Enabled = true;
                edit_desktop_scale_.Enabled = true;
                btn_check_camera_input_.Enabled = true;

                btn_add_image_watermark_.Enabled = true;

                timer_clock_.Enabled = false;

                if (btn_desktop_camera_switch.Checked
                    || btn_camera_overlay_to_desktop.Checked
                    || btn_desktop_overlay_to_camera.Checked)
                {
                    btn_check_desktop_input_.CheckState = CheckState.Checked;
                    btn_check_camera_input_.CheckState = CheckState.Checked;
                }
                else
                {
                }

                EnableAuidoInputControl();
            }
        }

预览推送数据

设置NT_PB_SetVideoPreviewImageCallBack(),调用NT_PB_StartPreview()接口即可。

        private void btn_preview_Click(object sender, EventArgs e)
        {
            if (btn_check_window_input_.Checked)
            {
                if (IntPtr.Zero == cur_sel_capture_window_)
                {
                    MessageBox.Show("请先下拉选择采集窗口");
                    return;
                }
            }

            if (publisher_handle_ == IntPtr.Zero)
            {
                if (!OpenPublisherHandle())
                {
                    return;
                }
            }

            if (publisher_handle_count_ < 1)
            {
                SetCommonOptionToPublisherSDK();
            }

            video_preview_image_callback_ = new NT_PB_SDKVideoPreviewImageCallBack(SDKVideoPreviewImageCallBack);

            NTSmartPublisherSDK.NT_PB_SetVideoPreviewImageCallBack(publisher_handle_, (int)NTSmartPublisherDefine.NT_PB_E_IMAGE_FORMAT.NT_PB_E_IMAGE_FORMAT_RGB32, IntPtr.Zero, video_preview_image_callback_);

            if (NTBaseCodeDefine.NT_ERC_OK != NTSmartPublisherSDK.NT_PB_StartPreview(publisher_handle_, 0, IntPtr.Zero))
            {
                if (0 == publisher_handle_count_)
                {
                    NTSmartPublisherSDK.NT_PB_Close(publisher_handle_);
                    publisher_handle_ = IntPtr.Zero;
                }

                 MessageBox.Show("预览失败, 请确保选择了视频采集选项");
                return;
            }

            publisher_handle_count_++;

            btn_preview.Enabled = false;
            btn_stop_preview.Enabled = true;

            if (1 == publisher_handle_count_)
            {
                if (btn_check_desktop_input_.Checked)
                {
                    btn_choose_screen_region_.Text = "移动屏幕区域";
                }

                btn_check_dxgi_screen_capturer_.Enabled = false;
                check_capture_layered_window_.Enabled = false;

                btn_check_wr_way_capture_window_.Enabled = false;

                btn_desktop_camera_switch.Enabled = false;
                btn_camera_overlay_to_desktop.Enabled = false;
                btn_desktop_overlay_to_camera.Enabled = false;

                btn_add_image_watermark_.Enabled = false;

                if (btn_desktop_camera_switch.Checked
                    || btn_camera_overlay_to_desktop.Checked
                    || btn_desktop_overlay_to_camera.Checked)
                {

                }
                else
                {
                    btn_check_desktop_input_.Enabled = false;
                    btn_check_camera_input_.Enabled = false;
                }

                DisableAuidoInputControl();
            }

            if (ui_preview_wnd_ == null)
            {
                ui_preview_wnd_ = new nt_pb_ui_preview_wnd();
            }

            ui_preview_wnd_.Show();
        }

        public void VideoPreviewImageCallBack(NT_VideoFrame frame)
        {
            if (cur_image_.plane_ != IntPtr.Zero)
            {
                Marshal.FreeHGlobal(cur_image_.plane_);
                cur_image_.plane_ = IntPtr.Zero;
            }

            cur_image_ = frame;

            if (ui_preview_wnd_ != null)
            {
                ui_preview_wnd_.OnRGBXImage(cur_image_);
            }
        }

        public void SDKVideoPreviewImageCallBack(IntPtr handle, IntPtr user_data, IntPtr image)
        {
            NT_PB_Image pb_image = (NT_PB_Image)Marshal.PtrToStructure(image, typeof(NT_PB_Image));

            NT_VideoFrame pVideoFrame = new NT_VideoFrame();

            pVideoFrame.width_ = pb_image.width_;
            pVideoFrame.height_ = pb_image.height_;

            pVideoFrame.stride_ = pb_image.stride_[0];

            Int32 argb_size = pb_image.stride_[0] * pb_image.height_;
            
            pVideoFrame.plane_ = Marshal.AllocHGlobal(argb_size);

            CopyMemory(pVideoFrame.plane_, pb_image.plane_[0], (UInt32)argb_size);

            if (InvokeRequired)
            {
                BeginInvoke(set_video_preview_image_callback_, pVideoFrame);
            }
            else
            {
                set_video_preview_image_callback_(pVideoFrame);
            }
        }

停止预览更简单,调用NT_PB_StopPreview()。

        private void btn_stop_preview_Click(object sender, EventArgs e)
        {
            publisher_handle_count_--;
            NTSmartPublisherSDK.NT_PB_StopPreview(publisher_handle_);

            if (0 == publisher_handle_count_)
            {
                NTSmartPublisherSDK.NT_PB_Close(publisher_handle_);
                publisher_handle_ = IntPtr.Zero;
            }

            btn_preview.Enabled = true;
            btn_stop_preview.Enabled = false;

            if (0 == publisher_handle_count_)
            {
                if (btn_check_desktop_input_.Checked)
                {
                    btn_choose_screen_region_.Text = "选择屏幕区域";
                }

                btn_check_dxgi_screen_capturer_.Enabled = true;
                check_capture_layered_window_.Enabled = true;

                btn_check_wr_way_capture_window_.Enabled = true;

                btn_desktop_camera_switch_.Text = "切换到摄像头";
                btn_disable_image_watermark_.Text = "停止水印";
                btn_disable_camera_overlay_.Text = "停止叠加摄像头";
                btn_disable_desktop_overlay_.Text = "停止叠加屏幕";

                btn_desktop_camera_switch.Enabled = true;
                btn_camera_overlay_to_desktop.Enabled = true;
                btn_desktop_overlay_to_camera.Enabled = true;
                btn_desktop_camera_switch.Enabled = true;

                btn_check_desktop_input_.Enabled = true;
                btn_check_camera_input_.Enabled = true;

                btn_add_image_watermark_.Enabled = true;

                timer_clock_.Enabled = false;

                if (btn_desktop_camera_switch.Checked
                    || btn_camera_overlay_to_desktop.Checked
                    || btn_desktop_overlay_to_camera.Checked)
                {
                    btn_check_desktop_input_.CheckState = CheckState.Checked;
                    btn_check_camera_input_.CheckState = CheckState.Checked;
                }
                else
                {
                }

                EnableAuidoInputControl();
            }

            ui_preview_wnd_.Hide();
            ui_preview_wnd_ = null;
        }

实时截图

            if (String.IsNullOrEmpty(capture_image_path_))
            {
                MessageBox.Show("请先设置保存截图文件的目录! 点击截图左边的按钮设置!");
                return;
            }

            if (publisher_handle_ == IntPtr.Zero)
            {
                return;
            }

            String name = capture_image_path_ + "\\" + DateTime.Now.ToString("hh-mm-ss") + ".png";

            byte[] buffer1 = Encoding.Default.GetBytes(name);
            byte[] buffer2 = Encoding.Convert(Encoding.Default, Encoding.UTF8, buffer1, 0, buffer1.Length);

            byte[] buffer3 = new byte[buffer2.Length + 1];
            buffer3[buffer2.Length] = 0;

            Array.Copy(buffer2, buffer3, buffer2.Length);

            IntPtr file_name_ptr = Marshal.AllocHGlobal(buffer3.Length);
            Marshal.Copy(buffer3, 0, file_name_ptr, buffer3.Length);

            capture_image_call_back_ = new NT_PB_SDKCaptureImageCallBack(SDKCaptureImageCallBack);

            UInt32 ret = NTSmartPublisherSDK.NT_PB_CaptureImage(publisher_handle_, file_name_ptr, IntPtr.Zero, capture_image_call_back_);

            Marshal.FreeHGlobal(file_name_ptr);

            if (NT.NTBaseCodeDefine.NT_ERC_OK == ret)
            {
                // 发送截图请求成功
            }
            else if ((UInt32)NT.NTSmartPublisherDefine.NT_PB_E_ERROR_CODE.NT_ERC_PB_TOO_MANY_CAPTURE_IMAGE_REQUESTS == ret)
            {
                // 通知用户延时
                MessageBox.Show("Too many capture image requests!");
            }
            else
            {
                // 其他失败
            }

       private void ImageCallBack(UInt32 result, String file_name)
        {
            if (file_name == null && file_name.Length == 0)
                return;

            MessageBox.Show(file_name);
        }

        public void SDKCaptureImageCallBack(IntPtr handle, IntPtr userData, UInt32 result, IntPtr file_name)
        {
            if (file_name == IntPtr.Zero)
                return;

            int index = 0;

            while (true)
            {
                if (0 == Marshal.ReadByte(file_name, index))
                    break;

                index++;
            }

            byte[] file_name_buffer = new byte[index];

            Marshal.Copy(file_name, file_name_buffer, 0, index);

            byte[] dst_buffer = Encoding.Convert(Encoding.UTF8, Encoding.Default, file_name_buffer, 0, file_name_buffer.Length);
            String image_name = Encoding.Default.GetString(dst_buffer, 0, dst_buffer.Length);

            if (InvokeRequired)
            {
                BeginInvoke(set_capture_image_call_back_, result, image_name);
            }
            else
            {
                set_capture_image_call_back_(result, image_name);
            }
        }

问答式参考

1视频采集设置

说明:

1. 屏幕和摄像头相互切换:用于在线教育或者无纸化等场景,推送或录像过程中,随时切换屏幕或摄像头数据(切换数据源),如需实时切换,点击页面“切换到摄像头”按钮即可;

2. 设置遮盖层,用于设定一个长方形或正方形区域(可自指定区域大小),遮盖不想给用户展示的部分;

3. 水印:添加PNG水印,支持推送或录像过程中,随时添加、取消水印;

4. 摄像头叠加到屏幕:意在用于同屏过程中,主讲人摄像头悬浮于屏幕之上(可指定叠加坐标),实现双画面展示,推送或录像过程中,可以随时取消摄像头叠加;

5. 屏幕叠加到摄像头:同4,效果展示,实际根据需求实现;

6. 采集桌面:可以通过点击“选择屏幕区域”获取采集区域,并可在采集过程中,随时切换区域位置,如不设定,默认全屏采集;

7. 使用DXGI采集屏幕,采集时停用Aero;

8. 采集窗口:可设定需要采集的窗口,窗口放大或缩小,推送端会自适应码率和分辨率;

9. 采集帧率(帧/秒):默认屏幕采集12帧,可根据实际场景需求设定到期望帧率;

10. 缩放屏幕大小缩放比:用于高清或超高清屏,通过设定一定的比例因子,缩放屏幕采集分辨率;

11. 采集摄像头:可选择需要采集的摄像头、采集分辨率、帧率、是否需要水平或者垂直反转、是否需要旋转;

追加提问:

问题[确认数据源]:采集桌面还是摄像头?如果桌面,全屏还是部分区域?

回答:

如果是摄像头:可以选择摄像头列表,然后分辨率、帧率。

如果是屏幕:默认帧率是12帧,可以根据实际场景调整,选取屏幕区域,可以实时拉取选择需要采集或录像区域;

如果是叠加模式:可选择摄像头叠加到屏幕,还是屏幕叠加到摄像头;

更高需求的用户,可以设置水印或应用层遮盖。

问题:如果是摄像头,采集到的摄像头角度不对怎么办?

回答:我们支持摄像头镜像和翻转设置,摄像头可通过SDK接口轻松实现水平/垂直翻转、镜像效果。

2 视频码率控制

如何选择适合我的码率

回答:如果不是有音视频背景的开发人员,可点击“获取视频码率默认值”,参考我们默认的码率推荐,如果觉得推荐码率过高或不够,可根据实际情况酌情调整。

265编码还是H.264编码?

回答:Windows平台支持H.265特定机型硬编码,如果推RTMP流,需要服务器支持RTMP H.265扩展,播放器SDK,也需要同步支持RTMP H.265扩展播放。

如果是轻量级RTSP服务SDK对接的话,只需要播放器支持RTSP H.265即可。

如果推摄像头数据,建议采用可变码率+H.265编码。

如何设置码率参数更合理?

回答:

关键帧间隔:一般来说,设置到帧率的2-4倍,比如帧率20,关键帧间隔可以设置到40-80;

平均码率:可以点击“获取视频码率默认值”,最大码率是平均码率的2倍;

视频质量:如果使用可变码率,建议采用大牛直播SDK默认推荐视频质量值;

编码速度:如高分辨率,建议1-3,值越小,编码速度越快;

H.264 Profile:默认baseline profile,可根据需要,酌情设置High profile;

NOTE:点击“推送”或“录像”或启动内置RTSP服务SDK之前,请务必设置视频码率,如不想手动设置,请点击“获取视频码率默认值”!!!

3 音频采集设置

问答式:采集音频吗?如果采集,采集麦克风还是扬声器的,亦或混音?

回答:

如果想采集电脑输出的音频(比如音乐之类),可以选择“采集扬声器”;

如果想采集麦克风音频,可以选择“采集麦克风”,并选择相关设备;

如果两个都想采集,可以两个都选择,混音输出。

4 实时音量调节

问答式:采集过程中可以改变麦克风或扬声器采集音量吗?

回答:可以,如果二者都选中,处于混音模式,也可单独调整麦克风或扬声器音量。

5 音频编码

问题:是AAC还是SPEEX?

回答:我们默认是AAC编码模式,如果需要码率更低,可以选择SPEEX编码模式,当然我们的AAC编码码率也不高,如果没有太高要求,考虑到通用性,建议使用AAC。

6 音频处理

问题:我想过滤背景噪音怎么办?

回答:选中“噪音抑制”,“噪音抑制“请和“自动增益控制”组合使用,“端点检测(VAD)”可选设置。

问题:我想做一对一互动怎么办?

回答:选中“回音消除”,可以和“噪音抑制”、“自动增益控制”组合使用,具体可参看回音消除的demo工程:WIN-EchoCancellation-CSharp-Demo。

问题:我推送或者录像过程中,随时静音怎么办?

回答:推送过程中,随时选择或取消选择“静音”功能。

7多路推送

问题:我想同时推送到多个url怎么办(比如一个内网服务器,一个外网服务器)?

回答:同时填写多个url(最多3个),然后点推送即可。

8 截图(快照)

问题:我想推送或者录像过程中,截取当前图像怎么办?

回答:那就设置好截图路径,推送或录像过程中,随时点击“截图”。

9 录像

问题:我还想录像,怎么办?

回答:设置录像文件存放目录,文件前缀、单个文件大小,是否加日期、时间,随时录制即可,此外,我们的SDK还支持录像过程中,暂停录像,恢复录像。

10 实时预览

问题:我还想看看推出去视频特别是合成后的效果,怎么办?

回答:点击页面的“预览”按钮,就可以看到。

 

[Android]大牛直播SDK基于unity3d平台的rtmp/rtsp直播播放端SDK接口说明

1.1 demo说明

  • SmartU3dAndroidPlayer: 大牛直播SDK Unity3D Android RTMP/RTSP直播播放端工程。

1.2 功能说明

标准接口:

  • 音频:AAC/G.711/speex;
  • 视频:264;
  • 播放协议:RTMP/RTSP;
  • 支持RTSP TCP/UDP模式切换;
  • 支持纯音频、纯视频、音视频播放;
  • 支持秒开模式;
  • 音视频多种render机制;
  • 支持buffer设置;
  • 真正靠谱的超低延迟;
  • 支持多实例播放;
  • 支持播放url快速切换;
  • 断网自动重连,支持视频追赶;
  • 支持视频video实时旋转。

增值接口:

  • 同时支持rtsp、rtmp播放;
  • 播放过程中,实时静音、取消静音;
  • 播放端回调YUV,供unity3d调用完成绘制;
  • 实时快照;
  • 实时录像。

1.3集成说明

  • Unity3D接口和调用demo,参见:SmartPlayerAndroidMono.cs
  • SmartU3dAndroidPlayer\Assets\Plugins\Android\libs下相关库到工程:
  • Smartavengine.jar加入到工程;
  • smartplayerunity3d.jar加入工程;
  • libs\arm64-v8a 和 SmartPlayer\libs\armeabi 下 libSmartPlayer.so。
  • 在SmartU3dAndroidPlayer\Assets\Plugins\Android\AndroidManifest.xml配置相关权限:

<uses-permission android:name=”android.permission.WRITE_EXTERNAL_STORAGE” > </uses-permission>

<uses-permission android:name=”android.permission.INTERNET” ></uses-permission>

<uses-permission android:name=”android.permission.MOUNT_UNMOUNT_FILESYSTEMS” />

<uses-permission android:name=”android.permission.MODIFY_AUDIO_SETTINGS” />

  • 如需集成到自己系统测试,请用大牛直播SDK的app name(不然集成提示license failed),正式授权版按照授权app name正常使用即可:
  • 如何改app-name:
  • Unity3D模式下:File–>Build Settings–>Android–>Player Settings,设置Product Name。

1.4 调用时序(V2)

  1. 【最先调用】NT_U3D_Init:player初始化,目前预留;
  2. 【获得player句柄】NT_U3D_Open,设置上下文信息,返回player句柄;
  3. 【设置GameObject】NT_U3D_Set_Game_Object,注册Game Object,用于消息传递;
  4. 【设置硬解码】NT_U3D_SetVideoDecoderMode,设置是否用硬解码播放,如硬解码不支持,自动适配到软解码;
  5. 【audio输出类型】NT_U3D_SetAudioOutputType(),如果use_audiotrack设置为0,将会自动选择输出设备,如果设置为1,使用audiotrack模式;
  6. 【缓冲设置】NT_U3D_SetBuffer,设置播放端缓存数据buffer,以毫秒(ms)为单位,如超低延迟模式下,不需buffer数据,设置为0;
  7. 【RTSP TCP/UDP设置】NT_U3D_SetRTSPTcpMode,设置TCP/UDP播放模式,注意:此接口仅用于RTSP;
  8. 【实时静音-可实时调用】NT_U3D_SetMute,设置播放过程中,实时静音/取消静音;
  9. 【快速启动】NT_U3D_SetFastStartup,Set fast startup(快速启动),设置快速启动后,如果CDN缓存GOP,daniulive player可快速出帧;
  10. 【低延迟模式】NT_U3D_SetPlayerLowLatencyMode,针对类似于直播娃娃机等期待超低延迟的使用场景,超低延迟播放模式下,延迟甚至可达到200~400ms;
  11. 【视频显示角度设置-可实时调用】NT_U3D_SetRotation,针对类似于安防摄像头或其他设备出来的图像倒置现象,支持视频播放view顺时针旋转, 当前支持 0度,90度, 180度, 270度 旋转,注意除了0度之外, 其他角度都会额外消耗性能;
  12. 【下载速度回调设置】NT_U3D_SetReportDownloadSpeed,设置下载速度上报, 默认不上报下载速度;
  13. 【快照设置】NT_U3D_SetSaveImageFlag(),设置是否需要在播放或录像过程中快照;
  14. 【快照-录像或播放后,可随时调用】NT_U3D_SaveCurImage,播放过程中,根据设置路径和文件名,实时快照;
  15. 【快速切换url-可实时调用】NT_U3D_SwitchPlaybackUrl,快速切换播放url,快速切换时,只换播放source部分,适用于不同数据流之间,快速切换(如娃娃机双摄像头切换或高低分辨率流切换);
  16. 【录像设置】NT_U3D_CreateFileDirectory,创建文件路径;
  17. 【录像设置】NT_U3D_SetRecorderDirectory,设置文件路径;
  18. 【录像设置】NT_U3D_SetRecorderFileMaxSize,设置每个录像文件最大size,以兆(M)为单位,范围(5M~500M);
  19. 【设置播放或录像URL】NT_U3D_SetUrl,设置播放/录像url;
  20. 【播放】NT_U3D_StartPlay,开始播放;
  21. 【播放】NT_U3D_GetVideoFrame,获取底层回调的YUV数据;
  22. 【播放】NT_U3D_StopPlay,停止播放;
  23. 【录像】NT_U3D_StartRecorder,开始录像;
  24. 【录像】NT_U3D_StopRecorder,停止录像;
  25. 【关闭】NT_U3D_Close, 关闭播放器实例;
  26. 【最后调用】NT_U3D_UnInit,UnInit Player,最后调用。

1.5 Event回调

/// <summary>

/// android 传递过来 code

/// </summary>

/// <param name=”code”></param>

public void onNTSmartEvent(string param)

{

if (!param.Contains(“,”))

{

Debug.Log(“[onNTSmartEvent] android传递参数错误”);

return;

}

string[] strs = param.Split(‘,’);

string player_handle =strs[0];

string code = strs[1];

string param1 = strs[2];

string param2 = strs[3];

string param3 = strs[4];

string param4 = strs[5];

Debug.Log(“[onNTSmartEvent] code: 0x” + Convert.ToString(Convert.ToInt32(code), 16));

switch (Convert.ToInt32(code))

{

case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_STARTED:

Debug.Log(“开始。。”);

break;

case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_CONNECTING:

Debug.Log(“连接中。。”);

break;

case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_CONNECTION_FAILED:

Debug.Log(“连接失败。。”);

break;

case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_CONNECTED:

Debug.Log(“连接成功。。”);

break;

case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_DISCONNECTED:

Debug.Log(“连接断开。。”);

break;

case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_STOP:

Debug.Log(“停止播放。。”);

break;

case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_RESOLUTION_INFO:

Debug.Log(“分辨率信息: width: ” + Convert.ToInt32(param1) + “, height: ” + Convert.ToInt32(param2));

break;

case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_NO_MEDIADATA_RECEIVED:

Debug.Log(“收不到媒体数据,可能是url错误。。”);

break;

case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_SWITCH_URL:

Debug.Log(“切换播放URL。。”);

break;

 

case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_CAPTURE_IMAGE:

Debug.Log(“快照: ” + param1 + ” 路径:” + param3);

 

if (Convert.ToInt32(param1) == 0)

{

Debug.Log(“截取快照成功。.”);

}

else

{

Debug.Log(“截取快照失败。.”);

}

break;

case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_RECORDER_START_NEW_FILE:

Debug.Log(“[record]开始一个新的录像文件 : ” + param3);

break;

case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_ONE_RECORDER_FILE_FINISHED:

Debug.Log(“[record]已生成一个录像文件 : ” + param3);

break;

case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_START_BUFFERING:

Debug.Log(“Start_Buffering”);

break;

case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_BUFFERING:

Debug.Log(“Buffering: ” + Convert.ToInt32(param1));

break;

case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_STOP_BUFFERING:

Debug.Log(“Stop_Buffering”);

break;

case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_DOWNLOAD_SPEED:

Debug.Log(“download_speed:” + param1 + “Byte/s” + “, ”

+ (Convert.ToInt32(param1) * 8 / 1000) + “kbps” + “, ” + (Convert.ToInt32(param1) / 1024)

+ “KB/s”);

break;

}

}

经测试,Android、iOS端效果如下,播放端延迟低于1秒,也可能是unity3d平台下最快最稳定的rtmp播放器/rtsp播放器:

视频效果图:

更多资料,可以访问 https://github.com/daniulive/SmarterStreaming or http://www.daniulive.com/

大牛直播SDK-Windows RTMP/RTSP推送端使用说明

由于大牛直播SDK Demo主要侧重于SDK接口展示,不必说自研,哪怕demo使用,庞大的功能让好多开发者望而却步,以下是Windows推送端SDK简单的介绍:

大牛直播SDK推送端提供C++/C#两套接口,对外提供32/64位debug/release库。

对应Demo:

  •  Windows测试程序:SmartPublisherDemo.exe;
  •  Windows C++工程:WIN-PublisherSDK-CPP-Demo;
  •  Windows C#工程:WIN-PublisherSDK-CSharp-Demo;

使用说明:

1视频采集设置

说明:

1. 屏幕和摄像头相互切换:用于在线教育或者无纸化等场景,推送或录像过程中,随时切换屏幕或摄像头数据(切换数据源),如需实时切换,点击页面“切换到摄像头”按钮即可;

2. 设置遮盖层,用于设定一个长方形或正方形区域(可自指定区域大小),遮盖不想给用户展示的部分;

3. 水印:添加PNG水印,支持推送或录像过程中,随时添加、取消水印;

4. 摄像头叠加到屏幕:意在用于同屏过程中,主讲人摄像头悬浮于屏幕之上(可指定叠加坐标),实现双画面展示,推送或录像过程中,可以随时取消摄像头叠加;

5. 屏幕叠加到摄像头:同4,效果展示,实际根据需求实现;

6. 采集桌面:可以通过点击“选择屏幕区域”获取采集区域,并可在采集过程中,随时切换区域位置,如不设定,默认全屏采集;

7. 使用DXGI采集屏幕,采集时停用Aero;

8. 采集窗口:可设定需要采集的窗口,窗口放大或缩小,推送端会自适应码率和分辨率;

9. 采集帧率(帧/秒):默认屏幕采集5帧,可根据实际场景需求设定到10-25帧;

10. 缩放屏幕大小缩放比:用于高清或超高清屏,通过设定一定的比例因子,缩放屏幕采集分辨率;

11. 采集摄像头:可选择需要采集的摄像头、采集分辨率、帧率、是否需要水平或者垂直反转、是否需要旋转;

追加提问:

问题[确认数据源]:采集桌面还是摄像头?如果桌面,全屏还是部分区域?

回答:

  • 如果是摄像头:可以选择摄像头列表,然后分辨率、帧率。
  • 如果是屏幕:默认帧率是5帧,可以根据实际场景调整,选取屏幕区域,可以实时拉取选择需要采集或录像区域;
  • 如果是叠加模式:可选择摄像头叠加到屏幕,还是屏幕叠加到摄像头;
  • 更高需求的用户,可以设置水印或应用层遮盖。

问题:如果是摄像头,采集到的摄像头角度不对怎么办?

回答:我们支持摄像头镜像和翻转设置,摄像头可通过SDK接口轻松实现水平/垂直翻转、镜像效果。

视频码率控制

我选可变码率还是平均码率?

回答:可变码率的优势在于,如果屏幕或摄像头变化不大,码率超低,特别是H.265编码,平均码率,码率比较均匀,需设置平均码率+最大码率,一般摄像头采集建议选择可变码率,屏幕采集选择平均码率,如需采用可变码率,请取消“使用平均码率”选项。

265编码还是H.264编码?

回答:Windows 64位库支持H.265编码,如果推RTMP流,需要服务器支持RTMP H.265扩展,播放器SDK,也需要同步支持RTMP H.265扩展播放。

如果是轻量级RTSP服务SDK对接的话,只需要播放器支持RTSP H.265即可。

如果推摄像头数据,建议采用可变码率+H.265编码。

如何设置码率参数更合理?

回答:

关键帧间隔:一般来说,设置到帧率的2-4倍,比如帧率20,关键帧间隔可以设置到40-80;

平均码率:可以点击“获取视频码率默认值”,最大码率是平均码率的2倍;

视频质量:如果使用可变码率,建议采用大牛直播SDK默认推荐视频质量值;

编码速度:如高分辨率,建议1-3,值越小,编码速度越快;

H.264 Profile:默认baseline profile,可根据需要,酌情设置High profile;

NOTE:点击“推送”或“录像”或启动内置RTSP服务SDK之前,请务必设置视频码率,如不想手动设置,请点击“获取视频码率默认值”!!!

音频采集设置

问答式:采集音频吗?如果采集,采集麦克风还是扬声器的,亦或混音?

回答:

  • 如果想采集电脑输出的音频(比如音乐之类),可以选择“采集扬声器”;
  • 如果想采集麦克风音频,可以选择“采集麦克风”,并选择相关设备;
  • 如果两个都想采集,可以两个都选择,混音输出。

音频编码

问题:是AAC还是SPEEX?

回答:我们默认是AAC编码模式,如果需要码率更低,可以选择SPEEX编码模式,当然我们的AAC编码码率也不高。

音频处理

问题:我想过滤背景噪音怎么办?

回答:选中“噪音抑制”,“噪音抑制“请和“自动增益控制”组合使用,“端点检测(VAD)”可选设置

问题:我想做一对一互动怎么办?

回答:选中“回音消除”,可以和“噪音抑制”、“自动增益控制”组合使用。

问题:我推送或者录像过程中,随时静音怎么办?

回答:推送过程中,随时选择或取消选择“静音”功能。

6多路推送

问题:我想同时推送到多个url怎么办(比如一个内网服务器,一个外网服务器)?

回答:同时填写多个url,然后点推送即可。

截图(快照)

问题:我想推送或者录像过程中,截取当前图像怎么办?

回答:那就设置好截图路径,推送或录像过程中,随时点击“截图”。

录像

问题:我还想录像,怎么办?

回答:设置录像文件存放目录,文件前缀、单个文件大小,是否加日期、时间,随时录制即可。

9 实时预览

问题:我还想看看视频特别是合成后的效果,怎么办?

回答:点击页面的“预览”按钮,就可以看到。

我是外行,我想快速测试推屏怎么办?

回答:

1. 推屏幕:

2. 推摄像头:

相关资料和测试程序下载:

Github: https://github.com/daniulive/SmarterStreaming

官网:https://www.daniulive.com

大牛直播SDK release note

视沃科技(大牛直播SDK)2021-04-02 release note:

1. Windows推送SDK优化Win10高版本窗口采集;

1. Android转发SDK测试Demo增加内置网关功能(拉取的RTSP|RTMP流注入轻量级RTSP服务);

视沃科技(大牛直播SDK)2021-03-02 release note:

1. Android播放SDK支持实时音量调节;

2. iOS播放SDK支持实时音量调节.

视沃科技(大牛直播SDK)2021-01-21 release note:

1. Windows播放SDK支持实时音量调节.

视沃科技(大牛直播SDK)2020-11-22 release note:

1. Windows推送SDK支持特定机型硬编码.

视沃科技(大牛直播SDK)2020-09-10 release note:

1. Android推送SDK支持YV12接口,支持输入数据旋转;

2. Android推送SDK支持NV21接口,支持输入数据旋转、水平反转、垂直反转.

视沃科技(大牛直播SDK)2020-07-07 release note:

1. 整体优化Android推送和播放SDK;

2. 整体优化iOS推送和播放SDK.

视沃科技(大牛直播SDK)2020-05-27 release note:

1.Android推送SDK增加实时音量设置接口;

2. Android推送SDK增加NV21图像传入接口;

3.整体优化Android推送和播放SDK.

视沃科技(大牛直播SDK)2020-04-29 release note:

1.Windows推送SDK增加实时音量设置接口(混音模式下支持单独控制麦克风、扬声器音量);

2.整体优化Windows推送和播放SDK.

视沃科技(大牛直播SDK)2020-03-25 release note:

1.Android推送SDK增加混音接口;

2.Android推送SDK支持双通道PCM音频数据输入;

3.Android推送SDK支持更多类型采样率的PCM音频数据输入(如8000,16000采样率等);

4.Android推送SDK增加short array类型的pcm音频数据接口,便于和其他系统对接;

5. Android推送SDK精简录像接口;

6.整体优化Android推送和播放SDK.

视沃科技(大牛直播SDK)2020-03-17 release note:

1.Windows平台发布基于标准RTMP服务的一对一互动DEMO(以C#为例,对应WIN-EchoCancellation-CSharp-Demo工程);

视沃科技(大牛直播SDK)2020-02-18 release note:

1.Windows播放SDK增加按比例缩放绘制接口;

2.更新Windows相关demo代码;

3.整体优化Windows推送和播放SDK.

视沃科技(大牛直播SDK)2020-02-12 release note:

1.iOS播放SDK增加按图像比例缩放绘制接口;

2.iOS播放SDK优化RTMP SM4解密;

3.整体优化iOS推送和播放SDK.

视沃科技(大牛直播SDK)2020-02-11 release note:

1.Android推送SDK增加android.media.Image.YUV_420_888格式(android.graphics.ImageFormat.YUV_420_888)传入接口,方便安卓Camera2接口对接;

2.Android播放SDK优化SurfaceView绘制方式;

3.Android播放SDK优化Opengles绘制方式;

4.Android播放SDK增加按图像比例缩放绘制接口;

5.整体优化Android推送和播放SDK.

视沃科技(大牛直播SDK)2019-12-17 release note:

1.iOS推送SDK增加音视频录像开关,方便更细粒度的控制录像;

2.iOS推送SDK摄像头demo支持缩放模式下多分辨率选择;

3.iOS推送SDK增加外部h264/aac编码后数据录像接口支持;

4.iOS平台整体优化屏幕采集推送模块,支持推送端横竖屏切换自动适配;

5.iOS播放SDK进一步降低在0缓存情况下的延时;

6.整体优化iOS推送和播放SDK.

视沃科技(大牛直播SDK)2019-12-12 release note:

1.Android推送SDK增加音视频录像开关,方便更细粒度的控制录像;

2.Android推送SDK增加外部h264/aac编码后数据录像接口支持;

3.Android录屏demo针对8.0及以上系统增加省电白名单动态权限申请代码(避免运行一分钟后被系统停掉);

4.Android平台优化安卓屏幕采集demo,进一步提高采集帧率;

5.Android播放SDK在使用surfaceview绘制情况下支持rgb565和rgb888两种图像格式选择;

6.Android播放SDK在使用surfaceview绘制情况下增加抗锯齿开关;

7.Android播放SDK增加音视频录像开关,方便更细粒度的控制录像;

8.Android播放SDK特定机型支持超高帧率播放;

9.Android推送SDK优化h264硬编码;

10.Android播放SDK优化h264硬解码;

11.Android播放SDK进一步降低在0缓存情况下的延时;

12.整体优化Android推送和播放SDK.

视沃科技(大牛直播SDK)2019-10-29 release note:

1.Windows推送SDK提高帧率限制到120fps;

2.Windows播放SDK支持超高帧率播放;

3. 优化Windows播放和推送SDK.

视沃科技(大牛直播SDK)2019-10-24 release note:

1.iOS平台优化回音消除功能;

2.iOS播放SDK支持超高帧率播放;

3. 优化iOS播放和推送SDK.

视沃科技(大牛直播SDK)2019-09-20 release note:

1.iOS推送端SDK增加AAC码率设置接口;

2.整理iOS推送播放日志打印;

3. 优化iOS播放和推送SDK.

视沃科技(大牛直播SDK)2019-09-02 release note:

发布“大牛直播SDK多路RTSP-RTMP转RTMP官方定制版”,官方定制版,支持守护进程启动、通过图形化配置实现多路转发,非专业人士亦可完成操作。

视沃科技(大牛直播SDK)2019-08-23 release note:

1.安卓推送增加AAC码率设置接口;

2.整理安卓推送播放日志打印;

3. 优化Android播放和推送SDK.

视沃科技(大牛直播SDK)2019-08-22 release note:

1.Windows播放SDK增加ARGB图像叠加到显示视频上的接口;

2.Windows播放SDK增加可以指定回调图像大小的接口(可以对原视图像缩放后再吐出来);

3. Windows播放SDK进一步降低0缓冲情况的播放延时;

4. Windows推送SDK增加休眠接口(设置成休眠模式后cpu会适当降低);

5. 优化Windows推送播放SDK.

视沃科技(大牛直播SDK)2019-06-19 release note:

1.iOS推送SDK增加录像实时暂停、恢复功能;

2.优化iOS播放和推送SDK.

视沃科技(大牛直播SDK)2019-06-14 release note:

1.Android推送SDK增加录像实时暂停、恢复功能;

2.Android推送SDK优化音频输入;

3.优化Android播放和推送SDK.

视沃科技(大牛直播SDK)2019-06-12 release note:

1.Windows推送SDK增加录像实时暂停、恢复功能;

2.Windows推送SDK扬声器采集增加静音帧补偿接口;

3.Windows播放SDK支持硬解码(h264,h265硬解);

4.优化Windows推送播放SDK.

视沃科技(大牛直播SDK)2019-05-24 release note:

1.iOS推送SDK支持RTMP h265加密;

2.iOS推送SDK支持RTMP h264加密;

3.iOS推送SDK支持AAC/Speex/G711加密;

4.iOS播放SDK支持对应的加密流播放;

5.iOS RTMP支持AES128, AES192, AES256, SM4(国密)加解密;

6.iOS内置轻量级RTSP服务SDK支持组播模式;

7.iOS播放SDK支持RTSP mjpeg播放;

8.优化iOS播放和推送SDK.

视沃科技(大牛直播SDK)2019-05-16 release note:

1.Android推送SDK支持RTMP h265加密;

2.Android推送SDK支持RTMP h264加密;

3.Android推送SDK支持AAC/Speex/G711加密;

4.Android播放SDK支持对应的加密流播放;

5.Android RTMP支持AES128, AES192, AES256, SM4(国密)加解密;

6.Android推送SDK增加rgbx图像输入裁剪接口;

7.优化Android播放和推送SDK.

视沃科技(大牛直播SDK)2019-04-24 release note:

1.Windows推送SDK支持RTMP SM4(国密)加密;

2.Windows播放SDK支持相应RTMP SM4(国密)加密流播放;

3.优化Windows播放和推送SDK.

视沃科技(大牛直播SDK)2019-04-10 release note:

1. Android/iOS平台发布Flutter RTSP/RTMP播放SDK二次封装接口:

视沃科技(大牛直播SDK)2019-04-09 release note:

1.Windows推送SDK支持RTMP h265加密;

2.Windows推送SDK支持RTMP h264加密;

3.Windows推送SDK支持AAC/Speex/G711加密;

4.Windows播放SDK支持对应的加密流播放;

5.Windows RTMP支持AES128, AES192, AES256加密;

6.优化Windows桌面采集;

7.优化Windows播放和推送SDK.

视沃科技(大牛直播SDK)2019-03-22 release note:

1. Windows播放SDK发布IE浏览器OCX控件:

视沃科技(大牛直播SDK)2019-03-08 release note:

1.Android平台全面支持x86、 x86-64位架构, 方便在模拟器上运行;

2.Android播放SDK支持rtsp mjpeg播放;

3.Android内置轻量级RTSP服务SDK支持组播模式;

4.Android推送SDK支持RGB565格式数据对接;

5.优化Android播放和推送SDK.

视沃科技(大牛直播SDK)2019-03-01 release note:

1.Windows推送SDK增加屏幕缩放功能,屏幕采集码率更低,体验更好;

2.Windows播放SDK支持rtsp mjpeg播放;

3. 优化Windows播放和推送SDK.

视沃科技(大牛直播SDK)2019-02-24 release note:

1. 发布iOS一对一互动SDK:

2. iOS推送端SDK增加回音消除接口;

3. iOS播放端SDK增加回音消除接口;

4. 增加iOS一对一互动SDK demo(SmartiOSEchoCancellation);

5. 优化iOS播放和推送SDK.

视沃科技(大牛直播SDK)2019-01-29 release note:

1. 为了更好的满足电子教室、无纸化办公等内网直播场景,减少服务器部署和带宽瓶颈:

1.1  Windows轻量级RTSP服务SDK支持组播方案;

1.2 Windows内网RTSP网关SDK支持组播方案;

2. 优化Windows播放和推送SDK.

视沃科技(大牛直播SDK)2019-01-24 release note:

1. 大牛直播SDK发布Android“RTSP直播推流SDK”;

2. Android rtsp推送支持H.264、H.265推送;

3. Android rtsp推送支持aac推送;

4. Android rtsp推送支持rtp over udp和rtp over tcp两种传输方式;

5. Android rtsp推送支持鉴权;

6. Android rtsp推送支持401事件上报;

7. Android rtsp推送支持重连和异常网络处理等常用功能;

8. 优化Android播放和推送SDK;

9. Android推屏demo支持横竖屏自动切换.

视沃科技(大牛直播SDK)2019-01-16 release note:

1. 大牛直播SDK发布iOS“RTSP直播推流SDK”;

2. iOS rtsp推送支持H.264、H.265推送;

3. iOS rtsp推送支持aac推送;

4. iOS rtsp推送支持rtp over udp和rtp over tcp两种传输方式;

5. iOS rtsp推送支持鉴权;

6. iOS rtsp推送支持401事件上报;

7. iOS rtsp推送支持重连和异常网络处理等常用功能;

8. 优化iOS播放和推送SDK.

视沃科技(大牛直播SDK)2018-12-26 release note:

1. Windows推送SDK支持MJPEG格式的摄像头采集;

2. Windows推送SDK支持外部音频和内置麦克风混音;

3. 优化Windows播放和推送SDK.

视沃科技(大牛直播SDK)2018-12-14 release note:

1. 大牛直播SDK发布Windows“RTSP直播推流SDK”;

2. Windows RTSP直播推流SDK支持RTMP直播推流SDK的除协议栈外的所有功能,支持RTSP H.264/H.265(64位库)推送,支持TCP/UDP模式设置、支持RTSP鉴权模式和401处理、支持网络重连和各种异常网络状态处理;

3. 优化Windows播放和推送SDK.

视沃科技(大牛直播SDK)2018-12-07 release note:

1. iOS播放端录像SDK支持录制纯音频或纯视频;

2. iOS播放端SDK支持RTMP/RTSP H.265硬解码,如硬解码不支持,自动跳转至软解码;

3. iOS推送端SDK支持H.265硬编码(可变码率,超低码率占用),RTMP推送和内置RTSP服务均支持H.265;

4. iOS推送端SDK支持音频软、硬编码设置;

5. iOS推送端SDK支持H.264软编码可变码率设置;

6. iOS推送端SDK支持设置H.264软编码profile设置(baseline/main/high profile);

7. iOS推送端SDK支持H.264软编码速度设置;

8. iOS推送端SDK支持外部PCM数据传输SDK;

9. iOS支持内置RTSP网关SDK(SmartiOSRelayDemoV2).

视沃科技(大牛直播SDK)2018-11-16 release note:

1. 安卓推送SDK支持H.265(hevc)硬编码;

2. 安卓推送SDK支持RTMP扩展H.265推送;

3. 安卓内置轻量级RTSP服务SDK支持H.265作为数据源;

4. 安卓推送SDK支持H.264可变码率设置接口;

5. 安卓SDK demo功能页面更新。

视沃科技(大牛直播SDK)2018-11-09 release note:

1. 大牛直播SDK发布“内置RTSP网关SDK”;

2. 内网RTSP网关SDK,系内置轻量级RTSP服务SDK扩展,完成外部RTSP/RTMP数据拉取并注入到轻量级RTSP服务SDK工作,多个内网客户端直接访问内网轻量级RTSP服务获取公网数据,无需部署单独的服务器,支持RTSP/RTMP H.265数据接入;

3. Windows播放SDK增加音视频录制选项(可以单独录制视频或者音频);

4. 优化Windows播放和推送SDK.

视沃科技(大牛直播SDK)2018-11-03 release note:

1. 安卓播放SDK支持H265(hevc)硬解(SetSmartPlayerVideoHevcHWDecoder,H.264/H.265硬解码可单独设置),硬解码使用设置surface模式(Demo对应is_enable_hardware_render_mode变量控制),H.265资源占用更低;

2. 安卓推送SDK和播放SDK整体优化;

视沃科技(大牛直播SDK)2018-11-01 release note:

1. Windows推送SDK支持h265编码(64位库);

2. Windows推送SDK支持rtmp h265推送,针对摄像头采集编码,使用H.265可变码率,带宽大幅节省,效果直逼传统H.265编码摄像头;

3. Windows推送SDK支持H265录像;

4. Windows内置rtsp server支持发布h265视频(64位库);

5. 优化Windows推送和播放sdk。

视沃科技(大牛直播SDK)2018-10-24 release note:

1. iOS播放SDK支持rtmp h.265播放;

2. iOS转发SDK支持h265转发(rtsp/rtmp h265转rtmp h265推送,提供配套RTMP H.265扩展服务器测试);

3. iOS播放端SDK优化;

4. iOS推送端SDK优化。

视沃科技(大牛直播SDK)2018-10-18 release note:

1. 安卓转发SDK支持音频(PCMU/PCMA,Speex等)转AAC后再推流;

2. 安卓播放SDK支持音频(PCMU/PCMA,Speex等)转AAC后再录像接口;

3. 安卓播放SDK优化rtmp h264播放;

4. 安卓播放SDK支持rtmp扩展h265播放;

5. 安卓转发SDK优化rtsp转发;

6. 安卓播放SDK优化rtsp录像;

7. 安卓播放SDK优化rtsp h264播放;

8. 安卓转发SDK支持h265转发(rtsp/rtmp h265转rtmp h265推送);

9. 安卓播放SDK硬解码支持Surface直接绘制模式;

10. 安卓推送SDK优化音频编码, 降低音频码率.

视沃科技(大牛直播SDK)2018-10-16 release note:

1. Windows转发SDK支持h265转发(rtsp/rtmp h265转rtmp h265推送);

2. Windows播放SDK优化rtsp h264播放;

3. Windows播放SDK优化rtsp录像;

4. Windows转发SDK优化rtsp转发;

5. Windows推送SDK常规优化.

视沃科技(大牛直播SDK)2018-09-26 release note:

1. Windows播放SDK支持rtmp扩展h265播放;

2. Windows播放SDK优化rtmp h264播放

3. Windows推送SDK增加外部PCM音频数据对接接口;

4. iOS录像SDK支持音频(PCMU/PCMA,Speex等)转AAC后再录像接口;

5. iOS转发SDK支持音频(PCMU/PCMA,Speex等)转AAC后再推流.

视沃科技(大牛直播SDK)2018-09-13 release note:

1. 安卓播放SDK支持rtsp h265播放;

2.安卓播放SDK支持rtsp h265录像;

3. 安卓播放SDK增加rtsp超时时间设置接口;

4. 安卓播放SDK增加rtsp tcp-udp自动切换设置接口;

5. 安卓播放SDK上报rtsp 401事件;

6. 安卓推送SDK吐编码后的AAC数据;

7. 安卓推送SDK吐编码后的H264数据方便对接第三方平台.

视沃科技(大牛直播SDK)2018-09-12 release note:

1. Windows播放SDK支持音频(PCMU/PCMA,Speex等)转AAC后再录像接口;

2. Windows转发支持音频(PCMU/PCMA,Speex等)转AAC后再推流;

3. Windows推送SDK优化音频推送.

视沃科技(大牛直播SDK)2018-09-06 release note:

1.  iOS播放SDK增加rtsp超时时间设置接口;

2. iOS播放SDK增加rtsp tcp-udp自动切换设置接口;

3. iOS播放SDK上报rtsp 401事件;

4. iOS播放SDK支持rtsp h265播放;

5. iOS录像SDK支持rtsp h265录制;

6. iOS推送、播放SDK支持模拟器编译运行;

7. 更新Windows推送、播放、转发C#demo至官方最新版本;

8. 更新Windows Unity3d播放demo;

9. 更新Windows SDK集成说明文档。

视沃科技(大牛直播SDK)2018-08-29 release note:

1.Windows播放SDK增加rtsp超时时间设置接口;

2. Windows播放SDK增加rtsp tcp-udp自动切换设置接口;

3. Windows播放SDK上报rtsp 401事件;

4. 优化Windows rtsp播放;

5. 优化Windows推送.

视沃科技(大牛直播SDK)2018-08-03 release note:

1.Android支持内置轻量级RTSP服务SDK;

2. iOS支持内置轻量级RTSP服务SDK;

3. 发布最新版本移动端SDK调用说明.

视沃科技(大牛直播SDK)2018-07-30 release note:

1.Windows 录像SDK支持rtsp h265录制,也许是业内为数不多的支持RTSP H.265录制到MP4文件的录像SDK.

视沃科技(大牛直播SDK)2018-07-25 release note:

1.Windows 播放SDK支持rtsp h265播放.

2.优化Windows推送和播放.

视沃科技(大牛直播SDK)2018-07-19 release note:

1.Android/iOS推送SDK增加推送字符串和二进制数据接口.

2.Android/iOS播放SDK增加用户数据回调接口.

3.Android/iOS播放SDK增加SEI数据回调接口.

4.Android/iOS播放SDK增加水平反转、垂直反转接口.

视沃科技(大牛直播SDK)2018-06-25 release note:

1.Windows推送内置rtsp server,无需部署服务器,即可发布rtsp音视频流.

2.安卓推送SDK扩展H264/AAC接口,方便用户直接传sps/pps给sdk.

3.安卓推送SDK支持可变分辨率水印.

4.Windows/安卓/iOS播放SDK优化rtsp播放.

5.Windows推送demo增加rtsp相关操作.

6.同步C#工程至2018年6月1日release版本.

视沃科技(大牛直播SDK)2018-06-01 release note:

1.Windows推送SDK增加预览接口.

2.Windows推送demo增加预览功能,可以先预览后推送.

3.Windows播放SDK深度优化rtsp播放,比好更好!

视沃科技(大牛直播SDK)2018-05-30 release note:

大牛直播SDK官方支持Android/iOS Unity3d RTMP/RTSP直播SDK.

视沃科技(大牛直播SDK)2018-05-10 release note:

1.Windows推送SDK增加发送文本,二进制数据接口.

2.Windows播放SDK增加吐文本,二进制数据接口.

3.Windows播放SDK增加吐H264 Sei数据接口.

4.Windows播放SDK增加水平垂直反转接口.

5.优化Windows播放SDK,降低CPU.

6.优化Windows推送SDK.

视沃科技(大牛直播SDK)2018-04-28 release note:

1.[Android]增加转发demo(rtsp转rtmp推送,rtmp转rtmp推送).

2.[Android]播放SDK优化rtsp播放.

3.[Android]播放SDK增加吐h264,aac/pcmu/pcma/speex接口.

4.[Android]推送SDK增加新的推送H264,AAC/PCMU/PCMA/Speex接口.

5.[Android]优化安卓推送SDK.

视沃科技(大牛直播SDK)2018-04-24 release note:

1.Windows推送SDK增加摄像头水平镜像,垂直反转接口, 增加90度,180度,270度旋转接口.

2.Windows推送SDK支持窗口采集推送,支持动态切换窗口.

3.Windows推送SDK增加设置多个视频码率的接口.

4.Windows推送SDK增加在采集屏幕时停用Win7 Aero的接口.

5.Windows推送SDK优化摄像头采集.

6.优化Windows播放SDK.

视沃科技(大牛直播SDK)2018-04-20 release note

1.Windows推送SDK增加DXGI屏幕采集方式,大大提高win8及以上系统桌面采集速度;

2.Windows推送SDK增加CPU自适应动态调整机制,降低SDK对机器性能的依赖性;

3.Windows推送SDK整体优化;

4.Windows推送SDK和播放SDK静态连接运行时库,方便各个vs版本对接;

5.优化Windows RTSP播放,兼容性和播放体验更优异。

视沃科技(大牛直播SDK)2018-03-29 release note

1.IOS播放SDK增加录像接口;

2.IOS播放SDK增加吐H264/AAC/PCMU/PCMA/SPEEX接口;

3.IOS推送SDK增强推送H264接口;

4.IOS推送SDK增加推送AAC/PCMU/PCMA/SPEEX接口;

5.IOS推送SDK支持推屏;

6.IOS增加播放-转发-录像三合一Demo;

7.IOS增加基于ReplayKit录屏推送demo;

8.IOS推送和播放SDK增加V2接口。

视沃科技(大牛直播SDK)2018-03-05 release note

1.[windows播放端]支持播放过程中,rtsp/rtmp或本地flv文件实时切换;

2.[windows转发端]支持转发过程中,拉取的rtsp/rtmp或本地flv文件实时内容切换;

3.[Android推送|播放端]Android全面升级V2接口(Android studio工程),并优化后台推屏幕/摄像头Demo。

视沃科技(大牛直播SDK)2018-02-28 release note

1.[windows播放端]支持本地flv点播:

  • 支持获取flv文件的duration(时长);
  • 支持显示当前播放位置;
  • 支持开始播放或播放过程中seek(跳转播放位置),也许是行业内seek最快的flv点播播放器。
  1. [windows转发端]支持本地flv文件转发,亦可支持指定位置转发。

视沃科技(大牛直播SDK)2018-02-01新功能抢先体验版:

1.[android]提供V2接口,支持播放端录像。

2.[iOS]支持播放端录像;

3.[iOS]支持iOS端转发功能(拉取rtsp/rtmp流,转发到设定rtmp url);

比“最好”还好:

  1. 大牛直播SDK录像

a) 支持switchUrl接口;

b) 同等参数配置的两个url,可以录制到同一个mp4文件(彻底解决了娃娃机抓取等场景,因为频繁切换url,想申诉时,用户只能录屏,用新的SDK接口,同等摄像头参数配置,无论怎么切换url,自动录制到一个mp4文件)

c) 不同参数配置的两个url,自动识别,自动录制到不同mp4文件。

  1. iOS转发:

a) 大牛直播SDK转发功能,同样支持switchUrl接口,切换不同分辨率的url,一样正常转发;

b) 配合大牛直播播放SDK,转发数据切换,自动适配。

  1. 大牛直播SDK的播放、录像、转发功能完全分离:

a) 可以只播放,随时录像,随时转发;

b) 可以只录像,随时播放,随时转发;

c) 可以只转发,随时播放,随时录像。

视沃科技(大牛直播SDK)2017-12-22 release note

1.iOS播放SDK增加旋转接口;

2.iOS播放推送SDK整体优化.

2017-11-20 release note

  1. 更新android studio demo工程;

视沃科技(大牛直播SDK)2017-11-16 release note

  1. [windows平台] 发布Windows C#多路流媒体转发模块SDK Demo;
  2. android Player增加buffer状态显示和实时带宽占用接口;
  3. iOS推送和播放端整体优化.

2017-11-10 release note:

  1. windows/android/iOS Player SDK增加”超低延迟”模式,适用于类似直播娃娃机等相关场景.
  2. iOS Player增加buffer状态显示和实时带宽占用接口.
  3. iOS Player增加回调YUV数据接口.
  4. android/iOS推送和播放器整体优化.

视沃科技(大牛直播SDK)2017-10-25 release note:

1.[Windows播放端]SDK增加下载速度上报接口.

2.[Windows播放端]SDK增加获取下载速度接口.

3.[Windows播放端]SDK增加buffer开始,停止,进度通知.

4.[Windows播放端]SDK增加吐PCM数据接口.

5.[Windows播放端]SDK增加和服务器链接状态上报接口.

6.[Windows播放端]SDK支持64位.

7.[Windows推送端]SDK支持64位.

8.[文档]更新ppt产品介绍.

视沃科技(大牛直播SDK)2017-09-25 release note:

1.[Windows播放端] sdk增加吐编码过的音视频数据接口.

2.[Windows推送端] sdk增加推送H264数据接口.

3.[Windows推送端] sdk增加推送AAC, Speex WB, PCMA, PCMU数据接口.

4.[Windows转发] 新增多路拉流转发demo.

…….