开发个好的RTMP播放器到底难在哪里?RTMP播放器对标和考察指标
好多開發者提到,RTMP播放器,不知道有哪些對標和考察指標,以下大概聊聊我們的一點經驗,感興趣的,可以關注 github:
1. 低延遲:大多數RTMP的播放都面向直播場景,如果延遲過大,嚴重影響體驗,所以,低延遲是衡量一個好的RTMP播放器非常重要的指標,目前大牛直播SDK的RTMP直播播放延遲比開源播放器更優異(大牛直播SDK延遲在1秒左右,開源播放器如VLC,延遲在5-7秒),而且長時間運行下,大牛直播SDK播放端不會造成延遲累積,開源或第三方播放器,長時間運行,容易產生延遲累積;
部分服務器會緩存GOP,確保快速實現首屏播放,又不影響延遲,對此,我們設計了快速啟動接口,快速render第一幀的同時,追到最新的播放數據:
/** 設置秒開, 1為秒開, 0為不秒開*/[DllImport(@"SmartPlayerSDK.dll")]public static extern UInt32 NT_SP_SetFastStartup(IntPtr handle, Int32 isFastStartup);2. 音視頻同步處理:大多播放器為了追求低延遲,甚至不做音視頻同步,拿到audio video直接播放,導致a/v不同步,還有就是時間戳亂跳等各種問題,大牛直播SDK提供的播放器,具備好的時間戳同步和異常時間戳矯正機制;
備注:如果是超低延遲模式下,可以0 buffer,不做音視頻同步:
/** 設置低延時播放模式,默認是正常播放模式* mode: 1為低延時模式, 0為正常模式,其他只無效* 接口調用成功返回NT_ERC_OK*/[DllImport(@"SmartPlayerSDK.dll")]public static extern UInt32 NT_SP_SetLowLatencyMode(IntPtr handle, Int32 mode);3. 支持多實例:大牛直播SDK提供的RTMP直播播放SDK支持在設備性能允許的情況下,支持多實例播放RTMP流數據,大多開源播放器對多實例支持不太友好;
除了常規的多實例外,比如大屏監控場景下,盡管我們CPU占用已經是行業內非常低的了,但是好多廠家下,不是每路都需要全幀播放,針對此種情況,我們做了實時只播放關鍵幀和全幀播放的接口設計,比如8個實例,其中不太重要的幾路數據,可以設置只播放關鍵幀,需要重點關注時,點擊全幀率播放即可,這樣既節省了系統開銷,又實現了多路播放的目的:
/** 設置只解碼視頻關鍵幀* is_only_dec_key_frame: 1:表示只解碼關鍵幀, 0:表示都解碼, 默認是0* 成功返回NT_ERC_OK*/[DllImport(@"SmartPlayerSDK.dll")]public static extern UInt32 NT_SP_SetOnlyDecodeVideoKeyFrame(IntPtr handle, Int32 is_only_dec_key_frame);4. 支持buffer time設置:在一些有網絡抖動的場景,播放器需要支持buffer time設置,一般來說,以毫秒計,開源播放器對此支持不夠友好;
5. 實時靜音:比如,多窗口播放RTMP流,如果每個audio都播放出來,體驗非常不好,所以實時靜音功能非常必要,開源播放器不具備實時靜音功能;
6. 視頻view旋轉:好多攝像頭由于安裝限制,導致圖像倒置,所以一個好的RTMP播放器應該支持如視頻view實時旋轉(0° 90° 180° 270°)、水平反轉、垂直反轉,開源或第三方播放器不具備此功能;
/**上下反轉(垂直反轉)*is_flip: 1:表示反轉, 0:表示不反轉*/[DllImport(@"SmartPlayerSDK.dll")]public static extern UInt32 NT_SP_SetFlipVertical(IntPtr handle, Int32 is_flip);/**水平反轉*is_flip: 1:表示反轉, 0:表示不反轉*/[DllImport(@"SmartPlayerSDK.dll")]public static extern UInt32 NT_SP_SetFlipHorizontal(IntPtr handle, Int32 is_flip);/** 設置旋轉,順時針旋轉* degress: 設置0, 90, 180, 270度有效,其他值無效* 注意:除了0度,其他角度播放會耗費更多CPU* 接口調用成功返回NT_ERC_OK*/[DllImport(@"SmartPlayerSDK.dll")]public static extern UInt32 NT_SP_SetRotation(IntPtr handle, Int32 degress);7. 支持解碼后audio/video數據輸出:大牛直播SDK接觸到好多開發者,希望能在播放的同時,獲取到YUV或RGB數據,進行人臉匹配等算法分析,開源播放器不具備此功能;
public void SDKVideoFrameCallBack(UInt32 status, NT_SP_VideoFrame frame){if (cur_video_frame_.plane0_ != IntPtr.Zero){Marshal.FreeHGlobal(cur_video_frame_.plane0_);cur_video_frame_.plane0_ = IntPtr.Zero;}cur_video_frame_ = frame;this.Invalidate();}public void SDKAudioPCMFrameCallBack(UInt32 status, IntPtr data, UInt32 size,Int32 sample_rate, Int32 channel, Int32 per_channel_sample_number){//這里拿到回調的PCM frame,進行相關操作(如自己播放)//label_debug.Text = per_channel_sample_number.ToString();//releaseMarshal.FreeHGlobal(data);}public void SetVideoFrameCallBack(IntPtr handle, IntPtr userData, UInt32 status, IntPtr frame){if (frame == IntPtr.Zero){return;}//如需直接處理RGB數據,請參考以下流程NT_SP_VideoFrame video_frame = (NT_SP_VideoFrame)Marshal.PtrToStructure(frame, typeof(NT_SP_VideoFrame));NT_SP_VideoFrame pVideoFrame = new NT_SP_VideoFrame();pVideoFrame.format_ = video_frame.format_;pVideoFrame.width_ = video_frame.width_;pVideoFrame.height_ = video_frame.height_;pVideoFrame.timestamp_ = video_frame.timestamp_;pVideoFrame.stride0_ = video_frame.stride0_;pVideoFrame.stride1_ = video_frame.stride1_;pVideoFrame.stride2_ = video_frame.stride2_;pVideoFrame.stride3_ = video_frame.stride3_;Int32 argb_size = video_frame.stride0_ * video_frame.height_;pVideoFrame.plane0_ = Marshal.AllocHGlobal(argb_size);CopyMemory(pVideoFrame.plane0_, video_frame.plane0_, (UInt32)argb_size);if (playWnd.InvokeRequired){BeginInvoke(set_video_frame_call_back_, status, pVideoFrame);}else{set_video_frame_call_back_(status, pVideoFrame);}}public void SetAudioPCMFrameCallBack(IntPtr handle, IntPtr user_data,UInt32 status, IntPtr data, UInt32 size,Int32 sample_rate, Int32 channel, Int32 per_channel_sample_number){if (data == IntPtr.Zero || size == 0){return;}IntPtr pcmData = Marshal.AllocHGlobal((Int32)size);CopyMemory(pcmData, data, (UInt32)size);if (playWnd.InvokeRequired){BeginInvoke(set_audio_pcm_frame_call_back_, status, pcmData, size, sample_rate, channel, per_channel_sample_number);}else{set_audio_pcm_frame_call_back_(status, pcmData, size, sample_rate, channel, per_channel_sample_number);}}8. 實時快照:感興趣或重要的畫面,實時截取下來非常必要,一般播放器不具備快照能力,開源播放器不具備此功能;
/** 捕獲圖片* file_name_utf8: 文件名稱,utf8編碼* call_back_data: 回調時用戶自定義數據* call_back: 回調函數,用來通知用戶截圖已經完成或者失敗* 成功返回 NT_ERC_OK* 只有在播放時調用才可能成功,其他情況下調用,返回錯誤.* 因為生成PNG文件比較耗時,一般需要幾百毫秒,為防止CPU過高,SDK會限制截圖請求數量,當超過一定數量時,* 調用這個接口會返回NT_ERC_SP_TOO_MANY_CAPTURE_IMAGE_REQUESTS. 這種情況下, 請延時一段時間,等SDK處理掉一些請求后,再嘗試.*/[DllImport(@"SmartPlayerSDK.dll")]public static extern UInt32 NT_SP_CaptureImage(IntPtr handle, IntPtr file_name_utf8,IntPtr call_back_data, SP_SDKCaptureImageCallBack call_back);public void SDKCaptureImageCallBack(IntPtr handle, IntPtr userData, UInt32 result, IntPtr file_name){if (file_name == IntPtr.Zero)return;int index = 0;while (true){if (0 == Marshal.ReadByte(file_name, index))break;index++;}byte[] file_name_buffer = new byte[index];Marshal.Copy(file_name, file_name_buffer, 0, index);byte[] dst_buffer = Encoding.Convert(Encoding.UTF8, Encoding.Default, file_name_buffer, 0, file_name_buffer.Length);String image_name = Encoding.Default.GetString(dst_buffer, 0, dst_buffer.Length);if (playWnd.InvokeRequired){BeginInvoke(set_capture_image_call_back_, result, image_name);}else{set_capture_image_call_back_(result, image_name);}}9. 網絡抖動處理(如斷網重連):穩定的網絡處理機制、支持如斷網重連等,開源播放器對網絡異常處理支持較差;
/*事件ID*/public enum NT_SP_E_EVENT_ID : uint{NT_SP_E_EVENT_ID_BASE = NTBaseCodeDefine.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*//* 接下來請從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)*/}10. 長期運行穩定性:大牛直播SDK提供的RTMP直播播放SDK適用于長時間運行,開源播放器對長時間運行穩定性支持較差;
11. 實時下載速度反饋:大牛直播SDK提供音視頻流實時下載回調,并可設置回調時間間隔,確保實時下載速度反饋,以此來監聽網絡狀態,開源播放器不具備此能力;
/** 設置下載速度上報, 默認不上報下載速度* is_report: 上報開關, 1: 表上報. 0: 表示不上報. 其他值無效.* report_interval: 上報時間間隔(上報頻率),單位是秒,最小值是1秒1次. 如果小于1且設置了上報,將調用失敗* 注意:如果設置上報的話,請設置SetEventCallBack, 然后在回調函數里面處理這個事件.* 上報事件是:NT_SP_E_EVENT_ID_DOWNLOAD_SPEED* 這個接口必須在StartXXX之前調用* 成功返回NT_ERC_OK*/[DllImport(@"SmartPlayerSDK.dll")]public static extern UInt32 NT_SP_SetReportDownloadSpeed(IntPtr handle, Int32 is_report, Int32 report_interval);/** 主動獲取下載速度* speed: 返回下載速度,單位是Byte/s* (注意:這個接口必須在startXXX之后調用,否則會失敗)* 成功返回NT_ERC_OK*/[DllImport(@"SmartPlayerSDK.dll")]public static extern UInt32 NT_SP_GetDownloadSpeed(IntPtr handle, ref Int32 speed);12. 異常狀態處理、Event狀態回調:如播放的過程中斷網,大牛直播SDK提供的播放器可實時回調相關狀態,確保上層模塊感知處理,開源播放器對此支持不好;
/** 設置事件回調,如果想監聽事件的話,建議調用Open成功后,就調用這個接口*/[DllImport(@"SmartPlayerSDK.dll")]public static extern UInt32 NT_SP_SetEventCallBack(IntPtr handle, IntPtr call_back_data, SP_SDKEventCallBack call_back);/** 設置視頻大小回調接口*/[DllImport(@"SmartPlayerSDK.dll")]public static extern UInt32 NT_SP_SetVideoSizeCallBack(IntPtr handle, IntPtr callbackdata, SP_SDKVideoSizeCallBack call_back);/** 設置視頻回調, 吐視頻數據出來* frame_format: 只能是NT_SP_E_VIDEO_FRAME_FORMAT_RGB32, NT_SP_E_VIDEO_FRAME_FROMAT_I420*/[DllImport(@"SmartPlayerSDK.dll")]public static extern UInt32 NT_SP_SetVideoFrameCallBack(IntPtr handle, Int32 frame_format,IntPtr callbackdata, 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*/[DllImport(@"SmartPlayerSDK.dll")]public static extern UInt32 NT_SP_SetVideoFrameCallBackV2(IntPtr handle,Int32 scale_width, Int32 scale_height,Int32 scale_filter_mode, Int32 frame_format,IntPtr call_back_data, SP_SDKVideoFrameCallBack call_back);/** 設置繪制視頻幀時,視頻幀時間戳回調* 注意如果當前播放流是純音頻,那么將不會回調,這個僅在有視頻的情況下才有效*/[DllImport(@"SmartPlayerSDK.dll")]public static extern UInt32 NT_SP_SetRenderVideoFrameTimestampCallBack(IntPtr handle,IntPtr callbackdata, SP_SDKRenderVideoFrameTimestampCallBack call_back);/** 設置音頻PCM幀回調, 吐PCM數據出來,目前每幀大小是10ms.*/[DllImport(@"SmartPlayerSDK.dll")]public static extern UInt32 NT_SP_SetAudioPCMFrameCallBack(IntPtr handle,IntPtr call_back_data, SP_SDKAudioPCMFrameCallBack call_back);/** 設置用戶數據回調*/[DllImport(@"SmartPlayerSDK.dll")]public static extern UInt32 NT_SP_SetUserDataCallBack(IntPtr handle,IntPtr call_back_data, SP_SDKUserDataCallBack call_back);/** 設置視頻sei數據回調*/[DllImport(@"SmartPlayerSDK.dll")]public static extern UInt32 NT_SP_SetSEIDataCallBack(IntPtr handle,IntPtr call_back_data, SP_SDKSEIDataCallBack call_back);13. 設置視頻填充模式(等比例顯示):好多情況下,有些場景需要全view鋪滿播放,有些為了防止視頻拉伸,可以設置成等比例縮放顯示;
/** 設置視頻畫面的填充模式,如填充整個繪制窗口、等比例填充繪制窗口,如不設置,默認填充整個繪制窗口* handle: 播放句柄* mode: 0: 填充整個繪制窗口; 1: 等比例填充繪制窗口, 默認值是0* 成功返回NT_ERC_OK*/[DllImport(@"SmartPlayerSDK.dll")]public static extern UInt32 NT_SP_SetRenderScaleMode(IntPtr handle, Int32 mode);14. D3D檢測:一般來說市面上的大多Windows都支持D3D,有些小眾化的,只支持GDI模式繪制,所以為了更好的兼容性,這個接口非常必要。
/** handle: 播放句柄* hwnd: 這個要傳入真正用來繪制的窗口句柄* is_support: 如果支持的話 *is_support 為1, 不支持的話為0* 接口調用成功返回NT_ERC_OK*/[DllImport(@"SmartPlayerSDK.dll")]public static extern UInt32 NT_SP_IsSupportD3DRender(IntPtr handle, IntPtr hwnd, ref Int32 is_support);?
總結
以上是生活随笔為你收集整理的开发个好的RTMP播放器到底难在哪里?RTMP播放器对标和考察指标的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何用U盘之家U盘启动盘制作工具实现U盘
- 下一篇: ECharts 饼图 legend 样式