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 实时预览

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

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

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/553059.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何实现Android端获取RTSP|RTMP流转推RTMP

技术背景 最近不少开发者找到我们&#xff0c;他们在做智能家居等传统行业时&#xff0c;希望实现在Android板件拉取本地的RTSP或RTMP流&#xff0c;然后对外推送RTMP出去&#xff0c;亦或内部启个轻量级RTSP服务&#xff0c;提供个对外对接的媒介URL&#xff0c;简单来说&…

foxmail地址簿怎么添加分组 foxmail地址簿新建分组的教程

foxmail有很多联系人&#xff0c;想要合理管理联系人&#xff0c;该怎么创建分组呢?下面我们就来看看详细的教程。 1、在进行打开地址簿之后&#xff0c;进行点击选中一个文件夹&#xff0c;然后进行点击"新建组" foxmail地址簿怎么添加分组? foxmail地址簿新建分…

Android平台RTSP轻量级服务|RTMP推送摄像头或屏幕之音频接口设计

好多开发者在做Android平台录像或者RTSP轻量级服务、RTMP推送相关模块时&#xff0c;对需要设计哪些常用接口会心存疑惑&#xff0c;本文主要以大牛直播SDK&#xff08;官方&#xff09;为例&#xff0c;简单介绍下Android平台直播推送SDK所有音频相关的接口&#xff0c;感兴趣…

Win7系统更换软件图标的详细方法

Win7系统怎么更换软件图标?相信许多用户会安装很多软件或游戏&#xff0c;并且安装这些软件会在桌面上生成图标&#xff0c;但是一些用户认为某些软件图标不好&#xff0c;因此他们想替换这些图标&#xff0c;但他们不知道怎样做&#xff0c;这里小编就和大家分享Win7系统更换…

QT实现低延迟的RTSP、RTMP播放器

好多开发者在QT环境下实现RTMP或RTSP播放时&#xff0c;首先考虑到的是集成VLC&#xff0c;集成后&#xff0c;却发现VLC在延迟、断网重连、稳定性等各个方面不尽人意&#xff0c;无法满足上线环境需求。本文以调用大牛直播SDK&#xff08;官方&#xff09;的Windows平台播放端…

Android对接实现内网无纸化会议|智慧教室|实时同屏功能

背景 本文主要讲的是基于Android平台实现RTMP的技术方案设计&#xff0c;基础架构图如下&#xff1a; 组网注意事项 1. 组网&#xff1a;无线组网&#xff0c;需要好的AP模块才能撑得住大的并发流量&#xff0c;推送端到AP&#xff0c;最好是有线网链接&#xff1b; 2. 服务…

bilibili里的硬币有什么用 硬币的作用详细介绍

很多bilibili中的用户发现自己的账户中拥有很多的硬币&#xff0c;却不知道这些硬币有什么用&#xff0c;下面小编就为大家带来硬币的作用介绍。 bilibili里的硬币有什么用 硬币的作用详细介绍 1、视频评分。向喜欢的视频投硬币以示鼓励(一个视频收到的硬币多了就会被推荐) …

Windows平台RTMP推送|轻量级RTSP服务实现本地摄像头|屏幕|叠加数据预览

背景 大家在做Windows平台RTMP推送或轻量级RTSP服务的时候&#xff0c;不管是采集屏幕还是采集摄像头&#xff0c;亦或屏幕摄像头的叠加模式&#xff0c;总会有这样的诉求&#xff0c;采集到的数据&#xff0c;希望能本地看看具体采集的数据或者图像实际效果&#xff0c;也就是…

Outlook2016怎么修改默认数据库

Outlook2016中想要修改默认数据库&#xff0c;该怎么修改呢?下面我们就来看看详细的教程。 Outlook2016怎么修改默认数据库? 1、下载安装outlook软件。 Outlook2016怎么修改默认数据库? 2、双击打开outlook软件。 Outlook2016怎么修改默认数据库? 3、点击“文件”——…

Windows平台RTMP|RTSP播放器为什么要兼容GDI绘制

为什么要支持GDI 先说结论&#xff0c;Windows平台播放渲染这块&#xff0c;一般来说99%以上的机器都是支持D3D的&#xff0c;实现GDI模式绘制&#xff0c;除了为了好的兼容性外&#xff0c;在远程连接的场景下&#xff0c;D3D创建不成功&#xff0c;需要使用GDI模式。 简单来…

Windows平台RTMP|RTSP播放器实现画面全屏功能

我们在Windows平台实现RTSP或者RTMP播放的时候&#xff0c;有个功能是绕不开的&#xff0c;那就是播放窗口全屏。本文就以大牛直播SDK&#xff08;官方&#xff09;的Windows播放器为例&#xff0c;大概讲下大概实现&#xff1a; 全屏播放需要考虑的点不多&#xff1a; 第一&…

tim怎么设置检测到新版本自动安装 tim安全自动更新的开启方法

TIM想要开启自动检测新版本并下载安装&#xff0c;该怎么设置呢?下面我们就来看看详细的教程。 1、首先&#xff0c;在你的 电脑中找到TIM; tim怎么设置检测到新版本自动安装?tim安全自动更新的开启方法 2、打开TIM&#xff0c;登录你的个人账号&#xff0c;登陆之后&…

Android平台实现Unity3D下RTMP推送

像Unity3D下的RTMP或RTSP播放器一样&#xff0c;好多开发者苦于在Unity环境下&#xff0c;如何高效率低延迟的把数据采集并编码实时推送到流媒体服务器&#xff0c;实现Unity场景下的低延迟推拉流方案。 关于屏幕采集&#xff0c;有两种方案&#xff1a; 1. 直接封装Android原…

Windows平台实现Unity下窗体|摄像头|屏幕采集推送

技术背景 随着Unity3D的应用范围越来越广&#xff0c;越来越多的行业开始基于Unity3D开发产品&#xff0c;如传统行业中虚拟仿真教育、航空工业、室内设计、城市规划、工业仿真等领域。 基于此&#xff0c;好多开发者苦于在Unity环境下&#xff0c;没有低延迟的推拉流解决方案…

钉钉调岗申请单怎么写 钉钉申请调岗的教程

钉钉中想要申请调岗申请单&#xff0c;调岗申请单在哪&#xff0c;该怎么填写呢?下面我们就来看看详细的教程。 1、首先打开钉钉客户端&#xff0c;点击下方的工作。 钉钉调岗申请单怎么写? 钉钉申请调岗的教程 2、向下滑动找到并打开调岗申请单应用。 钉钉调岗申请单怎么…

Android平台RTMP推送端实现外部数据对接推送和录像

背景 好多开发者在做Android平台RTMP推送对接的同时&#xff0c;除了编码前的数据外&#xff0c;还有些外部编码数据推送诉求&#xff0c;他们希望外部的编码音视频数据不止可以实现RTMP推送&#xff0c;还可以同时在推送端实时录制下来&#xff0c;本文以我们&#xff08;官方…

excel怎么删除浏览记录 方法介绍

Excel 2013工作表删除浏览记录的步骤&#xff1a; 1、鼠标左键双击计算机桌面Excel2013程序图标&#xff0c;将其打开运行。在打开的Excel2013程序窗口&#xff0c;点击“空白工作薄”选项&#xff0c;新建一个空白Excel工作薄。如图所示; excel怎么删除浏览记录&#xff1f;…

爱奇艺怎么开启数据流量自动播放

1、打开手机&#xff0c;点击爱奇艺 爱奇艺怎么开启数据流量自动播放 2、进入爱奇艺&#xff0c;点击我的 爱奇艺怎么开启数据流量自动播放 3、然后在我的界面&#xff0c;点击设置 爱奇艺怎么开启数据流量自动播放 4、进入设置界面&#xff0c;点击播放与下载 爱奇艺怎…

Win7系统账户被禁用的解决方法

我们都知道Win7系统中可以建立多个账户来进行不同的登录使用&#xff0c;十分的方便&#xff0c;但是有的用户建立了多个账户&#xff0c;却发现所有的账号都被禁用&#xff0c;那遇到这个问题应该怎么解决呢&#xff0c;下面就为小伙伴们带来 了Win7系统账户被禁用的解决方法&…

Win11系统如何隐藏快速搜索

近日网络中已经出现了很多Windows 11的泄露版本&#xff0c;意味着Win11版本正式确定&#xff0c;现在只是等待微软正式发布了。Windows系统中菜单栏都会默认放一个快速搜索的图标&#xff0c;快速搜索一直是Windows系统中的一个重要功能&#xff0c;那么在Win11系统中该如何隐…