跨平台低延迟的RTMP/RTSP直播播放器设计实现

开发背景

2015年,当我们试图在市面上找一款专供直播播放使用的低延迟播放器,来配合测试我们的RTMP推送模块使用时,居然发现没有一款好用的,市面上的,如VLC或Vitamio,说白了都是基于FFMPEG,在点播这块支持格式很多,也非常优异,但是直播这块,特别是RTMP,延迟要几秒钟,对如纯音频、纯视频播放,快速启播、网络异常状态处理、集成复杂度等各方面,支持非常差,而且因为功能强大,bug很多,除了行业内资深的开发者能驾驭,好多开发者甚至连编译整体环境,都要耗费很大的精力。

我们的直播播放器,始于Windows平台,Android和iOS同步开发,基于上述开源播放器的各种缺点,我们考虑全自研框架,确保整体设计跨平台,再保障播放流程度的前提下,尽可能的做到毫秒级延迟,接口设计三个平台统一化,确保多平台集成复杂度降到最低。

整体方案架构

RTMP或RTSP直播播放器,目标很明确,从RTMP服务器(自建服务器或CDN)或RTSP服务器(或NVR/IPC/编码器等)拉取流数据,完成数据解析、解码、音视频数据同步、绘制。

具体对应下图“接收端”部分:

初期模块设计目标

  • 自有框架,易于扩展,自适应算法让延迟更低、解码绘制效率更高;
  • 支持各种异常网络状态处理,如断网重连、网络抖动等控制;
  • 有Event状态回调,确保开发者可以了解到播放端整体的状态,从纯黑盒不可控,到更智能的了解到整体播放状态;
  • 支持多实例播放;
  • 视频支持H.264,音频支持AAC/PCMA/PCMU;
  • 支持缓冲时间设置(buffer time);
  • 实时静音。

经过迭代后的功能

  • [支持播放协议]RTSP、RTMP,毫秒级延迟;
  •  [多实例播放]支持多实例播放;
  •  [事件回调]支持网络状态、buffer状态等回调;
  •  [视频格式]支持RTMP扩展H.265,H.264;
  •  [音频格式]支持AAC/PCMA/PCMU/Speex;
  •  [H.264/H.265软解码]支持H.264/H.265软解;
  •  [H.264硬解码]Windows/Android/iOS支持H.264硬解;
  •  [H.265硬解]Windows/Android/iOS支持H.265硬解;
  •  [H.264/H.265硬解码]Android支持设置Surface模式硬解和普通模式硬解码;
  •  [缓冲时间设置]支持buffer time设置;
  •  [首屏秒开]支持首屏秒开模式;
  •  [低延迟模式]支持类似于线上娃娃机等直播方案的超低延迟模式设置(公网200~400ms);
  •  [复杂网络处理]支持断网重连等各种网络环境自动适配;
  •  [快速切换URL]支持播放过程中,快速切换其他URL,内容切换更快;
  •  [音视频多种render机制]Android平台,视频:surfaceview/OpenGL ES,音频:AudioTrack/OpenSL ES;
  •  [实时静音]支持播放过程中,实时静音/取消静音;
  •  [实时快照]支持播放过程中截取当前播放画面;
  •  [只播关键帧]Windows平台支持实时设置是否只播放关键帧;
  •  [渲染角度]支持0°,90°,180°和270°四个视频画面渲染角度设置;
  •  [渲染镜像]支持水平反转、垂直反转模式设置;
  •  [实时下载速度更新]支持当前下载速度实时回调(支持设置回调时间间隔);
  •  [ARGB叠加]Windows平台支持ARGB图像叠加到显示视频(参看C++的DEMO);
  •  [解码前视频数据回调]支持H.264/H.265数据回调;
  •  [解码后视频数据回调]支持解码后YUV/RGB数据回调;
  •  [解码后视频数据缩放回调]Windows平台支持指定回调图像大小的接口(可以对原视图像缩放后再回调到上层);
  •  [解码前音频数据回调]支持AAC/PCMA/PCMU/SPEEX数据回调;
  •  [音视频自适应]支持播放过程中,音视频信息改变后自适应;
  •  [扩展录像功能]支持RTSP/RTMP H.264、扩展H.265流录制,支持PCMA/PCMU/Speex转AAC后录制,支持设置只录制音频或视频等;

RTMP、RTSP直播播放开发设计考虑的点

1. 低延迟:大多数RTSP的播放都面向直播场景,所以,如果延迟过大,严重影响体验,所以,低延迟是衡量一个好的RTSP播放器非常重要的指标,目前大牛直播SDK的RTSP直播播放延迟比开源播放器更优异,而且长时间运行下,不会造成延迟累积;

2. 音视频同步处理有些播放器为了追求低延迟,甚至不做音视频同步,拿到audio video直接播放,导致a/v不同步,还有就是时间戳乱跳等各种问题,大牛直播SDK提供的播放器,具备好的时间戳同步和异常时间戳矫正机制;

3. 支持多实例:大牛直播SDK提供的播放器支持同时播放多路音视频数据,比如4-8-9窗口,大多开源播放器对多实例支持不太友好;

4. 支持buffer time设置:在一些有网络抖动的场景,播放器需要支持buffer time设置,一般来说,以毫秒计,开源播放器对此支持不够友好;

5. TCP/UDP模式设定自动切换:考虑到好多服务器仅支持TCP或UDP模式,一个好的RTSP播放器需要支持TCP/UDP模式设置,如链接不支持TCP或UDP,大牛直播SDK可自动切换,,开源播放器不具备自动切换TCP/UDP能力;

6. 实时静音:比如,多窗口播放RTSP流,如果每个audio都播放出来,体验非常不好,所以实时静音功能非常必要,开源播放器不具备实时静音功能;

7. 视频view旋转:好多摄像头由于安装限制,导致图像倒置,所以一个好的RTSP播放器应该支持如视频view实时旋转(0° 90° 180° 270°)、水平反转、垂直反转,开源播放器不具备此功能;

8. 支持解码后audio/video数据输出:大牛直播SDK接触到好多开发者,希望能在播放的同时,获取到YUV或RGB数据,进行人脸匹配等算法分析,开源播放器不具备此功能;

9. 实时快照:感兴趣或重要的画面,实时截取下来非常必要,一般播放器不具备快照能力,开源播放器不具备此功能;

10. 网络抖动处理(如断网重连):稳定的网络处理机制、支持如断网重连等,开源播放器对网络异常处理支持较差;

11. 长期运行稳定性:不同于市面上的开源播放器,大牛直播SDK提供的Windows平台RTSP直播播放SDK适用于数天长时间运行,开源播放器对长时间运行稳定性支持较差;

12. log信息记录:整体流程机制记录到LOG文件,确保出问题时,有据可依,开源播放器几无log记录。

13. 实时下载速度反馈:大牛直播SDK提供音视频流实时下载回调,并可设置回调时间间隔,确保实时下载速度反馈,以此来监听网络状态,开源播放器不具备此能力;

14. 异常状态处理Event状态回调如播放的过程中,断网、网络抖动、等各种场景,大牛直播SDK提供的播放器可实时回调相关状态,确保上层模块感知处理,开源播放器对此支持不好;

15. 关键帧/全帧播放实时切换:特别是播放多路画面的时候,如果路数过多,全部解码、绘制,系统资源占用会加大,如果能灵活的处理,可以随时只播放关键帧,全帧播放切换,对系统性能要求大幅降低。

接口设计

好多开发者,在初期设计接口的时候,如果没有足够的音视频背景,很容易反复推翻之前的设计,我们以Windows平台为例,共享我们的设计思路,如需要下载demo工程源码,可以到 GitHub 下载参考:

smart_player_sdk.h

#ifdef __cplusplus
extern "C"{
#endiftypedef struct _SmartPlayerSDKAPI{/*flag目前传0,后面扩展用, pReserve传NULL,扩展用,成功返回 NT_ERC_OK*/NT_UINT32(NT_API *Init)(NT_UINT32 flag, NT_PVOID pReserve);/*这个是最后一个调用的接口成功返回 NT_ERC_OK*/NT_UINT32(NT_API *UnInit)();/*flag目前传0,后面扩展用, pReserve传NULL,扩展用,NT_HWND hwnd, 绘制画面用的窗口, 可以设置为NULL获取Handle成功返回 NT_ERC_OK*/NT_UINT32(NT_API *Open)(NT_PHANDLE pHandle, NT_HWND hwnd, NT_UINT32 flag, NT_PVOID pReserve);/*调用这个接口之后handle失效,成功返回 NT_ERC_OK*/NT_UINT32(NT_API *Close)(NT_HANDLE handle);/*设置事件回调,如果想监听事件的话,建议调用Open成功后,就调用这个接口*/NT_UINT32(NT_API *SetEventCallBack)(NT_HANDLE handle,NT_PVOID call_back_data, NT_SP_SDKEventCallBack call_back);/*设置视频大小回调接口*/NT_UINT32(NT_API *SetVideoSizeCallBack)(NT_HANDLE handle, NT_PVOID call_back_data, SP_SDKVideoSizeCallBack call_back);/*设置视频回调, 吐视频数据出来frame_format: 只能是NT_SP_E_VIDEO_FRAME_FORMAT_RGB32, NT_SP_E_VIDEO_FRAME_FROMAT_I420*/NT_UINT32(NT_API *SetVideoFrameCallBack)(NT_HANDLE handle,NT_INT32 frame_format,NT_PVOID call_back_data, SP_SDKVideoFrameCallBack call_back);/*设置视频回调, 吐视频数据出来, 可以指定吐出来的视频宽高*handle: 播放句柄*scale_width:缩放宽度(必须是偶数,建议是 16 的倍数)*scale_height:缩放高度(必须是偶数*scale_filter_mode: 缩放质量, 0 的话 SDK 将使用默认值, 目前可设置范围为[1, 3], 值越大 缩放质量越好,但越耗性能*frame_format: 只能是NT_SP_E_VIDEO_FRAME_FORMAT_RGB32, NT_SP_E_VIDEO_FRAME_FROMAT_I420成功返回NT_ERC_OK*/NT_UINT32(NT_API *SetVideoFrameCallBackV2)(NT_HANDLE handle,NT_INT32 scale_width, NT_INT32 scale_height,NT_INT32 scale_filter_mode, NT_INT32 frame_format,NT_PVOID call_back_data, SP_SDKVideoFrameCallBack call_back);/**设置绘制视频帧时,视频帧时间戳回调*注意如果当前播放流是纯音频,那么将不会回调,这个仅在有视频的情况下才有效*/NT_UINT32(NT_API *SetRenderVideoFrameTimestampCallBack)(NT_HANDLE handle,NT_PVOID call_back_data, SP_SDKRenderVideoFrameTimestampCallBack call_back);/*设置音频PCM帧回调, 吐PCM数据出来,目前每帧大小是10ms.*/NT_UINT32(NT_API *SetAudioPCMFrameCallBack)(NT_HANDLE handle,NT_PVOID call_back_data, NT_SP_SDKAudioPCMFrameCallBack call_back);/*设置用户数据回调*/NT_UINT32(NT_API *SetUserDataCallBack)(NT_HANDLE handle,NT_PVOID call_back_data, NT_SP_SDKUserDataCallBack call_back);/*设置视频sei数据回调*/NT_UINT32(NT_API *SetSEIDataCallBack)(NT_HANDLE handle,NT_PVOID call_back_data, NT_SP_SDKSEIDataCallBack call_back);/*开始播放,传URL进去注意:这个接口目前不再推荐使用,请使用StartPlay. 为方便老客户升级,暂时保留. */NT_UINT32(NT_API *Start)(NT_HANDLE handle, NT_PCSTR url, NT_PVOID call_back_data, SP_SDKStartPlayCallBack call_back);/*停止播放注意: 这个接口目前不再推荐使用,请使用StopPlay. 为方便老客户升级,暂时保留. */NT_UINT32(NT_API *Stop)(NT_HANDLE handle);/**提供一组新接口++*//**设置URL成功返回NT_ERC_OK*/NT_UINT32(NT_API *SetURL)(NT_HANDLE handle, NT_PCSTR url);/*** 设置解密key,目前只用来解密rtmp加密流* key: 解密密钥* size: 密钥长度* 成功返回NT_ERC_OK*/NT_UINT32(NT_API *SetKey)(NT_HANDLE handle, const NT_BYTE* key, NT_UINT32 size);/*** 设置解密向量,目前只用来解密rtmp加密流* iv:  解密向量* size: 向量长度* 成功返回NT_ERC_OK*/NT_UINT32(NT_API *SetDecryptionIV)(NT_HANDLE handle, const NT_BYTE* iv, NT_UINT32 size);/*handle: 播放句柄hwnd: 这个要传入真正用来绘制的窗口句柄is_support: 如果支持的话 *is_support 为1, 不支持的话为0接口调用成功返回NT_ERC_OK*/NT_UINT32(NT_API *IsSupportD3DRender)(NT_HANDLE handle, NT_HWND hwnd, NT_INT32* is_support);/*设置绘制窗口句柄,如果在调用Open时设置过,那这个接口可以不调用如果在调用Open时设置为NULL,那么这里可以设置一个绘制窗口句柄给播放器成功返回NT_ERC_OK*/NT_UINT32(NT_API *SetRenderWindow)(NT_HANDLE handle, NT_HWND hwnd);/** 设置是否播放出声音,这个和静音接口是有区别的* 这个接口的主要目的是为了用户设置了外部PCM回调接口后,又不想让SDK播放出声音时使用* is_output_auido_device: 1: 表示允许输出到音频设备,默认是1, 0:表示不允许输出. 其他值接口返回失败* 成功返回NT_ERC_OK*/NT_UINT32(NT_API *SetIsOutputAudioDevice)(NT_HANDLE handle, NT_INT32 is_output_auido_device);/**开始播放, 注意StartPlay和Start不能混用,要么使用StartPlay, 要么使用Start.* Start和Stop是老接口,不推荐用。请使用StartPlay和StopPlay新接口*/NT_UINT32(NT_API *StartPlay)(NT_HANDLE handle);/**停止播放*/NT_UINT32(NT_API *StopPlay)(NT_HANDLE handle);/** 设置是否录视频,默认的话,如果视频源有视频就录,没有就没得录, 但有些场景下可能不想录制视频,只想录音频,所以增加个开关* is_record_video: 1 表示录制视频, 0 表示不录制视频, 默认是1*/NT_UINT32(NT_API *SetRecorderVideo)(NT_HANDLE handle, NT_INT32 is_record_video);/** 设置是否录音频,默认的话,如果视频源有音频就录,没有就没得录, 但有些场景下可能不想录制音频,只想录视频,所以增加个开关* is_record_audio: 1 表示录制音频, 0 表示不录制音频, 默认是1*/NT_UINT32(NT_API *SetRecorderAudio)(NT_HANDLE handle, NT_INT32 is_record_audio);/*设置本地录像目录, 必须是英文目录,否则会失败*/NT_UINT32(NT_API *SetRecorderDirectory)(NT_HANDLE handle, NT_PCSTR dir);/*设置单个录像文件最大大小, 当超过这个值的时候,将切割成第二个文件size: 单位是KB(1024Byte), 当前范围是 [5MB-800MB], 超出将被设置到范围内*/NT_UINT32(NT_API *SetRecorderFileMaxSize)(NT_HANDLE handle, NT_UINT32 size);/*设置录像文件名生成规则*/NT_UINT32(NT_API *SetRecorderFileNameRuler)(NT_HANDLE handle, NT_SP_RecorderFileNameRuler* ruler);/*设置录像回调接口*/NT_UINT32(NT_API *SetRecorderCallBack)(NT_HANDLE handle,NT_PVOID call_back_data, SP_SDKRecorderCallBack call_back);/*设置录像时音频转AAC编码的开关, aac比较通用,sdk增加其他音频编码(比如speex, pcmu, pcma等)转aac的功能.is_transcode: 设置为1的话,如果音频编码不是aac,则转成aac, 如果是aac,则不做转换. 设置为0的话,则不做任何转换. 默认是0.注意: 转码会增加性能消耗*/NT_UINT32(NT_API *SetRecorderAudioTranscodeAAC)(NT_HANDLE handle, NT_INT32 is_transcode);/*启动录像*/NT_UINT32(NT_API *StartRecorder)(NT_HANDLE handle);/*停止录像*/NT_UINT32(NT_API *StopRecorder)(NT_HANDLE handle);/** 设置拉流时,吐视频数据的回调*/NT_UINT32(NT_API *SetPullStreamVideoDataCallBack)(NT_HANDLE handle,NT_PVOID call_back_data, SP_SDKPullStreamVideoDataCallBack call_back);/** 设置拉流时,吐音频数据的回调*/NT_UINT32(NT_API *SetPullStreamAudioDataCallBack)(NT_HANDLE handle,NT_PVOID call_back_data, SP_SDKPullStreamAudioDataCallBack call_back);/*设置拉流时音频转AAC编码的开关, aac比较通用,sdk增加其他音频编码(比如speex, pcmu, pcma等)转aac的功能.is_transcode: 设置为1的话,如果音频编码不是aac,则转成aac, 如果是aac,则不做转换. 设置为0的话,则不做任何转换. 默认是0.注意: 转码会增加性能消耗*/NT_UINT32(NT_API *SetPullStreamAudioTranscodeAAC)(NT_HANDLE handle, NT_INT32 is_transcode);/*启动拉流*/NT_UINT32(NT_API *StartPullStream)(NT_HANDLE handle);/*停止拉流*/NT_UINT32(NT_API *StopPullStream)(NT_HANDLE handle);/**提供一组新接口--*//*绘制窗口大小改变时,必须调用*/NT_UINT32(NT_API* OnWindowSize)(NT_HANDLE handle, NT_INT32 cx, NT_INT32 cy);/*万能接口, 设置参数, 大多数问题, 这些接口都能解决*/NT_UINT32(NT_API *SetParam)(NT_HANDLE handle, NT_UINT32 id, NT_PVOID pData);/*万能接口, 得到参数, 大多数问题,这些接口都能解决*/NT_UINT32(NT_API *GetParam)(NT_HANDLE handle, NT_UINT32 id, NT_PVOID pData);/*设置buffer,最小0ms*/NT_UINT32(NT_API *SetBuffer)(NT_HANDLE handle, NT_INT32 buffer);/*静音接口,1为静音,0为不静音*/NT_UINT32(NT_API *SetMute)(NT_HANDLE handle, NT_INT32 is_mute);/*设置RTSP TCP 模式, 1为TCP, 0为UDP, 仅RTSP有效*/NT_UINT32(NT_API* SetRTSPTcpMode)(NT_HANDLE handle, NT_INT32 isUsingTCP);/*设置RTSP超时时间, timeout单位为秒,必须大于0*/NT_UINT32 (NT_API* SetRtspTimeout)(NT_HANDLE handle, NT_INT32 timeout);/*对于RTSP来说,有些可能支持rtp over udp方式,有些可能支持使用rtp over tcp方式. 为了方便使用,有些场景下可以开启自动尝试切换开关, 打开后如果udp无法播放,sdk会自动尝试tcp, 如果tcp方式播放不了,sdk会自动尝试udp.is_auto_switch_tcp_udp: 如果设置1的话, sdk将在tcp和udp之间尝试切换播放,如果设置为0,则不尝试切换.*/NT_UINT32 (NT_API* SetRtspAutoSwitchTcpUdp)(NT_HANDLE handle, NT_INT32 is_auto_switch_tcp_udp);/*设置秒开, 1为秒开, 0为不秒开*/NT_UINT32(NT_API* SetFastStartup)(NT_HANDLE handle, NT_INT32 isFastStartup);/*设置低延时播放模式,默认是正常播放模式mode: 1为低延时模式, 0为正常模式,其他只无效接口调用成功返回NT_ERC_OK*/NT_UINT32(NT_API* SetLowLatencyMode)(NT_HANDLE handle, NT_INT32 mode);/*检查是否支持H264硬解码如果支持的话返回NT_ERC_OK*/NT_UINT32(NT_API *IsSupportH264HardwareDecoder)();/*检查是否支持H265硬解码如果支持的话返回NT_ERC_OK*/NT_UINT32(NT_API *IsSupportH265HardwareDecoder)();/**设置H264硬解*is_hardware_decoder: 1:表示硬解, 0:表示不用硬解*reserve: 保留参数, 当前传0就好*成功返回NT_ERC_OK*/NT_UINT32(NT_API *SetH264HardwareDecoder)(NT_HANDLE handle, NT_INT32 is_hardware_decoder, NT_INT32 reserve);/**设置H265硬解*is_hardware_decoder: 1:表示硬解, 0:表示不用硬解*reserve: 保留参数, 当前传0就好*成功返回NT_ERC_OK*/NT_UINT32(NT_API *SetH265HardwareDecoder)(NT_HANDLE handle, NT_INT32 is_hardware_decoder, NT_INT32 reserve);/**设置只解码视频关键帧*is_only_dec_key_frame: 1:表示只解码关键帧, 0:表示都解码, 默认是0*成功返回NT_ERC_OK*/NT_UINT32(NT_API *SetOnlyDecodeVideoKeyFrame)(NT_HANDLE handle, NT_INT32 is_only_dec_key_frame);/**上下反转(垂直反转)*is_flip: 1:表示反转, 0:表示不反转*/NT_UINT32(NT_API *SetFlipVertical)(NT_HANDLE handle, NT_INT32 is_flip);/**水平反转*is_flip: 1:表示反转, 0:表示不反转*/NT_UINT32(NT_API *SetFlipHorizontal)(NT_HANDLE handle, NT_INT32 is_flip);/*设置旋转,顺时针旋转degress: 设置0, 90, 180, 270度有效,其他值无效注意:除了0度,其他角度播放会耗费更多CPU接口调用成功返回NT_ERC_OK*/NT_UINT32(NT_API* SetRotation)(NT_HANDLE handle, NT_INT32 degress);/** 在使用D3D绘制的情况下,给绘制窗口上画一个logo, logo的绘制由视频帧驱动, 必须传入argb图像* argb_data: argb图像数据, 如果传null的话,将清除之前设置的logo* argb_stride: argb图像每行的步长(一般都是image_width*4)* image_width: argb图像宽度* image_height: argb图像高度* left: 绘制位置的左边x* top: 绘制位置的顶部y* render_width: 绘制的宽度* render_height: 绘制的高度*/NT_UINT32(NT_API* SetRenderARGBLogo)(NT_HANDLE handle, const NT_BYTE* argb_data, NT_INT32 argb_stride,NT_INT32 image_width, NT_INT32 image_height,NT_INT32 left, NT_INT32 top,NT_INT32 render_width, NT_INT32 render_height);/*设置下载速度上报, 默认不上报下载速度is_report: 上报开关, 1: 表上报. 0: 表示不上报. 其他值无效.report_interval: 上报时间间隔(上报频率),单位是秒,最小值是1秒1次. 如果小于1且设置了上报,将调用失败注意:如果设置上报的话,请设置SetEventCallBack, 然后在回调函数里面处理这个事件.上报事件是:NT_SP_E_EVENT_ID_DOWNLOAD_SPEED这个接口必须在StartXXX之前调用成功返回NT_ERC_OK*/NT_UINT32(NT_API *SetReportDownloadSpeed)(NT_HANDLE handle,NT_INT32 is_report, NT_INT32 report_interval);/*主动获取下载速度speed: 返回下载速度,单位是Byte/s(注意:这个接口必须在startXXX之后调用,否则会失败)成功返回NT_ERC_OK*/NT_UINT32(NT_API *GetDownloadSpeed)(NT_HANDLE handle, NT_INT32* speed);/*获取视频时长对于直播的话,没有时长,调用结果未定义点播的话,如果获取成功返回NT_ERC_OK, 如果SDK还在解析中,则返回NT_ERC_SP_NEED_RETRY*/NT_UINT32(NT_API *GetDuration)(NT_HANDLE handle, NT_INT64* duration);/*获取当前播放时间戳, 单位是毫秒(ms)注意:这个时间戳是视频源的时间戳,只支持点播. 直播不支持.成功返回NT_ERC_OK*/NT_UINT32(NT_API *GetPlaybackPos)(NT_HANDLE handle, NT_INT64* pos);/*获取当前拉流时间戳, 单位是毫秒(ms)注意:这个时间戳是视频源的时间戳,只支持点播. 直播不支持.成功返回NT_ERC_OK*/NT_UINT32(NT_API *GetPullStreamPos)(NT_HANDLE handle, NT_INT64* pos);/*设置播放位置,单位是毫秒(ms)注意:直播不支持,这个接口用于点播成功返回NT_ERC_OK*/NT_UINT32(NT_API *SetPos)(NT_HANDLE handle, NT_INT64 pos);/*暂停播放isPause: 1表示暂停, 0表示恢复播放, 其他错误注意:直播不存在暂停的概念,所以直播不支持,这个接口用于点播成功返回NT_ERC_OK*/NT_UINT32(NT_API *Pause)(NT_HANDLE handle, NT_INT32 isPause);/*切换URLurl:要切换的urlswitch_pos: 切换到新url以后,设置的播放位置, 默认请填0, 这个只对设置播放位置的点播url有效, 直播url无效reserve: 保留参数注意: 1. 如果切换的url和正在播放的url相同,sdk则不做任何处理调用前置条件: 已经成功调用了 StartPlay, StartRecorder, StartPullStream 三个中的任意一个接口成功返回NT_ERC_OK*/NT_UINT32(NT_API *SwitchURL)(NT_HANDLE handle, NT_PCSTR url, NT_INT64 switch_pos, NT_INT32 reserve);/*捕获图片file_name_utf8: 文件名称,utf8编码call_back_data: 回调时用户自定义数据call_back: 回调函数,用来通知用户截图已经完成或者失败成功返回 NT_ERC_OK只有在播放时调用才可能成功,其他情况下调用,返回错误.因为生成PNG文件比较耗时,一般需要几百毫秒,为防止CPU过高,SDK会限制截图请求数量,当超过一定数量时,调用这个接口会返回NT_ERC_SP_TOO_MANY_CAPTURE_IMAGE_REQUESTS. 这种情况下, 请延时一段时间,等SDK处理掉一些请求后,再尝试.*/NT_UINT32(NT_API* CaptureImage)(NT_HANDLE handle, NT_PCSTR file_name_utf8,NT_PVOID call_back_data, SP_SDKCaptureImageCallBack call_back);/** 使用GDI绘制RGB32数据* 32位的rgb格式, r, g, b各占8, 另外一个字节保留, 内存字节格式为: bb gg rr xx, 主要是和windows位图匹配, 在小端模式下,按DWORD类型操作,最高位是xx, 依次是rr, gg, bb* 为了保持和windows位图兼容,步长(image_stride)必须是width_*4* handle: 播放器句柄* hdc: 绘制dc* x_dst: 绘制面左上角x坐标* y_dst: 绘制面左上角y坐标* dst_width: 要绘制的宽度* dst_height: 要绘制的高度* x_src: 源图像x位置* y_src: 原图像y位置* rgb32_data: rgb32数据,格式参见前面的注释说明* rgb32_data_size: 数据大小* image_width: 图像实际宽度* image_height: 图像实际高度* image_stride: 图像步长*/NT_UINT32(NT_API *GDIDrawRGB32)(NT_HANDLE handle, NT_HDC hdc,NT_INT32 x_dst, NT_INT32 y_dst,NT_INT32 dst_width, NT_INT32 dst_height,NT_INT32 x_src, NT_INT32 y_src,NT_INT32 src_width, NT_INT32 src_height,const NT_BYTE* rgb32_data, NT_UINT32 rgb32_data_size,NT_INT32 image_width, NT_INT32 image_height,NT_INT32 image_stride);/** 使用GDI绘制ARGB数据* 内存字节格式为: bb gg rr alpha, 主要是和windows位图匹配, 在小端模式下,按DWORD类型操作,最高位是alpha, 依次是rr, gg, bb* 为了保持和windows位图兼容,步长(image_stride)必须是width_*4* hdc: 绘制dc* x_dst: 绘制面左上角x坐标* y_dst: 绘制面左上角y坐标* dst_width: 要绘制的宽度* dst_height: 要绘制的高度* x_src: 源图像x位置* y_src: 原图像y位置* argb_data: argb图像数据, 格式参见前面的注释说明* image_stride: 图像每行步长* image_width: 图像实际宽度* image_height: 图像实际高度*/NT_UINT32(NT_API *GDIDrawARGB)(NT_HDC hdc,NT_INT32 x_dst, NT_INT32 y_dst,NT_INT32 dst_width, NT_INT32 dst_height,NT_INT32 x_src, NT_INT32 y_src,NT_INT32 src_width, NT_INT32 src_height,const NT_BYTE* argb_data, NT_INT32 image_stride,NT_INT32 image_width, NT_INT32 image_height);} SmartPlayerSDKAPI;NT_UINT32 NT_API GetSmartPlayerSDKAPI(SmartPlayerSDKAPI* pAPI);/*reserve1: 请传0NT_PVOID: 请传NULL成功返回: NT_ERC_OK*/NT_UINT32 NT_API NT_SP_SetSDKClientKey(NT_PCSTR cid, NT_PCSTR key, NT_INT32 reserve1, NT_PVOID reserve2);#ifdef __cplusplus
}
#endif

smart_player_define.h

#ifndef SMART_PLAYER_DEFINE_H_
#define SMART_PLAYER_DEFINE_H_#ifdef WIN32
#include <windows.h>
#endif#ifdef SMART_HAS_COMMON_DIC
#include "../../topcommon/nt_type_define.h"
#include "../../topcommon/nt_base_code_define.h"
#else
#include "nt_type_define.h"
#include "nt_base_code_define.h"
#endif#ifdef __cplusplus
extern "C"{
#endif#ifndef NT_HWND_
#define NT_HWND_
#ifdef WIN32
typedef HWND NT_HWND;
#else
typedef void* NT_HWND;
#endif
#endif#ifndef NT_HDC_
#define NT_HDC_#ifdef _WIN32
typedef HDC NT_HDC;
#else
typedef void* NT_HDC;
#endif#endif/*错误码*/
typedef enum _SP_E_ERROR_CODE
{NT_ERC_SP_HWND_IS_NULL = (NT_ERC_SMART_PLAYER_SDK | 0x1), // 窗口句柄是空NT_ERC_SP_HWND_INVALID = (NT_ERC_SMART_PLAYER_SDK | 0x2), // 窗口句柄无效NT_ERC_SP_TOO_MANY_CAPTURE_IMAGE_REQUESTS = (NT_ERC_SMART_PLAYER_SDK | 0x3), // 太多的截图请求NT_ERC_SP_WINDOW_REGION_INVALID = (NT_ERC_SMART_PLAYER_SDK | 0x4), // 窗口区域无效,可能窗口宽或者高小于1NT_ERC_SP_DIR_NOT_EXIST = (NT_ERC_SMART_PLAYER_SDK | 0x5), // 目录不存在NT_ERC_SP_NEED_RETRY = (NT_ERC_SMART_PLAYER_SDK | 0x6), // 需要重试
} SP_E_ERROR_CODE;/*设置参数ID, 这个目前这么写,SmartPlayerSDK 已经划分范围*/
typedef enum _SP_E_PARAM_ID
{SP_PARAM_ID_BASE = NT_PARAM_ID_SMART_PLAYER_SDK,} SP_E_PARAM_ID;/*事件ID*/
typedef enum _NT_SP_E_EVENT_ID
{NT_SP_E_EVENT_ID_BASE = NT_EVENT_ID_SMART_PLAYER_SDK,NT_SP_E_EVENT_ID_CONNECTING				= NT_SP_E_EVENT_ID_BASE | 0x2,	/*连接中*/NT_SP_E_EVENT_ID_CONNECTION_FAILED		= NT_SP_E_EVENT_ID_BASE | 0x3,	/*连接失败*/NT_SP_E_EVENT_ID_CONNECTED				= NT_SP_E_EVENT_ID_BASE | 0x4,	/*已连接*/NT_SP_E_EVENT_ID_DISCONNECTED			= NT_SP_E_EVENT_ID_BASE | 0x5,	/*断开连接*/NT_SP_E_EVENT_ID_NO_MEDIADATA_RECEIVED	= NT_SP_E_EVENT_ID_BASE | 0x8,	/*收不到RTMP数据*/NT_SP_E_EVENT_ID_RTSP_STATUS_CODE       = NT_SP_E_EVENT_ID_BASE | 0xB,  /*rtsp status code上报, 目前只上报401, param1表示status code*/NT_SP_E_EVENT_ID_NEED_KEY               = NT_SP_E_EVENT_ID_BASE | 0xC,  /*需要输入解密key才能播放*/NT_SP_E_EVENT_ID_KEY_ERROR              = NT_SP_E_EVENT_ID_BASE | 0xD,  /*解密key不正确*//* 接下来请从0x81开始*/NT_SP_E_EVENT_ID_START_BUFFERING = NT_SP_E_EVENT_ID_BASE | 0x81, /*开始缓冲*/NT_SP_E_EVENT_ID_BUFFERING		 = NT_SP_E_EVENT_ID_BASE | 0x82, /*缓冲中, param1 表示百分比进度*/NT_SP_E_EVENT_ID_STOP_BUFFERING  = NT_SP_E_EVENT_ID_BASE | 0x83, /*停止缓冲*/NT_SP_E_EVENT_ID_DOWNLOAD_SPEED  = NT_SP_E_EVENT_ID_BASE | 0x91, /*下载速度, param1表示下载速度,单位是(Byte/s)*/NT_SP_E_EVENT_ID_PLAYBACK_REACH_EOS		= NT_SP_E_EVENT_ID_BASE | 0xa1, /*播放结束, 直播流没有这个事件,点播流才有*/NT_SP_E_EVENT_ID_RECORDER_REACH_EOS		= NT_SP_E_EVENT_ID_BASE | 0xa2, /*录像结束, 直播流没有这个事件, 点播流才有*/NT_SP_E_EVENT_ID_PULLSTREAM_REACH_EOS   = NT_SP_E_EVENT_ID_BASE | 0xa3, /*拉流结束, 直播流没有这个事件,点播流才有*/NT_SP_E_EVENT_ID_DURATION				= NT_SP_E_EVENT_ID_BASE | 0xa8, /*视频时长,如果是直播,则不上报,如果是点播的话, 若能从视频源获取视频时长的话,则上报, param1表示视频时长,单位是毫秒(ms)*/} NT_SP_E_EVENT_ID;//定义视频帧图像格式
typedef enum _NT_SP_E_VIDEO_FRAME_FORMAT
{NT_SP_E_VIDEO_FRAME_FORMAT_RGB32 = 1, // 32位的rgb格式, r, g, b各占8, 另外一个字节保留, 内存字节格式为: bb gg rr xx, 主要是和windows位图匹配, 在小端模式下,按DWORD类型操作,最高位是xx, 依次是rr, gg, bbNT_SP_E_VIDEO_FRAME_FORMAT_ARGB  = 2, // 32位的argb格式,内存字节格式是: bb gg rr aa 这种类型,和windows位图匹配NT_SP_E_VIDEO_FRAME_FROMAT_I420  = 3, // YUV420格式, 三个分量保存在三个面上
} NT_SP_E_VIDEO_FRAME_FORMAT;// 定义视频帧结构.
typedef struct _NT_SP_VideoFrame
{NT_INT32  format_;  // 图像格式, 请参考NT_SP_E_VIDEO_FRAME_FORMATNT_INT32  width_;   // 图像宽NT_INT32  height_;  // 图像高NT_UINT64 timestamp_; // 时间戳, 一般是0,不使用, 以ms为单位的// 具体的图像数据, argb和rgb32只用第一个, I420用前三个NT_UINT8* plane0_;NT_UINT8* plane1_;NT_UINT8* plane2_;NT_UINT8* plane3_;// 每一个平面的每一行的字节数,对于argb和rgb32,为了保持和windows位图兼容,必须是width_*4// 对于I420, stride0_ 是y的步长, stride1_ 是u的步长, stride2_ 是v的步长,NT_INT32  stride0_;NT_INT32  stride1_;NT_INT32  stride2_;NT_INT32  stride3_;} NT_SP_VideoFrame;// 如果三项都是0的话,将不能启动录像
typedef struct _NT_SP_RecorderFileNameRuler
{NT_UINT32	type_; // 这个值目前默认是0,将来扩展用NT_PCSTR	file_name_prefix_; // 设置一个录像文件名前缀, 例如:daniuliveNT_INT32	append_date_; // 如果是1的话,将在文件名上加日期, 例如:daniulive-2017-01-17NT_INT32	append_time_; //  如果是1的话,将增加时间,例如:daniulive-2017-01-17-17-10-36
} NT_SP_RecorderFileNameRuler;/*
*拉流吐视频数据时,一些相关的数据
*/
typedef struct _NT_SP_PullStreamVideoDataInfo
{NT_INT32  is_key_frame_; /* 1:表示关键帧, 0:表示非关键帧 */NT_UINT64 timestamp_;	/* 解码时间戳, 单位是毫秒 */NT_INT32  width_;	/* 一般是0 */NT_INT32  height_; /* 一般也是0 */NT_BYTE*  parameter_info_; /* 一般是NULL */NT_UINT32 parameter_info_size_; /* 一般是0 */NT_UINT64 presentation_timestamp_; /*显示时间戳, 这个值要大于或等于timestamp_, 单位是毫秒*/} NT_SP_PullStreamVideoDataInfo;/*
*拉流吐音频数据时,一些相关的数据
*/
typedef struct _NT_SP_PullStreamAuidoDataInfo
{NT_INT32  is_key_frame_; /* 1:表示关键帧, 0:表示非关键帧 */NT_UINT64 timestamp_;	/* 单位是毫秒 */NT_INT32  sample_rate_;	/* 一般是0 */NT_INT32  channel_; /* 一般是0 */NT_BYTE*  parameter_info_; /* 如果是AAC的话,这个是有值的, 其他编码一般忽略 */NT_UINT32 parameter_info_size_; /*如果是AAC的话,这个是有值的, 其他编码一般忽略 */NT_UINT64 reserve_; /* 保留  */} NT_SP_PullStreamAuidoDataInfo;/*
当播放器得到时候视频大小后,会回调
*/
typedef NT_VOID(NT_CALLBACK *SP_SDKVideoSizeCallBack)(NT_HANDLE handle, NT_PVOID user_data,NT_INT32 width, NT_INT32 height);/*
调用Start时传入, 回调接口
*/
typedef NT_VOID(NT_CALLBACK *SP_SDKStartPlayCallBack)(NT_HANDLE handle, NT_PVOID user_data, NT_UINT32 result);/*
视频图像回调
status:目前不用,默认是0,将来可能会用
*/
typedef NT_VOID(NT_CALLBACK* SP_SDKVideoFrameCallBack)(NT_HANDLE handle, NT_PVOID user_data, NT_UINT32 status,const NT_SP_VideoFrame* frame);/*
音频PCM数据回调, 目前每帧长度是10ms
status:目前不用,默认是0,将来可能会用
data: PCM 数据
size: 数据大小
sample_rate: 采样率
channel: 通道数
per_channel_sample_number: 每个通道的采样数
*/
typedef NT_VOID(NT_CALLBACK* NT_SP_SDKAudioPCMFrameCallBack)(NT_HANDLE handle, NT_PVOID user_data, NT_UINT32 status,NT_BYTE* data, NT_UINT32 size,NT_INT32 sample_rate, NT_INT32 channel, NT_INT32 per_channel_sample_number);/*
截屏回调
result: 如果截屏成功的话,result是NT_ERC_OK,其他错误
*/
typedef NT_VOID(NT_CALLBACK* SP_SDKCaptureImageCallBack)(NT_HANDLE handle, NT_PVOID user_data, NT_UINT32 result,NT_PCSTR file_name);/*
绘制视频时,视频帧时间戳回调, 这个用在一些特殊场景下,没有特殊需求的用户不需要关注
timestamp: 单位是毫秒
reserve1: 保留参数
reserve2: 保留参数
*/
typedef NT_VOID(NT_CALLBACK* SP_SDKRenderVideoFrameTimestampCallBack)(NT_HANDLE handle, NT_PVOID user_data, NT_UINT64 timestamp,NT_UINT64 reserve1, NT_PVOID reserve2);/*
录像回调
status: 1:表示开始写一个新录像文件. 2:表示已经写好一个录像文件
file_name: 实际录像文件名
*/
typedef NT_VOID(NT_CALLBACK* SP_SDKRecorderCallBack)(NT_HANDLE handle, NT_PVOID user_data, NT_UINT32 status,NT_PCSTR file_name);/*
*拉流时,视频数据回调
video_codec_id: 请参考NT_MEDIA_CODEC_ID
data: 视频数据
size: 视频数据大小
info: 视频数据相关信息
reserve: 保留参数
*/
typedef NT_VOID(NT_CALLBACK* SP_SDKPullStreamVideoDataCallBack)(NT_HANDLE handle, NT_PVOID user_data,NT_UINT32 video_codec_id, NT_BYTE* data, NT_UINT32 size, NT_SP_PullStreamVideoDataInfo* info,NT_PVOID reserve);/*
*拉流时,音频数据回调
auido_codec_id: 请参考NT_MEDIA_CODEC_ID
data: 音频数据
size: 音频数据大小
info: 音频数据相关信息
reserve: 保留参数
*/
typedef NT_VOID(NT_CALLBACK* SP_SDKPullStreamAudioDataCallBack)(NT_HANDLE handle, NT_PVOID user_data,NT_UINT32 auido_codec_id, NT_BYTE* data, NT_UINT32 size, NT_SP_PullStreamAuidoDataInfo* info,NT_PVOID reserve);/*
*播放器事件回调
event_id: 事件ID,请参考NT_SP_E_EVENT_ID
param1 到 param6, 值的意义和具体事件ID相关, 注意如果具体事件ID没有说明param1-param6的含义,那说明这个事件不带参数
*/
typedef NT_VOID(NT_CALLBACK* NT_SP_SDKEventCallBack)(NT_HANDLE handle, NT_PVOID user_data,NT_UINT32 event_id,NT_INT64  param1,NT_INT64  param2,NT_UINT64 param3,NT_PCSTR  param4,NT_PCSTR  param5,NT_PVOID  param6);/*
*
* 用户数据回调,目前是推送端发送过来的
* data_type: 数据类型,1:表示二进制字节类型. 2:表示utf8字符串 
* data:实际数据, 如果data_type是1的话,data类型是const NT_BYTE*, 如果data_type是2的话,data类型是 const NT_CHAR*
* size: 数据大小
* timestamp: 视频时间戳
* reserve1: 保留
* reserve2: 保留
* reserve3: 保留
*/
typedef NT_VOID(NT_CALLBACK* NT_SP_SDKUserDataCallBack)(NT_HANDLE handle, NT_PVOID user_data,NT_INT32  data_type,NT_PVOID  data,NT_UINT32 size,NT_UINT64 timestamp,NT_UINT64 reserve1,NT_INT64  reserve2,NT_PVOID  reserve3);/*
*
* 视频的sei数据回调
* data: sei 数据
* size: sei 数据大小
* timestamp:视频时间戳
* reserve1: 保留
* reserve2: 保留
* reserve3: 保留
* 注意: 目前测试发现有些视频有好几个sei nal, 为了方便用户处理,我们把解析到的所有sei都吐出来,sei nal之间还是用 00 00 00 01 分隔, 这样方便解析
* 吐出来的sei数据目前加了 00 00 00 01 前缀
*/
typedef NT_VOID(NT_CALLBACK* NT_SP_SDKSEIDataCallBack)(NT_HANDLE handle, NT_PVOID user_data,NT_BYTE*  data,NT_UINT32 size,NT_UINT64 timestamp,NT_UINT64 reserve1,NT_INT64  reserve2,NT_PVOID  reserve3);#ifdef __cplusplus
}
#endif#endif

总结

总的来说,无论是基于开源播放器二次开发,还是全自研,一个好的RTMP播放器或RTSP播放器,设计的时候,更多考虑的应该是如何做的更灵活、稳定,单纯的几个接口,很难满足通用化的产品诉求。

以下共勉:厚积薄发,登上山顶,不是为了饱览风光,是为了寻找更高的山峰!

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

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

相关文章

win7系统锁定计算机设置方法

我们都知道电脑长时间不使用的话&#xff0c;计算机就会自动进入锁定状态&#xff0c;但是也有用户不想让计算机自动进入锁定状态&#xff0c;但是却不知道应该怎么操作&#xff0c;为此非常苦恼&#xff0c;那么Win7锁定计算机怎么设置呢?今天为大家分享win7系统锁定计算机设…

Windows平台基于RTMP实现一对一互动直播

目前市面上大多一对一互动都是基于WebRTC&#xff0c;缺点如下&#xff1a; 服务器部署非常复杂&#xff0c;不利于私有部署&#xff0c;在一些私密性高的场景下&#xff0c;无法使用&#xff0c;如公安、市政等体系&#xff1b;传输基于UDP&#xff0c;很难保证传输质量&…

网易云音乐电脑版怎么下载电台节目 主播电台节目下载教程

网易云音乐不仅可以听歌&#xff0c;还可以在主播电台中&#xff0c;听到各类主播的声音&#xff0c;下面我们就来讲讲网易云音乐电脑版怎么下载电台节目&#xff0c;一起来看教程吧! 网易云音乐电脑版怎么下载电台节目 主播电台节目下载教程 网易云音乐PC版主播电台节目下载…

如何实现RTMP推送Android Camera2数据

Camera2简介 在Google 推出Android 5.0的时候, Android Camera API 版本升级到了API2(android.hardware.camera2), 之前使用的API1(android.hardware.camera)就被标为 Deprecated 了。 Camera API2相较于API1有很大不同, 并且API2是为了配合HAL3进行使用的, API2有很多API1不…

Android平台RTMP多实例推送的几种情况探讨

好多开发者提到&#xff0c;如何实现Android平台&#xff0c;多实例推送&#xff0c;多实例推送&#xff0c;有几种理解&#xff1a; 多路编码&#xff0c;多个实例分别推送到不同的RTMP URL&#xff08;如Android采集板卡同时接2路出去&#xff09;&#xff1b;同一路编码&am…

雨林木风win11 64位全新专业版系统v2021.08

雨林木风win11 64位全新专业版系统v2021.08是目前非常火热的电脑操作系统&#xff0c;系统运行速度非常的快速&#xff0c;拥有稳定、安全、兼容性强等特点&#xff0c;多样化的服务可供你的使用&#xff0c;支持在线的升级&#xff0c;非常的便捷&#xff0c;可以提高系统的性…

面向内网无纸化会议/智慧教室/实时同屏,组播还是RTMP?

一、背景 为满足内网无纸化/电子教室等内网超低延迟需求&#xff0c;避免让用户配置单独的服务器&#xff0c;我们研发了轻量级RTSP服务开发包。 单播不再赘述&#xff0c;这里重点介绍下我们的组播技术方案&#xff1a; 组播解决的主要痛点是服务器部署和带宽占用问题&…

打印更无缝:微软改善Win11中通用打印体验

微软昨日透露&#xff0c;将会在 Windows 11 系统中改进打印体验。从下面的截图中可以看到&#xff0c;用户可以直接在设置应用中添加打印机。对于使用通用打印机驱动的打印机&#xff0c;微软增加了为打印作业添加密码的功能。 打印更无缝&#xff1a;微软改善Win11中通用打印…

Windows平台如何快速实现RTSP/RTMP直播播放

前段时间&#xff0c;我们在 https://blog.csdn.net/renhui1112/article/details/104143794 提到“RTSP播放器开发过程中需要考虑哪些关键因素”&#xff0c;本次主要介绍&#xff0c;如何调用SDK实现RTSP/RTMP播放能力。 本文以调用大牛直播SDK为例&#xff1a; demo说明 SD…

Windows平台RTSP播放器/RTMP播放器设计需要考虑的几个点

我们在实现Windows平台RTSP播放器或RTMP播放器的时候&#xff0c;需要考虑的点很多&#xff0c;比如多实例设计、多绘制模式兼容、软硬解码支持、快照、RTSP下TCP-UDP自动切换等&#xff0c;以下就其中几个方面&#xff0c;做个大概的探讨。 1. 视频绘制模式 我们在实现Windo…

网易邮箱大师如何定时发送 定时发送邮件方法步骤详解

网易邮箱大师是我们日常使用邮箱的最佳软件&#xff0c;不仅能批量登录邮件&#xff0c;还能定时发送邮件&#xff0c;可谓功能齐全&#xff0c;很多小伙伴不知道如何定时发送邮件&#xff0c;那么接下来小编说的这篇文章肯定会对你有帮助。 操作步骤如下&#xff1a; 1、打开…

Windows平台下如何实现Unity3D下的RTMP推送

好多开发者苦于很难在unity3d下实现RTMP直播推送&#xff0c;本次以大牛直播SDK&#xff08;Github&#xff09;的Windows平台RTMP推送模块&#xff08;以推摄像头为例&#xff0c;如需推屏幕数据&#xff0c;设置相关参数即可&#xff09;为例&#xff0c;介绍下unity3d的RTMP…

Android平台如何实现屏幕数据采集并推送至RTMP服务器

随着无纸化、智慧教室等场景的普及&#xff0c;好多企业或者开发者开始寻求更高效稳定低延迟的RTMP同屏方案&#xff0c;本文以大牛直播SDK(Github)的同屏demo&#xff08;对应工程&#xff1a;SmartServicePublisherV2&#xff09;为例&#xff0c;介绍下如何采集编码推送RTMP…

网易邮箱大师如何注册邮箱 注册邮箱方法步骤介绍

网易邮箱大师是款高效强大的全平台邮箱客户端&#xff0c;支持所有邮箱登录&#xff0c;功能强大&#xff0c;一个PC端就能登录多个邮箱&#xff0c;很多小伙伴不知道如何注册登录邮箱&#xff0c;那么就跟着小编一起来看看如何操作吧。 操作步骤如下&#xff1a; 1、打开网易…

D3D还是GDI? Windows平台播放RTSP或RTMP渲染模式比较

先说结论&#xff0c;Windows平台播放渲染这块&#xff0c;支持D3D的前提下&#xff0c;优先D3D&#xff0c;如果检测到不支持D3D&#xff0c;数据回调上来&#xff0c;GDI模式绘制。 相比GDI模式&#xff0c;D3D绘制更细腻&#xff0c;绘制效率更高&#xff0c;CPU占用低&…

Android投屏(屏幕共享)设计需要考虑的关键因素

许多开发者&#xff0c;在做智慧教室同屏、会议同屏之类的方案时&#xff0c;基于Andriod平台的采集&#xff0c;往往遇到各种各样的问题&#xff0c;以下就几个点&#xff0c;抛砖引玉&#xff1a; 1. 内网环境下&#xff0c;组播还是RTMP&#xff1f; 回答&#xff1a;这个…

微信公众号怎么给微店设置运费

微信小店想要设置运费&#xff0c;该怎么设置呢?今天我们就来看看使用微信公众号设置微店运费的教程。 1、在电脑登录你的微信公众号服务号&#xff0c;确保已经事先开通了微信小店功能 微信公众号怎么给微店设置运费? 2、点击左侧导航栏的微信小店&#xff0c;进去后点击…

RTSP/RTMP播放端录像不可忽视的几个设计要点

很多开发者提到&#xff0c;拉取的摄像机&#xff08;一般RTSP流&#xff09;或RTMP流&#xff0c;如果需要录制&#xff0c;需要考虑哪些因素&#xff0c;本文以大牛直播SDK的Windows平台拉流端录像为例&#xff08;github&#xff09;&#xff0c;做个简单的介绍&#xff1a;…

海康摄像机rtsp地址格式(官方最新版)

★目前海康录像机、网络摄像机&#xff0c;网络球机的RTSP单播取流格式如下&#xff08;车载录像机不支持RTSP取流&#xff09;&#xff1a; rtsp://用户名:密码IP:554/Streaming/Channels/101 →录像机示例&#xff1a; 取第1个通道的主码流预览 rtsp://admin:hik1234510.…

QQ邮箱怎么发送文件夹 怎样在QQ邮箱里发送压缩文件夹

有很多用户想要知道怎么样才能通过QQ邮箱来发送自己的一些文件压缩包&#xff0c;应该怎么操作呢?不要慌&#xff0c;现在小编就给大家分享一下&#xff0c;下面一起来学习操作步骤吧! 其实&#xff0c;无论何种邮箱都无法发送文件夹&#xff0c;都只能对文件进行操作。如果文…