Windows平臺RTMP/RTSP直播推送模塊設計和使用說明

開發背景

好多開發者一直反饋,Windows平臺,做個推屏或者推攝像頭,推RTMP或者RTSP出去,不知道哪些功能是必須的,哪些設計是可有可無的,還有就是,不知道如何選技術方案,以下是基于我們設計的Windows平臺RTSP、RTMP直播推送模塊,設計和使用說明,供大家參考。

整體方案架構

Windows平臺RTMP或RTSP推送,系采集端模塊,主要完成,屏幕或者攝像頭數據、麥克風或揚聲器數據的采集,編碼,然后按照特定格式打包,通過RTMP或者RTSP傳輸出去,實現直播目的。

對應設計架構圖的“發布端”,編碼后的音視頻數據,按照協議打包后,推送到流媒體服務器(如RTMP服務器,自建服務,可以考慮SRS或者nginx服務器,如果是RTSP服務器,可以考慮蘋果官方的darwin streaming server)。

這種方案的設計,一般是一對多設計模型,接收端接收RTMP或RTSP流,然后解析音視頻數據,解碼、同步音視頻數據,并繪制,實現整體的直播解決方案。

以下是設計架構圖:

?

模塊設計

  • 自有框架,易于擴展,自適應算法讓延遲更低、采集編碼傳輸效率更高;
  • 所有功能以接口形式提供,所有狀態,均有event回調,支持斷網自動重連;
  • 模塊化設計,可和大牛直播RTSP或RTMP直播播放模塊組合實現流媒體數據轉發、連麥、一對一互動等場景;
  • 推送疊加以層級模式提供,開發者可以自行組合數據源(如多攝像頭/屏幕/水印疊加);
  • 支持外部YUV/RGB/H.264/AAC/SPEEX/PCMA/PCMU數據源接入;
  • 所有參數均可通過SDK接口單獨設置,亦可通過默認參數,傻瓜式設置;
  • 推送、錄像、內置輕量級RTSP服務模塊完全分離,可單獨使用亦可組合使用。

功能設計

  • [本地預覽]支持攝像頭/屏幕/合成數據實時預覽功能;
  • [攝像頭反轉/旋轉]支持攝像頭水平反轉、垂直反轉、0°/90°/180°/270°旋轉;
  • [攝像頭采集]除常規YUV格式外,還支持MJPEG格式的攝像頭采集;
  • [RTMP推流]超低延時的RTMP協議直播推流SDK(Windows 64位庫支持RTMP擴展H.265推送);
  • [音視頻加密]RTMP支持AES128/AES192/AES256/SM4(國密)逐幀數據加密;
  • [音視頻加密]支持RTMP H.264/H.265加密;
  • [音視頻加密]支持RTMP AAC/Speex/G711加密;
  • [視頻格式]Windows支持H.264/H.265編碼;
  • [音頻格式]支持AAC編碼和Speex編碼;
  • [音頻編碼]支持Speex推送、Speex編碼質量設置;
  • [軟硬編碼參數配置]支持gop間隔、幀率、bit-rate設置;
  • [軟編碼參數配置]支持軟編碼profile、軟編碼速度、可變碼率設置;
  • [多實例推送]支持多實例推送(如同時推送屏幕/攝像頭和外部數據);
  • [RTMP擴展H.265]Windows/Android推送SDK支持RTMP擴展H.265推送,Windows針對攝像頭采集軟編碼,使用H.265可變碼率,帶寬大幅節省,效果直逼傳統H.265編碼攝像頭;
  • [多分辨率支持]支持攝像頭或屏幕多種分辨率設置;
  • [Windows推屏]支持屏幕裁剪、窗口采集、屏幕/攝像頭數據合成等多種模式推送;
  • [事件回調]支持各種狀態實時回調;
  • [水印]Windows平臺支持文字水印、png水印、實時遮擋;
  • [復雜網絡處理]支持斷網重連等各種網絡環境自動適配;
  • [動態碼率]支持根據網絡情況自動調整推流碼率;
  • [實時靜音]支持推送過程中,實時靜音/取消靜音;
  • [實時快照]支持推流過程中,實時快照;
  • [純音頻推流]支持僅采集音頻流并發起推流功能;
  • [純視頻推流]支持特殊場景下的純視頻推流功能;
  • [降噪]支持環境音、手機干擾等引起的噪音降噪處理、自動增益、VAD檢測;
  • [外部編碼前視頻數據對接]支持YUV數據對接;
  • [外部編碼前音頻數據對接]支持PCM對接;
  • [外部編碼后視頻數據對接]支持外部H.264數據對接;
  • [外部編碼后音頻數據對接]外部AAC/PCMA/PCMU/SPEEX數據對接;
  • [擴展錄像功能]完美支持和錄像SDK組合使用;
  • [服務器兼容]支持支持自建服務器(如Nginx、SRS)或CDN。

集成和使用說明

demo說明

  • Windows平臺RTMP/RTSP直播推送模塊對外提供C++/C#兩套接口,對外提供32/64位庫,C++和C#接口一一對應,C#接口比C++接口增加前綴NT_PB_。
  • WIN-PublisherSDK-CPP-Demo:推送端SDK對應的C++接口的demo;
  • WIN-PublisherSDK-CSharp-Demo:推送端SDK對應的C#接口的demo;
  • 推送端模塊支持Win7及以上系統。
  • 本demo基于VS2013開發。

C++頭文件:

  • [類型定義]nt_type_define.h
  • [Log定義]smart_log.h
  • [Log定義]smart_log_define.h
  • [音視頻類型定義]nt_common_media_define.h
  • [base code定義]nt_base_code_define.h
  • [publisher接口]nt_smart_publisher_define.h
  • [publisher接口]nt_smart_publisher_sdk.h

C#頭文件:

  • [Log定義]smart_log.cs
  • [Log定義]smart_log_define.cs
  • [base code定義]nt_base_code_define.cs
  • [publisher接口]nt_smart_publisher_define.cs
  • [publisher參數定義]nt_smart_publisher_sdk.cs

相關Lib:

  • SmartLog.dll
  • SmartLog.lib
  • SmartPublisherSDK.dll
  • SmartPublisherSDK.lib
  • avcodec-56.dll
  • avdevice-56.dll
  • avfilter-5.dll
  • avformat-56.dll
  • avutil-54.dll
  • postproc-53.dll
  • swresample-1.dll
  • swscale-3.dll

集成步驟

  1. 把lib目錄下debug/release庫拷貝到需要集成的工程對應的debug或release目錄下(確保32位/64位庫debug/release目錄一一對應);

lib目錄如下:

    1. 32位debug庫:debug
    2. 32位release庫:release
    3. 64位debug庫:x64\debug
    4. 64位release庫:x64\release

2. 相關cs頭文件,加入需要集成的工程;

3. 在需要集成的工程,右鍵->Properties->Application->Assembly name,寫入“SmartPulisherDemo”。

功能詳解

考慮到Windows平臺推送端SDK功能相對復雜,以問答式:

1視頻采集設置

1.?屏幕和攝像頭相互切換:用于在線教育或者無紙化等場景,推送或錄像過程中,隨時切換屏幕或攝像頭數據(切換數據源),如需實時切換,點擊頁面“切換到攝像頭”按鈕即可;

2.?設置遮蓋層,用于設定一個長方形或正方形區域(可自指定區域大小),遮蓋不想給用戶展示的部分;

3.?水印:添加PNG水印,支持推送或錄像過程中,隨時添加、取消水印;

4.?攝像頭疊加到屏幕:意在用于同屏過程中,主講人攝像頭懸浮于屏幕之上(可指定疊加坐標),實現雙畫面展示,推送或錄像過程中,可以隨時取消攝像頭疊加;

5.?屏幕疊加到攝像頭:同4,效果展示,實際根據需求實現;

6.?采集桌面:可以通過點擊“選擇屏幕區域”獲取采集區域,并可在采集過程中,隨時切換區域位置,如不設定,默認全屏采集;

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

8.?采集窗口:可設定需要采集的窗口,窗口放大或縮小,推送端會自適應碼率和分辨率;

9.?采集幀率(幀/秒):默認屏幕采集8幀,可根據實際場景需求設定到期望幀率;

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

11.?采集攝像頭:可選擇需要采集的攝像頭、采集分辨率、幀率、是否需要水平或者垂直反轉、是否需要旋轉;

追加提問:

問題[確認數據源]:采集桌面還是攝像頭?如果桌面,全屏還是部分區域?

回答:

如果是攝像頭:可以選擇攝像頭列表,然后分辨率、幀率。

如果是屏幕:默認幀率是5幀,可以根據實際場景調整,選取屏幕區域,可以實時拉取選擇需要采集或錄像區域;

如果是疊加模式:可選擇攝像頭疊加到屏幕,還是屏幕疊加到攝像頭;

更高需求的用戶,可以設置水印或應用層遮蓋。

問題:如果是攝像頭,采集到的攝像頭角度不對怎么辦?

回答:我們支持攝像頭鏡像和翻轉設置,攝像頭可通過SDK接口輕松實現水平/垂直翻轉、鏡像效果。

2?視頻碼率控制

我選可變碼率還是平均碼率?

回答:可變碼率的優勢在于,如果屏幕或攝像頭變化不大,碼率超低,特別是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之前,請務必設置視頻碼率,如不想手動設置,請點擊“獲取視頻碼率默認值”!!!

3?音頻采集設置

問答式:采集音頻嗎?如果采集,采集麥克風還是揚聲器的,亦或混音?

回答:

如果想采集電腦輸出的音頻(比如音樂之類),可以選擇“采集揚聲器”;

如果想采集麥克風音頻,可以選擇“采集麥克風”,并選擇相關設備;

如果兩個都想采集,可以兩個都選擇,混音輸出。

4?音頻編碼

問題:是AAC還是SPEEX?

回答:我們默認是AAC編碼模式,如果需要碼率更低,可以選擇SPEEX編碼模式,當然我們的AAC編碼碼率也不高。

5?音頻處理

問題:我想過濾背景噪音怎么辦?

回答:選中“噪音抑制”,“噪音抑制“請和“自動增益控制”組合使用,“端點檢測(VAD)”可選設置。

問題:我想做一對一互動怎么辦?

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

問題:我推送或者錄像過程中,隨時靜音怎么辦?

回答:推送過程中,隨時選擇或取消選擇“靜音”功能。

6多路推送

問題:我想同時推送到多個url怎么辦(比如一個內網服務器,一個外網服務器)?

回答:同時填寫多個url,然后點推送即可。

7?截圖(快照)

問題:我想推送或者錄像過程中,截取當前圖像怎么辦?

回答:那就設置好截圖路徑,推送或錄像過程中,隨時點擊“截圖”。

8?錄像

問題:我還想錄像,怎么辦?

回答:設置錄像文件存放目錄,文件前綴、單個文件大小,是否加日期、時間,隨時錄制即可,此外,我們的SDK還支持錄像過程中,暫停錄像,恢復錄像。

9 實時預覽

問題:我還想看看視頻特別是合成后的效果,怎么辦?

回答:點擊頁面的“預覽”按鈕,就可以看到。

10?音視頻加密

問題:我想我的數據走標準協議,但是加密流,怎么辦?

回答:大牛直播SDK的RTMP推流模塊,支持AES(AES128/AES192/AES256)和SM4加密。

接口調用時序(以C#為例)

如需下載demo源碼工程,可以到 Github?下載 “Windows平臺RTMP|RTSP推送SDK、內置RTSP服務SDK、錄像SDK”,C++或者C#的都有。

1 初始化

NT_PB_Init

如需配置log路徑,請在NT_PB_Init之前,做如下設置(目錄可自行指定):

// 設置日志路徑(請確保目錄存在)

//String log_path = “D:\\pulisherlog”;

//NTSmartLog.NT_SL_SetPath(log_path);

2 Open

NT_PB_Open

3 設置回調事件

  • NT_PB_SetEventCallBack:設置事件回調,如果想監聽事件的話,建議調用Open成功后,就調用這個接口
  • NT_PB_SetVideoPacketTimestampCallBack:設置視頻包時間戳回調
  • NT_PB_SetPublisherStatusCallBack:設置推送狀態回調

4 設置屏幕裁剪

  • NT_PB_SetScreenClip:設置屏幕裁剪
  • NT_PB_MoveScreenClipRegion:移動屏幕剪切區域,這個接口只能推送或者錄像中調用

5 屏幕選取工具

  • NT_PB_OpenScreenRegionChooseTool:打開一個屏幕選取工具的toolHandle
  • NT_PB_MoveScreenClipRegion:移動屏幕剪切區域,這個接口只能推送或者錄像中調用
  • NT_PB_AllocateImage:分配Image, 分配后,SDK內部會初始化這個結構體, 失敗的話返回NULL
  • NT_PB_FreeImage:釋放Image, 注意一定要調用這個接口釋放內存,如果在你自己的模塊中釋放,Windows會出問題的
  • NT_PB_CloneImage:克隆一個Image, 失敗返回NULL
  • NT_PB_CopyImage:拷貝Image, 會先釋放dst的資源,然后再拷貝
  • NT_PB_SetImagePlane:?給圖像一個面設置數據,如果這個面已經有數據,將會釋放掉再設置
  • NT_PB_LoadImage:加載PNG圖片

6 設置屏幕采集參數

  • NT_PB_EnableDXGIScreenCapturer:允許使用DXGI屏幕采集方式, 這種方式需要win8及以上系統才支持
  • NT_PB_DisableAeroScreenCapturer:采集屏幕時停用Aero, 這個只對win7有影響,win8及以上系統, 微軟已經拋棄了Aero Glass效果
  • NT_PB_CheckCapturerWindow:判斷頂層窗口能否能被捕獲, 如果不能被捕獲的話返回NT_ERC_FAILED(采集窗口)
  • NT_PB_SetCaptureWindow:設置要捕獲的窗口的句柄(采集窗口)

7 設置攝像頭采集參數

  • NT_PB_StartGetVideoCaptureDeviceImage:獲取句柄,且保存句柄
  • NT_PB_FlipVerticalVideoCaptureDeviceImage:上下反轉設備圖像
  • NT_PB_FlipHorizontalVideoCaptureDeviceImage:水平反轉設備圖像
  • NT_PB_RotateVideoCaptureDeviceImage:旋轉設備圖像, 順時針旋轉
  • NT_PB_GetVideoCaptureDeviceNumber:獲取攝像頭數量
  • NT_PB_GetVideoCaptureDeviceInfo:返回攝像頭設備信息
  • NT_PB_GetVideoCaptureDeviceCapabilityNumber:返回攝像頭能力數
  • NT_PB_GetVideoCaptureDeviceCapability:返回攝像頭能力
  • NT_PB_DisableVideoCaptureResolutionSetting:

在多個實例推送多路時,對于一個攝像頭來說,所有實例只能共享攝像頭,那么只有一個實例可以改變攝像頭分辨率,其他實例使用這個縮放后的圖像;

在使用多實例時,調用這個接口禁止掉實例的分辨率設置能力.只留一個實例能改變分辨,如果不設置,行為未定義;

這個接口必須在 SetLayersConfig, AddLayerConfig 之前調用。

  • NT_PB_StartVideoCaptureDevicePreview: 啟動攝像頭預覽
  • NT_PB_FlipVerticalCameraPreview:上下反轉攝像頭預覽圖像
  • NT_PB_FlipHorizontalCameraPreview:水平反轉攝像頭預覽圖像
  • NT_PB_RotateCameraPreview:旋轉攝像頭預覽圖像, 順時針旋轉
  • NT_PB_VideoCaptureDevicePreviewWindowSizeChanged:告訴SDK預覽窗口大小改變
  • NT_PB_StopVideoCaptureDevicePreview:停止攝像頭預覽
  • NT_PB_GetVideoCaptureDeviceImage:調用這個接口可以獲取攝像頭圖像
  • NT_PB_StopGetVideoCaptureDeviceImage:停止獲取攝像頭圖像
  • NT_PB_SetVideoCaptureDeviceBaseParameter:設置攝像頭信息
  • NT_PB_FlipVerticalCamera上下反轉攝像頭圖像
  • NT_PB_FlipHorizontalCamera:水平反轉攝像頭圖像
  1. NT_PB_RotateCamera:旋轉攝像頭圖像, 順時針旋轉

8 視頻合成圖層類型

public?enum?NT_PB_E_LAYER_TYPE?: int

{

NT_PB_E_LAYER_TYPE_SCREEN?= 1, ?????????????????// 屏幕層

NT_PB_E_LAYER_TYPE_CAMERA?= 2, ?????????????????// 攝像頭層

NT_PB_E_LAYER_TYPE_RGBA_RECTANGLE?= 3, ?????????// RGBA矩形

NT_PB_E_LAYER_TYPE_IMAGE?= 4, ??????????????????// 圖片層

NT_PB_E_LAYER_TYPE_EXTERNAL_VIDEO_FRAME?= 5, ???// 外部視頻數據層

NT_PB_E_LAYER_TYPE_WINDOW?= 6, // 窗口層

}

9 音視頻源類型

/*定義Video源選項*/

public?enum?NT_PB_E_VIDEO_OPTION?: uint

{

NT_PB_E_VIDEO_OPTION_NO_VIDEO?= 0x0,

NT_PB_E_VIDEO_OPTION_SCREEN?= 0x1, // 采集屏幕

NT_PB_E_VIDEO_OPTION_CAMERA?= 0x2, // 攝像頭采集

NT_PB_E_VIDEO_OPTION_LAYER?= 0x3, ?// 視頻合并,比如桌面疊加攝像頭等

NT_PB_E_VIDEO_OPTION_ENCODED_DATA?= 0x4, // 已經編碼的視頻數據,目前支持H264

NT_PB_E_VIDEO_OPTION_WINDOW?= 0x5, // 采集窗口

}

/*定義Auido源選項*/

public?enum?NT_PB_E_AUDIO_OPTION?: uint

{

NT_PB_E_AUDIO_OPTION_NO_AUDIO?= 0x0,

NT_PB_E_AUDIO_OPTION_CAPTURE_MIC?= 0x1, ??????????// 采集麥克風音頻

NT_PB_E_AUDIO_OPTION_CAPTURE_SPEAKER?= 0x2, ??????????// 采集揚聲器

NT_PB_E_AUDIO_OPTION_CAPTURE_MIC_SPEAKER_MIXER?= 0x3, ???// 麥克風揚聲器混音

NT_PB_E_AUDIO_OPTION_ENCODED_DATA?= 0x4, // 編碼后的音頻數據,目前支持AAC, speex寬帶(wideband mode)

}

10 視頻編碼接口

  • NT_PB_SetVideoEncoderType:設置編碼類型, 當前支持h264和h265(注意:h265只有64位sdk庫支持, 在32位庫上設置會失敗);
  • NT_PB_SetVideoQuality:設置視頻質量, 范圍[0-20], 默認是10, 值越小質量越好,但碼率會越大
  • NT_PB_SetVideoQualityV2:設置視頻質量, 范圍[1-50], 值越小視頻質量越好,但碼率會越大. 請優先考慮默認值;
  • NT_PB_SetFrameRate:設置幀率
  • NT_PB_SetVideoMaxBitRate:設置最大視頻碼率, 單位kbps
  • NT_PB_AddVideoEncoderBitrateGroupItem:

* 在一些特殊場景下, 視頻分辨率會改變, 如果設置一個固定碼率的的話,當視頻分辨率變大的時候會變的模糊,變小的話又會浪費碼率

* 所以提供可以設置一組碼率的接口,滿足不同分辨率切換的需求

* 規則: 比如設置兩組分辨率 640*360, 640*480, 那么當分辨率小于等于640*360時都使用640*360的碼率,

* 當分辨率大于640*360且小于等于640*480時,就使用640*480的碼率,如果分辨率大于640*480 那就使用640*480的分辨率

* 為了設置的更準確, 建議多劃分幾組, 讓區間變小

* 調用這個接口每次設置一組,設置多組就調用多次

* item對應 NT_PB_VideoEncoderBitrateGroupItem

  • NT_PB_ClearVideoEncoderBitrateGroup:清除視頻碼率組
  • NT_PB_SetVideoKeyFrameInterval:設置關鍵幀間隔, 比如1表示所有幀都是關鍵幀,10表示每10幀里面一個關鍵幀,25表示每25幀一個關鍵幀
  • NT_PB_SetVideoEncoderProfile:設置H264 profile,1: H264 baseline(默認值). 2: H264 main. 3. H264 high
  • NT_PB_SetVideoEncoderSpeed:設置H264編碼速度,speed: 范圍是 1 到 6, ?值越小,速度越快,質量也越差
  • NT_PB_SetVideoCompareSameImage:設置是否對圖像進行相同比較,相同圖像比較一般在采集桌面時有一定好處,可能能降低碼率
  • NT_PB_SetVideoMaxKeyFrameInterval:設置視頻最大關鍵幀間隔, 這個接口一般不使用,這里是用來配合SetVideoCompareSameImage接口的,比如開啟圖像比較后,SDK發現連續20s圖像都是相同的,但播放端需要收到關鍵幀才能解碼播放,所以需要一個限制

11 音頻編碼接口

  • NT_PB_GetAuidoInputDeviceNumber:獲取系統音頻輸入設備數
  • NT_PB_GetAuidoInputDeviceName:獲取音頻輸入設備名稱
  • NT_PB_SetPublisherAudioCodecType:設置推送音頻編碼類型,type: 1:使用AAC編碼, 2:使用speex編碼, 其他值返回錯誤
  • NT_PB_SetPublisherSpeexEncoderQuality:設置推送Speex編碼質量
  • NT_PB_SetAuidoInputDeviceId:設置音頻輸入設備ID
  • NT_PB_IsCanCaptureSpeaker:檢查是否能捕獲揚聲器音頻

12 音頻處理接口

  • NT_PB_SetEchoCancellation:設置回音消除
  • NT_PB_SetNoiseSuppression:設置音頻噪音抑制
  • NT_PB_SetAGC:設置音頻自動增益控制
  • NT_PB_SetVAD:設置端點檢測(Voice Activity Detection (VAD))

13 圖層合成等接口

  • NT_PB_SetLayersConfig:設置視頻合成層, 傳入的是一個數組, 請正確填充每一層
  • NT_PB_ClearLayersConfig:清除所有層配置,注意這個接口只能在推送或者錄像之前調用,否則結果未定義
  • NT_PB_AddLayerConfig:?增加層配置,注意這個接口只能在推送或者錄像之前調用,否則結果未定義
  • NT_PB_EnableLayer:動態禁止或者啟用層
  • NT_PB_UpdateLayerConfigV2:更新層相關配置, 注意不是層的所有字段都可以更新,只是部分可以更新,并且有些層沒有字段可以更新,傳入的參數,SDK只選擇能更新的字段更新,不能更新的字段會被忽略
  • NT_PB_UpdateLayerRegion:修改圖層
  • NT_PB_PostLayerImage:給index層投遞Image數據,目前主要是用來把rgb和yuv視頻數據傳給相關層
  • NT_PB_SetParam:萬能接口, 設置參數, 大多數問題, 這些接口都能解決
  • NT_PB_GetParam:萬能接口, 得到參數, 大多數問題,這些接口都能解決

14 RTMP推送-設置AES/SM4加密

  • NT_PB_SetRtmpEncryptionOption:設置rtmp推送加密選項,可單獨加密音頻或視頻
  • NT_PB_SetRtmpEncryptionAlgorithm:設置rtmp加密算法,encryption_algorithm: 加密算法, 當前支持aes和國標sm4. 1為aes, 2為sm4, 默認為aes
  • NT_PB_SetRtmpEncryptionKey:設置rtmp推送加密密鑰,key:加密密鑰,key_size: 如果加密算法是aes, key_size必須是16, 24, 32 這三個值, 其他返回錯誤; 如果加密算法是sm4, key_size必須是16, 其他值返回錯誤.
  • NT_PB_SetRtmpEncryptionIV:設置rtmp推送加密IV(初始化向量), 這個接口不調用的話, 將使用默認IV,iv: 初始化向量,iv_size: 當前必須是16, 其他值返回錯誤

15 RTMP推送-設置推送RTMP Url

NT_PB_SetURL:rtmp推送url設置

16 RTMP推送-啟動推送RTMP流

NT_PB_StartPublisher

17 RTMP推送-停止推送RTMP流

NT_PB_StopPublisher:注意,此接口和NT_PB_StartPublisher配套使用

18 RTSP推送-設置傳輸方式(TCP/UDP)

NT_PB_SetPushRtspTransportProtocol:設置推送rtsp傳輸方式,一般服務器可同時支持RTSP TCP或UDP傳輸模式,部分服務器只支持TCP或UDP模式。其中,transport_protocol: 1表示UDP傳輸rtp包; 2表示TCP傳輸rtp包. 默認是1, UDP傳輸。

19 RTSP推送-設置推送RTSP Url

NT_PB_SetPushRtspURL:注意,RTSP推送時,確保服務器推送URL可用。

20 RTSP推送-啟動推送RTSP流

NT_PB_StartPushRtsp

21 RTSP推送-啟動推送RTSP流

NT_PB_StopPushRtsp:注意,此接口和NT_PB_StartPushRtsp配套使用。

22 RTMP/RTSP推送端錄像

  • NT_PB_SetRecorderDirectory:設置本地錄像目錄, 必須是英文目錄,否則會失敗
  • NT_PB_SetRecorderFileMaxSize:設置單個錄像文件最大大小, 當超過這個值的時候,將切割成第二個文件
  • NT_PB_SetRecorderFileNameRuler:設置錄像文件名生成規則
  • NT_PB_StartRecorder:啟動錄像
  • NT_PB_PauseRecorder:暫停錄像,is_pause: 1表示暫停, 0表示恢復錄像, 輸入其他值將調用失敗
  • NT_PB_StopRecorder:停止錄像

23 實時靜音(實時調用)

NT_PB_SetMute:設置推送實時靜音

24 快照(實時調用)

NT_PB_CaptureImage:推送或者錄像過程中,實時快照

25 Close

NT_PB_Close:調用這個接口之后handle失效

26 Uninit

NT_PB_UnInit:這個是最后一個調用的接口

以上是我們的設計模塊部分資料,感興趣的開發者,可以酌情參考。

大牛直播SDK:如何設計一款跨平臺低延遲的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狀態等回調;
  • ?[音視頻加密]Windows平臺支持RTMP推送端加密(AES/SM4(國密))音視頻數據正常播放
  • ?[視頻格式]支持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"{
#endif

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


		/*
		切換URL
		url:要切換的url
		switch_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: 請傳0
	NT_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), // 窗口區域無效,可能窗口寬或者高小于1
	NT_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, bb
	NT_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_FORMAT
	NT_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_; // 設置一個錄像文件名前綴, 例如:daniulive
	NT_INT32	append_date_; // 如果是1的話,將在文件名上加日期, 例如:daniulive-2017-01-17
	NT_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播放器,設計的時候,更多考慮的應該是如何做的更靈活、穩定,單純的幾個接口,很難滿足通用化的產品訴求。

以下共勉:厚積薄發,登上山頂,不是為了飽覽風光,是為了尋找更高的山峰!

輕量級RTSP服務模塊和RTSP推流模塊適用場景區別

好多開發者一直搞不清我們輕量級RTSP服務SDK和RTSP推流SDK的區別,以下是相關區別:

1. 輕量級RTSP服務模塊:輕量級RTSP服務解決的核心痛點是避免用戶或者開發者單獨部署RTSP或者RTMP服務,實現本地的音視頻數據(如攝像頭、麥克風),編碼后,匯聚到內置RTSP服務,對外提供可供拉流的RTSP URL,輕量級RTSP服務,適用于內網環境下,對并發要求不高的場景,支持H.264/H.265,支持RTSP鑒權、單播、組播模式,考慮到單個服務承載能力,我們支持同時創建多個RTSP服務,并支持獲取當前RTSP服務會話連接數。

以下是接口詳解(以Android平臺為例):

Android內置輕量級RTSP服務SDK接口詳解

調用描述

接口

接口描述

常規功能

Android RTMP推送端所有功能依然有效,亦可同時推送RTMP

SmartRTSPServerSDK

初始化RTSP Server

InitRtspServer

Init rtsp server(和UnInitRtspServer配對使用,即便是啟動多個RTSP服務,也只需調用一次InitRtspServer,請確保在OpenRtspServer之前調用)

創建一個rtsp server

OpenRtspServer

創建一個rtsp server,返回rtsp server句柄

設置端口

SetRtspServerPort

設置rtsp server 監聽端口, 在StartRtspServer之前必須要設置端口

設置鑒權用戶名、密碼

SetRtspServerUserNamePassword

設置rtsp server 鑒權用戶名和密碼, 這個可以不設置,只有需要鑒權的再設置

獲取rtsp server當前會話數

GetRtspServerClientSessionNumbers

獲取rtsp server當前的客戶會話數, 這個接口必須在StartRtspServer之后再調用

啟動rtsp server

StartRtspServer

啟動rtsp server

停止rtsp server

StopRtspServer

停止rtsp server

關閉rtsp server

CloseRtspServer

關閉rtsp server

UnInit rtsp server

UnInitRtspServer

UnInit rtsp server(和InitRtspServer配對使用,即便是啟動多個RTSP服務,也只需調用一次UnInitRtspServer)

SmartRTSPServerSDK供Publisher調用的接口

設置rtsp的流名稱

SetRtspStreamName

設置rtsp的流名稱

給要發布的rtsp流設置rtsp server

AddRtspStreamServer

給要發布的rtsp流設置rtsp server, 一個流可以發布到多個rtsp server上,rtsp server的創建啟動請參考OpenRtspServer和StartRtspServer接口

清除設置的rtsp server

ClearRtspStreamServer

清除設置的rtsp server

啟動rtsp流

StartRtspStream

啟動rtsp流

停止rtsp流

StopRtspStream

停止rtsp流

2. RTSP推流模塊:RTSP推流模塊,和RTMP推流模塊類似,適用于內網或公網環境下,主要適用于第三方RTSP服務對接,如darwin stream server,或者第三方RTSP服務平臺,如視頻分析平臺等特定場景的服務器,支持H.264/H.265,支持TCP、UDP傳輸模式設定,也支持鑒權服務,RTSP協議的優勢主要在于UDP這塊,但是UDP數據包,公網容易被block住,而且,網絡不穩定容易丟包,所以,能用RTMP推流的場景,一般建議走RTMP,需要特定系統對接的,再走RTSP。

以下是接口詳解(以Android平臺為例):

調用描述

接口

接口描述

設置推送RTSP傳輸方式

SetPushRtspTransportProtocol

transport_protocol:1表示UDP傳輸rtp包; 2表示TCP傳輸rtp包

設置推送RTSP的URL

SetPushRtspURL

設置推送RTSP的URL

開始RTSP推送

StartPushRtsp

啟動推送RTSP流

停止RTSP推送

StopPushRtsp

停止推送RTSP流

參考資料:https://github.com/daniulive/SmarterStreaming

基于智慧教室|無紙化會議的新選擇:RTMP解決方案

基于智慧教室或是會議的技術方案,一般主要是涉及到屏幕采集和推送,整體技術方案這塊,一般建議走RTMP,說到這里,好人開發者提到,市面上也有RTSP的技術方案,甚至RTSP組播方案,這塊,大牛直播SDK Github 也做過相關對比,總的來說60人智慧教室或類似同屏場景下,最可靠的還是RTMP的解決方案(不贅述,具體可自行測試對比)。

有人說,RTMP延遲大,這種說法,相對片面,好多是由于推拉流模塊本身問題導致(如果服務器系NIGNX或SRS,基本可排除服務器轉發導致的大時延,不要再賴服務器了),從我們官方和實際場景來看,RTMP整體技術方案,延遲可做到1秒內,毫秒級。

整體設計方案如下

?

注意事項

1. 組網:無線組網,需要好的AP模塊才能撐得住大的并發流量,推送端到AP,最好是有線網鏈接;

2. 服務器部署:如果Windows平臺,可以考慮NGINX,如果是Linux,可以考慮SRS或NGINX,服務器可以和Windows平臺的教師機部署在一臺機器;

3. 教師端:如教師有移動的PAD,可以直接推到RTMP服務器,然后共享出去;

4. 學生端:直接拉取RTMP流播放即可;

5. 教師和學生互動:學生端如需作為示范案例,屏幕數據共享給其他同學,只需請求同屏,數據反推到RTMP服務器,其他學生查看即可。

6. 擴展監控:如果需要更進一步的技術方案,如教師端想監控學生端的屏幕情況,可以有兩種方案,如學生端直接推RTMP過來,或者,學生端啟動內置RTSP服務,教師端想看的時候,隨時看即可(亦可輪詢播放)。

以下分平臺介紹相關配置選項

Windows平臺RTMP推送端

對應DEMO:SmartPublisherDemo.exe

1. 如果采集屏幕,只要采集部分區域的話,可以點擊“選取屏幕區域”按鈕,選擇需要采集的區域,采集推送過程中,可以移動采集區域;

2. 如果是高分屏(如有些采集設備,是4K屏,原始分辨率過高),用戶又不想推這么高的分辨率的話,可以選中“縮放屏幕大小”,并指定縮放比例,可以先縮放,后編碼推送數據;

3. 設置采集幀率:如果是PPT/Word文檔類,一般8-12幀足矣,如果是電影之類,可以設置到20-30幀不等,關鍵幀間隔一般設置到幀率的2-4倍,屏幕推送的話,建議平均碼率模式;

4. 如果需要采集電腦端輸出的聲音,可以選中“采集揚聲器”,如果需要采集外部麥克風的音頻,選擇“采集麥克風”即可,并選擇對應的采集設備;

5. 設置下推送的RTMP URL,然后,點擊“推送”,就可以了;

6. 如果想預覽推送出去的數據,點擊“預覽”即可,想停止預覽的話,點擊“停止預覽”即可。

Android平臺RTMP屏幕推送端

對應工程:SmartServicePublisherV2

需要注意的事項:

1. Android 8.0及以上版本設備,需要加入省電優化白名單,6.0以上版本,需要動態獲取audio權限,具體代碼如下:

        //加入省電優化白名單,以免8.0及以上版本設備后臺運行超過一分鐘被自動停掉
        //if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
        if (Build.VERSION.SDK_INT >=26)
        {
            if(!isIgnoringBatteryOptimizations())
            {
                gotoSettingIgnoringBatteryOptimizations();
            }
        }

        //6.0及以上版本,動態獲取Audio權限
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
        {
            RequestAudioPermission();
        }


    //拉起請求加入省電白名單彈窗
    private void gotoSettingIgnoringBatteryOptimizations() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            try {
                Intent intent = new Intent();
                String packageName = getPackageName();
                intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
                intent.setData(Uri.parse("package:" + packageName));
                startActivityForResult(intent, REQUEST_IGNORE_BATTERY_CODE);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    //動態獲取Audio權限
    private void RequestAudioPermission()
    {
        if (PackageManager.PERMISSION_GRANTED ==  ContextCompat.checkSelfPermission(this.getApplicationContext(), android.Manifest.permission.RECORD_AUDIO))
        {
        }
        else {
            //提示用戶開戶權限音頻
            String[] perms = {"android.permission.RECORD_AUDIO"};
            ActivityCompat.requestPermissions(this, perms, RESULT_CODE_STARTAUDIO);
        }
    }

2. 持續的補幀策略,防止屏幕不動,沒數據下去;

3. 如果需要傳部分區域下去,可以用 SmartPublisherOnCaptureVideoClipedRGBAData() 接口;

4. 橫豎屏切換,上層無需過問,底層會自動切。

iOS平臺RTMP屏幕推送端

對應工程: SmartServiceCameraPublisherV2

注意事項:ReplayKit2 的直播擴展目前是有50M的內存使用限制,超過此限制系統會直接殺死擴展進程,因此 ReplayKit2 上建議推流分辨率和幀率、碼率不要太高。

以下是核心processSampleBuffer() 處理,iOS 11.0以上 加入了橫豎屏自動切換適配:

- (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer
                   withType:(RPSampleBufferType)sampleBufferType {
    
    CGFloat cur_memory = [self GetCurUsedMemoryInMB];
    
    if( cur_memory > 20.0f)
    {
        //NSLog(@"processSampleBuffer cur: %.2fM", cur_memory);
        return;
    }
        
    switch (sampleBufferType) {
        case RPSampleBufferTypeVideo:
            {
                if (!CMSampleBufferIsValid(sampleBuffer))
                    return;
                
                NSInteger rotation_degress = 0;
                //11.1以上支持自動旋轉
    #ifdef __IPHONE_11_1
                if (UIDevice.currentDevice.systemVersion.floatValue > 11.1) {
                    CGImagePropertyOrientation orientation = ((__bridge NSNumber*)CMGetAttachment(sampleBuffer, (__bridge CFStringRef)RPVideoSampleOrientationKey , NULL)).unsignedIntValue;
                    
                    //NSLog(@"cur org: %d", orientation);
                    
                    switch (orientation)
                    {
                        //豎屏
                        case kCGImagePropertyOrientationUp:{
                            rotation_degress = 0;
                        }
                            break;
                        case kCGImagePropertyOrientationDown:{
                            rotation_degress = 180;
                            break;
                        }
                        case kCGImagePropertyOrientationLeft: {
                            //靜音鍵那邊向上 所需轉90度
                            rotation_degress = 90;
                        }
                            break;
                        case kCGImagePropertyOrientationRight:{
                            //關機鍵那邊向上 所需轉270
                            rotation_degress = 270;
                        }
                            break;
                        default:
                            break;
                    }
                }
    #endif
                
                //NSLog(@"RPSampleBufferTypeVideo");
                if(_smart_publisher_sdk)
                {
                    //[_smart_publisher_sdk SmartPublisherPostVideoSampleBuffer:sampleBuffer];
                    [_smart_publisher_sdk SmartPublisherPostVideoSampleBufferV2:sampleBuffer rotateDegress:rotation_degress];
                }
                
                //NSLog(@"video ts:%.2f", CMTimeGetSeconds(CMSampleBufferGetPresentationTimeStamp(sampleBuffer)));
            }
            break;
        case RPSampleBufferTypeAudioApp:
            //NSLog(@"RPSampleBufferTypeAudioApp");
            if (CMSampleBufferDataIsReady(sampleBuffer) != NO)
            {
                if(_smart_publisher_sdk)
                {
                    NSInteger type = 2;
                    [_smart_publisher_sdk SmartPublisherPostAudioSampleBuffer:sampleBuffer inputType:type];
                }
            }
            //NSLog(@"App ts:%.2f", CMTimeGetSeconds(CMSampleBufferGetPresentationTimeStamp(sampleBuffer)));
            
            break;
        case RPSampleBufferTypeAudioMic:
            //NSLog(@"RPSampleBufferTypeAudioMic");
            if(_smart_publisher_sdk)
            {
                NSInteger type = 1;
                [_smart_publisher_sdk SmartPublisherPostAudioSampleBuffer:sampleBuffer inputType:type];
            }
            //NSLog(@"Mic ts:%.2f", CMTimeGetSeconds(CMSampleBufferGetPresentationTimeStamp(sampleBuffer)));
            
            break;
        default:
            break;
    }
}

大牛直播SDK多路RTSP-RTMP轉RTMP官方定制版

視沃科技(大牛直播SDK)多路RTMP/RTSP轉RTMP轉發軟件,系原有轉發SDK基礎上,官方推出的Windows平臺定制版。在秉承低延遲、靈活穩定、低資源占用的前提下,客戶無需關注開發細節,只需圖形化配置轉發等各類參數,實現產品快速上線目的。

如監控類攝像機、NVR等,通過廠商說明或Onvif工具,獲取拉流的RTSP地址,圖形化配置,完成拉流轉發等操作,輕松實現標準RTMP服務器(或CDN)對接。

視頻轉發支持H.264、H.265(需要RTMP服務器或CDN支持擴展H.265),音頻支持配置PCMA/PCMU轉AAC后轉發,并支持只轉發/錄制視頻或音頻,RTSP拉流端支持鑒權和TCP/UDP模式設置和TCP/UDP模式自動切換,整個拉流、轉發模塊都有非常完善的自動重連機制。

此外,可以通過點擊拉流地址或推流地址欄,實現推拉流地址,同步到左側預覽框,實現推拉流音視頻數據預覽。

運維方面,官方定制版轉發系統支持7*24小時不間斷運行,自帶守護進程,轉發程序被誤關等各種操作后,會自動啟動運行,此外,還支持開機自動啟動轉發或錄像。

多路RTSP/RTMP轉RTMP推送SDK概覽圖

官方測試版有1小時限制,拉流超過一小時會自動停止,如需長期運行或直接授權,請聯系我們。

image.png

功能說明
  1. 啟動程序

支持從守護進程(如需啟動轉發程序,可點擊SmartStreamRelayToolDaemon.exe,守護進程會自動拉起SmartStreamRelayTool.exe,如需關閉轉發程序,請先關閉SmartStreamRelayToolDaemon,轉發程序方可正常關閉):

image.png
  1. 添加轉發項配置信息
image.png

配置說明:

添加配置項:點擊頁面“添加”按鈕:

2 序號:無需關注,系統自動生成;

2 名稱:該路轉發配置項的描述信息;

2 拉流地址(必須填):需要轉發的RTSP或RTMP地址;

2 推流RTMP地址:需要轉推的RTMP地址;

2 推流播放地址:需要預覽的播放地址;

2 音視頻轉發選項:可選擇之轉發音頻或視頻,亦或同時轉發音視頻;

2 錄像參數配置:可選擇錄制音頻或視頻,亦或音視頻同時錄制,并可設定錄像文件前綴。

備注:雙擊列表配置項,可以查看或編輯配置信息;

刪除配置項:選中需要刪除的配置數據,點擊頁面“刪除”按鈕:

image.png

如何預覽推拉流數據?

點擊需要預覽的“拉流地址”或“推流地址”,URL會同步到左側預覽框,即可實現推拉流數據本地預覽。

如不需播放音頻,點擊“靜音”選項即可。

如何轉發數據?

  1. 選中需要轉發的配置數據項目(如需全部轉發,點擊全選選項即可);
  2. 點擊“拉流”按鈕,拉流生效后,頁面“流下載速度”會顯示當前下載速度;

image.png

  1. 如需停止拉流,選中配置項,點擊“停止拉流”即可;
  2. 拉流后,選中需要轉發的配置項,點擊“推流”按鈕;
image.png
  1. 如需停止推流,選中配置項,點擊“停止推流”即可;
  2. 如需對某一路錄像,在完成“錄像全局配置”的前提下,選中配置項,點擊“錄像”即可;
image.png
  1. 如需停止錄像,選中配置項,點擊“停止錄像”即可。

系統配置:

2 支持程序啟動后自動開啟轉發;

2 支持程序啟動后自動開啟錄像(考慮到Windows平臺磁盤讀寫性能,Windows平臺不做多路錄像承諾)

2 開機后自動啟動(可配置開機自動啟動配置名);

image.png

錄像全局配置:

2 支持設置錄像存儲目錄;

2 支持設定單個錄像文件大小;

2 支持設置文件是否增加日期、時間;

2 支持設置是否音頻自動轉AAC編碼后存儲。

image.png
[Windows平臺多路RTSP|RTMP轉RTMP推送官方定制版]
QQ交流群:

QQ群1(已滿):499687479
QQ群2:294891451

Windows平臺多路RTSP/RTMP流轉RTMP流深度定制版

大牛直播SDK提供的RTSP/RTMP轉RTMP流模塊,具備低延遲、足夠穩定靈活、有狀態反饋機制、資源占用低跨平臺,以SDK形式提供,給開發者提供更大的便利,已應用于諸多專業第三方公司。

其中:Windows平臺對外提供C++ C#接口,Android提供JNI接口封裝,iOS提供object c封裝。

Windows/Android/iOS RTMP/RTSP多路流媒體轉發SDK功能支持:

  1. 支持拉取rtmp流;
  2. 支持拉取rtsp流;
  3. Windows支持本地flv文件轉發(支持制定文件位置轉發,或轉發過程中seek);
  4. 支持本地預覽;
  5. 支持轉發過程中,實時靜音;
  6. 支持轉發過程中,切換rtmp/rtsp url,此外,windows平臺還支持切換本地flv文件;
  7. 支持錄像模塊擴展,可邊轉發邊錄制,每個文件錄制開始結束,均有狀態回饋;
  8. 支持內網RTSP網關模塊擴展,拉取的流數據,可以流入到內網RTSP網關模塊,對外微型RTSP媒體流服務(RTSP url),便于內網訪問;
  9. 音頻:AAC,并支持拉流后的音頻(PCMU/PCMA,Speex等)轉AAC后再轉發;
  10. 視頻:H.264、H.265,支持h265轉發(rtsp/rtmp h265轉rtmp h265推送)

對應Demo:

  • Windows測試程序:SmartStreamRelayDemo.exe;
  • Windows C++工程:WIN-RelaySDK-CPP-Demo;
  • Windows C#工程:WIN-RelaySDK-CSharp-Demo;
  • Android工程:SmartRelayDemoV2;
  • iOS工程:SmartiOSRelayDemoV2。

鑒于部分公司人員配備不齊或產品開發周期短,一方面想用好的SDK,另一方面,苦于短期內沒有好的人力配備完成上層業務邏輯開發,我們聯合第三方開發者實現了Windows轉發模塊深度定制版本:

先睹為快:

1. 啟動SmartStreamRelayDemo.exe

2. 輸入登陸用戶名、密碼,其中,用戶名 admin 密碼123456

3. 如需配置拉流和轉發RTSP RTMP url,請直接在relayconfig.ini配置

4. 頁面編輯配置:
4.1 讀取INI文件,獲取relayconfig.ini配置項;
4.2 保存INI文件,把上層編輯后的URL配置保存下來,配置后的,可直接保存,以便下次使用
4.3 增加工作任務:頁面添加新的轉發配置項
4.4 啟動工作任務:啟動所有轉發
4.5 停止工作任務:停止所有轉發
4.6 錄制:如需錄制流,直接點擊“功能選項”->“錄制”按鈕,默認錄制到“record”目錄
4.7 移除任務:如需刪除某一路流,直接點擊“功能選項”->“移除”按鈕
4.8 拉流預覽:預覽拉取的RTMP/RTSP流,預覽過程中,可實時靜音
4.9 推流預覽:轉發后的RTMP流,可實時預覽,亦可實時靜音

4. demo版,有一小時顯示,每超過一小時,自動停止運行

5. 提供底層SDK授權,上層系統OEM或上層源碼授權

更多資料或demo下載:

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

官網:http://www.nokunlock.com

QQ群:

Windows/Android/iOS平臺實現RTMP推送和播放端AES或SM4加解密實例

1. AES算法和SM4算法掃盲

AES算法

密碼學中的高級加密標準(AdvancedEncryptionStandard,AES),又稱Rijndael加密算法,是美國聯邦政府采用的一種區塊加密標準。這個標準用來替代原先的DES,已經被多方分析且廣為全世界所使用。經過五年的甄選流程,高級加密標準由美國國家標準與技術研究院(NIST)于2001年11月26日發布于FIPSPUB197,并在2002年5月26日成為有效的標準。2006年,高級加密標準已然成為對稱密鑰加密中最流行的算法之一。AES有一個固定的128位的塊大小和128,192或256位大小的密鑰大小。

該算法為比利時密碼學家JoanDaemen和VincentRijmen所設計,結合兩位作者的名字,以Rijndael命名之。AES在軟件及硬件上都能快速地加解密,相對來說較易于操作,且只需要很少的存儲空間。作為一個新的加密標準,目前正被部署應用到更廣大的范圍。

SM4算法

SM4算法全稱為SM4分組密碼算法,是國家密碼管理局2012年3月發布的第23號公告中公布的密碼行業標準。SM4算法是一個分組對稱密鑰算法,明文、密鑰、密文都是16字節,加密和解密密鑰相同。加密算法與密鑰擴展算法都采用32輪非線性迭代結構。解密過程與加密過程的結構相似,只是輪密鑰的使用順序相反。

SM4算法的優點是軟件和硬件實現容易,運算速度快。

2. 接口說明及調用展示

業內首家RTMP整體加解密SDK方案提供商。大牛直播SDK發布的跨平臺(Windows/Android/iOS平臺)的基于AES/SM4音視頻逐幀數據加密整體解決方案,第三方即便是破解了URL,也沒法播放,通過抓包工具抓取到數據,也沒法正常顯示。

此方案的難點是需要了解音視頻編碼相關的細節,才能進行適當的擴展。優點是常用的RTMP Server(如nginx或SRS)或CDN可以直接支持,通用性很強。只需要改推送端和播放端就好。

功能支持:支持AES 128、192、256加解密、支持SM4加解密、支持只加密音頻、視頻、音視頻

2.1 Windows平臺RTMP推送端

C++接口:

		/*
		設置rtmp推送加密選項
		url: 考慮到可能推送到多個服務器,可以根據推送url配置不同的加密選項, 請確保url和SetURL一致
		is_encrypt_video: 1:表示視頻加密, 0:表示視頻不加密, 默認不加密, 其他值返回錯誤
		is_encrypt_audio: 1:表示音頻加密, 0:表示音頻不加密, 默認不加密, 其他值返回錯誤
		成功返回 NT_ERC_OK
		*/
		NT_UINT32(NT_API *SetRtmpEncryptionOption)(NT_HANDLE handle, NT_PCSTR url, NT_INT32 is_encrypt_video, NT_INT32 is_encrypt_audio);


		/*
		設置rtmp加密算法
		url: 考慮到可能推送到多個服務器,可以根據推送url配置不同的加密選項, 請確保url和SetURL一致
		encryption_algorithm: 加密算法, 當前支持aes和國標sm4. 1為aes, 2為sm4, 默認為aes.
		*/
		NT_UINT32(NT_API *SetRtmpEncryptionAlgorithm)(NT_HANDLE handle, NT_PCSTR url, NT_INT32 encryption_algorithm);


		/*
		設置rtmp推送加密密鑰
		url: 考慮到可能推送到多個服務器,可以根據推送url配置不同的加密選項, 請確保url和SetURL一致
		key:加密密鑰
		key_size: 如果加密算法是aes, key_size必須是16, 24, 32 這三個值, 其他返回錯誤; 如果加密算法是sm4, key_size必須是16, 其他值返回錯誤.
		成功返回 NT_ERC_OK
		*/
		NT_UINT32(NT_API *SetRtmpEncryptionKey)(NT_HANDLE handle, NT_PCSTR url, const NT_BYTE* key, NT_UINT32 key_size);


		/*
		設置rtmp推送加密IV(初始化向量), 這個接口不調用的話, 將使用默認IV
		url: 考慮到可能推送到多個服務器,可以根據推送url配置不同的加密選項, 請確保url和SetURL一致
		iv: 初始化向量
		iv_size: 當前必須是16, 其他值返回錯誤
		成功返回 NT_ERC_OK
		*/
		NT_UINT32(NT_API *SetRtmpEncryptionIV)(NT_HANDLE handle, NT_PCSTR url, const NT_BYTE* iv, NT_UINT32 iv_size);

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

C#接口:

        /*
         * 設置rtmp推送加密選項
         * url: 考慮到可能推送到多個服務器,可以根據推送url配置不同的加密選項, 請確保url和SetURL一致
         * is_encrypt_video: 1:表示視頻加密, 0:表示視頻不加密, 默認不加密, 其他值返回錯誤
         * is_encrypt_audio: 1:表示音頻加密, 0:表示音頻不加密, 默認不加密, 其他值返回錯誤
         * 
         * 成功返回 NT_ERC_OK
		 */
        [DllImport(@"SmartPublisherSDK.dll")]
		public static extern UInt32 NT_PB_SetRtmpEncryptionOption(IntPtr handle, [MarshalAs(UnmanagedType.LPStr)]String url, Int32 is_encrypt_video, Int32 is_encrypt_audio);


		/*
         * 設置rtmp加密算法
         * url: 考慮到可能推送到多個服務器,可以根據推送url配置不同的加密選項, 請確保url和SetURL一致
         * encryption_algorithm: 加密算法, 當前支持aes和國標sm4. 1為aes, 2為sm4, 默認為aes.
		 */
        [DllImport(@"SmartPublisherSDK.dll")]
        public static extern UInt32 NT_PB_SetRtmpEncryptionAlgorithm(IntPtr handle, [MarshalAs(UnmanagedType.LPStr)]String url, Int32 encryption_algorithm);


		/*
         * 設置rtmp推送加密密鑰
         * url: 考慮到可能推送到多個服務器,可以根據推送url配置不同的加密選項, 請確保url和SetURL一致
         * key:加密密鑰
         * key_size: 如果加密算法是aes, key_size必須是16, 24, 32 這三個值, 其他返回錯誤; 如果加密算法是sm4, key_size必須是16, 其他值返回錯誤.
         * 成功返回 NT_ERC_OK
		 */
        [DllImport(@"SmartPublisherSDK.dll")]
        public static extern UInt32 NT_PB_SetRtmpEncryptionKey(IntPtr handle, [MarshalAs(UnmanagedType.LPStr)]String url, byte[] key, UInt32 key_size);

		/*
         * 設置rtmp推送加密IV(初始化向量), 這個接口不調用的話, 將使用默認IV
         * url: 考慮到可能推送到多個服務器,可以根據推送url配置不同的加密選項, 請確保url和SetURL一致
         * iv: 初始化向量
         * iv_size: 當前必須是16, 其他值返回錯誤
         * 成功返回 NT_ERC_OK
		 */
        [DllImport(@"SmartPublisherSDK.dll")]
        public static extern UInt32 NT_PB_SetRtmpEncryptionIV(IntPtr handle, [MarshalAs(UnmanagedType.LPStr)]String url, byte[] iv, UInt32 iv_size);

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

C#調用展示:

				//設置RTMP加密(AES/SM4)
                /*
                Int32 is_encrypt_video = 1;
                Int32 is_encrypt_audio = 1;
                NTSmartPublisherSDK.NT_PB_SetRtmpEncryptionOption(publisher_handle_, url, is_encrypt_video, is_encrypt_audio);

                Int32 encryption_algorithm = 1;
                NTSmartPublisherSDK.NT_PB_SetRtmpEncryptionAlgorithm(publisher_handle_, url, encryption_algorithm);

                String key_str = "1234567890123456";

                UInt32 key_size = 16;

                if (key_str.Length <= 16)
                {
                    key_size = 16;
                }
                else if (key_str.Length <= 24)
                {
                    key_size = 24;
                }
                else
                {
                    key_size = 32;
                }

                byte[] key = new byte[key_size];

                if (key_str.Length <= 32)
                {
                    key = System.Text.Encoding.Default.GetBytes(key_str);
                }
                else
                {
                    key = System.Text.Encoding.Default.GetBytes(key_str.Substring(0, 32));
                }
                
                NTSmartPublisherSDK.NT_PB_SetRtmpEncryptionKey(publisher_handle_, url, key, key_size);

                String iv_str = "1234567890123456";

                UInt32 iv_size = 16;

                byte[] iv = new byte[iv_size];

                if (iv_str.Length <= 16)
                {
                    iv = System.Text.Encoding.Default.GetBytes(iv_str);
                }
                else
                {
                    iv = System.Text.Encoding.Default.GetBytes(key_str.Substring(0, 16));
                }

                NTSmartPublisherSDK.NT_PB_SetRtmpEncryptionIV(publisher_handle_, url, iv, iv_size);

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

2.2 Windows平臺RTMP播放端

C++接口:

		/*
		*
		* 設置解密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);

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

C#接口:

        /*
         * 設置解密key,目前只用來解密rtmp加密流
		 * key: 解密密鑰
		 * size: 密鑰長度
		 * 成功返回NT_ERC_OK
		 */
        [DllImport(@"SmartPlayerSDK.dll")]
        public static extern UInt32 NT_SP_SetKey(IntPtr handle, byte[] key, UInt32 size);

		/*
		 * 設置解密向量,目前只用來解密rtmp加密流
		 * iv:  解密向量
		 * size: 向量長度
		 * 成功返回NT_ERC_OK
		 */
        [DllImport(@"SmartPlayerSDK.dll")]
        public static extern UInt32 NT_SP_SetDecryptionIV(IntPtr handle, byte[] iv, UInt32 size);

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

調用展示:

            String key_str = "1234567890123456";

            UInt32 key_size = 16;

            if (key_str.Length <= 16)
            {
                key_size = 16;
            }
            else if (key_str.Length <= 24)
            {
                key_size = 24;
            }
            else
            {
                key_size = 32;
            }

            byte[] key = new byte[key_size];

            if (key_str.Length <= 32)
            {
                key = System.Text.Encoding.Default.GetBytes(key_str);
            }
            else
            {
                key = System.Text.Encoding.Default.GetBytes(key_str.Substring(0, 32));
            }

            NTSmartPlayerSDK.NT_SP_SetKey(player_handle_, key, key_size);

            String iv_str = "1234567890123456789012345678901211";

            UInt32 iv_size = 16;

            byte[] iv = new byte[iv_size];

            if (iv_str.Length <= 16)
            {
                iv = System.Text.Encoding.Default.GetBytes(iv_str);
            }
            else
            {
                iv = System.Text.Encoding.Default.GetBytes(key_str.Substring(0, 16));
            }
            
            iv = System.Text.Encoding.Default.GetBytes(iv_str);

            NTSmartPlayerSDK.NT_SP_SetDecryptionIV(player_handle_, iv, iv_size);

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

2.3?Android平臺RTMP推送端

	/**
	 * 設置rtmp推送加密選項
	 *
	 * @param url: 考慮到可能推送到多個服務器,可以根據推送url配置不同的加密選項, 請確保url和SetURL一致
	 * @param is_encrypt_video: 1:表示視頻加密, 0:表示視頻不加密, 默認不加密, 其他值返回錯誤
	 * @param is_encrypt_audio: 1:表示音頻加密, 0:表示音頻不加密, 默認不加密, 其他值返回錯誤
	 *
	 * @return {0} if successful
	 */
	public native int SetRtmpEncryptionOption(long handle,  String url, int is_encrypt_video, int is_encrypt_audio);

	/**
	 * 設置rtmp加密算法
	 *
	 * @param url: 考慮到可能推送到多個服務器,可以根據推送url配置不同的加密選項, 請確保url和SetURL一致
	 * @param encryption_algorithm: 加密算法, 當前支持aes和國標sm4. 1為aes, 2為sm4, 默認為aes.
	 *
	 * @return {0} if successful
	 */
	public native int SetRtmpEncryptionAlgorithm(long handle,  String url, int encryption_algorithm);

	/**
	 * 設置rtmp推送加密密鑰
	 *
	 * @param url: 考慮到可能推送到多個服務器,可以根據推送url配置不同的加密選項, 請確保url和SetURL一致
	 * @param key:加密密鑰
	 * @param key_size: 當前key_size必須是16, 24, 32 這三個值,其他返回錯誤
	 *
	 * @return {0} if successful
	 */
	public native int SetRtmpEncryptionKey(long handle, String url, byte[] key, int key_size);

	/**
	 * 設置rtmp推送加密IV(初始化向量), 這個接口不調用的話, 將使用默認IV
	 *
	 * @param url: 考慮到可能推送到多個服務器,可以根據推送url配置不同的加密選項, 請確保url和SetURL一致
	 * @param iv:初始化向量
	 * @param iv_size: 當前必須是16, 其他值返回錯誤
	 *
	 * @return {0} if successful
	 */
	public native int SetRtmpEncryptionIV(long handle, String url, byte[] iv, int iv_size);

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

調用展示:

if(encrypt_key != null && !encrypt_key.isEmpty()) {
                Log.i(TAG, "encrypt_key:" + encrypt_key);

                int is_encrypt_video = 1;
                int is_encrypt_audio = 1;

                if (pushType == 1)
                {
                    is_encrypt_video = 0;
                }
                else if (pushType == 2)
                {
                    is_encrypt_audio = 0;
                }

                libPublisher.SetRtmpEncryptionOption(publisherHandle, publishURL, is_encrypt_video, is_encrypt_audio);

                //加密算法可自行設置
                int encryption_algorithm = 1;
                libPublisher.SetRtmpEncryptionAlgorithm(publisherHandle, publishURL, encryption_algorithm);

                int key_len = 16;

                if (encrypt_key.length() > 16 && encrypt_key.length() <= 24) {
                    key_len = 24;
                } else if (encrypt_key.length() > 24) {
                    key_len = 32;
                }

                byte[] key = new byte[key_len];

                for (int i = 0; i < key_len; i++) {
                    key[i] = 0;
                }

                try {
                    byte[] key_utf8 = encrypt_key.getBytes("UTF-8");

                    int copy_len = key_utf8.length < key_len ? key_utf8.length : key_len;

                    for (int i = 0; i < copy_len; ++i) {
                        key[i] = key_utf8[i];
                    }

                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }

                int ret = libPublisher.SetRtmpEncryptionKey(publisherHandle, publishURL, key, key.length);

                if(ret != 0)
                {
                    Log.e(TAG, "Call SmartPublisherSetRtmpEncryptionKey failed, errorID: " + ret);
                }
            }

            if(encrypt_iv != null && !encrypt_iv.isEmpty()) {
                int iv_len = 16;

                byte[] iv = new byte[iv_len];

                for (int i = 0; i < iv_len; i++) {
                    iv[i] = 0;
                }

                try {
                    byte[] iv_utf8 = encrypt_iv.getBytes("UTF-8");

                    int copy_len = iv_utf8.length < iv_len ? iv_utf8.length : iv_len;

                    for (int i = 0; i < copy_len; ++i) {
                        iv[i] = iv_utf8[i];
                    }

                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }

                int ret = libPublisher.SetRtmpEncryptionIV(publisherHandle, publishURL, iv, iv.length);

                if(ret != 0)
                {
                    Log.e(TAG, "Call SetRtmpEncryptionIV failed, errorID: " + ret);
                }
            }

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

2.4 Android平臺RTMP播放端

	/**
	 * 設置解密key,目前只用來解密rtmp加密流
	 *
	 * @param handle: return value from SmartPlayerOpen()
	 *
	 * @param key:解密密鑰
	 *
	 * @param size:密鑰長度
	 *
	 * @return {0} if successful
	 */
	public native int SmartPlayerSetKey(long handle, byte[] key, int size);

	/**
	 * 設置解密向量,目前只用來解密rtmp加密流
	 *
	 * @param handle: return value from SmartPlayerOpen()
	 *
	 * @param iv:解密向量
	 *
	 * @param size:向量長度
	 *
	 * @return {0} if successful
	 */
	public native int SmartPlayerSetDecryptionIV(long handle, byte[] iv, int size);

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

調用展示:

        if (encrypt_key != null && !encrypt_key.isEmpty()) {
            Log.i(TAG, "encrypt_key:" + encrypt_key);

            int key_len = 16;

            if (encrypt_key.length() > 16 && encrypt_key.length() <= 24) {
                key_len = 24;
            } else if (encrypt_key.length() > 24) {
                key_len = 32;
            }

            byte[] key = new byte[key_len];

            for (int i = 0; i < key_len; i++) {
                key[i] = 0;
            }

            try {
                byte[] key_utf8 = encrypt_key.getBytes("UTF-8");

                int copy_key_len = key_utf8.length < key_len ? key_utf8.length : key_len;

                for (int i = 0; i < copy_key_len; ++i) {
                    key[i] = key_utf8[i];
                }

            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }

            libPlayer.SmartPlayerSetKey(playerHandle, key, key.length);

            if (encrypt_iv != null && !encrypt_iv.isEmpty()) {
                Log.i(TAG, "encrypt_iv:" + encrypt_iv);

                int iv_len = 16;
                byte[] iv = new byte[iv_len];

                for (int i = 0; i < iv_len; i++) {
                    iv[i] = 0;
                }

                try {
                    byte[] iv_utf8 = encrypt_iv.getBytes("UTF-8");

                    int copy_iv_len = iv_utf8.length < key_len ? iv_utf8.length : key_len;

                    for (int i = 0; i < copy_iv_len; ++i) {
                        iv[i] = iv_utf8[i];
                    }

                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }

                libPlayer.SmartPlayerSetDecryptionIV(playerHandle, iv, iv.length);
            }
        }

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

2.5?iOS平臺RTMP推送端

/**
 * 設置rtmp推送加密選項
 *
 * @param url 考慮到可能推送到多個服務器,可以根據推送url配置不同的加密選項, 請確保url和SetURL一致
 * @param is_encrypt_video 1:表示視頻加密, 0:表示視頻不加密, 默認不加密, 其他值返回錯誤
 * @param is_encrypt_audio 1:表示音頻加密, 0:表示音頻不加密, 默認不加密, 其他值返回錯誤
 *
 * @return {0} if successful
 */
-(NSInteger)SetRtmpEncryptionOption:(NSString*)url is_encrypt_video:(NSInteger)is_encrypt_video is_encrypt_audio:(NSInteger)is_encrypt_audio;

/**
 * 設置rtmp加密算法
 *
 * @param url 考慮到可能推送到多個服務器,可以根據推送url配置不同的加密選項, 請確保url和SetURL一致
 * @param encryption_algorithm 加密算法, 當前支持aes和國標sm4. 1為aes, 2為sm4, 默認為aes.
 *
 * @return {0} if successful
 */
-(NSInteger)SetRtmpEncryptionAlgorithm:(NSString*)url encryption_algorithm:(NSInteger)encryption_algorithm;

/**
 * 設置rtmp推送加密密鑰
 *
 * @param url 考慮到可能推送到多個服務器,可以根據推送url配置不同的加密選項, 請確保url和SetURL一致
 * @param key 加密密鑰
 * @param key_size 當前key_size必須是16, 24, 32 這三個值,其他返回錯誤
 *
 * @return {0} if successful
 */
-(NSInteger)SetRtmpEncryptionKey:(NSString*)url key:(unsigned char*)key key_size:(NSInteger)key_size;

/**
 * 設置rtmp推送加密IV(初始化向量), 這個接口不調用的話, 將使用默認IV
 *
 * @param url 考慮到可能推送到多個服務器,可以根據推送url配置不同的加密選項, 請確保url和SetURL一致
 * @param iv 初始化向量
 * @param iv_size 當前必須是16, 其他值返回錯誤
 *
 * @return {0} if successful
 */
-(NSInteger)SetRtmpEncryptionIV:(NSString*)url iv:(unsigned char*)iv iv_size:(NSInteger)iv_size;

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

調用展示:

    NSInteger key_length = [encrypt_key_ length];
    
    if(key_length > 0)
    {
        NSInteger is_encrypt_video = 1;
        NSInteger is_encrypt_audio = 1;
        
        if(video_opt_ == 0)
        {
            is_encrypt_video = 0;
        }
        
        if(audio_opt_ == 0)
        {
            is_encrypt_audio = 0;
        }
        
        [_smart_publisher_sdk SetRtmpEncryptionOption:rtmp_push_url is_encrypt_video:is_encrypt_video is_encrypt_audio:is_encrypt_audio];
        
        //默認AES加密,如需SM4加密,參數設置2即可
        NSInteger encryption_algorithm = 1;
        [_smart_publisher_sdk SetRtmpEncryptionAlgorithm:rtmp_push_url encryption_algorithm:encryption_algorithm];
        
        int key_len = 16;
        
        if (key_length > 16 && key_length <= 24) {
            key_len = 24;
        } else if (key_length > 24) {
            key_len = 32;
        }
        
        unsigned char key[32];
        memset(key, 0, 32);
        
        NSData* key_data = [encrypt_key_ dataUsingEncoding:NSUTF8StringEncoding];
        
        NSInteger copy_key_len = key_length < key_len ? key_length : key_len;
        
        Byte *copy_key_data = (Byte *)[key_data bytes];
        
        for(int i=0;i<copy_key_len;i++)
        {
            key[i] = copy_key_data[i];
        }
            
        [_smart_publisher_sdk SetRtmpEncryptionKey:rtmp_push_url key:key key_size:key_len];
        
        NSInteger iv_length = [encrypt_iv_ length];
        
        if(iv_length > 0)
        {
            int iv_len = 16;
            
            unsigned char iv[16];
            memset(iv, 0, 16);
            
            NSData* iv_data = [encrypt_iv_ dataUsingEncoding:NSUTF8StringEncoding];
            
            NSInteger copy_iv_len = iv_length < iv_len ? iv_length : iv_len;
            
            Byte *copy_iv_data = (Byte *)[iv_data bytes];
            
            for(int i=0;i<copy_iv_len;i++)
            {
                iv[i] = copy_iv_data[i];
            }
            
            [_smart_publisher_sdk SetRtmpEncryptionIV:rtmp_push_url iv:iv iv_size:iv_len];
        }

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

2.6?iOS平臺RTMP播放端

/**
 * 設置解密key,目前只用來解密rtmp加密流
 *
 * @param key 解密密鑰
 *
 * @param key_size 密鑰長度
 *
 * @return {0} if successful
 */
- (NSInteger)SmartPlayerSetKey:(unsigned char*)key key_size:(NSInteger)key_size;

/**
 * 設置解密向量,目前只用來解密rtmp加密流
 *
 * @param iv 解密向量
 *
 * @param iv_size 向量長度
 *
 * @return {0} if successful
 */
- (NSInteger)SmartPlayerSetDecryptionIV:(unsigned char*)iv iv_size:(NSInteger)iv_size;

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

調用展示:

    NSInteger key_length = [encrypt_key_ length];
    
    if(key_length > 0)
    {
        int key_len = 16;
        
        if (key_length > 16 && key_length <= 24) {
            key_len = 24;
        } else if (key_length > 24) {
            key_len = 32;
        }
        
        unsigned char key[32];
        memset(key, 0, 32);
        
        NSData* key_data = [encrypt_key_ dataUsingEncoding:NSUTF8StringEncoding];
  
        NSInteger copy_key_len = key_length < key_len ? key_length : key_len;
        
        Byte *copy_key_data = (Byte *)[key_data bytes];
        
        for(int i=0;i<copy_key_len;i++)
        {
            key[i] = copy_key_data[i];
        }
        
        [_smart_player_sdk SmartPlayerSetKey:key key_size:key_len];
    }
    
    NSInteger iv_length = [encrypt_iv_ length];
    
    if(iv_length > 0)
    {
        int iv_len = 16;
        
        unsigned char iv[16];
        memset(iv, 0, 16);
        
        NSData* iv_data = [encrypt_iv_ dataUsingEncoding:NSUTF8StringEncoding];
        
        NSInteger copy_iv_len = iv_length < iv_len ? iv_length : iv_len;
        
        Byte *copy_iv_data = (Byte *)[iv_data bytes];
        
        for(int i=0;i<copy_iv_len;i++)
        {
            iv[i] = copy_iv_data[i];
        }
        
        [_smart_player_sdk SmartPlayerSetDecryptionIV:iv iv_size:iv_len];
    }

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

3.注意事項

1. RTMP推送端什么時候調用加密接口?

回答:SetUrl之后,開始推送之前;

2. RTMP播放端,什么時候設置Key和IV解密向量?

回答:可以實現自動檢測,如檢測到推送的RTMP流系AES或SM4加密,會回調上來NT_SP_E_EVENT_ID_NEED_KEY事件,彈出輸入Key和IV框,如輸入的Key和IV不正確,播放端會收到NT_SP_E_EVENT_ID_KEY_ERROR事件

 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不正確*/

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

3. 設置加解密Key和IV,有什么注意事項?

回答:key_size: 如果加密算法是aes, key_size必須是16, 24, 32 這三個值, 其他返回錯誤; 如果加密算法是sm4, key_size必須是16, 其他值返回錯誤;iv_size: 當前必須是16, 其他值返回錯誤。

相關資料:Github:?https://github.com/daniulive/SmarterStreaming

如何在IE瀏覽器播放RTSP或RTMP流(RTSP/RTMP OCX播放控件)

好多開發者一直苦惱于如何在IE瀏覽器環境下,構建低延遲的RTSP或RTMP播放,對于RTSP流來說,好多公司通常的做法是把RTSP轉RTMP,然后分發到RTMP服務器,然后服務器轉http-flv出來,瀏覽器直接播放http-flv流,亦或通過flash控件直接播放RTMP流,還有就是,轉hls流出來,缺點是hls流延遲更大。

以上方案未嘗不可,如果對播放體驗和延遲要求更高,最簡單的做法是直接在IE瀏覽器下加載activex控件。

大牛直播SDK在現有SDK的基礎上,擴展了ocx控件,用于IE瀏覽器下的低延遲RTMP或RTSP播放,不謙虛的說,也可能是行業內功能支持和延遲最好的RTMP和RTSP播放器(支持RTMP/RTSP H.265(hevc)播放)。

頁面展示

1. 功能齊全的單畫面RTMP流或RTSP流播放:

?

2. 同時播放4路RTMP流或RTSP流畫面:

?

本地播放和集成說明:

點我下載DEMO

本地播放

DEMO說明

  1. 1_player_ocx.html:單個窗口功能展示。
  2. 4_player_ocx.html:4窗口功能展示。
  3. SmartPlayer.exe:cs架構播放器。

運行網頁播放端之前,請確保以管理員權限注冊ocx控件:regplayerocx.bat右鍵–>“以管理員身份運行(A)”,同理,反注冊也是需要管理員身份。

?

注意:大牛直播RTSP/RTMP播放OCX控件只適用于微軟IE瀏覽器。

對應封裝接口

	ULONG NT_SetLogPath();
	ULONG NT_Open();
	ULONG NT_Close();
	ULONG NT_StartPlay();
	ULONG NT_StopPlay();
	ULONG NT_SetMute(LONG is_mute);
	ULONG NT_SetURL(LPCTSTR url);
	ULONG NT_SetBuffer(LONG buffer);
	ULONG NT_SetRTSPTcpMode(LONG isUsingTCP);
	ULONG NT_SetRtspTimeout(LONG timeout);
	ULONG NT_SetRtspAutoSwitchTcpUdp(LONG is_auto_switch_tcp_udp);
	ULONG NT_SetFastStartup(LONG isFastStartup);
	ULONG NT_SetLowLatencyMode(LONG mode);
	ULONG NT_SetFlipVertical(LONG is_flip);
	ULONG NT_SetFlipHorizontal(LONG is_flip);
	ULONG NT_SetRotation(LONG degress);
	ULONG NT_SwitchURL(LPCTSTR url);
	ULONG NT_SetCaptureImagePath(LPCTSTR path);
	ULONG NT_CaptureImage();
	ULONG NT_SetRecorderDirectory(LPCTSTR dir);
	ULONG NT_SetRecorderFileMaxSize(ULONG size);
	ULONG NT_NT_SP_RecorderFileNameRuler(ULONG type, LPCTSTR file_name_prefix, LONG append_date, LONG append_time);
	ULONG NT_SetRecorderAudioTranscodeAAC(LONG is_transcode);
	ULONG NT_SetRecorderVideo(LONG is_record_video);
	ULONG NT_SetRecorderAudio(LONG is_record_audio);
	ULONG NT_StartRecorder();
	ULONG NT_StopRecorder();
	ULONG NT_FullScreen();
	void OnSDKEventReceived(ULONG event_id, ULONG param1);
	void OnVideoSizeReceived(ULONG width, ULONG height);

設置LOG存放路徑:

ULONG CSmartPlayerActiveXCtrl::NT_SetLogPath(LPCTSTR log_path)

請于NT_Open() 之前調用,代碼示例:

var obj = document.getElementById("SmartPlayerActiveX");
				
//如需記錄log文件,請確保log路徑存在, 如多級目錄, 可按照"D:\\Daniulive\\log"類似格式設定, 記錄文件名: smart_sdk.log

obj.NT_SetLogPath("D:\\");

接口說明:

1.? ULONG NT_Open();

打開player實例;
2. ULONG NT_Close();

關閉player實例;
3. ULONG NT_StartPlay();

開始播放;
4. ULONG NT_StopPlay();

停止播放;
5. ULONG NT_SetMute(LONG is_mute);

設置實時靜音;
6. ULONG NT_SetURL(LPCTSTR url);

設置播放的RTMP或RTSP url;
7. ULONG NT_SetBuffer(LONG buffer);

設置buffer time,緩沖時間,單位:毫秒;
8. ULONG NT_SetRTSPTcpMode(LONG isUsingTCP);

設置RTSP TCP/UDP播放模式;
9. ULONG NT_SetRtspTimeout(LONG timeout);

設置RTSP超時時間;
10. ULONG NT_SetRtspAutoSwitchTcpUdp(LONG is_auto_switch_tcp_udp);

設置是否自動切換TCP/UDP模式;
11. ULONG NT_SetFastStartup(LONG isFastStartup);

設置是否快速啟動;
12. ULONG NT_SetLowLatencyMode(LONG mode);

設置是否低延遲模式播放;
13. ULONG NT_SetFlipVertical(LONG is_flip);

設置垂直反轉模式圖像;
14. ULONG NT_SetFlipHorizontal(LONG is_flip);

設置水平反轉圖像;
15. ULONG NT_SetRotation(LONG degress);

設置旋轉圖像,可設定角度:0度 90度 180度 270度;
16. ULONG NT_SwitchURL(LPCTSTR url);

設置快速切換RTSP/RTMP url;
17. ULONG NT_SetCaptureImagePath(LPCTSTR path);

設置快照保存位置;
18. ULONG NT_CaptureImage();

設置實時快照功能;
19. ULONG NT_SetRecorderDirectory(LPCTSTR dir);

設置錄像保存位置;
20. ULONG NT_SetRecorderFileMaxSize(ULONG size);

設置單個錄像文件最大size,單位:兆;
21. ULONG NT_NT_SP_RecorderFileNameRuler(ULONG type, LPCTSTR file_name_prefix, LONG append_date, LONG append_time);

設置錄像文件命名規則:是否需要前綴、是否添加日期、是否添加時間;
22. ULONG NT_SetRecorderAudioTranscodeAAC(LONG is_transcode);

設置錄像音頻文件是否轉AAC后錄制,支持PCMA/PCMU/SPEEX轉AAC后錄制文件;
23. ULONG NT_SetRecorderVideo(LONG is_record_video);

設置是否錄制視頻;
24. ULONG NT_SetRecorderAudio(LONG is_record_audio);

設置是否錄制音頻;
25. ULONG NT_StartRecorder();

開始錄像;
26. ULONG NT_StopRecorder();

停止錄像;
27. ULONG NT_FullScreen();

全屏顯示窗口。

事件Event:?

1. void OnSDKEventReceived(ULONG event_id, ULONG param1);

回調網絡狀態、buffering狀態、下載速度等;

事件類型:

<script>
	var NT_EVENT_ID_SMART_PLAYER_SDK = 0x01000000;
	var NT_SP_E_EVENT_ID_BASE = NT_EVENT_ID_SMART_PLAYER_SDK;
	var NT_SP_E_EVENT_ID_CONNECTING				= NT_SP_E_EVENT_ID_BASE | 0x2;	/*連接中*/
	var NT_SP_E_EVENT_ID_CONNECTION_FAILED		= NT_SP_E_EVENT_ID_BASE | 0x3;	/*連接失敗*/
	var NT_SP_E_EVENT_ID_CONNECTED				= NT_SP_E_EVENT_ID_BASE | 0x4;	/*已連接*/
	var NT_SP_E_EVENT_ID_DISCONNECTED			= NT_SP_E_EVENT_ID_BASE | 0x5;	/*斷開連接*/
	var NT_SP_E_EVENT_ID_NO_MEDIADATA_RECEIVED	= NT_SP_E_EVENT_ID_BASE | 0x8;	/*收不到RTMP數據*/
	var NT_SP_E_EVENT_ID_RTSP_STATUS_CODE       = NT_SP_E_EVENT_ID_BASE | 0xB;  /*rtsp status code上報, 目前只上報401, param1表示status code*/

	/* 接下來請從0x81開始*/
	var NT_SP_E_EVENT_ID_START_BUFFERING = NT_SP_E_EVENT_ID_BASE | 0x81; /*開始緩沖*/
	var NT_SP_E_EVENT_ID_BUFFERING		 = NT_SP_E_EVENT_ID_BASE | 0x82; /*緩沖中, param1 表示百分比進度*/
	var NT_SP_E_EVENT_ID_STOP_BUFFERING  = NT_SP_E_EVENT_ID_BASE | 0x83; /*停止緩沖*/

	var NT_SP_E_EVENT_ID_DOWNLOAD_SPEED  = NT_SP_E_EVENT_ID_BASE | 0x91; /*下載速度, param1表示下載速度,單位是(Byte/s)*/

	var NT_SP_E_EVENT_ID_PLAYBACK_REACH_EOS		= NT_SP_E_EVENT_ID_BASE | 0xa1; /*播放結束, 直播流沒有這個事件,點播流才有*/
	var NT_SP_E_EVENT_ID_RECORDER_REACH_EOS		= NT_SP_E_EVENT_ID_BASE | 0xa2; /*錄像結束, 直播流沒有這個事件, 點播流才有*/
	var NT_SP_E_EVENT_ID_PULLSTREAM_REACH_EOS   = NT_SP_E_EVENT_ID_BASE | 0xa3; /*拉流結束, 直播流沒有這個事件,點播流才有*/
	var NT_SP_E_EVENT_ID_DURATION = NT_SP_E_EVENT_ID_BASE | 0xa8; /*視頻時長,如果是直播,則不上報,如果是點播的話, 若能從視頻源獲取視頻時長的話,則上報, param1表示視頻時長,單位是毫秒(ms)*/
</script>

調用展示:

<script language='javascript' for="SmartPlayerActiveX"  event="OnSDKEventReceived(event_id, param1)">
		// Test 1 - statically load the script (This is the basis for the hack)
		// Works on IE8, IE9, IE10 and IE11
		
		var show_str = "";

		var connection_status = event_id;

		if (connection_status != 0)
		{
			show_str += "鏈接狀態: ";

			if (NT_SP_E_EVENT_ID_CONNECTING == connection_status)
			{
				show_str += "鏈接中";
			}
			else if (NT_SP_E_EVENT_ID_CONNECTION_FAILED == connection_status)
			{
				show_str += "鏈接失敗";
			}
			else if (NT_SP_E_EVENT_ID_CONNECTED == connection_status)
			{
				show_str += "鏈接成功";
			}
			else if (NT_SP_E_EVENT_ID_DISCONNECTED == connection_status)
			{
				show_str += "鏈接斷開";
			}
			else if (NT_SP_E_EVENT_ID_NO_MEDIADATA_RECEIVED == connection_status)
			{
				show_str += "收不到數據";
			}
		}

		var download_speed = -1;
		
		if (NT_SP_E_EVENT_ID_DOWNLOAD_SPEED == event_id)
		{
			download_speed = param1;
		}
		
		if (download_speed != -1)
		{
			show_str += "下載速度:" + (download_speed * 8 / 1000).toFixed(0) + "kbps " + (download_speed / 1024).toFixed(0) + "KB/s";
		}
		
		var buffer_status = 0;
		
		if (NT_SP_E_EVENT_ID_START_BUFFERING == event_id
		|| NT_SP_E_EVENT_ID_BUFFERING == event_id
		|| NT_SP_E_EVENT_ID_STOP_BUFFERING == event_id)
		{
			buffer_status = event_id;
		}

		if (buffer_status != 0)
		{
			show_str += "緩沖狀態: ";

			if (NT_SP_E_EVENT_ID_START_BUFFERING == buffer_status)
			{
				show_str += "開始緩沖";
			}
			else if (NT_SP_E_EVENT_ID_BUFFERING == buffer_status)
			{
				show_str += "緩沖中" + param1 + "%";
			}
			else if (NT_SP_E_EVENT_ID_STOP_BUFFERING == buffer_status)
			{
				show_str += "結束緩沖";
			}
		}
		
		var EventMsgText = document.getElementById("EventMsg");
					
		EventMsgText.innerHTML = show_str;
	</script>

2. void OnVideoSizeReceived(ULONG width, ULONG height);

回調視頻寬高信息。

調用展示:

<script language='javascript' for="SmartPlayerActiveX"  event="OnVideoSizeReceived(width, height)">
	// Test 1 - statically load the script (This is the basis for the hack)
	// Works on IE8, IE9, IE10 and IE11
	
	var VideoResolutionText = document.getElementById("VideoResolution");
				
	VideoResolutionText.innerHTML = width + "*" + height;
</script>

SDK接口調用實例:

播放和錄像調用示例:

var is_player_opened = false;
var is_playing = false;
var is_recording = false;

function OpenPlayer()
{			   
	if(is_player_opened)
	{
		return;
	}
	
	var obj = document.getElementById("SmartPlayerActiveX");
	
	//如需記錄log文件,請確保log路徑存在, 如多級目錄, 可按照"D:\\Daniulive\\log"類似格式設定, 記錄文件名: smart_sdk.log
	obj.NT_SetLogPath("D:\\");
	
	var ret = obj.NT_Open();
	
	if(ret == 0)
	{   
		//設置TCP/UDP模式
		var rtsp_tcp_mode = document.getElementById("rtspTcpMode").checked ? 1 : 0;
		obj.NT_SetRTSPTcpMode(rtsp_tcp_mode);
		
		//設置RTSP超時時間
		var rtsp_timeout = document.getElementById("rtspTimeout").value;
		obj.NT_SetRtspTimeout(rtsp_timeout);
		
		//設置是否自動切換TCP-UDP模式
		var rtsp_auto_switch_tcp_udp = document.getElementById("rtspAutoSwitchTcpUdp").checked ? 1 : 0;
		obj.NT_SetRtspAutoSwitchTcpUdp(rtsp_auto_switch_tcp_udp);
		
		//設置是否快速啟動
		var fast_startup_mode = document.getElementById("fastStartupMode").checked ? 1 : 0;
		obj.NT_SetFastStartup(fast_startup_mode);
		
		//設置需要播放或錄像的RTSP/RTMP url
		var url = document.getElementById("playorReocordUrl").value;
		obj.NT_SetURL(url);
		
		//設置實時截圖路徑(可自行設置或選取系統存在的文件夾), 如多級目錄可按照"D:\\Daniulive\\image"類似格式設定
		//var image_path = "D:\\";
		obj.NT_SetCaptureImagePath(image_path);
	
		is_player_opened = true;
	}
}

function ClosePlayer()
{
	if(is_player_opened)
	{
		var obj = document.getElementById("SmartPlayerActiveX");
		obj.NT_Close();
		
		var EventMsgText = document.getElementById("EventMsg");	
		EventMsgText.innerHTML = "";
		
		is_player_opened = false;
	}
}

function OnBnClickedPlay()
{
	if(!isIE())
	{
		alert("非IE瀏覽器,請用IE打開播放控件..");
		return;
	}
	
	if(!isActiveXInstalled())
	{
		alert("控件未加載,請先加載控件..");
		return;
	}
	
	if(is_playing)
	{
		StopPlayback();
	}
	else
	{
		StartPlayback();
	}
}

//開始播放
function StartPlayback() {
	
	if(!is_playing && !is_recording)
	{
		OpenPlayer();
	}
	
	var obj = document.getElementById("SmartPlayerActiveX");

	//設置是否啟用低延遲模式
	var low_latency_mode = document.getElementById("lowlatencyMode").checked ? 1 : 0;
	obj.NT_SetLowLatencyMode(low_latency_mode);
					
	//設置緩沖時間
	var buffer_time = document.getElementById("bufferTime").value;
	obj.NT_SetBuffer(buffer_time);
					
	var ret = obj.NT_StartPlay();
	
	if(ret == 0)
	{
		is_playing = true;	
		
		var playBtnText = document.getElementById("playBtn");
	
		playBtnText.innerHTML = "停止播放";
	}		
}

//停止播放
function StopPlayback() {

	if(!is_playing)
	{
		return;
	}
	
	var obj = document.getElementById("SmartPlayerActiveX");

	obj.NT_StopPlay();
	 
	is_playing = false;
	
	var playBtnText = document.getElementById("playBtn");
	
	playBtnText.innerHTML = "開始播放";
	
	if(!is_recording)
	{
		ClosePlayer();
	}
	
	var VideoResolutionText = document.getElementById("VideoResolution");
			
	VideoResolutionText.innerHTML = "";
}
			
function OnBnClickedRecord()
{
	if(!isIE())
	{
		alert("非IE瀏覽器,請用IE打開播放控件..");
		return;
	}
	
	if(!isActiveXInstalled())
	{
		alert("控件未加載,請先加載控件..");
		return;
	}

	if(is_recording)
	{
		StopRecorder();
	}
	else
	{
		StartRecorder();
	}
}

//開始錄像
function StartRecorder() {
	
	if(!is_playing && !is_recording)
	{
		OpenPlayer();
	}
	
	var obj = document.getElementById("SmartPlayerActiveX");

	//設置實時錄像存放路徑(可自行設置或選取系統存在的文件夾), 如多級目錄可按照"D:\\Daniulive\\rec"類似格式設定
	var rec_dir = "D:\\";
	obj.NT_SetRecorderDirectory(rec_dir);
	
	var rec_max_size = 200;
	obj.NT_SetRecorderFileMaxSize(rec_max_size);
	
	var type = 0;
	var file_name_prefix = "daniulive";
	var append_date = 1;
	var append_time = 1;
	obj.NT_NT_SP_RecorderFileNameRuler(type, file_name_prefix, append_date, append_time);
	
	var is_transcode = 1;
	obj.NT_SetRecorderAudioTranscodeAAC(is_transcode);
	
	var is_record_video = 1;
	obj.NT_SetRecorderVideo(is_record_video);
	
	var is_record_audio = 1;
	obj.NT_SetRecorderAudio(is_record_audio);
	
	var ret = obj.NT_StartRecorder();
	
	if(ret == 0)
	{
		is_recording = true;
		
		var recordBtnText = document.getElementById("recordBtn");
	
		recordBtnText.innerHTML = "停止錄像";
	}
}

//停止錄像
function StopRecorder() {

	if(!is_recording)
	{
		return;
	}
	
	var obj = document.getElementById("SmartPlayerActiveX");

	obj.NT_StopRecorder();
	
	is_recording = false;
	
	var recordBtnText = document.getElementById("recordBtn");
	
	recordBtnText.innerHTML = "開始錄像";
	
	if(!is_playing)
	{
		ClosePlayer();
	}
}

快速切換URL調用示例:

//快速切換播放URL
function SwitchUrl() {

	if(!is_playing)
	{
		return;
	}

	var obj = document.getElementById("SmartPlayerActiveX");

	var switch_url = document.getElementById("playorReocordUrl").value;
	obj.NT_SwitchURL(switch_url);
}

實時靜音調用示例:

//實時靜音
var is_mute = 1;	
function SetMute() {
	
	var obj = document.getElementById("SmartPlayerActiveX");
	
	obj.NT_SetMute(is_mute);
	
	var muteText = document.getElementById("MuteBtn");
	
	if(is_mute == 1 )
	{
		is_mute = 0;
		muteText.innerHTML = "取消靜音";
	}
	else
	{
		is_mute = 1;
		muteText.innerHTML  = "實時靜音";
	}
}

視頻view垂直反轉、水平反轉、旋轉調用示例:

//垂直反轉
var is_flip_vertical = 1;
function SetFlipVertical() {
	
	var obj = document.getElementById("SmartPlayerActiveX");
	
	obj.NT_SetFlipVertical(is_flip_vertical);
	
	var flipVerticalText = document.getElementById("FlipVerticalBtn");
	
	if(is_flip_vertical == 1 )
	{
		is_flip_vertical = 0;
		flipVerticalText.innerHTML = "取消反轉";
	}
	else
	{
		is_flip_vertical = 1;
		flipVerticalText.innerHTML  = "垂直反轉";
	}
}

//水平反轉
var is_flip_horizontal = 1;
function SetFlipHorizontal() {
	
	var obj = document.getElementById("SmartPlayerActiveX");
	
	obj.NT_SetFlipHorizontal(is_flip_horizontal);
	
	var flipHorizontalText = document.getElementById("FlipHorizontalBtn");
	
	if(is_flip_horizontal == 1 )
	{
		is_flip_horizontal = 0;
		flipHorizontalText.innerHTML = "取消反轉";
	}
	else
	{
		is_flip_horizontal = 1;
		flipHorizontalText.innerHTML  = "水平反轉";
	}
}

//視頻view旋轉
var rotate_degrees_ = 0;
function SetRotation() {
	
	rotate_degrees_ += 90;
	rotate_degrees_ = rotate_degrees_ % 360;
	
	var obj = document.getElementById("SmartPlayerActiveX");
	
	obj.NT_SetRotation(rotate_degrees_);
	
	var rotateText = document.getElementById("RotateBtn");
					
	if (0 == rotate_degrees_)
	{
		rotateText.innerHTML = "旋轉90度";
	}
	else if (90 == rotate_degrees_)
	{
		rotateText.innerHTML = "旋轉180度";
	}
	else if (180 == rotate_degrees_)
	{
		rotateText.innerHTML = "旋轉270度";
	}
	else if (270 == rotate_degrees_)
	{
		rotateText.innerHTML = "不旋轉";
	}
}

實時截圖調用示例:

function CaptureImage() {
	var obj = document.getElementById("SmartPlayerActiveX");

	obj.NT_CaptureImage();
}

全屏顯示窗口調用示例:

//全屏顯示窗口
function FullScreen() {
	var obj = document.getElementById("SmartPlayerActiveX");

	obj.NT_FullScreen();
}

相關資料和測試控件下載:

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

官網:http://www.nokunlock.com

QQ群:

RTSP直播推流SDK

技術特點和優勢:

  1. 全自研框架,易于擴展,自適應算法讓延遲更低、采集編碼傳輸效率更高;
  2. 所有功能以SDK接口形式提供,所有狀態,均有event回調,完美支持斷網自動重連;
  3. SDK模塊化,可和大牛直播播放器SDK組合實現流媒體數據轉發、內置輕量級RTSP服務、連麥、一對一互動等場景;
  4. Windows推送端SDK以層級模式提供,開發者可以自行組合數據源(如多攝像頭/屏幕/水印疊加);
  5. 支持外部YUV/RGB/H.264/AAC/SPEEX/PCMA/PCMU數據源接入;
  6. 所有參數均可通過SDK接口單獨設置,亦可通過默認參數,傻瓜式設置;
  7. RTMP推送、RTSP推送、錄像、內置輕量級RTSP服務模塊完全分離,可單獨使用亦可組合使用;
  8. 業內甚至很難找到效果接近的SDK

具體參見下圖“RTSP推流SDK”關聯部分:

???

功能支持:

如不單獨說明,系Windows、Android、iOS全平臺支持。

  • ?[視頻采集處理]Windows平臺涵蓋“Windows視頻采集處理SDK”功能;
  • ?[音頻采集處理]Windows平臺涵蓋“Windows音頻采集處理SDK”功能;
  • ?[本地預覽]Windows平臺支持攝像頭/屏幕/合成數據實時預覽功能,Android/iOS平臺支持本地前后置攝像頭預覽;
  • ?[攝像頭反轉/旋轉]Windows平臺支持攝像頭水平反轉、垂直反轉、0°/90°/180°/270°旋轉;
  • ?[攝像頭采集]除常規YUV格式外,Windows平臺還支持MJPEG格式的攝像頭采集;
  • ?[RTSP推流]超低延時的RTSP協議直播推流SDK;
  • ?[視頻格式]Windows/Android平臺支持H.264/H.265編碼(Android H.265硬編碼),iOS平臺支持H.264編碼;
  • ?[音頻格式]Windows/Android/iOS平臺支持AAC編碼;
  • ?[音量調節]Windows/Android平臺采集端支持實時音量調節(其中,Windows平臺混音模式下支持單獨控制麥克風、揚聲器音量);
  • ?[H.264硬編碼]Android/iOS平臺支持H.264硬編碼;
  • ?[H.265硬編碼]Android/iOS平臺支持H.265硬編碼;
  • ?[硬編碼自適應]Android/iOS平臺支持硬編碼自適應,如檢測到硬編碼不支持,自動切換到軟編(iOS如H.265硬編,先切換到H.264硬編碼,如不支持再嘗試H.264軟編);
  • ?[RTSP鑒權]支持RTSP鑒權推送;
  • ?[TCP/UDP模式]支持rtp over udp和rtp over tcp兩種傳輸方式;
  • ?[401事件處理]RTSP推送支持401事件上報;
  • ?[視頻格式]支持H.264/H.265(64位庫)編碼;
  • ?[音頻格式]支持AAC編碼;
  • ?[軟硬編碼參數配置]支持gop間隔、幀率、bit-rate設置;
  • ?[軟編碼參數配置]支持軟編碼profile、軟編碼速度、可變碼率設置;
  • ?[多實例推送]支持多實例推送(如同時推送屏幕/攝像頭和外部數據);
  • ?[多分辨率支持]支持攝像頭或屏幕多種分辨率設置;
  • ?[Windows推屏]Windows平臺支持屏幕裁剪、窗口采集、屏幕/攝像頭數據合成等多種模式推送;
  • ?[事件回調]支持各種狀態實時回調;
  • ?[水印]Windows平臺支持文字水印、png水印、實時遮擋,Android平臺支持文字水印、png水印;
  • ?[復雜網絡處理]支持斷網重連等各種網絡環境自動適配;
  • ?[動態碼率]支持根據網絡情況自動調整推流碼率;
  • ?[實時靜音]支持推送過程中,實時靜音/取消靜音;
  • ?[實時快照]支持推流過程中,實時快照;
  • ?[純音頻推流]支持僅采集音頻流并發起推流功能;
  • ?[純視頻推流]支持特殊場景下的純視頻推流功能;
  • ?[降噪]Windows/Android平臺支持降噪處理、自動增益、VAD檢測;
  • ?[回音消除]Android平臺支持實時傳遞遠端PCM數據,方便回音消除處理;
  • ?[外部編碼前視頻數據對接]支持YUV數據對接;
  • ?[外部編碼前音頻數據對接]支持PCM對接;
  • ?[外部編碼后視頻數據對接]支持外部H.264數據對接;
  • ?[外部編碼后音頻數據對接]外部AAC/PCMA/PCMU數據對接;
  • ?[推送端休眠設置]Windows平臺支持休眠接口(設置成休眠模式后CPU會適當降低);
  • ?[擴展錄像功能]完美支持和錄像SDK組合使用,錄像相關功能,可參見”Windows/Android/iOS錄像SDK“;
  • ?[服務器兼容]支持自建服務器(如Darwin Stream Server)。

對應Demo:

  • ?Windows測試程序:SmartPublisherDemo.exe;
  • ?Windows C++工程:WIN-PublisherSDK-CPP-Demo;
  • ?Android工程:SmartPublisherV2;
  • ?iOS工程:SmartiOSPublisherV2。

移動端使用說明不再贅述,點擊查看Windows使用說明

大牛直播RTMP播放器SDK

技術特點和優勢:

在沒測試過大牛直播SDK的RTMP播放器之前,你甚至不相信行業內,RTMP播放器延遲可以穩定的做到1秒以內。

無需贅述,全自研內核,行業內一致認可的跨平臺RTMP直播播放器SDK,功能齊全、高穩定、超低延遲、超低資源占用,超300家公司明智之選。

具體參見下圖“RTMP播放SDK”關聯部分:

功能支持:

如不單獨說明,系Windows、Android、iOS全平臺支持。

  • ?[支持播放協議]高穩定、超低延遲(一秒內,行業內幾無效果接近的播放端)、業內首屈一指的RTMP直播播放器SDK;
  • ?[多實例播放]支持多實例播放;
  • ?[事件回調]支持網絡狀態、buffer狀態等回調;
  • ?[音視頻加密]Windows平臺支持RTMP推送端加密(AES/SM4(國密))音視頻數據正常播放
  • ?[視頻格式]支持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數據回調;
  • ?[音視頻自適應]支持播放過程中,音視頻信息改變后自適應;
  • ?[擴展錄像功能]完美支持和錄像SDK組合使用(支持RTMP擴展H.265流錄制,支持PCMA/PCMU/Speex轉AAC后錄制,支持設置只錄制音頻或視頻),錄像相關功能,可參見”Windows/Android/iOS錄像SDK“。

對應Demo:

  • ?Windows測試程序:SmartPlayer.exe;
  • ?Windows C++工程:WIN-PlayerSDK-CPP-Demo;
  • ?Windows C#工程:WIN-PlayerSDK-CSharp-Demo;
  • ?Android工程:SmartPlayerV2;
  • ?iOS工程:SmartiOSPlayerV2。

Demo使用說明:

大牛直播sdk-windows-rtmp-rtsp-本地flv播放器使用說明

 

大牛直播RTSP播放器SDK

技術特點和優勢:

無需贅述,全自研內核,行業內一致認可的跨平臺RTSP直播播放器SDK,功能齊全、高穩定、超低延遲,超低資源占用,適用于安防、教育、單兵指揮等行業。

具體參見下圖“RTSP播放SDK”關聯部分:

?

功能支持:

如不單獨說明,系Windows、Android、iOS全平臺支持。

  • ?[支持播放協議]高穩定、超低延遲、業內首屈一指的RTSP直播播放器SDK;
  • ?[多實例播放]支持多實例播放;
  • ?[事件回調]支持網絡狀態、buffer狀態等回調;
  • ?[視頻格式]支持H.265、H.264,此外,還支持RTSP MJPEG播放;
  • ?[音頻格式]支持AAC/PCMA/PCMU;
  • ?[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模式硬解和普通模式硬解碼;
  • ?[RTSP模式設置]支持RTSP TCP/UDP模式設置;
  • ?[RTSP TCP/UDP自動切換]支持RTSP TCP、UDP模式自動切換;
  • ?[RTSP超時設置]支持RTSP超時時間設置,單位:秒;
  • ?[RTSP 401認證處理]支持上報RTSP 401事件,如URL攜帶鑒權信息,會自動處理;
  • ?[緩沖時間設置]支持buffer time設置;
  • ?[首屏秒開]支持首屏秒開模式;
  • ?[復雜網絡處理]支持斷網重連等各種網絡環境自動適配;
  • ?[快速切換URL]支持播放過程中,快速切換其他URL,內容切換更快;
  • ?[音視頻多種render機制]Android平臺,視頻:surfaceview/OpenGL ES,音頻:AudioTrack/OpenSL ES;
  • ?[實時靜音]支持播放過程中,實時靜音/取消靜音;
  • ?[實時快照]支持播放過程中截取當前播放畫面;
  • ?[只播關鍵幀]Windows平臺支持實時設置是否只播放關鍵幀;
  • ?[渲染角度]支持0°,90°,180°和270°四個視頻畫面渲染角度設置;
  • ?[渲染鏡像]支持水平反轉、垂直反轉模式設置;
  • ?[等比例縮放]支持圖像等比例縮放繪制;
  • ?[實時下載速度更新]支持當前下載速度實時回調(支持設置回調時間間隔);
  • ?[解碼前視頻數據回調]支持H.264/H.265數據回調;
  • ?[解碼后視頻數據回調]支持解碼后YUV/RGB數據回調;
  • ?[解碼前音頻數據回調]支持AAC/PCMA/PCMU數據回調;
  • ?[音視頻自適應]支持播放過程中,音視頻信息改變后自適應;
  • ?[擴展錄像功能]完美支持和錄像SDK組合使用(支持RTSP H.265流錄制,支持PCMA/PCMU轉AAC后錄制,支持設置只錄制音頻或視頻),錄像相關功能,可參見”Windows/Android/iOS錄像SDK“。

對應Demo:

  • ?Windows測試程序:SmartPlayer.exe;
  • ?Windows C++工程:WIN-PlayerSDK-CPP-Demo;
  • ?Windows C#工程:WIN-PlayerSDK-CSharp-Demo;
  • ?Android工程:SmartPlayerV2;
  • ?iOS工程:SmartiOSPlayerV2。

Demo使用說明

大牛直播sdk-windows-rtmp-rtsp-本地flv播放器使用說明

一對一互動SDK

大牛直播一對一互動SDK涵蓋Windows、Android和iOS平臺。

目前市面上大多一對一互動都是基于WebRTC,缺點如下:

  1. 服務器部署非常復雜,不利于私有部署,在一些私密性高的場景下,無法使用,如公安、市政等體系;
  2. 傳輸基于UDP,很難保證傳輸質量,由于UDP是不可靠的傳輸協議,在復雜的公網網絡環境下,各種突發流量、偶爾的傳輸錯誤、網絡抖動、超時等等都會引起丟包異常,都會在一定程度上影響音視頻通信的質量;
  3. 難以應對復雜的互聯網環境,如跨區跨運營商、低帶寬、高丟包等場景;
  4. 整個框架體系不夠靈活,代碼復雜度高,行話說的好:從demo到實用,中間還差1萬個WebRTC

RTMP/RTSP一對一互動SDK技術特點和優勢:

  • ?基于官方現有RTMP、RTSP推送、或內置RTSP服務、播放SDK,產品穩定度高,行業內首屈一指的超低延遲特性;
  • ?加入噪音抑制、回音消除、自動增益控制等特性,確保通話效果;
  • ?采用通用的RTMP和RTSP服務器,如nginx、SRS或 Darwin Stream Server(原生版本),更有利于私有部署;
  • ?支持H.264的擴展SEI消息發送機制;
  • ?支持H.265編碼(Windows 64位庫,Android/iOS硬編碼)和H.264可變碼率設定,換句話說,之前大牛直播SDK推送端支持的功能,都可以同步支持;
  • ?支持H.265解碼,直播播放器支持的功能,一對一互動模塊都可以有選擇的支持;
  • ?Windows平臺支持雙流合成大小屏錄制;
  • ?Windows支持攝像頭、屏幕合成、水印等各種組合模式,擴展度高;
  • ?適用于應急指揮、教育培訓等領域;
  • ?支持RTMP擴展AES/SM4加解密,確保音視頻數據安全性;

對應Demo:

  • 以C#為例,對應SmartEchoCancellation.exe(WIN-EchoCancellation-CSharp-Demo);
  • ?Android工程:SmartEchoCancellationV2;
  • ?iOS工程:SmartiOSEchoCancellation。

本地FLV播放SDK

大牛直播本地FLV播放SDK,目前覆蓋Windows平臺。

功能支持:

  1. 視頻:H.264;
  2. 音頻:AAC;
  3. 支持本地flv文件播放(支持獲取flv文件的duration(時長);
  4. 支持顯示當前播放位置;
  5. 支持開始播放或播放過程中seek(跳轉播放位置),也許是行業內seek最快的flv點播播放器);
  6. 可通過回調本地FLV音視頻數據幀,配合RTMP推送模塊,實現本地FLV文件的實時RTMP流轉發。

大牛直播SDK Demo展示

大牛直播SDK Demo頁面展示:

1. Windows RTMP直播推送SDK:

2. Windows轉發SDK:

3.Windows導播SDK:

4. Android RTMP直播推送SDK:

5. iOS RTMP直播推送:

6. Windows RTMP/RTSP直播播放SDK:

7. Android RTMP/RTSP直播播放SDK:

8. iOS RTMP/RTSP直播播放SDK:

9. Android播放、錄像、RTMP轉發-內置網關SDK(SmartRelayDemoV2)

音頻采集處理SDK

Windows音頻采集處理SDK

  1. 支持音頻源
  • ?支持Windows采集麥克風揚聲器和外部AAC, Speex WB, PCMA, PCMU數據接口輸入;
  1. 音頻合成
  • ?[音頻]支持揚聲器和麥克風音頻混音輸出(同時選擇“采集揚聲器”和“采集麥克風”);
  1. 音頻處理
  • ?支持音頻“端點檢測(VAD)”,自適應碼流,音頻碼流更節省;
  • ?支持回音消除功能;
  • ?支持噪音抑制功能;
  • ?支持自動增益控制。
  1. 對應Demo:
  • ?測試程序:SmartPublisherDemo.exe;
  • ?C++工程:WIN-PublisherSDK-CPP-Demo;
  • ?C#工程:WIN-PublisherSDK-CSharp-Demo。

大牛直播互動SDK

目前,大牛直播SDK支持Windows/android一對一互動。

其中,windows需要在推送端,開啟回音消除功能,移動端,參考?SmartEchoCancellationV2 工程。

互動SDK
功能 功能描述
標準功能 支持推送端常規功能
支持播放端常規功能
回音消除 支持回音消除
降噪 支持環境音、手機干擾等引起的噪音降噪處理、自動增益、VAD檢測

大牛直播SEI擴展數據發送/接收SDK

大牛直播SDK支持推送端通過H.264 SEI信息擴展,實時傳輸文本/二進制數據信息,播放端做相應解析和回顯。

適用場景:

1、公告廣播:推送將相對/絕對時間戳/時間/公告內容發到播放端,播放端實時接收消息并做相應的邏輯處理。

2、沖頂大會:推流端實時將題目分發到播放端,借助于大牛直播SDK低延遲特性,輕松實現“音-畫-題”同步接收;

3、直播:推流端將歌詞/字幕分發到播放端,播放端實時繪制出歌詞;

4、應急指揮/單兵:推送端將GIS信息/現場采集到的數據實時寫入并分發到播放端;

5、在線教育:推流端將激光筆涂鴉操作分發到播放端,播放端實時劃圈劃線,實現特定特效。

目前Windows/Android/iOS平臺推送和播放端均已支持,效果如下:

http://daniulive.gz.bcebos.com/SEI_send_recv.png

 

大牛直播SDK-Windows RTMP/RTSP/本地FLV播放器使用說明

大牛直播播放器SDK相對推送SDK來說,接口沒有那么多,不過客戶95%以上的常規需求均已覆蓋,目前支持RTMP和RTSP直播播放(涵蓋H.265),還有本地flv文件回放。

大牛直播SDK播放端提供C++/C#兩套接口,并支持IE瀏覽器OCX控件調用,對外提供32/64位debug/release庫。

對應Demo:

  • ?Windows測試程序:SmartPlayer.exe;
  • ?Windows C++工程:WIN-PlayerSDK-CPP-Demo;
  • ?Windows C#工程:WIN-PlayerSDK-CSharp-Demo;

如何使用

RTMP/RTSP/本地FLV播放

根據提示,在RTMP/RTSP URL或FLV文件處,輸入需要播放的url,如“rtmp://live.hkstv.hk.lxdns.com/live/hks1”;

設置緩沖(buffer time)

播放RTMP/RTSP流之前,可以設置緩沖時間(單位:毫秒),SDK支持0~10000ms區間設置;

RTMP秒開

如果給出的rtmp url服務器緩存GOP,選中秒開模式,大牛直播SDK可以快速播放rtmp,實現秒開效果;

RTSP相關設置

點擊頁面“Rtsp設置”按鈕,可以設置RTSP timeout時間、默認TCP還是UDP模式、是否TCP-UDP模式自動切換。

RTMP解密播放

SetUrl之前,設置解密的Key和IV解密向量即可。

FLV本地文件播放

根據提示,在RTMP/RTSP URL或FLV文件處,輸入整體的flv文件全路徑,如“E:\daniulivetestflv.flv”,SDK會獲取到FLV文件的時長(Duration)和當前播放位置。

FLV文件seek

在“設置位置(秒)”處輸入需要跳轉的秒數,設置后,可直接跳轉到指定位置,并從flv制定位置開始播放;

FLV文件暫停

點擊“暫停”按鈕,即可暫停播放本地flv文件,如需回復播放,點擊“恢復”按鈕即可;

RTMP/RTSP/FLV文件播放實時靜音

播放過程中,可選擇實時靜音/取消靜音;

RTMP/RTSP/FLV文件播放實時快照

點擊“設置截圖路徑”,播放過程中,點擊“截圖”按鈕,即可完成快照保存;

RTMP/RTSP/FLV文件實時錄像

點擊“錄像配置”,設置錄像路徑,播放或非播放狀態下,點擊“錄像”,可拉取rtmp或rtsp流錄制本地文件,如需截取flv文件一部分,亦可通過開始錄像/停止錄像重新錄制mp4文件。

RTMP/RTSP/FLV文件切換地址

在url輸入框輸入新的播放地址,點擊“切換地址”按鈕,SDK快速跳轉到指定地址,此功能如android/iOS播放端,用于快速切換URL,適用于多路URL輪詢;

RTMP/RTSP/FLV文件播放過程中旋轉view

不是所有的url播放角度都朝觀眾預期的方向,如需view旋轉,用戶可點擊旋轉按鈕,我們的SDK將會對view進行 0° 90° 180° 270°旋轉、除此之外,還可以進行水平反轉、垂直反轉;

播放過程中全屏

Windows C++ Demo雙擊播放畫面或點擊“全屏”按鈕,進入全屏模式,再次雙擊,退出全屏。

IE瀏覽器OCX控件調用說明

點我查看OCX控件使用說明和SDK集成文檔

大牛直播SDK功能支持列表

windows屏幕截取/攝像頭推送錄像

  1. 視頻源相關:
  • ?[屏幕/攝像頭]支持幀率、關鍵幀間隔、碼率、編碼profile、編碼速度等設置;
  • ?[屏幕]支持屏幕裁剪,根據幀率和推送分辨率,自動推薦碼流;
  • ?[攝像頭]支持攝像頭選擇、分辨率設置、幀率設置;
  • ?[擴展數據]支持外部H.264接口輸入;
  1. 音頻源相關
  • ?[音頻]采集麥克風;
  • ?[音頻]采集揚聲器;
  • ?[擴展數據]AAC, Speex WB, PCMA, PCMU數據接口輸入;
  1. 攝像頭和屏幕合成
  • ?[攝像頭和屏幕實時切換]支持推送過程中,攝像頭和屏幕互相切換,單畫面顯示攝像頭或屏幕;
  • ?[攝像頭疊加到屏幕] 支持攝像頭按照設置坐標,疊加到屏幕指定位置,并支持實時關閉疊加層;
  • ?[屏幕疊加到攝像頭] 支持屏幕按照設定坐標,疊加到攝像頭指定位置,并支持實時關閉疊加層;
  1. 水印和透明度遮擋
  • ?[實時水印]支持動態水印設置,完美支持文字水印、實時時間水印和圖片水印
  • ?[透明度]可以設置透明度處理(設置遮蓋);
  1. 音頻合成
  • ?[音頻]支持揚聲器和麥克風音頻混音輸出(同時選擇“采集揚聲器”和“采集麥克風”);
  1. 音頻處理
  • ?[音頻]支持音頻“端點檢測(VAD)”,自適應碼流,音頻碼流更節省;
  • ?[音頻]支持回音消除功能(一對一功能:可通過在兩臺windows機器同時開啟daniulive的推送和播放端demo,相互推送播放測試);
  • ?[音頻]支持噪音抑制功能;
  • ?[音頻]支持自動增益控制;
  1. 音視頻推送類型選擇
  • ?[視頻]支持推送H.264;
  • ?[音頻]支持推送AAC;
  • ?[音頻]支持推送Speex;
  • ?[音頻]支持推送PCMA/PCMU;
  1. 音視頻類型、靜音、快照、錄像等
  • ?[音視頻]支持純音頻、純視頻、音視頻推送;
  • ?[音頻]推送過程中實時靜音/取消靜音;
  • ?[對接服務器]完美支持自建服務器或CDN;
  • ?[錄像]錄像和推送完全分離,完美支持“邊推送邊錄像”、“先推送、后錄像”、“先錄像,后推送;
  • ?[錄像]支持設置錄像文件前綴、錄像文件大小,錄像文件增加日期、時間;
  • ?[快照]支持推送或錄像過程中,隨時快照

Windows導播平臺或多路合成、混音推流/錄像

對應“SmartMixStreamDemo.exe”

  • ?支持“windows屏幕截取/攝像頭推送錄像”模塊所有功能;
  • ?支持拉取rtmp流;
  • ?支持拉取rtsp流;
  • ?支持本地采集到屏幕或攝像頭數據,和遠程拉取得rtmp或rtsp流做合成、混音輸出;
  • ?支持導播過程中,隨時切斷某一路音視頻或音頻;
  • ?支持rtsp數據轉rtmp推送出去;
  • ?音頻混音同時選擇“采集麥克風”+“采集揚聲器”。

windows/iOS拉流轉發模塊

對應“SmartStreamRelayDemo.exe”

  • ?[拉流]支持拉取rtsp流;
  • ?[拉流]支持拉取rtmp流;
  • ?[預覽]支持拉取到的rtsp/rtmp隨時本地預覽、關閉預覽;
  • ?[拉流音頻調節]支持拉取的rtsp/rtmp流靜音;
  • ?[url切換]支持轉發過程中,拉取的rtsp/rtmp或本地flv文件實時內容切換
  • ?[轉發]超低延遲轉發拉取的rtsp/rtmp流到rtmp server。

android推流/iOS推流

  • ?多分辨率選擇;
  • ?支持橫豎屏推送;
  • ?音視頻推送、純音頻推送、純視頻推送;
  • ?支持邊采集、邊錄像
  • ?支持rtmp推送 live|record模式設置;
  • ?真正靠譜的錄像、推流分離模式,支持推流過程中隨時開啟錄像,錄像過程中,隨時推流;
  • ?支持本地錄像文件回放、處理;
  • ?采集過程中,前后攝像頭切換;
  • ?提供編碼前(YUV/RGB)、編碼后音視頻(H.264/AAC)接口對接,方便AR/VR設備調用。
  • ?android/iOS自帶美顏功能;
  • ?android完美支持文字水印、實時時間水印和圖片水印
  • ?支持推送端實時靜音/取消靜音
  • ?支持軟硬編碼自適應;
  • ?android支持后臺service推送攝像頭或屏幕(推送屏幕需要5.0+版本);
  • ?iOS支持后臺推送屏幕(基于ReplayKit,需要iOS 10.0+版本);
  • ?android支持實時傳遞遠端PCM數據;
  • ?支持gop間隔、幀率、bierate、android編碼profile和編碼速度設置;
  • ?支持推送端鏡像設置;
  • ?[音頻]android支持噪音抑制功能;
  • ?[音頻]android支持自動增益控制;
  • ?[音頻]android支持Speex推送;
  • ?[音頻]android支持Speex編碼質量設置;
  • ?[快照]支持推送或錄像過程中,隨時快照;
  • ?iOS支持裁剪模式設置;
  • ?完美支持各個廠家CDN。

windows播放器/android播放器/iOS播放器

  • ?超低延遲的rtmp播放器;
  • ?超低延遲的rtsp播放器;
  • ?完美支持多實例播放(同時播放多路stream,可同時支持rtmp、rtsp stream播放);
  • ?支持RTSP TCP/UDP模式切換;
  • ?支持播放端,buffer設置;
  • ?支持秒開模式;
  • ?windows雙擊畫面進入全屏模式;
  • ?audio支持aac/speex/g.711;
  • ?windows/iOS播放端sdk支持回調編碼過的音視頻數據(Video:H.264/YUV Audio:aac/speex/pcma/pcmu)到上層;
  • ?android播放端sdk支持回調編碼過的音視頻數據(Video:YUV/RGB Audio:pcma/pcmu)到上層;
  • ?支持自定義播放布局;
  • ?音視頻多種render機制;
  • ?支持播放過程中,’實時靜音/取消靜音’;
  • ?支持播放段視頻view實時旋轉(0° 90° 180° 270°);
  • ?支持播放url快速切換,同等配置的流,切換url依舊可以錄制到同一個文件
  • ?android/iOS支持軟硬解碼,業內真正靠譜的超低延遲、低資源占用播放rtsp/rtmp 1080p+;
  • ?[快照]支持播放/錄像過程中,隨時快照
  • ?[windows點播播放器]支持本地flv文件播放(支持獲取flv文件的duration(時長);支持顯示當前播放位置;支持開始播放或播放過程中seek(跳轉播放位置),也許是行業內seek最快的flv點播播放器。)
  • ?支持針對類似于娃娃機直播方案的超低延遲模式設置(公網200~400ms)。
污污直播app-污污直播破解版永久免费版