{"id":3612,"date":"2025-11-19T18:17:01","date_gmt":"2025-11-19T10:17:01","guid":{"rendered":"http:\/\/www.51cos.com\/?p=3612"},"modified":"2025-11-19T18:28:02","modified_gmt":"2025-11-19T10:28:02","slug":"%e5%a6%82%e4%bd%95%e9%99%8d%e4%bd%8ev4l2rtspserver%e7%9a%84%e5%bb%b6%e6%97%b6%ef%bc%9f","status":"publish","type":"post","link":"http:\/\/www.51cos.com\/?p=3612","title":{"rendered":"\u5982\u4f55\u964d\u4f4ev4l2rtspserver\u7684\u5ef6\u65f6\uff1f"},"content":{"rendered":"<p>\u60a8\u60f3\u5728\u547d\u4ee4 <code>v4l2rtspserver -f H264 -W 1920 -H 1080 -F 60 -P 8554 \/dev\/video0<\/code> \u7684\u57fa\u7840\u4e0a\u8fdb\u4e00\u6b65\u4f18\u5316\u5ef6\u8fdf,\u5305\u62ec\u4fee\u6539\u6e90\u7801\u5c42\u9762\u7684\u7f13\u51b2\u7b56\u7565\u548c\u96f6\u62f7\u8d1d\u673a\u5236\u3002<\/p>\n<h2>\u547d\u4ee4\u884c\u4f18\u5316<\/h2>\n<p>\u9996\u5148,\u5728\u60a8\u7684\u547d\u4ee4\u57fa\u7840\u4e0a\u6dfb\u52a0\u4f4e\u5ef6\u8fdf\u53c2\u6570:<\/p>\n<pre><code class=\"language-bash line-numbers\">v4l2rtspserver -f H264 -W 1920 -H 1080 -F 60 -P 8554 -Q 1 -c \/dev\/video0 &amp;\n<\/code><\/pre>\n<ul>\n<li><code>-Q 1<\/code>: \u5c06\u5e27\u961f\u5217\u8bbe\u7f6e\u4e3a 1,\u6700\u5c0f\u5316\u7f13\u51b2 <a class=\"wp-editor-md-post-content-link\" href=\"#3-0\">1<\/a><\/li>\n<li><code>-c<\/code>: \u7981\u7528 SPS\/PPS \u914d\u7f6e\u5e27\u91cd\u590d <a class=\"wp-editor-md-post-content-link\" href=\"#3-1\">2<\/a><\/li>\n<\/ul>\n<h2>\u6e90\u7801\u7ea7\u4f18\u5316\u5efa\u8bae<\/h2>\n<h3>1. \u964d\u4f4e select() \u8d85\u65f6\u65f6\u95f4<\/h3>\n<p><strong>\u4f4d\u7f6e<\/strong>: <code>src\/V4L2DeviceSource.cpp:104-105<\/code> <a class=\"wp-editor-md-post-content-link\" href=\"#3-2\">3<\/a><\/p>\n<p>\u5f53\u524d\u6355\u83b7\u7ebf\u7a0b\u4f7f\u7528 1 \u79d2\u8d85\u65f6,\u8fd9\u4f1a\u589e\u52a0\u8f6e\u8be2\u5ef6\u8fdf\u3002 <a class=\"wp-editor-md-post-content-link\" href=\"#3-3\">4<\/a><\/p>\n<p><strong>\u4fee\u6539<\/strong>:<\/p>\n<pre><code class=\"language-cpp line-numbers\">tv.tv_sec=0;\ntv.tv_usec=1000;  \/\/ 1ms,\u66f4\u6fc0\u8fdb\u7684\u8f6e\u8be2\n<\/code><\/pre>\n<h3>2. \u4f18\u5316\u961f\u5217\u89e6\u53d1\u673a\u5236<\/h3>\n<p><strong>\u4f4d\u7f6e<\/strong>: <code>src\/V4L2DeviceSource.cpp:268-279<\/code> <a class=\"wp-editor-md-post-content-link\" href=\"#3-4\">5<\/a><\/p>\n<p>\u5f53\u524d\u5b9e\u73b0\u5728\u961f\u5217\u6ee1\u65f6\u624d\u4e22\u5f03\u65e7\u5e27\u3002\u5bf9\u4e8e <code>-Q 1<\/code> \u914d\u7f6e,\u53ef\u4ee5\u4fee\u6539\u4e3a\u7acb\u5373\u66ff\u6362\u7b56\u7565:<\/p>\n<p><strong>\u4fee\u6539<\/strong>:<\/p>\n<pre><code class=\"language-cpp line-numbers\">void V4L2DeviceSource::queueFrame(char * frame, int frameSize, const timeval &amp;tv, char * allocatedBuffer) \n{\n    pthread_mutex_lock (&amp;m_mutex);\n\n    \/\/ \u5bf9\u4e8e queueSize=1,\u76f4\u63a5\u66ff\u6362\u800c\u4e0d\u662f\u7b49\u5f85\u961f\u5217\u6ee1\n    if (m_queueSize == 1 &amp;&amp; !m_captureQueue.empty()) {\n        delete m_captureQueue.front();\n        m_captureQueue.pop_front();\n    }\n\n    while (m_captureQueue.size() &gt;= m_queueSize) {\n        delete m_captureQueue.front();\n        m_captureQueue.pop_front();\n    }\n\n    m_captureQueue.push_back(new Frame(frame, frameSize, tv, allocatedBuffer)); \n    pthread_mutex_unlock (&amp;m_mutex);\n\n    envir().taskScheduler().triggerEvent(m_eventTriggerId, this);\n}\n<\/code><\/pre>\n<h3>3. \u96f6\u62f7\u8d1d\u4f18\u5316\u5df2\u5b9e\u73b0<\/h3>\n<p>\u7cfb\u7edf\u5df2\u7ecf\u5b9e\u73b0\u4e86\u96f6\u62f7\u8d1d\u8bbe\u8ba1: <a class=\"wp-editor-md-post-content-link\" href=\"#3-5\">6<\/a><\/p>\n<ul>\n<li><code>splitFrames()<\/code> \u8fd4\u56de\u6307\u5411\u539f\u59cb\u7f13\u51b2\u533a\u7684\u6307\u9488,\u4e0d\u8fdb\u884c\u6570\u636e\u62f7\u8d1d <a class=\"wp-editor-md-post-content-link\" href=\"#3-6\">7<\/a><\/li>\n<li>\u53ea\u6709\u6700\u540e\u4e00\u4e2a\u5e27\u8d1f\u8d23\u91ca\u653e <code>allocatedBuffer<\/code> <a class=\"wp-editor-md-post-content-link\" href=\"#3-7\">8<\/a><\/li>\n<li>Frame \u7ed3\u6784\u4f53\u4f7f\u7528\u6307\u9488\u800c\u975e\u62f7\u8d1d <a class=\"wp-editor-md-post-content-link\" href=\"#3-8\">9<\/a><\/li>\n<\/ul>\n<h3>4. \u4f7f\u7528 MMAP \u800c\u975e READWRITE<\/h3>\n<p>\u786e\u4fdd\u4f7f\u7528\u5185\u5b58\u6620\u5c04\u6a21\u5f0f(\u9ed8\u8ba4),\u907f\u514d\u4f7f\u7528 <code>-r<\/code> \u53c2\u6570: <a class=\"wp-editor-md-post-content-link\" href=\"#3-9\">10<\/a><\/p>\n<p>MMAP \u6a21\u5f0f (<code>IOTYPE_MMAP<\/code>) \u63d0\u4f9b\u771f\u6b63\u7684\u96f6\u62f7\u8d1d,\u76f4\u63a5\u8bbf\u95ee\u5185\u6838\u7f13\u51b2\u533a\u3002<cite\/><\/p>\n<h3>5. \u589e\u5927 OutPacketBuffer \u5927\u5c0f<\/h3>\n<p><strong>\u4f4d\u7f6e<\/strong>: <code>inc\/DeviceSourceFactory.h:44-47<\/code> <a class=\"wp-editor-md-post-content-link\" href=\"#3-10\">11<\/a><\/p>\n<p>\u5bf9\u4e8e 1920&#215;1080@60fps H.264,\u53ef\u80fd\u9700\u8981\u66f4\u5927\u7684\u7f13\u51b2\u533a\u3002\u7cfb\u7edf\u5df2\u81ea\u52a8\u8c03\u6574,\u4f46\u53ef\u4ee5\u9884\u5148\u8bbe\u7f6e:<\/p>\n<p><strong>\u4fee\u6539<\/strong> (\u5728 <code>main.cpp<\/code> \u7684\u670d\u52a1\u5668\u521b\u5efa\u524d):<\/p>\n<pre><code class=\"language-cpp line-numbers\">\/\/ \u5728\u521b\u5efa replicator \u4e4b\u524d\nOutPacketBuffer::maxSize = 2000000;  \/\/ 2MB,\u9002\u5e94\u9ad8\u7801\u7387\n<\/code><\/pre>\n<h3>6. \u7981\u7528\u65e5\u5fd7\u8f93\u51fa<\/h3>\n<p>\u751f\u4ea7\u73af\u5883\u4e2d\u79fb\u9664 <code>-v<\/code> \u53c2\u6570,\u65e5\u5fd7 I\/O \u4f1a\u589e\u52a0\u5ef6\u8fdf: <a class=\"wp-editor-md-post-content-link\" href=\"#3-11\">12<\/a><\/p>\n<h3>7. \u4f7f\u7528\u975e\u963b\u585e\u6a21\u5f0f<\/h3>\n<p>\u786e\u4fdd\u4e0d\u4f7f\u7528 <code>-B<\/code> \u53c2\u6570,\u4fdd\u6301\u975e\u963b\u585e\u6a21\u5f0f: <a class=\"wp-editor-md-post-content-link\" href=\"#3-12\">13<\/a><\/p>\n<p>\u975e\u963b\u585e\u6a21\u5f0f (<code>O_NONBLOCK<\/code>) \u907f\u514d I\/O \u7b49\u5f85\u3002<cite\/><\/p>\n<h3>8. \u4f18\u5316 H.264 \u89e3\u6790<\/h3>\n<p><strong>\u4f4d\u7f6e<\/strong>: H.264 \u89e3\u6790\u5728 <code>H264_V4L2DeviceSource::splitFrames()<\/code> \u4e2d\u8fdb\u884c <a class=\"wp-editor-md-post-content-link\" href=\"#3-13\">14<\/a><\/p>\n<p>\u4f7f\u7528 <code>-c<\/code> \u53c2\u6570\u5df2\u7ecf\u7981\u7528\u4e86\u914d\u7f6e\u5e27\u91cd\u590d,\u8fd9\u662f\u6700\u4f18\u914d\u7f6e\u3002\u7cfb\u7edf\u4f1a\u81ea\u52a8\u68c0\u6d4b H.264 \u683c\u5f0f\u5e76\u4f7f\u7528\u4e13\u7528\u6e90: <a class=\"wp-editor-md-post-content-link\" href=\"#3-14\">15<\/a><\/p>\n<h2>\u5b8c\u6574\u4f18\u5316\u547d\u4ee4<\/h2>\n<pre><code class=\"language-bash line-numbers\">v4l2rtspserver -f H264 -W 1920 -H 1080 -F 60 -P 8554 -Q 1 -c -t 5 \/dev\/video0 &amp;\n<\/code><\/pre>\n<p>\u53c2\u6570\u8bf4\u660e:<br \/>\n&#8211; <code>-Q 1<\/code>: \u6700\u5c0f\u961f\u5217<br \/>\n&#8211; <code>-c<\/code>: \u7981\u7528\u914d\u7f6e\u91cd\u590d<br \/>\n&#8211; <code>-t 5<\/code>: \u964d\u4f4e RTCP \u8d85\u65f6\u5230 5 \u79d2<\/p>\n<h2>\u6027\u80fd\u9a8c\u8bc1<\/h2>\n<p>\u4f7f\u7528\u8be6\u7ec6\u65e5\u5fd7\u6d4b\u91cf\u5b9e\u9645\u5ef6\u8fdf:<\/p>\n<pre><code class=\"language-bash line-numbers\">v4l2rtspserver -vv -f H264 -W 1920 -H 1080 -F 60 -P 8554 -Q 1 -c \/dev\/video0\n<\/code><\/pre>\n<p>\u67e5\u770b <code>diff:<\/code> \u5b57\u6bb5\u663e\u793a\u7684\u6beb\u79d2\u5ef6\u8fdf\u3002 <a class=\"wp-editor-md-post-content-link\" href=\"#3-15\">16<\/a><\/p>\n<h2>Notes<\/h2>\n<ul>\n<li>\u7cfb\u7edf\u5df2\u7ecf\u5b9e\u73b0\u4e86\u96f6\u62f7\u8d1d\u8bbe\u8ba1,\u901a\u8fc7 MMAP \u548c\u6307\u9488\u4f20\u9012\u5b9e\u73b0<\/li>\n<li>\u4e3b\u8981\u4f18\u5316\u70b9\u662f\u961f\u5217\u5927\u5c0f\u548c\u8f6e\u8be2\u8d85\u65f6<\/li>\n<li>60fps \u9ad8\u5e27\u7387\u4e0b,\u7f51\u7edc\u5e26\u5bbd\u548c\u5ba2\u6237\u7aef\u89e3\u7801\u80fd\u529b\u4e5f\u662f\u5173\u952e\u56e0\u7d20<\/li>\n<li>\u5efa\u8bae\u5ba2\u6237\u7aef\u4f7f\u7528 <code>ffplay -fflags nobuffer -flags low_delay<\/code> \u6216 VLC \u7684 <code>--network-caching=0<\/code> \u53c2\u6570<\/li>\n<\/ul>\n<p>Wiki pages you might want to explore:<br \/>\n&#8211; <a class=\"wp-editor-md-post-content-link\" href=\"\/wiki\/mpromonet\/v4l2rtspserver#10.1\">Source Code Organization (mpromonet\/v4l2rtspserver)<\/a><br \/>\n&#8211; <a class=\"wp-editor-md-post-content-link\" href=\"\/wiki\/mpromonet\/v4l2rtspserver#3\">Architecture (mpromonet\/v4l2rtspserver)<\/a><br \/>\n&#8211; <a class=\"wp-editor-md-post-content-link\" href=\"\/wiki\/mpromonet\/v4l2rtspserver#7.1\">Video Capture and Processing (mpromonet\/v4l2rtspserver)<\/a><\/p>\n<h3>Citations<\/h3>\n<p><strong>File:<\/strong> main.cpp (L80-80)<\/p>\n<pre><code class=\"language-cpp line-numbers\">    int queueSize = 5;\n<\/code><\/pre>\n<p><strong>File:<\/strong> main.cpp (L87-87)<\/p>\n<pre><code class=\"language-cpp line-numbers\">    V4l2IoType ioTypeIn  = IOTYPE_MMAP;\n<\/code><\/pre>\n<p><strong>File:<\/strong> main.cpp (L89-89)<\/p>\n<pre><code class=\"language-cpp line-numbers\">    int openflags = O_RDWR | O_NONBLOCK; \n<\/code><\/pre>\n<p><strong>File:<\/strong> main.cpp (L95-95)<\/p>\n<pre><code class=\"language-cpp line-numbers\">    bool repeatConfig = true;\n<\/code><\/pre>\n<p><strong>File:<\/strong> src\/V4L2DeviceSource.cpp (L100-106)<\/p>\n<pre><code class=\"language-cpp line-numbers\">    while (!stop) \n    {\n        int fd = m_device-&gt;getFd();\n        FD_SET(fd, &amp;fdset);\n        tv.tv_sec=1;\n        tv.tv_usec=0;   \n        int ret = select(fd+1, &amp;fdset, NULL, NULL, &amp;tv);\n<\/code><\/pre>\n<p><strong>File:<\/strong> src\/V4L2DeviceSource.cpp (L164-167)<\/p>\n<pre><code class=\"language-cpp line-numbers\">            timeval diff;\n            timersub(&amp;curTime,&amp;(frame-&gt;m_timestamp),&amp;diff);\n\n            LOG(DEBUG) &lt;&lt; \"deliverFrame\\ttimestamp:\" &lt;&lt; curTime.tv_sec &lt;&lt; \".\" &lt;&lt; curTime.tv_usec &lt;&lt; \"\\tsize:\" &lt;&lt; fFrameSize &lt;&lt;\"\\tdiff:\" &lt;&lt;  (diff.tv_sec*1000+diff.tv_usec\/1000) &lt;&lt; \"ms\\tqueue:\" &lt;&lt; m_captureQueue.size();      \n<\/code><\/pre>\n<p><strong>File:<\/strong> src\/V4L2DeviceSource.cpp (L241-262)<\/p>\n<pre><code class=\"language-cpp line-numbers\">void V4L2DeviceSource::processFrame(char * frame, int frameSize, const timeval &amp;ref) \n{\n    timeval tv;\n    gettimeofday(&amp;tv, NULL);                                                \n    timeval diff;\n    timersub(&amp;tv,&amp;ref,&amp;diff);\n\n    std::list&lt; std::pair&lt;unsigned char*,size_t&gt; &gt; frameList = this-&gt;splitFrames((unsigned char*)frame, frameSize);\n    while (!frameList.empty())\n    {\n        std::pair&lt;unsigned char*,size_t&gt;&amp; item = frameList.front();\n        size_t size = item.second;\n        char* allocatedBuffer = NULL;\n        if (frameList.size() == 1) {\n            \/\/ last frame will release buffer\n            allocatedBuffer = frame;\n        }\n        queueFrame((char*)item.first,size,ref,allocatedBuffer);\n        frameList.pop_front();\n\n        LOG(DEBUG) &lt;&lt; \"queueFrame\\ttimestamp:\" &lt;&lt; ref.tv_sec &lt;&lt; \".\" &lt;&lt; ref.tv_usec &lt;&lt; \"\\tsize:\" &lt;&lt; size &lt;&lt;\"\\tdiff:\" &lt;&lt;  (diff.tv_sec*1000+diff.tv_usec\/1000) &lt;&lt; \"ms\";       \n    }           \n<\/code><\/pre>\n<p><strong>File:<\/strong> src\/V4L2DeviceSource.cpp (L268-279)<\/p>\n<pre><code class=\"language-cpp line-numbers\">    pthread_mutex_lock (&amp;m_mutex);\n    while (m_captureQueue.size() &gt;= m_queueSize)\n    {\n        LOG(DEBUG) &lt;&lt; \"Queue full size drop frame size:\"  &lt;&lt; (int)m_captureQueue.size() ;       \n        delete m_captureQueue.front();\n        m_captureQueue.pop_front();\n    }\n    m_captureQueue.push_back(new Frame(frame, frameSize, tv, allocatedBuffer)); \n    pthread_mutex_unlock (&amp;m_mutex);\n\n    \/\/ post an event to ask to deliver the frame\n    envir().taskScheduler().triggerEvent(m_eventTriggerId, this);\n<\/code><\/pre>\n<p><strong>File:<\/strong> inc\/V4L2DeviceSource.h (L36-47)<\/p>\n<pre><code class=\"language-text line-numbers\">        struct Frame\n        {\n            Frame(char* buffer, int size, timeval timestamp, char * allocatedBuffer = NULL) : m_buffer(buffer), m_size(size), m_timestamp(timestamp), m_allocatedBuffer(allocatedBuffer) {};\n            Frame(const Frame&amp;);\n            Frame&amp; operator=(const Frame&amp;);\n            ~Frame()  { delete [] m_allocatedBuffer; };\n\n            char* m_buffer;\n            unsigned int m_size;\n            timeval m_timestamp;\n            char* m_allocatedBuffer;\n        };\n<\/code><\/pre>\n<p><strong>File:<\/strong> inc\/DeviceSourceFactory.h (L24-26)<\/p>\n<pre><code class=\"language-text line-numbers\">            if (format == V4L2_PIX_FMT_H264)\n            {\n                source = H264_V4L2DeviceSource::createNew(*env, devCapture, outfd, queueSize, captureMode, repeatConfig, false);\n<\/code><\/pre>\n<p><strong>File:<\/strong> inc\/DeviceSourceFactory.h (L44-47)<\/p>\n<pre><code class=\"language-text line-numbers\">                \/\/ extend buffer size if needed\n                if (devCapture-&gt;getBufferSize() &gt; OutPacketBuffer::maxSize)\n                {\n                    OutPacketBuffer::maxSize = devCapture-&gt;getBufferSize();\n<\/code><\/pre>\n<p><strong>File:<\/strong> inc\/H264_V4l2DeviceSource.h (L30-30)<\/p>\n<pre><code class=\"language-text line-numbers\">        virtual std::list&lt; std::pair&lt;unsigned char*,size_t&gt; &gt; splitFrames(unsigned char* frame, unsigned frameSize);\n<\/code><\/pre>\n<pre><code class=\"language-bash line-numbers\">.\/v4l2rtspserver -Q 1 -c \/dev\/video0\n<\/code><\/pre>\n<p>-Q 1: \u5c06\u5e27\u961f\u5217\u8bbe\u7f6e\u4e3a 1,\u6700\u5c0f\u5316\u7f13\u51b2\u5ef6\u8fdf<br \/>\n-c: \u7981\u7528 SPS\/PPS \u914d\u7f6e\u5e27\u91cd\u590d,\u51cf\u5c11\u6570\u636e\u91cf<\/p>\n<p>\u60a8\u7684\u9700\u6c42\u662f\u4f7f\u7528 v4l2rtspserver \u4ece UVC H.264 \u6444\u50cf\u5934\u8bfb\u53d6\u5e76\u8f6c\u53d1\u89c6\u9891\u6570\u636e,\u65e0\u9700\u91cd\u65b0\u7f16\u7801,\u5e76\u5b9e\u73b0\u6700\u4f4e\u5ef6\u8fdf\u3002<cite\/><\/p>\n<h2>\u6838\u5fc3\u914d\u7f6e<\/h2>\n<p>v4l2rtspserver \u5df2\u7ecf\u539f\u751f\u652f\u6301 H.264 \u76f4\u901a(passthrough)\u6a21\u5f0f,\u65e0\u9700\u91cd\u65b0\u7f16\u7801\u3002 <a class=\"wp-editor-md-post-content-link\" href=\"#1-0\">1<\/a>  \u7cfb\u7edf\u4f1a\u81ea\u52a8\u68c0\u6d4b H.264 \u683c\u5f0f\u5e76\u4f7f\u7528 <code>H264_V4L2DeviceSource<\/code> \u8fdb\u884c\u5904\u7406\u3002 <a class=\"wp-editor-md-post-content-link\" href=\"#1-1\">2<\/a><\/p>\n<h3>\u63a8\u8350\u7684\u542f\u52a8\u547d\u4ee4<\/h3>\n<pre><code class=\"language-bash line-numbers\">.\/v4l2rtspserver -Q 1 -c \/dev\/video0\n<\/code><\/pre>\n<p>\u53c2\u6570\u8bf4\u660e:<br \/>\n&#8211; <code>-Q 1<\/code>: \u5c06\u5e27\u961f\u5217\u8bbe\u7f6e\u4e3a 1,\u6700\u5c0f\u5316\u7f13\u51b2\u5ef6\u8fdf <a class=\"wp-editor-md-post-content-link\" href=\"#1-2\">3<\/a><br \/>\n&#8211; <code>-c<\/code>: \u7981\u7528 SPS\/PPS \u914d\u7f6e\u5e27\u91cd\u590d,\u51cf\u5c11\u6570\u636e\u91cf <a class=\"wp-editor-md-post-content-link\" href=\"#1-3\">4<\/a><\/p>\n<h2>\u4ee3\u7801\u5c42\u9762\u7684\u4f18\u5316<\/h2>\n<h3>1. \u964d\u4f4e select() \u8d85\u65f6\u65f6\u95f4<\/h3>\n<p>\u5728 <code>src\/V4L2DeviceSource.cpp<\/code> \u7684\u6355\u83b7\u7ebf\u7a0b\u4e2d,<code>select()<\/code> \u8d85\u65f6\u8bbe\u7f6e\u4e3a 1 \u79d2: <a class=\"wp-editor-md-post-content-link\" href=\"#1-4\">5<\/a><\/p>\n<p><strong>\u4fee\u6539\u5efa\u8bae<\/strong>: \u5c06 <code>tv.tv_sec=1<\/code> \u6539\u4e3a <code>tv.tv_sec=0<\/code> \u548c <code>tv.tv_usec=10000<\/code> (10ms),\u51cf\u5c11\u8f6e\u8be2\u5ef6\u8fdf:<\/p>\n<pre><code class=\"language-cpp line-numbers\">tv.tv_sec=0;\ntv.tv_usec=10000;  \/\/ 10ms\n<\/code><\/pre>\n<h3>2. \u7981\u7528\u914d\u7f6e\u5e27\u91cd\u590d\u903b\u8f91<\/h3>\n<p>H.264 \u5904\u7406\u4e2d,\u7cfb\u7edf\u4f1a\u5728 IDR \u5e27\u524d\u63d2\u5165 SPS\/PPS: <a class=\"wp-editor-md-post-content-link\" href=\"#1-5\">6<\/a><\/p>\n<p>\u4f7f\u7528 <code>-c<\/code> \u53c2\u6570\u53ef\u4ee5\u7981\u7528\u6b64\u529f\u80fd,\u4f46\u5982\u679c\u9700\u8981\u5728\u4ee3\u7801\u5c42\u9762\u5f3a\u5236\u7981\u7528,\u53ef\u4ee5\u5728\u521b\u5efa <code>H264_V4L2DeviceSource<\/code> \u65f6\u5c06 <code>repeatConfig<\/code> \u53c2\u6570\u8bbe\u4e3a <code>false<\/code>: <a class=\"wp-editor-md-post-content-link\" href=\"#1-6\">7<\/a><\/p>\n<h3>3. \u961f\u5217\u7ba1\u7406\u4f18\u5316<\/h3>\n<p>\u5f53\u961f\u5217\u6ee1\u65f6,\u7cfb\u7edf\u4f1a\u4e22\u5f03\u6700\u65e7\u7684\u5e27: <a class=\"wp-editor-md-post-content-link\" href=\"#1-7\">8<\/a><\/p>\n<p>\u5bf9\u4e8e\u8d85\u4f4e\u5ef6\u8fdf\u573a\u666f,\u53ef\u4ee5\u8003\u8651\u4fee\u6539\u961f\u5217\u903b\u8f91,\u5728\u961f\u5217\u6709\u6570\u636e\u65f6\u7acb\u5373\u89e6\u53d1\u53d1\u9001,\u800c\u4e0d\u662f\u7b49\u5f85\u961f\u5217\u586b\u6ee1\u3002<\/p>\n<h2>H.264 \u6570\u636e\u6d41\u5904\u7406<\/h2>\n<p>v4l2rtspserver \u5bf9 H.264 \u7684\u5904\u7406\u6d41\u7a0b:<\/p>\n<ol>\n<li><strong>NAL \u5355\u5143\u89e3\u6790<\/strong>: \u7cfb\u7edf\u4f1a\u89e3\u6790 H.264 NAL \u5355\u5143,\u8bc6\u522b SPS(\u7c7b\u578b 7)\u3001PPS(\u7c7b\u578b 8)\u548c IDR \u5e27(\u7c7b\u578b 5) <a class=\"wp-editor-md-post-content-link\" href=\"#1-8\">9<\/a><\/p>\n<\/li>\n<li>\n<p><strong>SDP \u53c2\u6570\u751f\u6210<\/strong>: \u81ea\u52a8\u63d0\u53d6 SPS\/PPS \u5e76\u751f\u6210 Base64 \u7f16\u7801\u7684 SDP \u53c2\u6570 <a class=\"wp-editor-md-post-content-link\" href=\"#1-9\">10<\/a><\/p>\n<\/li>\n<li>\n<p><strong>RTP \u5c01\u88c5<\/strong>: \u4f7f\u7528 Live555 \u7684 <code>H264VideoRTPSink<\/code> \u8fdb\u884c RTP \u5c01\u88c5 <a class=\"wp-editor-md-post-content-link\" href=\"#1-10\">11<\/a><\/p>\n<\/li>\n<\/ol>\n<p>\u6574\u4e2a\u8fc7\u7a0b<strong>\u4e0d\u6d89\u53ca\u91cd\u65b0\u7f16\u7801<\/strong>,\u53ea\u662f\u5bf9 H.264 \u7801\u6d41\u8fdb\u884c\u89e3\u6790\u548c RTP \u5c01\u88c5\u3002<cite\/><\/p>\n<h2>\u9a8c\u8bc1\u5ef6\u8fdf<\/h2>\n<p>\u542f\u7528\u8be6\u7ec6\u65e5\u5fd7\u67e5\u770b\u5b9e\u9645\u5ef6\u8fdf:<\/p>\n<pre><code class=\"language-bash line-numbers\">.\/v4l2rtspserver -vv -Q 1 -c \/dev\/video0\n<\/code><\/pre>\n<p>\u65e5\u5fd7\u4f1a\u663e\u793a\u6bcf\u5e27\u7684\u65f6\u95f4\u6233\u5dee\u5f02: <a class=\"wp-editor-md-post-content-link\" href=\"#1-11\">12<\/a><\/p>\n<h2>Notes<\/h2>\n<ul>\n<li>v4l2rtspserver \u539f\u751f\u652f\u6301 H.264 \u76f4\u901a,\u65e0\u9700\u4efb\u4f55\u7f16\u7801\u914d\u7f6e<\/li>\n<li>\u4e3b\u8981\u5ef6\u8fdf\u6765\u6e90\u662f\u5e27\u961f\u5217\u7f13\u51b2\u548c\u7f51\u7edc\u4f20\u8f93<\/li>\n<li>\u5ba2\u6237\u7aef\u64ad\u653e\u5668\u7684\u7f13\u51b2\u7b56\u7565\u4e5f\u4f1a\u5f71\u54cd\u7aef\u5230\u7aef\u5ef6\u8fdf,\u5efa\u8bae\u4f7f\u7528\u4f4e\u5ef6\u8fdf\u64ad\u653e\u5668\u5982 VLC (\u4f7f\u7528 <code>--network-caching=0<\/code> \u53c2\u6570)<\/li>\n<li>UVC \u6444\u50cf\u5934\u672c\u8eab\u7684\u7f16\u7801\u5ef6\u8fdf\u65e0\u6cd5\u901a\u8fc7 v4l2rtspserver \u4f18\u5316<\/li>\n<\/ul>\n<p>Wiki pages you might want to explore:<br \/>\n&#8211; <a class=\"wp-editor-md-post-content-link\" href=\"\/wiki\/mpromonet\/v4l2rtspserver#7.1\">Video Capture and Processing (mpromonet\/v4l2rtspserver)<\/a><br \/>\n&#8211; <a class=\"wp-editor-md-post-content-link\" href=\"\/wiki\/mpromonet\/v4l2rtspserver#7.3\">Format Support and Codec Handling (mpromonet\/v4l2rtspserver)<\/a><\/p>\n<h3>Citations<\/h3>\n<p><strong>File:<\/strong> inc\/H264_V4l2DeviceSource.h (L18-23)<\/p>\n<pre><code class=\"language-text line-numbers\">class H264_V4L2DeviceSource : public H26X_V4L2DeviceSource\n{\n    public:             \n        static H264_V4L2DeviceSource* createNew(UsageEnvironment&amp; env, DeviceInterface * device, int outputFd, unsigned int queueSize, CaptureMode captureMode, bool repeatConfig, bool keepMarker) {\n            return new H264_V4L2DeviceSource(env, device, outputFd, queueSize, captureMode, repeatConfig, keepMarker);\n        }\n<\/code><\/pre>\n<p><strong>File:<\/strong> inc\/DeviceSourceFactory.h (L22-27)<\/p>\n<pre><code class=\"language-text line-numbers\">        static FramedSource* createFramedSource(UsageEnvironment* env, int format, DeviceInterface* devCapture, int queueSize = 5, V4L2DeviceSource::CaptureMode captureMode = V4L2DeviceSource::CAPTURE_INTERNAL_THREAD, int outfd = -1, bool repeatConfig = true) {\n            FramedSource* source = NULL;\n            if (format == V4L2_PIX_FMT_H264)\n            {\n                source = H264_V4L2DeviceSource::createNew(*env, devCapture, outfd, queueSize, captureMode, repeatConfig, false);\n            }\n<\/code><\/pre>\n<p><strong>File:<\/strong> inc\/V4L2DeviceSource.h (L114-120)<\/p>\n<pre><code class=\"language-text line-numbers\">        std::list&lt;Frame*&gt; m_captureQueue;\n        Stats m_in;\n        Stats m_out;\n        EventTriggerId m_eventTriggerId;\n        int m_outfd;\n        DeviceInterface * m_device;\n        unsigned int m_queueSize;\n<\/code><\/pre>\n<p><strong>File:<\/strong> src\/H264_V4l2DeviceSource.cpp (L37-60)<\/p>\n<pre><code class=\"language-cpp line-numbers\">        switch (frameType&amp;0x1F)                 \n        {\n            case 7: LOG(INFO) &lt;&lt; \"SPS size:\" &lt;&lt; size &lt;&lt; \" bufSize:\" &lt;&lt; bufSize; m_sps.assign((char*)buffer,size); m_pps.clear(); break;\n            case 8: LOG(INFO) &lt;&lt; \"PPS size:\" &lt;&lt; size &lt;&lt; \" bufSize:\" &lt;&lt; bufSize; m_pps.assign((char*)buffer,size); break;\n            case 5: LOG(INFO) &lt;&lt; \"IDR size:\" &lt;&lt; size &lt;&lt; \" bufSize:\" &lt;&lt; bufSize; \n                if (m_repeatConfig &amp;&amp; !m_sps.empty() &amp;&amp; !m_pps.empty())\n                {\n                    frameList.push_back(std::pair&lt;unsigned char*,size_t&gt;((unsigned char*)m_sps.c_str(), m_sps.size()));\n                    frameList.push_back(std::pair&lt;unsigned char*,size_t&gt;((unsigned char*)m_pps.c_str(), m_pps.size()));\n                }\n                if (!m_sps.empty() &amp;&amp; !m_pps.empty()) {\n                    pthread_mutex_lock (&amp;m_lastFrameMutex);\n                    m_lastFrame.assign(H264marker, sizeof(H264marker));\n                    m_lastFrame.append(m_sps.c_str(), m_sps.size());\n                    m_lastFrame.append(H264marker, sizeof(H264marker));\n                    m_lastFrame.append(m_pps.c_str(), m_pps.size());\n                    m_lastFrame.append(H264marker, sizeof(H264marker));\n                    m_lastFrame.append((char*)buffer, size);\n                    pthread_mutex_unlock (&amp;m_lastFrameMutex);\n                }\n            break;\n            default: \n                break;\n        }\n<\/code><\/pre>\n<p><strong>File:<\/strong> src\/H264_V4l2DeviceSource.cpp (L64-77)<\/p>\n<pre><code class=\"language-cpp line-numbers\">            u_int32_t profile_level_id = 0;                 \n            if (m_sps.size() &gt;= 4) profile_level_id = (((unsigned char)m_sps[1])&lt;&lt;16)|(((unsigned char)m_sps[2])&lt;&lt;8)|((unsigned char)m_sps[3]); \n\n            char* sps_base64 = base64Encode(m_sps.c_str(), m_sps.size());\n            char* pps_base64 = base64Encode(m_pps.c_str(), m_pps.size());       \n\n            std::ostringstream os; \n            os &lt;&lt; \"profile-level-id=\" &lt;&lt; std::hex &lt;&lt; std::setw(6) &lt;&lt; std::setfill('0') &lt;&lt; profile_level_id;\n            os &lt;&lt; \";sprop-parameter-sets=\" &lt;&lt; sps_base64 &lt;&lt;\",\" &lt;&lt; pps_base64;\n            m_auxLine.assign(os.str());\n\n            delete [] sps_base64;\n            delete [] pps_base64;\n        }\n<\/code><\/pre>\n<p><strong>File:<\/strong> src\/V4L2DeviceSource.cpp (L102-106)<\/p>\n<pre><code class=\"language-cpp line-numbers\">        int fd = m_device-&gt;getFd();\n        FD_SET(fd, &amp;fdset);\n        tv.tv_sec=1;\n        tv.tv_usec=0;   \n        int ret = select(fd+1, &amp;fdset, NULL, NULL, &amp;tv);\n<\/code><\/pre>\n<p><strong>File:<\/strong> src\/V4L2DeviceSource.cpp (L142-152)<\/p>\n<pre><code class=\"language-cpp line-numbers\">        pthread_mutex_lock (&amp;m_mutex);\n        if (m_captureQueue.empty())\n        {\n            LOG(DEBUG) &lt;&lt; \"Queue is empty\";     \n        }\n        else\n        {               \n            timeval curTime;\n            gettimeofday(&amp;curTime, NULL);           \n            Frame * frame = m_captureQueue.front();\n            m_captureQueue.pop_front();\n<\/code><\/pre>\n<p><strong>File:<\/strong> src\/V4L2DeviceSource.cpp (L164-167)<\/p>\n<pre><code class=\"language-cpp line-numbers\">            timeval diff;\n            timersub(&amp;curTime,&amp;(frame-&gt;m_timestamp),&amp;diff);\n\n            LOG(DEBUG) &lt;&lt; \"deliverFrame\\ttimestamp:\" &lt;&lt; curTime.tv_sec &lt;&lt; \".\" &lt;&lt; curTime.tv_usec &lt;&lt; \"\\tsize:\" &lt;&lt; fFrameSize &lt;&lt;\"\\tdiff:\" &lt;&lt;  (diff.tv_sec*1000+diff.tv_usec\/1000) &lt;&lt; \"ms\\tqueue:\" &lt;&lt; m_captureQueue.size();      \n<\/code><\/pre>\n<p><strong>File:<\/strong> src\/ServerMediaSubsession.cpp (L55-58)<\/p>\n<pre><code class=\"language-cpp line-numbers\">    else if (format == \"video\/H264\")\n        {\n        videoSink = H264VideoRTPSink::createNew(env, rtpGroupsock,rtpPayloadTypeIfDynamic);\n    }\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>\u60a8\u60f3\u5728\u547d\u4ee4 v4l2rtspserver -f H264 -W 1920 -H 1080 -F 60 -P 8 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[22],"tags":[],"class_list":["post-3612","post","type-post","status-publish","format-standard","hentry","category-plana"],"_links":{"self":[{"href":"http:\/\/www.51cos.com\/index.php?rest_route=\/wp\/v2\/posts\/3612","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.51cos.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.51cos.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.51cos.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.51cos.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3612"}],"version-history":[{"count":4,"href":"http:\/\/www.51cos.com\/index.php?rest_route=\/wp\/v2\/posts\/3612\/revisions"}],"predecessor-version":[{"id":3616,"href":"http:\/\/www.51cos.com\/index.php?rest_route=\/wp\/v2\/posts\/3612\/revisions\/3616"}],"wp:attachment":[{"href":"http:\/\/www.51cos.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3612"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.51cos.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3612"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.51cos.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3612"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}