JCHub

  • Home
  • Category
    • A/V
    • WebRTC
    • Beauty of Programming
    • Linux
    • Windows
    • Moments of Life
    • Campus Life
  • Reference
    • API Reference
    • Utilities
    • AV Test
    • Doc
  • Message Board
  • About
JCHub
Code as My Sword, Lost in Obsession
A/V

vlc播放rtsp over tcp画面突然卡住问题

继完成rtmp服务器开发后,最近也写完了rtsp服务器,可以将国标ps流以及其他格式协议码流转rtsp协议输出。中间开发过程用了许多播放器测试,最常用的就是vlc。使用vlc测试过程,遇到了许多问题。今天就记录一个比较奇怪的问题。 使用rtp over udp模式播放时,没出现问题,但是使用rtp over tcp模式时,vlc播放几十秒后画面突然卡住不动了,看了vlc 的debug message没发现异常。用ffplay,live555,potplayer测了都没异常。后面换了不同版本vlc测试,更奇怪了,vlc3.0.0以及之前,3.0.5以及之后版本都正常。应该是vlc对rtp over tcp做了特殊处理。此时抓包分析rtsp交互数据,发现出现问题版本的vlc每隔一定时间除了会发送OPTIONS命令,然后还有以'$'开头的一串特殊字节,发送完这个播放画面就卡住了。为什么会卡住不播放了呢?只能看vlc源码查找问题了。 通过阅读相关源码,终于定位到了原因。这个是vlc的keep-alive机制造成的。由于vlc使用了live555做rtsp处理,所以对应处理代码在modules/access/live555.cpp这个文件里。下面结合代码说下原因。 [crayon-69cf85f6b70bd571536503/] 如上函数是vlc的rtsp超时处理代码,出现问题的vlc版本没有 [crayon-69cf85f6b70ca570655790/] 这两行代码,我们先把这两行代码注释,分析下为什么会出现播放画面突然不动的现象。 1)rtsp交互开始vlc客户端会发送OPTIONS请求,我们服务器需要回应支持的方法。如果我们服务器回应包括GET_PARAMETER方法(可选),use_get_param就为true,然后keep-alive机制就会定时sendGetParameterCommand,否则sendOptionsCommand,我这边服务没去做GET_PARAMETER方法的支持,所以会定时收到vlc发的OPTIONS命令请求。vlc发送完OPTIONS请求命令后,开始wait_Live555_response(p_demux)。看下这个函数: [crayon-69cf85f6b70cf012350162/] 传入的参数中i_timeout为默认值0,所以没有超时时间,会一直等服务器响应请求。 2)我这边服务器有个命令解析类,只处理标准的命令(OPTIONS,DESCRIBE,PLAY等)。由于vlc会定时发送'$'开头数据,跟OPTIONS请求数据混在一起送到我的命令解析里,导致我这边没能正确解析,所以也没有回应vlc keep-alive机制的OPTIONS请求。我们再看下TimeoutPrevention函数,该函数进入后会: [crayon-69cf85f6b70d2937025627/] 由于我的服务器没有回应OPTIONS请求,所以这个锁会一直阻塞,我们看下这个锁用在哪个地方: [crayon-69cf85f6b70d5830340382/] 可知由于TimeoutPrevention一直阻塞,所以Demux过程不能执行了,所以播放画面不动了。 新版vlc已经通过 [crayon-69cf85f6b70d8496791733/] 取消了rtp over tcp的keep-alive机制,所以3.0.5以及之后版本没有出现问题。我的rtsp服务器后面也针对'$'开头数据做了处理,测了下,一切都正常了。 '$'开头数据是做什么的呢?在我服务器发RTCP数据时才用到,没想到客户端也有类似机制。在rfc2326中,'$'(0x24)开头数据叫做:Embedded (Interleaved) Binary Data,称为嵌入式二进制数据。测试的那么多播放器,只有vlc实现了这个。而且这个Embedded (Interleaved) Binary Data只工作在rtp over tcp下。这个数据有什么作用呢?rfx2326 10.12这么介绍的: [crayon-69cf85f6b70dc660977914/] rtp over tcp模式下,就一个socket端口进行命令控制以及流传输,不像rtp over udp,另开udp socket传输数据。由于防火墙以及其他外部因素,可能造成rtsp方法与rtp流数据交织混在一起。为了避免这个,才有这个设计。通过: [crayon-69cf85f6b70e0880818588/] 对控制信息以及流数据进行区分。具体介绍可以参考: RTP over RTSP包混合发送的解决办法:https://blog.csdn.net/myslq/article/details/79819179 由于Embedded (Interleaved) Binary Data是在是在服务器回应PLAY推流后vlc才这样处理的,我这边没注意到,所以导致解析出现错误。不过除了vlc,其他播放器都没支持Embedded (Interleaved) Binary Data,因为推流是服务器端,前面命令交互完,服务器就开始推流了,对于客户端我觉得用处不大。

2018年12月23日 0comments 3677hotness 7likes Jeff Read all
A/V

Intel media SDK编码去除多余信息

使用Intel media SDK硬编码H264数据时,生成的每一帧H264数据都包含Access unit delimiter+Picture parameter set+Additional information (SEI)。如下图是使用默认参数生成的一个非IDR帧H264数据。 IDR帧数据结构如下: 根据nal uint type表 可知: 默认编码IDR帧结构:0x00 00 00 01 09(分隔符)|| 0x00 00 00 01 27(SPS)|| 0x00 00 00 01 28(PPS)|| 0x00 00 00 01 06(SEI)|| 0x00 00 01 25(IDR) 默认编码非IDR帧结构:0x00 00 00 01 09(分隔符)|| 0x00 00 00 01 28(PPS)|| 0x00 00 00 01 06(SEI)|| 0x00 00 01 21(非IDR) 但是默认编码有个问题,不是所有播放器可以支持直接播放,测了下VLC不支持(以前文章说过VLC播放带SEI的视频花屏问题),PotPlayer可以播放,这个问题在于编码出来的每帧数据都多了分隔符与SEI以及PPS,不是所有的播放器都去解析这些头部,这方面NVIDIA Video Codec硬编码就简单多了,IDR帧结构就SPS+PPS+IDR,非IDR帧就一个头部。所以为了兼容大多数播放器我们需要去掉多余的分隔符、SEI以及PPS信息,这些信息用途不大,PPS没必要每帧都带,反而增加数据量。如何去除呢,一种方法是手动解析这些头部,然后手动去除,另一种方法是使用编码的扩展参数,这个编码扩展参数如果没认真研究官方文档,还真不知道怎么用。 如下是编码扩展参数如何使用的代码。代码中我们将设置的参数放到一个数组中,然后传递给编码参数mfxVideoParam的ExtParam成员。 [crayon-69cf85f6b85dc583010873/] mfxExtCodingOption.PicTimingSEI: Set this flag to insert the picture timing SEI with pic_struct syntax element. See sub-clauses D.1.2 and D.2.2 of the ISO /IEC 14496-10 specification for the definition of this syntax element. See the CodingOptionValue enumerator for values of this option. The default value is ON. 也就是这个成员用于在每帧插入图像时序SEI信息,默认是开启的。 mfxExtCodingOption.AUDelimite: Set this flag to insert the Access Unit Delimiter NAL. See the CodingOptionValue enumerator for values of this option.该标志用于插入分隔符。 mfxExtCodingOption2.RepeatPPS: This flag controls picture parameter set repetition in AVC encoder. Turn ON this flag to repeat PPS with each frame. See the CodingOptionValue enumerator for values of this option. The default value is ON. This parameter is valid only during initialization.用于设置AVC编码器在每一帧编码中插入PPS。默认是开启的。 通过关闭如上编码参数,即可去除多余的数据,编码生成"简洁"的H264帧。

2018年8月14日 1comments 3059hotness 4likes Jeff Read all
Web

浏览器获取所安装插件列表

最近需要一个功能,浏览器能够判断我们的插件是否安装,没安装的话提示用户安装。查了下,只要我们插件成功注册到火狐浏览器中,可通过navigator.plugins数据获取所有安装的插件信息。 如下图是我通过该方法在火狐上获取的插件信息: 我也测了下Chrome上获取的信息: Edge浏览器情况: 可以看到不同浏览器都支持这一方法,但是获取的插件信息是不一样的。虽然我的Chrome与Edge不支持插件安装,但是本身内置了几个插件,比如pdf阅读与flash播放器,通过该方法都可以看到,所以不能说现在的浏览器完全没有插件。获取插件信息代码如下: [crayon-69cf85f6b965d503645552/] 参考 navigator.plugins使用:https://developer.mozilla.org/en-US/docs/Web/API/NavigatorPlugins/plugins

2018年7月5日 0comments 3258hotness 4likes Jeff Read all
Web

web页面npapi插件资源管理问题

最近写的一个npapi视频插件花了一个月基本搞定了要求功能,最近一直在做测试及优化,然后就是配合前端使用。前端那边有个功能是视频播放区域窗口切换,他找我说切换后浏览器卡住了。我问了他切换是怎么实现的,他每次切换后原有的插件标签都没了,然后加载了新的插件标签。我想了下,原有插件标签没了,相当于这个npapi插件对象拥有的资源都被强行释放了,然后又加载新的插件,一个插件对象本身会占有许多资源,包括内存及显存,每次切换都会不断的释放,初始化,造成很多不必要的开销,甚至导致页面卡顿,最坏的是插件崩溃了。 这种情况下,前端写带有插件界面不能像平时那么随意了。怪不得很多公司做的视频窗口切换都是由插件完成,所有的播放窗口都在一个插件内,插件管理窗口切换,这样前端不用考虑什么内存加载释放问题,但是会导致播放界面不灵活,窗口布局都被插件写死了,限制了前端发挥。我现在做的是一个窗口对应一个插件,界面设计更灵活,有点类似自己实现了一个Html5的video标签。 既然插件不能频繁释放加载,参照线程池思想,我们就让所有的插件对象始终存在,需要时再拿出来,不需要就隐藏,不释放。那如何在页面上隐藏插件标签呢,这里面也是有很多限制条件的。比如:插件标签的父标签不能改变,每个插件本身绑定一个窗口句柄,父标签变了,相当于新窗口了,原来那个插件还是被浏览器强制释放了。所以我们要让插件标签一直存在,通过一些技巧让它不用时暂时消失。我试了下设置父标签:visibility: hidden属性也有问题存在,虽然切换不卡了,但是切换回来视频却不显示了。这问题也是棘手。我自己对前端也是不怎么熟悉,只能找资料了。后面找了很久查到可通过如下方法。 假设插件标签object,我放到一个div中,这个div是浮动的,绝对定位的,当插件要移动位置或者隐藏时,只需要计算好位置,然后把这个浮动的div移动到对应位置即可。我想浏览器内部对绝对定位的标签(脱离文档流)在界面改变后没有释放该标签窗口资源,改变位置也只是移动下该标签窗口,不受其它标签影响,不像其它标签,一改变都要重新释放创建。

2018年6月16日 0comments 1769hotness 0likes Jeff Read all
A/V

基于FireBreath的npapi插件在Firefox下的调试

最近要做基于浏览器的视频播放,可以播放各种格式的流。首先为了快速出产品先做一个npapi插件,没用activex,因为IE限制了前端们的想象力与创造力,H5播放技术留在最后面做。刚开始做npapi插件用的是火狐原生api开发,比较繁琐。后面找了一个叫做firebreath的开发框架,开发的插件可以在IE,firefox以及chrome旧版本使用,提高了些开发效率,不过还是很多坑,网上资料也少。 看了一天firebreath官网文档,就开始动手搭建开发环境,搭建还是很快的,下个cmake,python,按官网教程一步步来都不会有问题。 随着播放插件越来越复杂必定少不了调试了。不过发现官网给的插件调试方法用不了。官网给的方法是直接附加到firefox进程,不过进不了断点。后来摸索了下,得附加到plugin-container.exe才可以,火狐这样做也是为了安全与稳定性,将插件与标签页进程做了隔离。附加进程操作如下图: 参考链接: 1)FireBreath:http://www.firebreath.org/

2018年5月15日 0comments 2220hotness 1likes Jeff Read all
Audio & Video Sharing

ffmpeg从mp4提取音频命令

从mp4中提取出aac文件(听歌必备): [crayon-69cf85f6b9ec2063581635/]

2018年3月19日 0comments 3339hotness 4likes Jeff Read all
A/V

html5播放flv

好久没看优酷了,发现优酷也支持html5播放了,这样看1080p视频电脑不会呼呼叫了。看了下,优酷用的是hls方案。如下为我观看的动漫视频: 鼠标右键复制调试信息可以得到: [crayon-69cf85f6ba6f8999881152/] 其中"supportType":"hls"就说明了优酷用的hls。hls延迟比较大,像这种非直播应用问题不大。话说我还是习惯用youtube,因为youtube播放器强大多了,可以设置自动字幕翻译,而且可以实时查看调试信息。 目前大多数直播都是采用rtmp协议,延迟小,有很多现成方案,比如librtmp库推流,srs或者nginx rtmp做服务器。但是网页端播放大多还是采用flash插件,耗电,性能差,开个1080p电脑就要呼呼叫了。所以这时候就需要html5了,浏览器通过html5播放视频支持硬件加速,可以明显降低CPU负载。 html5中播放视频用的是video标签,用法:http://www.w3school.com.cn/tags/tag_video.asp。支持Ogg、MPEG4、WebM三种格式。 其中WebM主要是谷歌在使用,Youtube现在用的WebM封装的是vp9视频,接着最常见的是MP4了。 由于html5 video标签只支持mp4,要想也支持flv,我们就要拆解flv了。由于flv容器封装的是H264+AAC,所以我们可以在网页端收到flv后,使用js代码解析flv,取出H264以及AAC,然后封装成mp4文件,再喂给video标签就可以了。这样我们就可以无插件播放flv了,由于mp4封装比flv复杂多了,所以这样可以减轻服务器压力,服务器不用再专门封装mp4文件。前面说到youku用的hls,跟flv类似,也需要一个js插件把hls转成mp4。 如果要学习flv容器格式,可以参考:http://blog.jianchihu.net/flvanalyzer.html 附带的工具,这是我两年前写的。 如果要学习mp4容器格式,可以参考:http://blog.jianchihu.net/mp4-elst-box.html 附带的工具,我当初做mp4解析就是用到该工具,然后配合标准文档:http://blog.jianchihu.net/doc 基本就没问题了,源码的话可以参考ffmpeg demux模块。 市面上有很多现成方案,可以参考下bibili的flv.js。

2018年3月1日 0comments 3180hotness 3likes Jeff Read all
golang

Forward :How Goroutines Work

Goroutines and Threads - the differences Go uses goroutines while a language like Java uses threads. What are the differences between the two? We need to look at 3 factors - memory consumption, setup and teardown and switching time. Memory consumption The creation of a goroutine does not require much memory - only 2kB of stack space. They grow by allocating and freeing heap storage as required.[2][3] Threads on the other hand start out at 1Mb (500 times more), along with a region of memory called a guard page that acts as a guard between one thread’s memory and another.[7] A server handling incoming requests can therefore create one goroutine per request without a problem, but one thread per request will eventually lead to the dreaded OutOfMemoryError. This isn’t limited to Java - any language that uses OS threads as the primary means of concurrency will face this issue. Setup and teardown costs Threads have significant setup and teardown costs because it has to request resources from the OS and return it once its done. The workaround to this problem is to maintain a pool of threads. In contrast, goroutines are created and destroyed by the runtime and those operations are pretty cheap. The language doesn’t support manual management of goroutines. Switching costs When a thread blocks, another has to be scheduled in its place. Threads are scheduled preemptively, and during a thread switch, the scheduler needs to save/restore ALL registers, that is, 16 general purpose registers, PC (Program Counter), SP (Stack Pointer), segment registers, 16 XMM registers, FP coprocessor state,…

2018年1月24日 0comments 1934hotness 0likes Jeff Read all
1…678910…26
Copyright Statement

Unauthorized reproduction or plagiarism in any form is strictly prohibited. For reprint requests, please contact via email.

Recent Comments
SanuyemScume Published at 3 hours ago(04 04202643002 03 03pm26) Localized microdontia is widespread, most incessan...
snail Published at 7 days ago(03 03202633105 27 27pm26) 多谢,大佬。醍醐灌顶!
dongxuh Published at 8 months ago(07 07202573103 27 27pm25) 真心不错的博客,有机会能一起分享
南南 Published at 9 months ago(07 07202573103 15 15pm25) 写的超棒!
Jeff Published at 11 months ago(05 05202553105 15 15pm25) 2025-03-12的提交已经支持了
Ad

COPYRIGHT © 2026 jianchihu.net. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang