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群:

如何對RTSP播放器做功能和性能評估

好多開發者在做產品競品分析的時候,不知道如何界定一個RTSP播放器,大牛直播SDK認為,一個RTSP播放器,不是說有幾個類似于Open/Close接口就夠了,好的RTSP播放器需要具備以下功能和性能屬性:

1. 低延遲:大多數RTSP的播放都面向直播場景,所以,如果延遲過大,比如監控行業,小偷都走了,客戶端才看到,或者別人已經按過門鈴幾秒,主人才看到圖像,嚴重影響體驗,所以,低延遲是衡量一個好的RTSP播放器非常重要的指標,目前大牛直播SDK的RTSP播放延遲控制在幾百毫秒,VLC在幾秒,這個延遲,是長時間的低延遲,比如運行1天、一周、一個月甚至更久;

2. 音視頻同步或跳轉:有些開發者為了追求低延遲體驗,甚至不做音視頻同步,拿到audio video直接播放,導致a/v不同步,還有就是時間戳亂跳;

3. 支持多實例:一個好的播放器,需要支持同時播放多路音視頻數據,比如4-8-9-16-32窗口;

4. 支持buffer time設置:在一些有網絡抖動的場景,播放器需要支持精準的buffer time設置,一般來說,以毫秒計;

5. H.265的播放和錄制:除了H.264,還需要支持H.265,目前市面上的RTSP H.265攝像頭越來越多,支持H.265的RTSP播放器迫在眉睫,此外,單純的播放H.265還不夠,還需要可以能把H.265的數據能錄制下來;

6. TCP/UDP模式切換:考慮到好多服務器僅支持TCP或UDP模式,一個好的RTSP播放器需要支持TCP/UDP模式自動切換;

7. 靜音支持:比如,多窗口播放RTSP流,如果每個audio都播放出來,體驗非常不好,所以實時靜音功能非常必要;

8. 視頻view旋轉:好多攝像頭由于安裝限制,導致圖像倒置,所以一個好的RTSP播放器應該支持如視頻view實時旋轉(0° 90° 180° 270°)、水平反轉、垂直反轉;

9. 支持解碼后audio/video數據輸出(可選):大牛直播SDK接觸到好多開發者,希望能在播放的同時,獲取到YUV或RGB數據,進行人臉匹配等算法分析,所以音視頻回調可選;

10. 快照:感興趣或重要的畫面,實時截取下來非常必要;

11. 網絡抖動處理(如斷網重連):基本功能,不再贅述;

12. 跨平臺:一個好的播放器,跨平臺(Windows/Android/iOS)很有必要,起碼為了后續擴展性考慮,開發的時候,有這方面的考慮,目前大牛直播SDK的RTSP播放器,完美支持以上平臺;

13. 長期運行穩定性:提到穩定性,好多開發者不以為然,實際上,一個好的產品,穩定是最基本的前提,不容忽視!
14. 可以錄像:播放的過程中,隨時錄制下來感興趣的視頻片斷,存檔或其他二次處理;

15. log信息記錄:整體流程機制實時反饋,不多打log,但是不能一些重要的log,如播放過程中出錯等;

16. download速度實時反饋:可以看到實時下載速度反饋,以此來監聽網絡狀態;

17. 異常狀態處理:如播放的過程中,斷網、網絡抖動、來電話、切后臺后返回等各種場景的處理。

說了這么多,有開發者會反問,大牛直播SDK到底支持了哪些?以下做個簡單功能概述,如不單獨說明,系Windows、Android、iOS全平臺支持:

  • ?[支持播放協議]高穩定、超低延遲、業內首屈一指的RTSP直播播放器SDK;
  • ?[多實例播放]支持多實例播放;
  • ?[事件回調]支持網絡狀態、buffer狀態等回調;
  • ?[視頻格式]支持H.265、H.264,此外,Windows/Android平臺還支持RTSP MJPEG播放;
  • ?[音頻格式]支持AAC/PCMA/PCMU;
  • ?[H.264/H.265軟解碼]支持H.264/H.265軟解;
  • ?[H.264硬解碼]Android/iOS支持H.264硬解;
  • ?[H.265硬解]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;
  • ?[實時靜音]支持播放過程中,實時靜音/取消靜音;
  • ?[實時快照]支持播放過程中截取當前播放畫面;
  • ?[渲染角度]支持0°,90°,180°和270°四個視頻畫面渲染角度設置;
  • ?[渲染鏡像]支持水平反轉、垂直反轉模式設置;
  • ?[實時下載速度更新]支持當前下載速度實時回調(支持設置回調時間間隔);
  • ?[解碼前視頻數據回調]支持H.264/H.265數據回調;
  • ?[解碼后視頻數據回調]支持解碼后YUV/RGB數據回調;
  • ?[解碼前音頻數據回調]支持AAC/PCMA/PCMU/SPEEX數據回調;
  • ?[音視頻自適應]支持播放過程中,音視頻信息改變后自適應;
  • ?[擴展錄像功能]完美支持和錄像SDK組合使用(支持RTSP H.265流錄制,支持PCMA/PCMU轉AAC后錄制,支持設置只錄制音頻或視頻)。

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

基于AES加密的RTSP/RTMP多路轉發設計方案

很多開發者最近咨詢我們,除了我們Windows推送端采集編碼的音視頻數據可以加密外,其他RTSP/RTMP流如果想更安全的轉推到RTMP服務器或相應CDN改怎么辦?

實際上,我們在做RTMP整體加密方案的時候已經考慮到這種情況,SmartStreamRelayDemo在拉取RTSP或RTMP流,轉推RTMP的時候,可以選擇加密視頻,加密音頻或音視頻都加密,廢話不多說,參看代碼:

bool nt_stream_relay_wrapper::StartPush(const std::string& url)
{
    if ( is_pushing_ )
        return false;

    if ( url.empty() )
        return false;

    if ( !OpenPushHandle() )
        return false;

    auto push_handle = GetPushHandle();
    ASSERT(push_handle != nullptr);

    ASSERT(push_api_ != NULL);
    if ( NT_ERC_OK != push_api_->SetURL(push_handle, url.c_str(), NULL) )
    {
        if ( !is_started_rtsp_stream_ )
        {
            push_api_->Close(push_handle);
            SetPushHandle(nullptr);
        }

        return false;
    }

    // 加密測試 +++

    push_api_->SetRtmpEncryptionOption(push_handle, url.c_str(), 1, 1);

    NT_BYTE test_key[16] = {'1', '2', '3'};

    push_api_->SetRtmpEncryptionKey(push_handle, url.c_str(), test_key, 16);

    // 加密測試 --

    if ( NT_ERC_OK != push_api_->StartPublisher(push_handle, NULL) )
    {
        if ( !is_started_rtsp_stream_ )
        {
            push_api_->Close(push_handle);
            SetPushHandle(nullptr);
        }

        return false;
    }


    // // test push rtsp ++

    // push_api_->SetPushRtspTransportProtocol(push_handle, 1);
    // // push_api_->SetPushRtspTransportProtocol(push_handle, 2);

    // push_api_->SetPushRtspURL(push_handle, "rtsp://player.daniulive.com:554/liverelay111.sdp");

    // push_api_->StartPushRtsp(push_handle, 0);

    // // test push rtsp--

    is_pushing_ = true;

    return true;
}

上圖:

relay

這個時候,輸入轉發設置的Key(支持aes 128, aes 192, aes 256加密,即將發布SM4加密),方可正常播放音視頻數據。

此種方案的優勢在于基于AES音視頻逐幀數據加密音視頻數據,第三方即便是破解了URL,也沒法播放,通過抓包工具抓取到數據,也沒法正常顯示。

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

Flutter下實現低延遲的跨平臺RTSP/RTMP播放

為什么要用Flutter?

Flutter是谷歌的移動UI框架,可以快速在iOS和Android上構建高質量的原生用戶界面。 Flutter可以與現有的代碼一起工作。在全世界,Flutter正在被越來越多的開發者和組織使用,并且Flutter是完全免費、開源的。

Flutter有哪些與眾不同

image

1. Beautiful – Flutter 允許你控制屏幕上的每一寸像素,這讓「設計」不用再對「實現」妥協;

2. Fast – 一個應用不卡頓的標準是什么,你可能會說 16ms 抑或是 60fps,這對桌面端應用或者移動端應用來說已足夠,但當面對廣闊的 AR/VR 領域,60fps 仍然會成為使人腦產生眩暈的瓶頸,而 Flutter 的目標遠不止 60fps;借助 Dart 支持的 AOT 編譯以及 Skia 的繪制,Flutter 可以運行的很快;

3. Productive – 前端開發可能已經習慣的開發中 hot reload 模式,但這一特性在移動開發中還算是個新鮮事。Flutter 提供有狀態的 hot reload 開發模式,并允許一套 codebase 運行于多端;其他的,再比如開發采用 JIT 編譯與發布的 AOT 編譯,都使得開發者在開發應用時可以更加高效;

4. Open – Dart / Skia / Flutter (Framework),這些都是開源的,Flutter 與 Dart 團隊也對包括 Web 在內的多種技術持開放態度,只要是優秀的他們都愿意借鑒吸收。而在生態建設上,Flutter 回應 GitHub Issue 的速度更是讓人驚嘆,因為是真的快(closed 狀態的 issue 平均解決時間為 0.29天);

除了支持APICloud, Unity3d, React Native外,大牛直播SDK為什么要做Flutter下的RTSP/RTMP播放器

首先,Flutter則是依靠Flutter Engine虛擬機在iOS和Android上運行,開發人員可以通過Flutter框架和API在內部進行交互。Flutter Engine使用C/C++編寫,具有低延遲輸入和高幀速率的特點,不像Unity3d一樣,我們是回調YUV/RGB數據,在Unity3d里面繪制,Flutter直接調用native SDK,效率更高。

其次,客戶和開發者驅動,Flutter發展至今,目前還沒有個像樣的RTSP或RTMP播放器,一個播放器,不是說,有個界面,有個開始、停止按鈕就可以了,一個好用的直播播放器,對功能和性能屬性要求很高,特別是穩定性和低延遲這塊,不謙虛的說,可能是首款功能強大、真正好用的Flutter RTSP/RTMP直播播放SDK

以大牛直播SDK的播放器為例:

RTMP直播播放器功能介紹:

  • [支持播放協議]高穩定、超低延遲(一秒內,行業內幾無效果接近的播放端)、業內首屈一指的RTMP直播播放器SDK;
  • [多實例播放]支持多實例播放;
  • [事件回調]支持網絡狀態、buffer狀態等回調;
  • [視頻格式]支持RTMP擴展H.265,H.264;
  • [音頻格式]支持AAC/PCMA/PCMU/Speex;
  • [H.264/H.265軟解碼]支持H.264/H.265軟解;
  • [H.264硬解碼]Android/iOS支持H.264硬解;
  • [H.265硬解]Android/iOS支持H.265硬解;
  • [H.264/H.265硬解碼]Android支持設置Surface模式硬解和普通模式硬解碼;
  • [緩沖時間設置]支持buffer time設置;
  • [首屏秒開]支持首屏秒開模式;
  • [低延遲模式]支持類似于線上娃娃機等直播方案的超低延遲模式設置(公網200~400ms);
  • [復雜網絡處理]支持斷網重連等各種網絡環境自動適配;
  • [快速切換URL]支持播放過程中,快速切換其他URL,內容切換更快;
  • [音視頻多種render機制]Android平臺,視頻:surfaceview/OpenGL ES,音頻:AudioTrack/OpenSL ES;
  • [實時靜音]支持播放過程中,實時靜音/取消靜音;
  • [實時快照]支持播放過程中截取當前播放畫面;
  • [渲染角度]支持0°,90°,180°和270°四個視頻畫面渲染角度設置;
  • [渲染鏡像]支持水平反轉、垂直反轉模式設置;
  • [實時下載速度更新]支持當前下載速度實時回調(支持設置回調時間間隔);
  • [解碼前視頻數據回調]支持H.264/H.265數據回調;
  • [解碼后視頻數據回調]支持解碼后YUV/RGB數據回調;
  • [解碼前音頻數據回調]支持AAC/PCMA/PCMU/SPEEX數據回調;
  • [音視頻自適應]支持播放過程中,音視頻信息改變后自適應;
  • [擴展錄像功能]完美支持和錄像SDK組合使用(支持RTMP擴展H.265流錄制,支持PCMA/PCMU/Speex轉AAC后錄制,支持設置只錄制音頻或視頻)

RTSP直播播放器功能介紹:

  • [支持播放協議]高穩定、超低延遲、業內首屈一指的RTSP直播播放器SDK;
  • [多實例播放]支持多實例播放;
  • [事件回調]支持網絡狀態、buffer狀態等回調;
  • [視頻格式]支持H.265、H.264,此外,Windows/Android平臺還支持RTSP MJPEG播放;
  • [音頻格式]支持AAC/PCMA/PCMU;
  • [H.264/H.265軟解碼]支持H.264/H.265軟解;
  • [H.264硬解碼]Android/iOS支持H.264硬解;
  • [H.265硬解]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;
  • [實時靜音]支持播放過程中,實時靜音/取消靜音;
  • [實時快照]支持播放過程中截取當前播放畫面;
  • [渲染角度]支持0°,90°,180°和270°四個視頻畫面渲染角度設置;
  • [渲染鏡像]支持水平反轉、垂直反轉模式設置;
  • [實時下載速度更新]支持當前下載速度實時回調(支持設置回調時間間隔);
  • [解碼前視頻數據回調]支持H.264/H.265數據回調;
  • [解碼后視頻數據回調]支持解碼后YUV/RGB數據回調;
  • [解碼前音頻數據回調]支持AAC/PCMA/PCMU/SPEEX數據回調;
  • [音視頻自適應]支持播放過程中,音視頻信息改變后自適應;
  • [擴展錄像功能]完美支持和錄像SDK組合使用(支持RTSP H.265流錄制,支持PCMA/PCMU轉AAC后錄制,支持設置只錄制音頻或視頻)

Android和iOS手機上RTSP/RTMP播放效果:

1. 視頻播放效果:

http://www.iqiyi.com/w_19s8dv6yht.html

2. 界面截圖:

image

上接口:

//
//  smartplayer.dart
//  smartplayer
//
//  GitHub: https://github.com/daniulive/SmarterStreaming
//  website: http://www.nokunlock.com
//
//  Created by daniulive on 2019/02/25.
//  Copyright ? 2014~2019 daniulive. All rights reserved.
//

import 'dart:async';
import 'dart:convert';

import 'package:flutter/services.dart';

class EVENTID {
  static const EVENT_DANIULIVE_COMMON_SDK = 0x00000000;
  static const EVENT_DANIULIVE_PLAYER_SDK = 0x01000000;
  static const EVENT_DANIULIVE_PUBLISHER_SDK = 0x02000000;

  static const EVENT_DANIULIVE_ERC_PLAYER_STARTED =
      EVENT_DANIULIVE_PLAYER_SDK | 0x1;
  static const EVENT_DANIULIVE_ERC_PLAYER_CONNECTING =
      EVENT_DANIULIVE_PLAYER_SDK | 0x2;
  static const EVENT_DANIULIVE_ERC_PLAYER_CONNECTION_FAILED =
      EVENT_DANIULIVE_PLAYER_SDK | 0x3;
  static const EVENT_DANIULIVE_ERC_PLAYER_CONNECTED =
      EVENT_DANIULIVE_PLAYER_SDK | 0x4;
  static const EVENT_DANIULIVE_ERC_PLAYER_DISCONNECTED =
      EVENT_DANIULIVE_PLAYER_SDK | 0x5;
  static const EVENT_DANIULIVE_ERC_PLAYER_STOP =
      EVENT_DANIULIVE_PLAYER_SDK | 0x6;
  static const EVENT_DANIULIVE_ERC_PLAYER_RESOLUTION_INFO =
      EVENT_DANIULIVE_PLAYER_SDK | 0x7;
  static const EVENT_DANIULIVE_ERC_PLAYER_NO_MEDIADATA_RECEIVED =
      EVENT_DANIULIVE_PLAYER_SDK | 0x8;
  static const EVENT_DANIULIVE_ERC_PLAYER_SWITCH_URL =
      EVENT_DANIULIVE_PLAYER_SDK | 0x9;
  static const EVENT_DANIULIVE_ERC_PLAYER_CAPTURE_IMAGE =
      EVENT_DANIULIVE_PLAYER_SDK | 0xA;

  static const EVENT_DANIULIVE_ERC_PLAYER_RECORDER_START_NEW_FILE =
      EVENT_DANIULIVE_PLAYER_SDK | 0x21; /*錄像寫入新文件*/
  static const EVENT_DANIULIVE_ERC_PLAYER_ONE_RECORDER_FILE_FINISHED =
      EVENT_DANIULIVE_PLAYER_SDK | 0x22; /*一個錄像文件完成*/

  static const EVENT_DANIULIVE_ERC_PLAYER_START_BUFFERING =
      EVENT_DANIULIVE_PLAYER_SDK | 0x81;
  static const EVENT_DANIULIVE_ERC_PLAYER_BUFFERING =
      EVENT_DANIULIVE_PLAYER_SDK | 0x82;
  static const EVENT_DANIULIVE_ERC_PLAYER_STOP_BUFFERING =
      EVENT_DANIULIVE_PLAYER_SDK | 0x83;

  static const EVENT_DANIULIVE_ERC_PLAYER_DOWNLOAD_SPEED =
      EVENT_DANIULIVE_PLAYER_SDK | 0x91;
}

typedef SmartEventCallback = void Function(int, String, String, String);

class SmartPlayerController {
  MethodChannel _channel;
  EventChannel _eventChannel;
  SmartEventCallback _eventCallback;

  void init(int id) {
    _channel = MethodChannel('smartplayer_plugin_$id');
    _eventChannel = EventChannel('smartplayer_event_$id');
    _eventChannel.receiveBroadcastStream().listen(_onEvent, onError: _onError);
  }

  void setEventCallback(SmartEventCallback callback) {
    _eventCallback = callback;
  }

  void _onEvent(Object event) {
    if (event != null) {
      Map valueMap = json.decode(event);
      String param = valueMap['param'];
      onSmartEvent(param);
    }
  }

  void _onError(Object error) {
    // print('error:'+ error);
  }

  Future<dynamic> _smartPlayerCall(String funcName) async {
    var ret = await _channel.invokeMethod(funcName);
    return ret;
  }

  Future<dynamic> _smartPlayerCallInt(String funcName, int param) async {
    var ret = await _channel.invokeMethod(funcName, {
      'intParam': param,
    });
    return ret;
  }

  Future<dynamic> _smartPlayerCallIntInt(
      String funcName, int param1, int param2) async {
    var ret = await _channel.invokeMethod(funcName, {
      'intParam': param1,
      'intParam2': param2,
    });
    return ret;
  }

  Future<dynamic> _smartPlayerCallString(String funcName, String param) async {
    var ret = await _channel.invokeMethod(funcName, {
      'strParam': param,
    });
    return ret;
  }

  /// 設置解碼方式 false 軟解碼 true 硬解碼 默認為false
  /// </summary>
  /// <param name="isHwDecoder"></param>
  Future<dynamic> setVideoDecoderMode(int isHwDecoder) async {
    return _smartPlayerCallInt('setVideoDecoderMode', isHwDecoder);
  }

  /// <summary>
  /// 設置音頻輸出模式: if 0: 自動選擇; if with 1: audiotrack模式, 此接口僅限于Android平臺使用
  /// </summary>
  /// <param name="use_audiotrack"></param>
  Future<dynamic> setAudioOutputType(int useAudiotrack) async {
    return _smartPlayerCallInt('setAudioOutputType', useAudiotrack);
  }

  /// <summary>
  /// 設置播放端緩存大小, 默認200毫秒
  /// </summary>
  /// <param name="buffer"></param>
  Future<dynamic> setBuffer(int buffer) async {
    return _smartPlayerCallInt('setBuffer', buffer);
  }

  /// <summary>
  /// 接口可實時調用:設置是否實時靜音,1:靜音; 0: 取消靜音
  /// </summary>
  /// <param name="is_mute"></param>
  Future<dynamic> setMute(int isMute) async {
    return _smartPlayerCallInt('setMute', isMute);
  }

  /// <summary>
  /// 設置RTSP TCP模式, 1: TCP; 0: UDP
  /// </summary>
  /// <param name="is_using_tcp"></param>
  Future<dynamic> setRTSPTcpMode(int isUsingTcp) async {
    return _smartPlayerCallInt('setRTSPTcpMode', isUsingTcp);
  }

  /// <summary>
  /// 設置RTSP超時時間, timeout單位為秒,必須大于0
  /// </summary>
  /// <param name="timeout"></param>
  Future<dynamic> setRTSPTimeout(int timeout) async {
    return _smartPlayerCallInt('setRTSPTimeout', timeout);
  }

  /// <summary>
  /// 設置RTSP TCP/UDP自動切換
  /// 對于RTSP來說,有些可能支持rtp over udp方式,有些可能支持使用rtp over tcp方式.
  /// 為了方便使用,有些場景下可以開啟自動嘗試切換開關, 打開后如果udp無法播放,sdk會自動嘗試tcp, 如果tcp方式播放不了,sdk會自動嘗試udp.
  /// </summary>
  /// <param name="is_auto_switch_tcp_udp"></param>
  Future<dynamic> setRTSPAutoSwitchTcpUdp(int is_auto_switch_tcp_udp) async {
    return _smartPlayerCallInt('setRTSPAutoSwitchTcpUdp', is_auto_switch_tcp_udp);
  }

  /// <summary>
  /// 設置快速啟動該模式,
  /// </summary>
  /// <param name="is_fast_startup"></param>
  Future<dynamic> setFastStartup(int isFastStartup) async {
    return _smartPlayerCallInt('setFastStartup', isFastStartup);
  }

  /// <summary>
  /// 設置超低延遲模式 false不開啟 true開啟 默認false
  /// </summary>
  /// <param name="mode"></param>
  Future<dynamic> setPlayerLowLatencyMode(int mode) async {
    return _smartPlayerCallInt('setPlayerLowLatencyMode', mode);
  }

  /// <summary>
  /// 設置視頻垂直反轉
  /// </summary>
  /// <param name="is_flip"></param>
  Future<dynamic> setFlipVertical(int is_flip) async {
    return _smartPlayerCallInt('setFlipVertical', is_flip);
  }

  /// <summary>
  /// 設置視頻水平反轉
  /// </summary>
  /// <param name="is_flip"></param>
  Future<dynamic> setFlipHorizontal(int is_flip) async {
    return _smartPlayerCallInt('setFlipHorizontal', is_flip);
  }

  /// <summary>
  /// 設置順時針旋轉, 注意除了0度之外, 其他角度都會額外消耗性能
  /// degress: 當前支持 0度,90度, 180度, 270度 旋轉
  /// </summary>
  /// <param name="degress"></param>
  Future<dynamic> setRotation(int degress) async {
    return _smartPlayerCallInt('setRotation', degress);
  }

  /// <summary>
  /// 設置是否回調下載速度
  /// is_report: if 1: 上報下載速度, 0: 不上報.
  /// report_interval: 上報間隔,以秒為單位,>0.
  /// </summary>
  /// <param name="is_report"></param>
  /// <param name="report_interval"></param>
  Future<dynamic> setReportDownloadSpeed(
      int isReport, int reportInterval) async {
    return _smartPlayerCallIntInt(
        'setReportDownloadSpeed', isReport, reportInterval);
  }

  /// <summary>
  /// Set playback orientation(設置播放方向),此接口僅適用于Android平臺
  /// </summary>
  /// <param name="surOrg"></param>
  /// surOrg: current orientation,  PORTRAIT 1, LANDSCAPE with 2
  Future<dynamic> setOrientation(int surOrg) async {
    return _smartPlayerCallInt('setOrientation', surOrg);
  }

  /// <summary>
  /// 設置是否需要在播放或錄像過程中快照
  /// </summary>
  /// <param name="is_save_image"></param>
  Future<dynamic> setSaveImageFlag(int isSaveImage) async {
    return _smartPlayerCallInt('setSaveImageFlag', isSaveImage);
  }

  /// <summary>
  /// 播放或錄像過程中快照
  /// </summary>
  /// <param name="imageName"></param>
  Future<dynamic> saveCurImage(String imageName) async {
    return _smartPlayerCallString('saveCurImage', imageName);
  }

  /// <summary>
  /// 播放或錄像過程中,快速切換url
  /// </summary>
  /// <param name="uri"></param>
  Future<dynamic> switchPlaybackUrl(String uri) async {
    return _smartPlayerCallString('switchPlaybackUrl', uri);
  }

  /// <summary>
  /// 創建錄像存儲路徑
  /// </summary>
  /// <param name="path"></param>
  Future<dynamic> createFileDirectory(String path) async {
    return _smartPlayerCallString('createFileDirectory', path);
  }

  /// <summary>
  /// 設置錄像存儲路徑
  /// </summary>
  /// <param name="path"></param>
  Future<dynamic> setRecorderDirectory(String path) async {
    return _smartPlayerCallString('setRecorderDirectory', path);
  }

  /// <summary>
  /// 設置單個錄像文件大小
  /// </summary>
  /// <param name="size"></param>
  Future<dynamic> setRecorderFileMaxSize(int size) async {
    return _smartPlayerCallInt('setRecorderFileMaxSize', size);
  }

  /// <summary>
  /// 設置錄像時音頻轉AAC編碼的開關
  /// aac比較通用,sdk增加其他音頻編碼(比如speex, pcmu, pcma等)轉aac的功能.
  /// </summary>
  /// <param name="is_transcode"></param>
  /// is_transcode: 設置為1的話,如果音頻編碼不是aac,則轉成aac,如果是aac,則不做轉換. 設置為0的話,則不做任何轉換. 默認是0.
  Future<dynamic> setRecorderAudioTranscodeAAC(int is_transcode) async {
    return _smartPlayerCallInt('setRecorderAudioTranscodeAAC', is_transcode);
  }

  /// <summary>
  /// 設置播放路徑
  /// </summary>
  Future<dynamic> setUrl(String url) async {
    return _smartPlayerCallString('setUrl', url);
  }

  /// <summary>
  /// 開始播放
  /// </summary>
  Future<dynamic> startPlay() async {
    return _smartPlayerCall('startPlay');
  }

  /// <summary>
  /// 停止播放
  /// </summary>
  Future<dynamic> stopPlay() async {
    return _smartPlayerCall('stopPlay');
  }

  /// <summary>
  /// 開始錄像
  /// </summary>
  Future<dynamic> startRecorder() async {
    return _smartPlayerCall('startRecorder');
  }

  /// <summary>
  /// 停止錄像
  /// </summary>
  Future<dynamic> stopRecorder() async {
    return _smartPlayerCall('stopRecorder');
  }

  /// <summary>
  /// 關閉播放
  /// </summary>
  Future<dynamic> dispose() async {
    return await _channel.invokeMethod('dispose');
  }

  void onSmartEvent(String param) {
    if (!param.contains(",")) {
      print("[onNTSmartEvent] android傳遞參數錯誤");
      return;
    }

    List<String> strs = param.split(',');

    String code = strs[1];
    String param1 = strs[2];
    String param2 = strs[3];
    String param3 = strs[4];
    String param4 = strs[5];

    int evCode = int.parse(code);

    var p1, p2, p3;
    switch (evCode) {
      case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_STARTED:
        print("開始。。");
        break;
      case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_CONNECTING:
        print("連接中。。");
        break;
      case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_CONNECTION_FAILED:
        print("連接失敗。。");
        break;
      case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_CONNECTED:
        print("連接成功。。");
        break;
      case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_DISCONNECTED:
        print("連接斷開。。");
        break;
      case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_STOP:
        print("停止播放。。");
        break;
      case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_RESOLUTION_INFO:
        print("分辨率信息: width: " + param1 + ", height: " + param2);
        p1 = param1;
        p2 = param2;
        break;
      case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_NO_MEDIADATA_RECEIVED:
        print("收不到媒體數據,可能是url錯誤。。");
        break;
      case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_SWITCH_URL:
        print("切換播放URL。。");
        break;

      case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_CAPTURE_IMAGE:
        print("快照: " + param1 + " 路徑:" + param3);

        if (int.parse(param1) == 0) {
           print("截取快照成功。.");
        } else {
           print("截取快照失敗。.");
        }
        p1 = param1;
        p2 = param3;
        break;

      case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_RECORDER_START_NEW_FILE:
        print("[record]開始一個新的錄像文件 : " + param3);
        p3 = param3;
        break;
      case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_ONE_RECORDER_FILE_FINISHED:
        print("[record]已生成一個錄像文件 : " + param3);
        p3 = param3;
        break;

      case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_START_BUFFERING:
        print("Start_Buffering");
        break;

      case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_BUFFERING:
        print("Buffering: " + param1 + "%");
        p1 = param1;
        break;

      case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_STOP_BUFFERING:
        print("Stop_Buffering");
        break;

      case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_DOWNLOAD_SPEED:
         print("download_speed:" + (double.parse(param1) * 8 / 1000).toStringAsFixed(0) + "kbps" + ", " + (double.parse(param1) / 1024).toStringAsFixed(0) + "KB/s");
        p1 = param1;
        break;
    }
    if (_eventCallback != null) {
      _eventCallback(evCode, p1, p2, p3);
    }
  }
}

image.gif

調用實例:

//
//  main.dart
//  main
//
//  GitHub: https://github.com/daniulive/SmarterStreaming
//  website: http://www.nokunlock.com
//
//  Created by daniulive on 2019/02/25.
//  Copyright ? 2014~2019 daniulive. All rights reserved.
//

import 'dart:io';
import 'package:flutter/services.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:smartplayer_native_view/smartplayer.dart';
import 'package:smartplayer_native_view/smartplayer_plugin.dart';

void main() {
  ///
  /// 強制豎屏
  ///
  SystemChrome.setPreferredOrientations(
      [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);

  runApp(new MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => new _MyAppState();
}

class _MyAppState extends State<MyApp> {
  SmartPlayerController player;
  double aspectRatio = 4.0 / 3.0;

  //輸入需要播放的RTMP/RTSP url
  TextEditingController playback_url_controller_ = TextEditingController();

  //Event事件回調顯示
  TextEditingController event_controller_ = TextEditingController();

  bool is_playing_ = false;
  bool is_mute_ = false;

  var rotate_degrees_ = 0;

  Widget smartPlayerView() {
      return SmartPlayerWidget(
        onSmartPlayerCreated: onSmartPlayerCreated,
      );
    }

  @override
  void initState() {
     print("initState called..");
    super.initState();
  }

  @override
  void didChangeDependencies() {
    print('didChangeDependencies called..');
    super.didChangeDependencies();
  }

  @override
  void deactivate() {
    print('deactivate called..');
    super.deactivate();
  }

  @override
  void dispose() {
    print("dispose called..");
    player.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
          appBar: AppBar(
            title: const Text('Flutter SmartPlayer Demo'),
          ),
          body: new SingleChildScrollView(
            child: new Column(
              children: <Widget>[
                new Container(
                  color: Colors.black,
                  child: AspectRatio(
                    child: smartPlayerView(),
                    aspectRatio: aspectRatio,
                  ),
                ),
                new TextField(
                  controller: playback_url_controller_,
                  keyboardType: TextInputType.text,
                  decoration: InputDecoration(
                    contentPadding: EdgeInsets.all(10.0),
                    icon: Icon(Icons.link),
                    labelText: '請輸入RTSP/RTMP url',
                  ),
                  autofocus: false,
                ),
                new Row(
                  children: [
                    new RaisedButton(
                        onPressed: this.onSmartPlayerStartPlay,
                        child: new Text("開始播放")),
                    new Container(width: 20),
                    new RaisedButton(
                        onPressed: this.onSmartPlayerStopPlay,
                        child: new Text("停止播放")),
                    new Container(width: 20),
                    new RaisedButton(
                        onPressed: this.onSmartPlayerMute,
                        child: new Text("實時靜音")),
                  ],
                ),
                new Row(
                  children: [
                    new RaisedButton(
                        onPressed: this.onSmartPlayerSwitchUrl,
                        child: new Text("實時切換URL")),
                    new Container(width: 20),
                    new RaisedButton(
                        onPressed: this.onSmartPlayerSetRotation,
                        child: new Text("實時旋轉View")),
                  ],
                ),
                new TextField(
                  controller: event_controller_,
                  keyboardType: TextInputType.text,
                  decoration: InputDecoration(
                    contentPadding: EdgeInsets.all(10.0),
                    icon: Icon(Icons.event_note),
                    labelText: 'Event狀態回調',
                  ),
                  autofocus: false,
                ),
              ],
            ),
          )),
    );
  }

  void _eventCallback(int code, String param1, String param2, String param3) {
    String event_str;

    switch (code) {
      case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_STARTED:
        event_str = "開始..";
        break;
      case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_CONNECTING:
        event_str = "連接中..";
        break;
      case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_CONNECTION_FAILED:
        event_str = "連接失敗..";
        break;
      case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_CONNECTED:
        event_str = "連接成功..";
        break;
      case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_DISCONNECTED:
        event_str = "連接斷開..";
        break;
      case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_STOP:
        event_str = "停止播放..";
        break;
      case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_RESOLUTION_INFO:
        event_str = "分辨率信息: width: " + param1 + ", height: " + param2;
        setState(() {
          aspectRatio = double.parse(param1) / double.parse(param2);
          print('change aspectRatio:$aspectRatio');
        });
        break;
      case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_NO_MEDIADATA_RECEIVED:
        event_str = "收不到媒體數據,可能是url錯誤..";
        break;
      case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_SWITCH_URL:
        event_str = "切換播放URL..";
        break;
      case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_CAPTURE_IMAGE:
        event_str = "快照: " + param1 + " 路徑: " + param3;

        if (int.parse(param1) == 0) {
          print("截取快照成功。.");
        } else {
          print("截取快照失敗。.");
        }
        break;
      case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_RECORDER_START_NEW_FILE:
        event_str = "[record] new file: " + param3;
        break;
      case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_ONE_RECORDER_FILE_FINISHED:
        event_str = "[record] record finished: " + param3;
        break;
      case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_START_BUFFERING:
        //event_str = "Start Buffering";
        break;
      case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_BUFFERING:
        event_str = "Buffering: " + param1 + "%";
        break;
      case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_STOP_BUFFERING:
        //event_str = "Stop Buffering";
        break;
      case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_DOWNLOAD_SPEED:
        event_str = "download_speed:" +
            (double.parse(param1) * 8 / 1000).toStringAsFixed(0) +
            "kbps" +
            ", " +
            (double.parse(param1) / 1024).toStringAsFixed(0) +
            "KB/s";
        break;
    }

    event_controller_.text = event_str;
  }

  void onSmartPlayerCreated(SmartPlayerController controller) async {
    player = controller;
    player.setEventCallback(_eventCallback);

    var ret = -1;

    //設置video decoder模式
    var is_video_hw_decoder = 0;
    if (defaultTargetPlatform == TargetPlatform.android)
    {
      ret = await player.setVideoDecoderMode(is_video_hw_decoder);
    }
    else if(defaultTargetPlatform == TargetPlatform.iOS)
    {
      is_video_hw_decoder = 1;
      ret = await player.setVideoDecoderMode(is_video_hw_decoder);
    }

    //設置緩沖時間
    var play_buffer = 100;
    ret = await player.setBuffer(play_buffer);

    //設置快速啟動
    var is_fast_startup = 1;
    ret = await player.setFastStartup(is_fast_startup);

    //是否開啟低延遲模式
    var is_low_latency_mode = 0;
    ret = await player.setPlayerLowLatencyMode(is_low_latency_mode);

    //set report download speed(默認5秒一次回調 用戶可自行調整report間隔)
    ret = await player.setReportDownloadSpeed(1, 2);

    //設置RTSP超時時間
        var rtsp_timeout = 10;
      ret = await player.setRTSPTimeout(rtsp_timeout);

    var is_auto_switch_tcp_udp = 1;
        ret = await player.setRTSPAutoSwitchTcpUdp(is_auto_switch_tcp_udp);

    // 設置RTSP TCP模式
        //ret = await player.setRTSPTcpMode(1);

    //第一次啟動 為方便測試 設置個初始url
    playback_url_controller_.text = "rtmp://live.hkstv.hk.lxdns.com/live/hks2";
  }

  Future<void> onSmartPlayerStartPlay() async {
    var ret = -1;

    if (playback_url_controller_.text.length < 8) {
      playback_url_controller_.text =
          "rtmp://live.hkstv.hk.lxdns.com/live/hks1"; //給個初始url
    }

    //實時靜音設置 
    ret = await player.setMute(is_mute_ ? 1 : 0);

    if (!is_playing_) {
      ret = await player.setUrl(playback_url_controller_.text);
      ret = await player.startPlay();

      if (ret == 0) {
        is_playing_ = true;
      }
    }
  }

  Future<void> onSmartPlayerStopPlay() async {
    if (is_playing_) {
      await player.stopPlay();
      playback_url_controller_.clear();
      is_playing_ = false;
      is_mute_ = false;
    }
  }

  Future<void> onSmartPlayerMute() async {
    if (is_playing_) {
      is_mute_ = !is_mute_;
      await player.setMute(is_mute_ ? 1 : 0);
    }
  }

  Future<void> onSmartPlayerSwitchUrl() async {
    if (is_playing_) {
      if (playback_url_controller_.text.length < 8) {
        playback_url_controller_.text =
            "rtmp://live.hkstv.hk.lxdns.com/live/hks1";
      }

      await player.switchPlaybackUrl(playback_url_controller_.text);
    }
  }

  Future<void> onSmartPlayerSetRotation() async {
    if (is_playing_) {
      rotate_degrees_ += 90;
      rotate_degrees_ = rotate_degrees_ % 360;

      if (0 == rotate_degrees_) {
        print("旋轉90度");
      } else if (90 == rotate_degrees_) {
        print("旋轉180度");
      } else if (180 == rotate_degrees_) {
        print("旋轉270度");
      } else if (270 == rotate_degrees_) {
        print("不旋轉");
      }

      await player.setRotation(rotate_degrees_);
    }
  }
}

image.gif

經測試,Flutter環境下,RTMP和RTSP播放,擁有Native SDK一樣優異的播放體驗。

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

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

5張圖看懂如何實現Windows RTMP實時導播功能

一直以來,好多開發者苦于如何實現RTMP導播數據源實時切換,以下是大牛直播SDK導播切換說明,支持只切換數據源模式,或音視頻混音合成輸出模式:

數據源:

1. rtmp/rtsp音視頻流;

2. 本地屏幕/攝像頭/音頻數據;

3.本地flv文件。

輸出:

1. 多路流合成一路流后,推送到RTMP服務器;

2. 多路合成后的流,支持本地錄像、快照。

使用說明:

無視頻合成/音頻混音模式:

1. 打開SmartStreamRelayDemo.exe,輸入一路RTMP或RTSP流,在拉流地址輸入需要轉推的RTMP的url,如“rtmp://player.daniulive.com:1935/hls/stream666”,先點擊“拉流”,再點擊“推流”按鈕,如需本地預覽,可以點擊“預覽”按鈕。

打開SmartPlayer.exe,輸入剛剛設置的RTMP url:rtmp://player.daniulive.com:1935/hls/stream666,點擊“播放”即可。

如下圖所示:

?2. 切換一路RTMP數據源,輸入新的RTMP地址,點擊“切換拉流地址”即可:

?

3. 切換一路RTSP數據源,輸入新的RTSP地址,點擊“切換拉流地址”即可:

?

視頻合成/音頻混音模式:

1. 合流界面:

?

2. 播放輸出界面:

?

細心的你會發現,三路流分辨率和協議封裝不同,不過依然可自動切換,從而實現播放端觀眾無感知的導播體驗。

技術優勢:

1. 以SDK形式輸出,企業或開發者可根據需求完成多樣化的產品需求;

2. 行業內接口更靈活,資源占用更低;

3. 超低延遲輸出,效率更高;

4. 支持合流后的圖像預覽;

5. 支持合流后的音頻混音;

6. 支持導播過程中,隨時切斷某一路音視頻或音頻;

7. 豈止是合流,還可以實時錄像、快照等,接口更豐富。

相關資料和測試程序下載:

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

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

如何在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)RTMP推送-RTSP/RTMP直播SDK

視沃科技-大牛直播SDK?daniulive.com

始于2014年,國內外為數不多致力于極致體驗的超強全自研跨平臺(windows/android/iOS)流媒體內核,通過模塊化自由組合,支持實時RTMP推流、RTMP/RTSP直播播放(支持RTSP/RTMP H.265)、實時錄像、多路流媒體轉發、音視頻導播、動態視頻合成、音頻混音、互動直播、內置輕量級RTSP服務等,比快更快,業界真正靠譜的超低延遲直播SDK(1秒內,低延遲模式下200~400ms)。

適用于在線教育、無紙化推屏/會議、智慧教室、直播答題、智能可視門禁對講、智慧安防、智能家居、物聯網、智能車載、傳統硬件領域、超低延遲娃娃機抓取播放方案、媒體移動直播、應急指揮調度(針對保險、城管、交警、消防、公安等職能管理部門的單兵應急執法系統)、可視化購物、遠程專家診斷、可視化巡檢、(如電信/電力線路/鐵路沿線/水利設施/油田/消防設施巡檢)、移動視頻安防監控,企業內訓、金融在線直播室、微信直播、監控對接、活動現場直播、游戲直播、秀場直播等場景。

latest release note

除此之外,大牛直播SDK播放端,支持APICloudReact Native二次封裝,并且全平臺支持Unity3D平臺,也可能是Unity3D平臺下首款真正高穩定、超低延遲的rtmp/rtsp直播播放器。

android/iOS播放器SDK(V2)APICloud調用說明

windows/android/iOS播放器SDK(V2)Unity3D調用說明(更新于2018/10/31)

大牛直播SDK基于unity3d平臺的rtmp/rtsp直播播放端SDK視頻演示

Unity3D-Windows播放端APP下載(更新于2018/09/04)

Unity3D-Android播放端APK下載(更新于2018/10/24)

Windows端

  • ?RTMP直播推流SDK?rtmp推送SDK(支持同時推多路url,支持RTMP擴展H.265推送(64位庫));
  • ?RTMP/RTSP直播播放器SDK?業內首屈一指的rtmp/rtsp超低延遲直播播放器SDK(支持RTMP H.265擴展播放);
  • ?Unity3D RTMP/RTSP直播播放器SDK?業內首家Windows支持Unity3D的超低延遲RTMP/RTSP直播播放器SDK,支持快照、錄像、實時靜音、view旋轉、快速切換URL等特性;
  • ?RTMP/RTSP多路流媒體轉RTMP推送SDK?支持同時多路拉取rtmp/rtsp流/本地flv文件,并分別轉發到服務器,支持轉發過程中,拉取的rtsp/rtmp或本地flv文件實時內容切換,業內為數不多支持RTSP/RTMP H.265拉流轉發的SDK(提供配套RTMP擴展H.265服務器);
  • ?輕量級RTSP服務SDK?為滿足內網無紙化/電子教室等內網超低延遲需求,避免讓用戶配置單獨的服務器,大牛直播SDK在推送端支持輕量級RTSP服務SDK,推送端SDK支持的功能,內置輕量級RTSP服務SDK后,功能繼續支持,windows端64位庫支持RTSP H.265視頻輸出;
  • ?內網RTSP網關SDK?內網RTSP網關SDK,系內置輕量級RTSP服務SDK擴展,完成外部RTSP/RTMP數據拉取并注入到輕量級RTSP服務SDK工作,多個內網客戶端直接訪問內網輕量級RTSP服務獲取公網數據,無需部署單獨的服務器,支持RTSP/RTMP H.265數據接入;
  • ?導播SDK?數據源:1. rtmp/rtsp音視頻流;2. 本地屏幕/攝像頭/音頻數據;3.本地flv文件;多路流合成一路實時導播推送;
  • ?錄像SDK?支持拉取rtmp/rtsp流實時錄像模塊/實時快照功能,支持純音頻、純視頻、音視頻錄制模式,支持音頻(PCMU/PCMA,Speex等)轉AAC后再錄像,業內為數不多的支持RTSP/RTMP H.265錄制到MP4文件的錄像SDK;
  • ?[互動SDK] Windows一對一互動(可windows與windows/android互動);
  • ?連麥SDK?以標準協議為基礎,完美支持Windows連麥;
  • ?[點播播放器SDK] 支持本地flv文件播放(支持獲取flv文件的duration(時長);支持顯示當前播放位置;支持開始播放或播放過程中seek(跳轉播放位置),也許是行業內seek最快的flv點播播放器);
  • ?SEI擴展數據發送/接收SDK?支持推送端通過H.264 SEI信息擴展,實時傳輸文本/二進制數據信息(如實時字幕/時間戳/題目分發/公告廣播等),播放端做相應解析和回顯;
  • ?視頻處理SDK?屏幕/多攝像頭/水印/遮擋區域多層自由合成模塊;
  • ?音頻處理SDK?多路混音、回音消除、噪音抑制、自動增益、VAD檢測模塊;

Android端

  • ?RTMP直播推流端SDK?Android屏幕、攝像頭RTMP推流SDK;
  • ?RTMP/RTSP直播播放器SDK?業內首屈一指的rtmp/rtsp超低延遲直播播放器SDK(支持RTMP H.265擴展播放);
  • ?Unity3D RTMP/RTSP直播播放器SDK?業內首家Android支持Unity3D的超低延遲RTMP/RTSP直播播放器SDK,支持快照、錄像、實時靜音、view旋轉、快速切換URL等特性;
  • ?錄像SDK?支持拉取rtmp/rtsp流實時錄像模塊/實時快照功能,支持純音頻、純視頻、音視頻錄制模式,支持音頻(PCMU/PCMA,Speex等)轉AAC后再錄像,業內為數不多的支持RTSP/RTMP H.265錄制到MP4文件的錄像SDK;
  • ?RTMP/RTSP多路流媒體轉RTMP推送SDK?支持實時拉取的rtmp/rtsp流轉發到指定rtmp url;
  • ?輕量級RTSP服務SDK?為滿足內網無紙化/電子教室等內網超低延遲需求,避免讓用戶配置單獨的服務器,大牛直播SDK在推送端支持輕量級RTSP服務SDK,推送端SDK支持的功能,內置輕量級RTSP服務SDK后,功能繼續支持;
  • ?[互動SDK] Android一對一互動(可android與windows/android/iOS互動);
  • ?SEI擴展數據發送/接收SDK?支持推送端通過H.264 SEI信息擴展,實時傳輸文本/二進制數據信息(如實時字幕/時間戳/題目分發/公告廣播等),播放端做相應解析和回顯;
  • ?視頻處理SDKAndroid文字水印、png圖片水印;
  • ?音頻處理SDKAndroid回音消除、噪音抑制、自動增益、VAD檢測模塊;

iOS端

  • ?RTMP直播推流端SDK?iOS屏幕(基于ReplayKit)、攝像頭RTMP推流SDK;
  • ?RTMP/RTSP直播播放器SDK?業內首屈一指的rtmp/rtsp超低延遲直播播放器SDK(支持RTMP H.265擴展播放);
  • ?Unity3D RTMP/RTSP直播播放器SDK?業內首家iOS支持Unity3D的超低延遲RTMP/RTSP直播播放器SDK,支持快照、錄像、實時靜音、view旋轉、快速切換URL等特性;
  • ?錄像SDK?支持拉取rtmp/rtsp流實時錄像模塊/實時快照功能,支持純音頻、純視頻、音視頻錄制模式,支持音頻(PCMU/PCMA,Speex等)轉AAC后再錄像,業內為數不多的支持RTSP/RTMP H.265錄制到MP4文件的錄像SDK;
  • ?RTMP/RTSP多路流媒體轉RTMP推送SDK?支持實時拉取的rtmp/rtsp流轉發到指定rtmp url;
  • ?輕量級RTSP服務SDK?為滿足內網無紙化/電子教室等內網超低延遲需求,避免讓用戶配置單獨的服務器,大牛直播SDK在推送端支持輕量級RTSP服務SDK,推送端SDK支持的功能,內置輕量級RTSP服務SDK后,功能繼續支持;
  • ?SEI擴展數據發送/接收SDK?支持推送端通過H.264 SEI信息擴展,實時傳輸文本/二進制數據信息(如實時字幕/時間戳/題目分發/公告廣播等),播放端做相應解析和回顯;

本地下載

很多開發者反應,由于項目龐大,github下載整個工程很慢,我們已經把相關demo文件和使用說明,全部上傳到QQ群共享:

或者直接從私有服務器下載(Windows提供C#/C++ demo, android提供android studio demo,iOS提供xcode demo):

大牛直播SDK相關demo本地下載

NOTE:?Windows平臺,以C++ SDK Demo為最新,C# Demo更新速度稍滯于C++ Demo。

大牛直播SDK集成和調用說明

大牛直播SDK Demo使用說明

上層源碼目錄

  1. android推流 SmartPublisherV2https://github.com/daniulive/SmarterStreaming/tree/master/SourceCode/AndroidStudio/SmartPublisherV2
  2. android推流 SmartServicePublisherV2(后臺service推送屏幕)https://github.com/daniulive/SmarterStreaming/tree/master/SourceCode/AndroidStudio/SmartServicePublisherV2
  3. android推流 SmartServiceCameraPublisherV2(后臺service推送攝像頭)https://github.com/daniulive/SmarterStreaming/tree/master/SourceCode/AndroidStudio/SmartServiceCameraPublisherV2
  4. android一對一回音消除 SmartEchoCancellationV2https://github.com/daniulive/SmarterStreaming/tree/master/SourceCode/AndroidStudio/SmartEchoCancellationV2
  5. android播放器 SmartPlayerV2:https://github.com/daniulive/SmarterStreaming/tree/master/SourceCode/AndroidStudio/SmartPlayerV2
  6. android轉發-錄像-播放三合一 SmartRelayDemoV2:https://github.com/daniulive/SmarterStreaming/tree/master/SourceCode/AndroidStudio/SmartRelayDemoV2
  7. iOS推流 SmartiOSPublisherV2:https://github.com/daniulive/SmarterStreaming/tree/master/SourceCode/IOS/SmartiOSPublisherV2
  8. iOS后臺推屏 SmartiOSScreenPublisherV2:https://github.com/daniulive/SmarterStreaming/tree/master/SourceCode/IOS/SmartiOSScreenPublisherV2
  9. iOS播放器 SmartiOSPlayerV2:https://github.com/daniulive/SmarterStreaming/tree/master/SourceCode/IOS/SmartiOSPlayerV2
  10. iOS轉發-錄像-播放三合一 SmartiOSRelayDemoV2:https://github.com/daniulive/SmarterStreaming/tree/master/SourceCode/IOS/SmartiOSRelayDemoV2

功能支持


1. Windows視頻采集處理SDK

  1. 支持視頻源
  • ?支持Windows屏幕采集、屏幕裁剪特定窗口采集、攝像頭采集、擴展外部H.264數據對接;
  1. 攝像頭和屏幕合成
  • ?[攝像頭和屏幕實時切換]支持推送過程中,攝像頭和屏幕互相切換,單畫面顯示攝像頭或屏幕;
  • ?[攝像頭疊加到屏幕] 支持攝像頭按照設置坐標,疊加到屏幕指定位置,并支持實時關閉疊加層;
  • ?[屏幕疊加到攝像頭] 支持屏幕按照設定坐標,疊加到攝像頭指定位置,并支持實時關閉疊加層;
  1. 水印和透明度遮擋
  • ?[實時水印]支持動態水印設置,完美支持文字水印、實時時間水印和圖片水印
  • ?[透明度]可以設置透明度處理(設置遮蓋);
  1. 對應Demo:
  • ?測試程序:SmartPublisherDemo.exe;
  • ?C++工程:WIN-PublisherSDK-CPP-Demo;
  • ?C#工程:WIN-PublisherSDK-CSharp-Demo。

2. 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。

3. Windows/Android/iOS RTMP直播推流SDK

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

  • ?[視頻采集處理]Windows平臺涵蓋“Windows視頻采集處理SDK”功能;
  • ?[音頻采集處理]Windows平臺涵蓋“Windows音頻采集處理SDK”功能;
  • ?[本地預覽]Windows平臺支持攝像頭/屏幕/合成數據實時預覽功能,Android/iOS平臺支持本地前后置攝像頭預覽;
  • ?[攝像頭反轉/旋轉]Windows平臺支持攝像頭水平反轉、垂直反轉、0°/90°/180°/270°旋轉;
  • ?[RTMP推流]超低延時的RTMP協議直播推流SDK(Windows支持RTMP擴展H.265推送);
  • ?[視頻格式]Windows平臺支持H.264/H.265編碼,Android/iOS平臺支持H.264編碼;
  • ?[音頻格式]Windows/Android/iOS平臺支持AAC編碼,Windows/Android平臺支持Speex編碼;
  • ?[音頻編碼]Windows/Android平臺支持Speex推送、Speex編碼質量設置;
  • ?[H.264硬編碼]Android/iOS支持H.264硬編碼;
  • ?[硬編碼碼自適應]Android/iOS平臺支持硬編碼自適應,如檢測到硬編碼不支持,自動切換到軟編;
  • ?[編碼參數配置]支持gop間隔、幀率、bit-rate、軟編碼profile、軟編碼速度設置;
  • ?[多實例推送]支持多實例推送(如同時推送屏幕/攝像頭和外部數據);
  • ?[RTMP擴展H.265]Windows推送SDK支持RTMP擴展H.265推送,針對攝像頭采集編碼,使用H.265可變碼率,帶寬大幅節省,效果直逼傳統H.265編碼攝像頭;
  • ?[橫豎屏推流]Android/iOS平臺支持支持橫屏、豎屏推流;
  • ?[多分辨率支持]支持攝像頭或屏幕多種分辨率設置;
  • ?[Windows推屏]支持屏幕裁剪、窗口采集、屏幕/攝像頭數據合成等多種模式推送;
  • ?[移動端推屏]Android平臺支持后臺service推送攝像頭或屏幕(推送屏幕需要5.0+版本);
  • ?[移動端推屏]iOS平臺支持后臺推送屏幕(基于ReplayKit,需要iOS 10.0+版本);
  • ?[事件回調]支持各種狀態實時回調;
  • ?[水印]Windows平臺支持文字水印、png水印、實時遮擋,Android平臺支持文字水印、png水印;
  • ?[RTMP推送模式]支持RTMP推送 live|record模式設置(需服務器支持);
  • ?[鏡像]Android/iOS平臺支持前置攝像頭實時鏡像功能;
  • ?[前后攝像頭實時切換]Android/iOS平臺支持采集過程中,前后攝像頭切換;
  • ?[復雜網絡處理]支持斷網重連等各種網絡環境自動適配;
  • ?[動態碼率]支持根據網絡情況自動調整推流碼率;
  • ?[實時靜音]支持推送過程中,實時靜音/取消靜音;
  • ?[實時快照]支持推流過程中,實時快照;
  • ?[純音頻推流]支持僅采集音頻流并發起推流功能;
  • ?[純視頻推流]支持特殊場景下的純視頻推流功能;
  • ?[降噪]Windows/Android平臺支持環境音、手機干擾等引起的噪音降噪處理、自動增益、VAD檢測;
  • ?[回音消除]android支持實時傳遞遠端PCM數據,方便回音消除處理;
  • ?[外部編碼前視頻數據對接]支持YUV數據對接;
  • ?[外部編碼前音頻數據對接]支持PCM對接;
  • ?[外部編碼后視頻數據對接]支持外部H.264數據對接;
  • ?[外部編碼后音頻數據對接]外部AAC/PCMA/PCMU/SPEEX數據對接;
  • ?[編碼后數據輸出]Android平臺支持輸出編碼后的H264/AAC數據到上層,方便對接第三方平臺(如GB28181)對接(接口說明和demo請點擊以下鏈接);
  • ?[擴展錄像功能]完美支持和錄像SDK組合使用,錄像相關功能,可參見”8. Windows/Android/iOS錄像SDK“;
  • ?[基礎美顏]iOS平臺自帶基礎美顏功能;
  • ?[裁剪模式]Android/iOS平臺支持特定分辨率攝像頭裁剪模式設置;
  • ?[服務器兼容]支持支持自建服務器(如Nginx、SRS)或CDN。

對應Demo:

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

4. Windows/Android/iOS RTMP、RTSP直播播放器SDK

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

  • ?[支持播放協議]高穩定、超低延遲(一秒內,行業內幾無效果接近的播放端)、業內首屈一指的RTMP/RTSP直播播放器SDK;
  • ?[多實例播放]支持多實例播放(如同時播放多路RTMP/RTSP流);
  • ?[事件回調]支持網絡狀態、buffer狀態等回調;
  • ?[視頻格式]支持RTSP H.265、RTMP擴展H.265,RTSP/RTMP H.264;
  • ?[音頻格式]RTMP/RTSP支持AAC/PCMA/PCMU,此外RTMP還支持Speex;
  • ?[H.264/H.265軟解碼]支持H.264/H.265軟解;
  • ?[H.264硬解碼]Android/iOS支持H.264硬解;
  • ?[H.265硬解]Android支持H.265硬解;
  • ?[H.264/H.265硬解碼]Android支持設置Surface模式硬解和普通模式硬解碼;
  • ?[硬解碼自適應]Android/iOS平臺支持硬解碼碼自適應,如檢測到硬解碼不支持,自動切換到軟解;
  • ?[RTSP模式設置]支持RTSP TCP/UDP模式設置;
  • ?[RTSP TCP/UDP自動切換]支持RTSP TCP、UDP模式自動切換;
  • ?[RTSP超時設置]支持RTSP超時時間設置,單位:秒;
  • ?[RTSP 401認證處理]支持上報RTSP 401事件,如URL攜帶鑒權信息,會自動處理;
  • ?[緩沖時間設置]支持buffer time設置;
  • ?[首屏秒開]支持首屏秒開模式;
  • ?[低延遲模式]支持類似于線上娃娃機等直播方案的超低延遲模式設置(公網200~400ms);
  • ?[復雜網絡處理]支持斷網重連等各種網絡環境自動適配;
  • ?[快速切換URL]支持播放過程中,快速切換其他URL,內容切換更快;
  • ?[音視頻多種render機制]Android平臺,視頻:surfaceview/OpenGL ES,音頻:AudioTrack/OpenSL ES;
  • ?[實時靜音]支持播放過程中,實時靜音/取消靜音;
  • ?[實時快照]支持播放過程中截取當前播放畫面;
  • ?[渲染角度]支持0°,90°,180°和270°四個視頻畫面渲染角度設置;
  • ?[渲染鏡像]支持水平反轉、垂直反轉模式設置;
  • ?[實時下載速度更新]支持當前下載速度實時回調(支持設置回調時間間隔);
  • ?[解碼前視頻數據回調]支持H.264/H.265數據回調;
  • ?[解碼后視頻數據回調]支持解碼后YUV/RGB數據回調;
  • ?[解碼前音頻數據回調]支持AAC/PCMA/PCMU/SPEEX數據回調;
  • ?[音視頻自適應]支持播放過程中,音視頻信息改變后自適應;
  • ?[擴展錄像功能]完美支持和錄像SDK組合使用,錄像相關功能,可參見”8. Windows/Android/iOS錄像SDK“;
  • ?[全屏]Windows平臺雙擊畫面進入全屏模式;
  • ?[Windows本地FLV播放器]支持本地FLV文件播放(支持獲取FLV文件的duration(時長);支持顯示當前播放位置;
  • ?[Windows本地FLV播放器]支持開始播放或播放過程中seek(跳轉播放位置),也許是行業內seek最快的flv點播播放器)。

對應Demo:

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

5. Windows/Android/iOS內置輕量級RTSP服務SDK

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

  • ?[基礎功能]支持Windows/Android/iOS平臺RTMP直播SDK除推送RTMP外的所有常規功能;
  • ?[音頻格式]AAC;
  • ?[視頻格式]H.264、H.265;
  • ?[協議類型]RTSP;
  • ?[端口設置]支持RTSP端口設置;
  • ?[鑒權設置]支持RTSP鑒權用戶名、密碼設置;
  • ?[獲取session連接數]支持獲取當前RTSP服務會話連接數;
  • ?[多服務支持]支持同時創建多個內置RTSP服務;
  • ?[H.265支持]Windows內置rtsp server支持發布H.265視頻(64位庫);
  • ?[RTSP url回調]支持設置后的rtsp url通過event回調到上層。

對應Demo:

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

6. Windows內網RTSP網關SDK

內網RTSP網關SDK,系內置輕量級RTSP服務SDK擴展,完成外部RTSP/RTMP數據拉取并注入到輕量級RTSP服務SDK工作,多個內網客戶端直接訪問內網輕量級RTSP服務獲取公網數據,無需部署單獨的服務器,支持RTSP/RTMP H.265數據接入。 簡單來說:內置輕量級RTSP服務SDK和內置RTSP網關SDK的區別在于數據來源不同,內置輕量級RTSP服務SDK數據來源于終端設備自帶攝像頭數據/屏幕數據/外部編碼前后數據,內置RTSP網關SDK的數據源是RTSP/RTMP流數據。

  • ?[音頻格式]AAC;
  • ?[視頻格式]H.264、H.265;
  • ?[接入協議]支持內外網RTMP/RTSP流接入;
  • ?[輸出協議]RTSP,拉取的RTSP/RTMP流,注入輕量級RTSP服務SDK;
  • ?[音頻轉碼]支持音頻(PCMU/PCMA,Speex等)轉AAC后注入;
  • ?[端口設置]支持RTSP端口設置;
  • ?[鑒權設置]支持RTSP鑒權用戶名、密碼設置;
  • ?[獲取session連接數]支持獲取當前RTSP服務會話連接數;
  • ?[多服務支持]支持同時創建多個內置RTSP服務;
  • ?[H.265支持]Windows內置rtsp server支持發布H.265視頻(64位庫);
  • ?[RTSP url回調]支持設置后的rtsp url通過event回調到上層;

對應Demo:

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

7. Windows/Android/iOS RTMP/RTSP多路流媒體轉RTMP推送SDK

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

  • ?[拉流]支持拉取RTSP流;
  • ?[拉流]支持拉取RTMP流;
  • ?[預覽]支持拉取到的RTMP/RTSP隨時本地預覽、關閉預覽;
  • ?[拉流音頻調節]支持拉取的RTMP/RTSP流靜音;
  • ?[音頻轉碼]支持拉取的RTMP/RTSP的PCMA/PCMU/SPEEX音頻格式轉AAC后再轉發到RTMP服務器;
  • ?[url切換]支持轉發過程中,拉取的RTMP/RTSP或本地FLV文件實時內容切換
  • ?[轉發]超低延遲轉發拉取的rtsp/rtmp流到rtmp server;
  • ?[H.265支持]業內首家支持RTSP/RTMP H.265轉RTMP推送的SDK(提供配套RTMP擴展H.265服務器);

對應Demo:

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

8. Windows導播SDK

  • ?[拉流]支持拉取RTSP流;
  • ?[拉流]支持拉取RTMP流;
  • ?[混音合成]支持本地采集到屏幕或攝像頭數據,和遠程拉取得RTSP或RTMP流做合成、混音輸出;
  • ?[導播]支持導播過程中,隨時切斷某一路音視頻或音頻;
  • ?[混音]支持音頻混音(同時選擇“采集麥克風”+“采集揚聲器”);
  • ?[合成]多路流合成一路流后,推送到RTMP服務器;
  • ?[擴展錄像快照]多路合成后的流,支持本地錄像、快照。

對應Demo:

  • ?測試程序:SmartMixStreamDemo.exe;
  • ?C++工程:WIN-MixStreamSDK-CPP-Demo;

9. Windows/Android/iOS錄像SDK

  • ?[拉流]支持拉取RTSP流錄像;
  • ?[拉流]支持拉取RTMP流錄像;
  • ?[推流端錄像]支持推送端同步錄像;
  • ?[邏輯分離]大牛直播錄像SDK不同于普通錄像接口,更智能,和推送、播放、轉發、內置輕量級RTSP服務SDK功能完全分離,支持隨時錄像;
  • ?[url切換]在錄像過程中,支持切換不同URL,如兩個URL配置一致,則可以錄制到同一個MP4文件,如不一致,可自動分割到下一個文件;
  • ?[參數設置]支持設置單個錄像文件大小、錄像路徑等,并支持純音頻、純視頻、音視頻錄制模式;
  • ?[音頻轉碼]支持音頻(PCMU/PCMA,Speex等)轉AAC后再錄像;
  • ?[265支持]支持RTSP/RTMP H.265錄制到MP4文件;
  • ?[推送端265錄像]Windows推送SDK支持H265錄像;
  • ?[事件回調]從開始錄像,到錄像結束均有event callback上來,網絡堵塞、音視頻同步均做了非常友好的處理。

對應Demo:

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

10. Windows/Android/iOS SEI擴展數據發送/接收SDK

  • ?[RTSP SEI]支持內置RTSP服務SDK攜帶SEI擴展信息(H.264);
  • ?[RTMP SEI]支持RTMP推送SDK攜帶SEI擴展信息(H.264);
  • ?[自定義數據]持發送自定義用戶數據(如自定義utf8字符串);
  • ?[二進制數據]支持發送二進制數據;
  • ?[播放端解析]RTSP/RTMP直播播放端SDK支持utf8文本、二進制、和原SEI數據解析。

對應Demo:

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

編譯注意事項

  • iOS平臺支持真機和模擬器編譯運行.
  • iOS播放端編譯時找不到 libSmartPlayerSDK.a 時,請先到 SmartiOSPlayer/SmartiOSPlayer/libs 目錄, 解壓libSmartPlayerSDK.zip.
  • iOS推送端編譯時找不到 libSmartPublisherSDK.a 時,請先到 SmartiOSPublisher/SmartiOSPublisher/libs 目錄, 解壓libSmartPublisherSDK.zip.
  • 未授權版本,限制app-name,如果需要集成到自己工程里面調試,可以用以下名字:
Windows推送端:SmartPublisherDemo
Windows播放端:SmartPlayer
Windows轉發端:SmartStreamRelayDemo
Windows合流導播端:SmartMixStreamDemo
android推送端:SmartPublisherSDKDemo
android后臺Service推送:SmartServicePublisherSDKDemo
android一對一互動:SmartEchoCancellation
android播放器:SmartPlayerSDKDemo
iOS推送端:SmartiOSPublisher
iOS轉發端:SmartiOSRelayDemo
iOS播放器:SmartiOSPlayer
  • 集成到自己工程,如何改名字(以推送端為例):
android:strings.xml:
<string name="app_name">SmartPublisherSDKDemo</string>
iOS:Info.plist-->右鍵Open As-->Source Code,添加或者編輯
<key>CFBundleName</key>	
<string>SmartiOSPublisher</string>

聯系我們

點擊查看聯系方式

QQ交流群:

大牛直播SDK技術交流群1:499687479

大牛直播SDK技術交流群2:294891451

內網RTSP網關SDK

技術特點和優勢:

內網RTSP網關模塊,系內置輕量級RTSP服務模塊擴展,完成外部RTSP/RTMP數據拉取并注入到輕量級RTSP服務模塊工作,多個內網客戶端直接訪問內網輕量級RTSP服務獲取公網數據,無需部署單獨的服務器,支持RTSP/RTMP H.265數據接入。

內置輕量級RTSP服務模塊和內置RTSP網關模塊共同點:

內置輕量級RTSP服務模塊和內置RTSP網關模塊,核心痛點是避免用戶或者開發者單獨部署RTSP或者RTMP服務,數據匯聚到內置RTSP服務,對外提供可供拉流的RTSP URL,適用于內網環境下,對并發要求不高的場景,支持H.264/H.265,支持RTSP鑒權、單播、組播模式,考慮到單個服務承載能力,我們支持同時創建多個RTSP服務,并支持獲取當前RTSP服務會話連接數。

內置輕量級RTSP服務模塊和內置RTSP網關模塊不同點:數據來源不同

1. 內置輕量級RTSP服務模塊,數據源來自攝像頭、屏幕、麥克風等編碼前數據,或者本地編碼后的對接數據;

2. 內置RTSP網關模塊,實際上是RTSP/RTMP拉流模塊+內置輕量級RTSP服務模塊組合出來的。數據源來自RTSP或RTMP網絡流,拉流模塊完成編碼后的音視頻數據回調,然后,匯聚到內置輕量級RTSP服務模塊。

整體設計方案如下:

???

功能支持:

  • ?[音頻格式]AAC;
  • ?[視頻格式]H.264、H.265;
  • ?[接入協議]支持內外網RTMP/RTSP流接入;
  • ?[輸出協議]RTSP,拉取的RTSP/RTMP流,注入輕量級RTSP服務SDK;
  • ?[傳輸模式]Windows支持單播組播模式,Android/iOS平臺支持單播模式;
  • ?[音頻轉碼]支持音頻(PCMU/PCMA,Speex等)轉AAC后注入;
  • ?[端口設置]支持RTSP端口設置;
  • ?[鑒權設置]支持RTSP鑒權用戶名、密碼設置;
  • ?[獲取session連接數]支持獲取當前RTSP服務會話連接數;
  • ?[多服務支持]支持同時創建多個內置RTSP服務;
  • ?[H.265支持]Windows內置rtsp server支持發布H.265視頻(64位庫);
  • ?[RTSP url回調]支持設置后的rtsp url通過event回調到上層;

對應Demo:

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

基本使用步驟(以Windows平臺為例):

  1. 點擊“配置查看Rtsp服務”按鈕,啟動rtsp服務;
  2. 輸入需要拉流的rtsp或rtmp地址;
  3. 點擊拉流,獲取rtsp或rtsp流數據;
  4. 點擊“發送rtsp流”,即可把數據注入內網rtsp網關sdk;
  5. 發送成功后,會回調可用來播放的內網rtsp url;
  6. 播放端,輸入步驟5回調的rtsp地址,完成拉流播放;
  7. 如果查看連接的內網播放session數,點擊“配置查看Rtsp服務”,可實時查詢每個rtsp service連接的session數;
  8. 如需本地拉取的rtsp或rtmp流,點擊“預覽”;
  9. 如需停止,點擊“停止rtsp流”;

下載Demo源碼測試:

Github?下載Windows平臺轉發DEMO,對應(?Windows平臺多路RTSP|RTMP轉RTMP推送模塊SDK(C++) Demo工程),DEMO基于VS2013開發,如下圖配置:

?

播放端,用SmartPlayer.exe 或者 VLC播放 即可。

大牛直播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)

年轻人片-年轻人看片-年轻人免费在线看片