开发个好的RTMP播放器到底难在哪里?RTMP播放器对标和考察指标

简介: 好多开发者提到,RTMP播放器,不知道有哪些对标和考察指标,以下大概聊聊我们的一点经验,感兴趣的,可以关注 github:1. 低延迟:大多数RTMP的播放都面向直播场景,如果延迟过大,严重影响体验,所以,低延迟是衡量一个好的RTMP播放器非常重要的指标,目前大牛直播SDK的RTMP直播播放延迟比开源播放器更优异(大牛直播SDK延迟在1秒左右,开源播放器如VLC,延迟在5-7秒),而且长时间运行下,大牛直播SDK播放端不会造成延迟累积,开源或第三方播放器,长时间运行,容易产生延迟累积;

好多开发者提到,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();
            //release
            Marshal.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);


相关文章
|
10月前
|
缓存 网络协议 开发工具
庖丁解牛之-Android平台RTSP|RTMP播放器设计
我们在做Android平台RTSP或者RTMP播放器开发的时候,需要注意的点非常多,以下,以大牛直播SDK(官方)的接口为例,大概介绍下相关接口设计:
119 0
|
10月前
|
Web App开发 数据采集 物联网
Android平台基于RTMP或RTSP的一对一音视频互动技术方案探讨
随着智能门禁等物联网产品的普及,越来越多的开发者对音视频互动体验提出了更高的要求。目前市面上大多一对一互动都是基于WebRTC,优点不再赘述,我们这里先说说可能需要面临的问题:WebRTC的服务器部署非常复杂,可以私有部署,但是非常复杂。传输基于UDP,很难保证传输质量,由于UDP是不可靠的传输协议,在复杂的公网网络环境下,各种突发流量、偶尔的传输错误、网络抖动、超时等等都会引起丢包异常,都会在一定程度上影响音视频通信的质量,难以应对复杂的互联网环境,如跨区跨运营商、低带宽、高丢包等场景,行话说的好:从demo到实用,中间还差1万个WebRTC。
107 0
|
10月前
|
编解码 监控 网络协议
Android平台音视频推送选RTMP还是GB28181?
早在2015年,我们发布了RTMP直播推送模块,那时候音视频直播这块场景需求,还不像现在这么普遍,我们做这块的初衷,主要是为了实现移动单兵应急指挥系统的低延迟音视频数据传输。好多开发者可能会疑惑,走RTMP怎么可能低延迟?网上看到的RTMP推拉流延迟,总归要2-3秒起,如果是自己实现框架,RTMP推拉流逻辑自己实现的话,延迟确实可以控制在毫秒级,这个已无需赘述。
|
2月前
|
Web App开发 移动开发 前端开发
web端实现rtsp实时推流视频播放可行性方案
总之,要在Web端实现RTSP实时推流视频播放,需要使用适当的前端技术(如HTML5 Video或WebRTC),以及媒体服务器或流转换器来处理RTSP流。这需要一些开发和配置工作,但是可以实现实时视频流的播放。具体的实现方案可能会根据您的需求和技术栈而有所不同,所以需要仔细评估和选择适合您的解决方案。
107 0
|
2月前
|
网络协议 Linux 测试技术
音视频学习之rtsp推流学习1(rtspserver开源库example运行及流程梳理)
音视频学习之rtsp推流学习1(rtspserver开源库example运行及流程梳理)
211 0
|
10月前
|
编解码 网络协议 Android开发
Android平台RTMP|RTSP直播播放器功能进阶探讨
很多开发者在跟我聊天的时候,经常问我,为什么一个RTMP或RTSP播放器,你们需要设计那么多的接口,真的有必要吗?带着这样的疑惑,我们今天聊聊Android平台RTMP、RTSP播放器常规功能,如软硬解码设置、实时音量调节、实时快照、实时录像、视频view翻转和旋转、画面填充模式设定、解码后YUV、RGB数据回调等:
127 0
|
10月前
|
编解码 网络协议 开发工具
跨平台低延迟的RTMP/RTSP直播播放器设计实现
2015年,当我们试图在市面上找一款专供直播播放使用的低延迟播放器,来配合测试我们的RTMP推送模块使用时,居然发现没有一款好用的,市面上的,如VLC或Vitamio,说白了都是基于FFMPEG,在点播这块支持格式很多,也非常优异,但是直播这块,特别是RTMP,延迟要几秒钟,对如纯音频、纯视频播放,快速启播、网络异常状态处理、集成复杂度等各方面,支持非常差,而且因为功能强大,bug很多,除了行业内资深的开发者能驾驭,好多开发者甚至连编译整体环境,都要耗费很大的精力。
285 0
|
10月前
|
编解码 开发工具 C#
RTSP/RTMP播放端录像不可忽视的几个设计要点
很多开发者提到,拉取的摄像机(一般RTSP流)或RTMP流,如果需要录制,需要考虑哪些因素,本文以大牛直播SDK的Windows平台拉流端录像为例(github),做个简单的介绍:
130 0
|
10月前
|
编解码 开发工具 图形学
Unity环境下RTMP推流+RTMP播放低延迟解决方案
在本文之前,我们发布了Unity环境下的RTMP推流(Windows平台+Android平台)和RTMP|RTSP拉流(Windows平台+Android平台+iOS平台)低延迟的解决方案,今天做个整体汇总,权当抛砖引玉。
479 0
|
10月前
|
存储 编解码 监控
跨平台低延迟RTSP转RTMP推送技术方案探讨
实现RTSP摄像头数据转RTMP推送到服务器,可以用第三方库或者工具实现,总体设计架构如下:
239 0