<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="rss.xsl"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>SRS Blog</title>
        <link>https://ossrs.io/lts/zh-cn/blog</link>
        <description>SRS Blog</description>
        <lastBuildDate>Sun, 04 Oct 2026 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>zh-cn</language>
        <item>
            <title><![CDATA[SRS - 我两周没搞定的ST，AI九小时全自动搞定了]]></title>
            <link>https://ossrs.io/lts/zh-cn/blog/ai-autopilot</link>
            <guid>https://ossrs.io/lts/zh-cn/blog/ai-autopilot</guid>
            <pubDate>Sun, 04 Oct 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[AI现在可以连续几个小时全自动开发SRS，代码质量不仅没有变差，反而更好了。AI写的代码大部分是测试，而不是功能，这些测试正是我们能信任AI的原因。]]></description>
            <content:encoded><![CDATA[<p>AI现在可以连续几个小时全自动开发SRS，代码质量不仅没有变差，反而更好了。AI写的代码大部分是测试，而不是功能，这些测试正是我们能信任AI的原因。</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-bug-i-gave-up-on">A Bug I Gave Up On<a href="https://ossrs.io/lts/zh-cn/blog/ai-autopilot#a-bug-i-gave-up-on" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>大约两年前，我把SRS底层的协程库State Threads（ST）通过Cygwin移植到Windows。协程切换没问题，但只要开启SRT，SRS就会崩溃。查了两周，才找到原因：SRT使用了C++异常，而Windows上的C++异常是基于SEH实现的，SEH依赖一些寄存器，协程切换时必须保存和恢复这些寄存器。我找不到足够的资料说明这些寄存器，最终只好放弃了。</p>
<p>最近我拿同样的问题问AI，它6分钟就写了一个测试程序，说已经解决了。然后我用一个新的Skill，<code>srs-autopilot</code>，让它全自动运行。九个小时后，它把ST移植到了原生Windows平台，没有用Cygwin，C++异常的测试也通过了。</p>
<p>这是AI第一次解决了我没解决的问题。但快并不是最有意思的地方。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-real-question-is-trust">The Real Question Is Trust<a href="https://ossrs.io/lts/zh-cn/blog/ai-autopilot#the-real-question-is-trust" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>让AI无人监督地运行很容易：Claude有<code>--dangerously-skip-permissions</code>参数，Codex有<code>--yolo</code>参数。你可以让AI把SRS用Go或Rust重写，甚至还能跑起来。但这真的是同一个SRS吗？还能继续维护吗？敢上线吗？</p>
<p>人写的代码，如果变更比较小，有测试，而且有人做Code Review，一般就可以放心上线。AI的变更从来都不小，也没人能逐行Review这么多代码。剩下唯一真正的保障，就是非常完整的测试。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="most-of-what-ai-writes-is-tests">Most of What AI Writes Is Tests<a href="https://ossrs.io/lts/zh-cn/blog/ai-autopilot#most-of-what-ai-writes-is-tests" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>以AI最近实现的一个功能为例：WebRTC的RFC 4588 RTX，提交<a href="https://github.com/ossrs/srs/commit/3fc1810a46870d9bb5341986e16b26b70a91a58f" target="_blank" rel="noopener noreferrer" class="">3fc1810a4</a>（<a href="https://github.com/ossrs/srs/pull/4746" target="_blank" rel="noopener noreferrer" class="">#4746</a>），新增了8928行代码：</p>
<table><thead><tr><th>部分</th><th style="text-align:right">新增行数</th><th style="text-align:right">占比</th></tr></thead><tbody><tr><td><code>trunk/src</code>中的功能代码</td><td style="text-align:right">451</td><td style="text-align:right">5.1%</td></tr><tr><td><code>trunk/src/utest</code>中的C++单元测试</td><td style="text-align:right">2245</td><td style="text-align:right">25.1%</td></tr><tr><td><code>trunk/3rdparty/srs-bench</code>中的Go集成测试</td><td style="text-align:right">819</td><td style="text-align:right">9.2%</td></tr><tr><td><code>skills/srs-develop/scripts</code>中的端到端测试脚本</td><td style="text-align:right">1823</td><td style="text-align:right">20.4%</td></tr><tr><td><code>tools/pion-whip</code>和<code>tools/pion-whep</code>中的WHIP和WHEP测试工具，包括工具自身的单元测试</td><td style="text-align:right">3423</td><td style="text-align:right">38.3%</td></tr><tr><td>配置、文档和其他</td><td style="text-align:right">167</td><td style="text-align:right">1.9%</td></tr></tbody></table>
<p>测试和测试工具共8310行，占这次变更的93.1%，用来证明451行功能代码是正确的：每一行功能代码，大约有18行测试。没有哪个人类维护者是这样工作的。人一般是先写功能，有时间再补几个测试。AI先写测试，而且覆盖所有情况，因为对它来说，写测试几乎没有成本。</p>
<p>ST也是一样：AI把它的测试覆盖率从45%提升到了96%，还为它的关键功能增加了集成测试。</p>
<p>这些测试并不是凑数的测试。人给已有代码补测试时，测试往往会重复代码的错误：代码是错的，测试也认为它是对的。AI可以对照文档、RFC和其他实现来检查代码，所以它写的测试能真正找到bug。SRS的很多bug就是这样找到的。即使是解决bug，也要先写一个测试证明这个bug存在，否则可能解决的是一个并不存在的问题。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="tests-must-be-local-and-fast">Tests Must Be Local and Fast<a href="https://ossrs.io/lts/zh-cn/blog/ai-autopilot#tests-must-be-local-and-fast" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>保证AI正确的测试，必须能在本地运行。用GitHub Actions测试一次变更，每轮至少要20分钟。在本地，全部测试只需要大约1分钟，而且AI能看到所有的结果，所以它能很快发现并纠正自己的错误。</p>
<p>只有单元测试是不够的，功能和接口需要真正的集成测试。SRS有回归测试、黑盒测试和脚本测试，它们会启动真实的SRS，用FFmpeg和SRS Bench等工具来测试。以前跑一轮完整的测试要20分钟；改进了端口分配之后，多个SRS可以并行运行，跑完一轮只要1分钟。缺少工具时，就让AI自己写。RTX提交中的WHIP和WHEP测试工具，就是AI写的。</p>
<p>有了这些测试，我可以放心地合并AI的大变更。没有这些测试，就只能祈祷模型永远不犯错误。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="testable-code-is-maintainable-code">Testable Code Is Maintainable Code<a href="https://ossrs.io/lts/zh-cn/blog/ai-autopilot#testable-code-is-maintainable-code" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>要测试所有代码，代码就必须能被Mock：依赖接口，而不是依赖实现。现在SRS的每个类都实现了一个接口，而且只依赖其他接口，所以测试可以把任何依赖替换成Mock对象，完全控制它。</p>
<p>这次重构改动了大量的代码，非常无聊，没有人愿意主动去做。AI做了。结果是代码更容易理解、测试和修改，无论对AI还是对人。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="skills-turn-the-process-into-rules">Skills Turn the Process into Rules<a href="https://ossrs.io/lts/zh-cn/blog/ai-autopilot#skills-turn-the-process-into-rules" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>只有测试还不够，AI还需要定义好的工作流。SRS把工作流写成了Skill，放在<a href="https://github.com/ossrs/srs/tree/develop/skills" target="_blank" rel="noopener noreferrer" class="">skills</a>目录中：</p>
<ul>
<li class=""><code>srs-develop</code>是代码和文档的索引，AI不用搜索整个项目就能找到正确的文件，也不会让无关的内容填满上下文。它还要求测试驱动开发：先写测试，再写代码。</li>
<li class=""><code>srs-autopilot</code>根据一个计划文件执行大型任务。主Agent先和我讨论背景和目标，写好计划，然后每个任务启动一个Subagent。每个Subagent实现、测试并提交一个任务。主Agent保持很小，只检查进度，所以可以连续运行几个小时。</li>
</ul>
<p>Skill不过就是文档。你也可以每次都把这些话和AI说一遍，但有了Skill，你只需要说一次。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-the-maintainer-still-does">What the Maintainer Still Does<a href="https://ossrs.io/lts/zh-cn/blog/ai-autopilot#what-the-maintainer-still-does" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>如果AI能自己正确地完成工作，那我还需要做什么？</p>
<ul>
<li class=""><strong>读计划。</strong> 计划说明了背景和步骤，基本不涉及代码。读RTX的计划，让我学到了RTX是什么、如何工作，也让我知道AI是否理解了这个问题。如果有遗漏或者说得不清楚，那就是bug的来源。</li>
<li class=""><strong>做选择。</strong> 理论上RTX也可以用于音频，最初的计划也包括了音频。但Chrome只对视频使用RTX，所以我选择只支持视频。这些选择来自经验，这也是同一个模型，不同的人用会得到不同结果的原因。</li>
<li class=""><strong>异步Review。</strong> 大部分测试代码我不Review，因为AI会遵守测试规范。但核心变更我一定会Review。AI每完成一个任务就提交，并更新计划；另一个Agent帮我在单独的Review分支上Review这些提交，同时主循环继续运行。我不会阻塞AI，AI也不用等我。</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://ossrs.io/lts/zh-cn/blog/ai-autopilot#conclusion" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>AI就像挖掘机。有了挖掘机，就不再需要用锄头挖了。以前，我只能维护Linux版本的SRS；现在，同样的时间，我可以维护跨平台的服务器和配套的客户端，而且代码的测试比我手写的时候任何时候都更完整。</p>]]></content:encoded>
            <category>srs</category>
            <category>ai</category>
            <category>testing</category>
            <category>autopilot</category>
        </item>
        <item>
            <title><![CDATA[SRS for GSoC 2025]]></title>
            <link>https://ossrs.io/lts/zh-cn/blog/GSoC-2025</link>
            <guid>https://ossrs.io/lts/zh-cn/blog/GSoC-2025</guid>
            <pubDate>Mon, 10 Feb 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Project Description]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="project-description">Project Description<a href="https://ossrs.io/lts/zh-cn/blog/GSoC-2025#project-description" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>SRS is a simple, high efficiency and realtime video server, supports RTMP/WebRTC/HLS/HTTP-FLV/SRT.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="information-for-students">Information for Students<a href="https://ossrs.io/lts/zh-cn/blog/GSoC-2025#information-for-students" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="getting-started">Getting Started<a href="https://ossrs.io/lts/zh-cn/blog/GSoC-2025#getting-started" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h3>
<ol>
<li class=""><strong>Get to know SRS.</strong> If you are a student interested in contributing to SRS, it is recommended to start by join to the SRS <a href="https://discord.gg/DfJFjpxmC7" target="_blank" rel="noopener noreferrer" class="">Discord</a> and exploring both the codebase and the development workflow. Feel free to contact us if you have any questions. Also do not hesitate to answer questions from other students on our <a href="https://discord.gg/DfJFjpxmC7" target="_blank" rel="noopener noreferrer" class="">Discord</a> channel if you know the answer to something.</li>
<li class=""><strong>Find a project.</strong> Listed on this page are mentored and un-mentored projects. Mentored projects are well-defined and mentor(s) have already volunteered. Un-mentored projects are additional ideas you may want to consider, but you will have to contact us to find a mentor. You can also propose your own project, if you can think of one that better fits your interest and skill level. If a project description is unclear or you have any questions, please get in touch with its mentor and/or join our <a href="https://discord.gg/DfJFjpxmC7" target="_blank" rel="noopener noreferrer" class="">Discord</a> channel at <em>#general</em>.</li>
<li class=""><strong>Contact us.</strong> If you decide on a project, get in touch with the community and let us know. If you want to work on a qualification task, let the respective mentor know so we can avoid duplicated efforts.</li>
<li class=""><strong>Apply.</strong> Students should apply definitely before deadline on April 8th. The "work" period begins on June 2th and ends in September. Take a look at <a href="https://developers.google.com/open-source/gsoc/timeline" target="_blank" rel="noopener noreferrer" class="">GSoC timeline</a> for additional information. Note, make sure you apply to Google before April 19th, even if you have not yet finished your qualification task. Please apply as soon as possible: Applications can be improved until the 19th but not afterwards!</li>
</ol>
<blockquote>
<p><strong>Note</strong>: A friendly reminder that while the application to GSoC is important for you and GSoC, SRS mentors will not base their decision solely on the GSoC application. We will judge applicants based on their qualification tasks to understand their abilities in coding, learning the tools, communication skills etc. So please do not worry about your application being perfect for us. Although it is very important to follow GSoC's application rules so they can pay you.</p>
</blockquote>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="qualification-tasks">Qualification Tasks<a href="https://ossrs.io/lts/zh-cn/blog/GSoC-2025#qualification-tasks" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h3>
<p>In order to get accepted you have to complete a small qualification task which in all cases include sending a patch to the development mailing list. SRS development can be quite challenging and the qualification task helps us figure out whether you are motivated enough and have the potential to deliver successfully.</p>
<p>The qualification tasks are usually shown in the project description. Contact the respective mentor(s) for assistance on getting a related qualification task or if you want to propose your own. You can also browse the <a href="https://github.com/ossrs/srs" target="_blank" rel="noopener noreferrer" class="">SRS Bug Issue</a> for qualification task ideas. In general qualification tasks should include submitting a patch to the <a href="https://github.com/ossrs/srs" target="_blank" rel="noopener noreferrer" class="">SRS Bug Issue</a> which passes review and is accepted into the SRS codebase. It will be common for such patches to need multiple iterations of submissions and reviews, so don't wait too long with the first submission! Note, please avoid picking a qualification task which another student is already working on, each student should work on a different qualification task.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="development">Development<a href="https://ossrs.io/lts/zh-cn/blog/GSoC-2025#development" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h3>
<p>If you are selected for a particular project then you are not only expected to present a working implementation but you should also submit your work for inclusion for the SRS codebase. This should be done at least 2-3 weeks before the end of the second work period by sending patches to the <a href="https://github.com/ossrs/srs" target="_blank" rel="noopener noreferrer" class="">SRS Bug Issue</a>&amp;<a href="https://discord.gg/DfJFjpxmC7" target="_blank" rel="noopener noreferrer" class="">Discord</a> where the SRS community and your mentor will review your work. You will likely be asked to make some changes and resend improved versions. If you feel that no consensus is reached about how something should be done then follow the advice of your mentor.</p>
<p>In order to create good quality patches make sure to read the <a class="" href="https://ossrs.io/lts/zh-cn/docs/v5/doc/getting-started">Developer Documentation</a>.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="contacting-srs">Contacting SRS<a href="https://ossrs.io/lts/zh-cn/blog/GSoC-2025#contacting-srs" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h3>
<p>If you have questions or comments feel free to contact us via our mail, Discord one of the SRS GSoC admins:</p>
<ul>
<li class=""><strong>Discord:</strong> <em>#general</em></li>
<li class=""><strong>SRS GSoC Admins:</strong> Winlin (winlin in #general on <a href="https://discord.gg/DfJFjpxmC7" target="_blank" rel="noopener noreferrer" class="">Discord</a>, winlinvip at gmail dot com ), Devin (Devin in <em>#general</em> on <a href="https://discord.gg/DfJFjpxmC7" target="_blank" rel="noopener noreferrer" class="">Discord</a>, devin at ossrs dot io), LiuQi (Steven in <em>#general</em> on <a href="https://discord.gg/DfJFjpxmC7" target="_blank" rel="noopener noreferrer" class="">Discord</a>, lq at chinaffmpeg dot org)
You may also contact a mentor directly if you have questions specifically related to one of the projects listed on this page.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="mentored-project-ideas">Mentored Project Ideas<a href="https://ossrs.io/lts/zh-cn/blog/GSoC-2025#mentored-project-ideas" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>This section lists well-defined projects that have one or more available mentors. If you are new to SRS, and have relatively little experience with multimedia, you should favor one of these ideas rather than propose your own. Contact the respective mentor(s) to get more information about the project and the requested qualification task.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-yaml-configuration-file-support">1. YAML Configuration File Support<a href="https://ossrs.io/lts/zh-cn/blog/GSoC-2025#1-yaml-configuration-file-support" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h3>
<table><thead><tr><th style="text-align:left">Name of project</th><th style="text-align:left">YAML Configuration File Support</th></tr></thead><tbody><tr><td style="text-align:left">Project Description</td><td style="text-align:left">SRS currently uses a proprietary configuration format similar to NGINX. YAML is a widely adopted configuration format, familiar to many users.</td></tr><tr><td style="text-align:left">Mentor</td><td style="text-align:left">Junqin Zhang(<a href="mailto:chundonglinlin@163.com" target="_blank" rel="noopener noreferrer" class="">chundonglinlin@163.com</a>)</td></tr><tr><td style="text-align:left">Backup Mentor</td><td style="text-align:left">Haibo Chen(<a href="mailto:495810242@qq.com" target="_blank" rel="noopener noreferrer" class="">495810242@qq.com</a>)</td></tr><tr><td style="text-align:left">Required Skills</td><td style="text-align:left">Familiar with yaml file format and its parsing method, skilled in C++ programming.</td></tr><tr><td style="text-align:left">Difficulty</td><td style="text-align:left">Beginner</td></tr><tr><td style="text-align:left">Expected Outcome</td><td style="text-align:left">Convert existing SRS configuration files to YAML format with proper parsing and execution.</td></tr><tr><td style="text-align:left">Qualification Task</td><td style="text-align:left">Implement YAML file parsing.</td></tr></tbody></table>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-hls-llhls-mode">2. HLS LLHLS mode<a href="https://ossrs.io/lts/zh-cn/blog/GSoC-2025#2-hls-llhls-mode" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h3>
<table><thead><tr><th style="text-align:left">Name of project</th><th style="text-align:left">HLS support LLHLS mode</th></tr></thead><tbody><tr><td style="text-align:left">Project Description</td><td style="text-align:left">HLS, developed by Apple, is a method for file-based live streaming with high latency. LLHLS significantly reduces this latency.</td></tr><tr><td style="text-align:left">Mentor</td><td style="text-align:left">Zhihong Xiao(<a href="mailto:hondaxiao@tencent.com" target="_blank" rel="noopener noreferrer" class="">hondaxiao@tencent.com</a>)</td></tr><tr><td style="text-align:left">Backup Mentor</td><td style="text-align:left">Haibo Chen(<a href="mailto:495810242@qq.com" target="_blank" rel="noopener noreferrer" class="">495810242@qq.com</a>)</td></tr><tr><td style="text-align:left">Required Skills</td><td style="text-align:left">Familiarity with HLS and LLHLS, strong ability to read standards documentation, proficient in C++ programming</td></tr><tr><td style="text-align:left">Difficulty</td><td style="text-align:left">Advanced</td></tr><tr><td style="text-align:left">Expected Outcome</td><td style="text-align:left">Achieve playback on LLHLS-supported players with expected latency.</td></tr><tr><td style="text-align:left">Qualification Task</td><td style="text-align:left">Complete LLHLS encoding, re-muxing, and manifest file generation.</td></tr></tbody></table>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-coroutine-based-dns-resolution-in-srs-network-library-st-state-thread">3. Coroutine-based DNS Resolution in SRS Network Library ST (State-Thread)<a href="https://ossrs.io/lts/zh-cn/blog/GSoC-2025#3-coroutine-based-dns-resolution-in-srs-network-library-st-state-thread" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h3>
<table><thead><tr><th style="text-align:left">Name of project</th><th style="text-align:left">Coroutine-based DNS Resolution in SRS Network Library ST (State-Thread)</th></tr></thead><tbody><tr><td style="text-align:left">Project Description</td><td style="text-align:left">ST (State-Thread) is a coroutine library with coroutine-based wrappers for common network interfaces. Currently, DNS resolution is not adapted to ST and needs full coroutine support.</td></tr><tr><td style="text-align:left">Mentor</td><td style="text-align:left">Zhihong Xiao (<a href="mailto:hondaxiao@tencent.com" target="_blank" rel="noopener noreferrer" class="">hondaxiao@tencent.com</a>)</td></tr><tr><td style="text-align:left">Backup Mentor</td><td style="text-align:left">Winlin (<a href="mailto:winlinvip@gmail.com" target="_blank" rel="noopener noreferrer" class="">winlinvip@gmail.com</a>)</td></tr><tr><td style="text-align:left">Required Skills</td><td style="text-align:left">Familiarity with DNS resolution process, understanding of coroutine principles, proficient in C++ programming</td></tr><tr><td style="text-align:left">Difficulty</td><td style="text-align:left">Intermediate</td></tr><tr><td style="text-align:left">Expected Outcome</td><td style="text-align:left">Implement coroutine-based DNS resolution for all DNS operations in the code.</td></tr><tr><td style="text-align:left">Qualification Task</td><td style="text-align:left">Develop a DNS resolution interface based on State-Thread.</td></tr></tbody></table>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-hls-support-for-cmaf">4. HLS Support for CMAF<a href="https://ossrs.io/lts/zh-cn/blog/GSoC-2025#4-hls-support-for-cmaf" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h3>
<table><thead><tr><th style="text-align:left">Name of project</th><th style="text-align:left">HLS Support for CMAF</th></tr></thead><tbody><tr><td style="text-align:left">Project Description</td><td style="text-align:left">CMAF (Common Media Application Format) is an international standard proposed by industry leaders like Microsoft and Apple, approved in 2017. Implementing CMAF in SRS allows compatibility with more platforms.</td></tr><tr><td style="text-align:left">Mentor</td><td style="text-align:left">Zhihong Xiao(<a href="mailto:hondaxiao@tencent.com" target="_blank" rel="noopener noreferrer" class="">hondaxiao@tencent.com</a>)</td></tr><tr><td style="text-align:left">Backup Mentor</td><td style="text-align:left">Steven Liu(<a href="mailto:lq@chinaffmpeg.org" target="_blank" rel="noopener noreferrer" class="">lq@chinaffmpeg.org</a>)</td></tr><tr><td style="text-align:left">Required Skills</td><td style="text-align:left">Familiarity with HLS, CMAF, MP4 standards, strong ability to read standards documentation, proficient in C++ programming</td></tr><tr><td style="text-align:left">Difficulty</td><td style="text-align:left">Advanced</td></tr><tr><td style="text-align:left">Expected Outcome</td><td style="text-align:left">Output CMAF-HLS manifests and corresponding packaging formats.</td></tr><tr><td style="text-align:left">Qualification Task</td><td style="text-align:left">Complete CMAF packaging and CMAF-HLS manifest file generation.</td></tr></tbody></table>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-enhanced-rtmp-v2">5. Enhanced RTMP (V2)<a href="https://ossrs.io/lts/zh-cn/blog/GSoC-2025#5-enhanced-rtmp-v2" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h3>
<table><thead><tr><th style="text-align:left">Name of project</th><th style="text-align:left">Enhanced RTMP (V2)</th></tr></thead><tbody><tr><td style="text-align:left">Project Description</td><td style="text-align:left">Implement Enhanced RTMP (V2) to support advanced streaming capabilities.</td></tr><tr><td style="text-align:left">Mentor</td><td style="text-align:left">Zhihong Xiao (<a href="mailto:hondaxiao@tencent.com" target="_blank" rel="noopener noreferrer" class="">hondaxiao@tencent.com</a>)</td></tr><tr><td style="text-align:left">Backup Mentor</td><td style="text-align:left">Winlin (<a href="mailto:winlinvip@gmail.com" target="_blank" rel="noopener noreferrer" class="">winlinvip@gmail.com</a>)</td></tr><tr><td style="text-align:left">Required Skills</td><td style="text-align:left">Familiarity with Enhanced RTMP (V2) standard, strong ability to read standards documentation, proficient in C++ programming</td></tr><tr><td style="text-align:left">Difficulty</td><td style="text-align:left">Advanced</td></tr><tr><td style="text-align:left">Expected Outcome</td><td style="text-align:left">Support streaming, playback, and relay using Enhanced RTMP (V2).</td></tr><tr><td style="text-align:left">Qualification Task</td><td style="text-align:left">Implement Enhanced RTMP (V2) features and successfully achieve streaming, playback, and relay.</td></tr></tbody></table>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/gif/v1/sls.gif?site=ossrs.io&amp;path=/lts/blog-en/22-02-10-GSoC" alt="" class="img_ev3q"></p>]]></content:encoded>
            <category>GSoC</category>
        </item>
        <item>
            <title><![CDATA[SRS - 使用Smart Pointers解决内存泄露问题]]></title>
            <link>https://ossrs.io/lts/zh-cn/blog/smart-pointer</link>
            <guid>https://ossrs.io/lts/zh-cn/blog/smart-pointer</guid>
            <pubDate>Sat, 15 Jun 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[8年后，我们使用自己实现的有限的简单Smart Pointers，解决了SRS的内存泄漏问题，保持项目的可维护性。]]></description>
            <content:encoded><![CDATA[<p>8年后，我们使用自己实现的有限的简单Smart Pointers，解决了SRS的内存泄漏问题，保持项目的可维护性。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="introduction">Introduction<a href="https://ossrs.io/lts/zh-cn/blog/smart-pointer#introduction" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>每个流在SRS服务器上有个Source对象，用于管理流的生命周期。为了逻辑和代码简单，SRS一直没有释放Source对象；在流特别多的情况下，
比如不断更换推流的地址，会导致内存不断增长和泄露。</p>
<!-- -->
<p>之前绕过这个问题的办法，就是半夜三更重启服务。SRS支持<a href="https://github.com/ossrs/srs/issues/1579#issuecomment-587414898" target="_blank" rel="noopener noreferrer" class="">Gracefully Quit</a>，
会在没有连接时重启服务，但是这个方法并没有彻底解决这个问题。</p>
<p>为了解决这个问题，我们引入了Smart Pointer，用于管理Source对象的生命周期。我们并没有使用C++ 11，因为SRS需要支持在各种不同的环境编译。
相反，我们实现了一个简化版本的Smart Pointer，只支持了部分功能。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="design">Design<a href="https://ossrs.io/lts/zh-cn/blog/smart-pointer#design" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>在处理这个问题之前，我们需要改进 SRS 的 shared ptr，它用于 RTMP 共享消息、GB 会话以及未来的源对象。</p>
<p>参考 <a href="https://public.websites.umich.edu/~eecs381/handouts/C++11_smart_ptrs.pdf" target="_blank" rel="noopener noreferrer" class="">使用 C++11 的智能指针</a>，
智能指针有三种类型：</p>
<ul>
<li class="">Shared ptr：类似于用于 RTMP 消息的 <code>SrsSharedPtrMessage</code> 和用于 GB28181 的 <code>SrsLazyObjectWrapper</code>。</li>
<li class="">Weak ptr：在 SRS 5.0 版本之前没有这种指针。我们可以通过消除任何指针的循环引用来避免这种情况。</li>
<li class="">Unique ptr：对应的指针是 <code>SrsAutoFree</code>，它在本地范围内释放指针。</li>
</ul>
<p>如果我们仔细设计并限制智能指针的使用，例如没有循环链接，这意味着我们不需要 weak ptr，我们可以为 SRS 实现一个简单且易于维护的智能指针。
我们还考虑以下特性：</p>
<ul>
<li class="">继承：不要在智能指针中使用继承，尽管我们可以编写正确的代码，但讨论起来很复杂。</li>
<li class="">比较：不支持比较智能指针，因为我们只需要自动管理内存。</li>
<li class="">make_shared：不支持这个辅助函数，因为我们不考虑通过 new 操作符的性能问题。</li>
<li class="">shared_from_this：不支持这个辅助模板，因为我们不需要这个特性。</li>
<li class="">make_unique：不支持这个，因为我们允许裸 new 操作符，并且需要仔细的代码审查。</li>
</ul>
<p>我们不想切换到 C++11，因为我认为现代的 C++ 11/14/17/20 实在是糟糕的东西，没有解决任何问题，反而引入了很多糟糕的语法糖。
我们不需要任何语法糖，这对交流非常有害。我们经历了很多智能指针和语法糖的灾难，所以我们希望保持使用非常简单：</p>
<ol>
<li class="">无语法糖：没有 weak ptr，没有 make shared，没有 make unique，没有继承，没有比较，没有循环引用，没有 C++11/14/17/20/22 等等。</li>
<li class="">如果确实需要任何 API，请遵循 C++ 标准 API，不要发明新的轮子，不要有新的函数和名称。</li>
<li class="">仔细的代码审查，程序员应该对代码和内存问题负责。</li>
</ol>
<p>另一方面，我们不应该重新发明轮子，特别是对于智能指针，所以我们必须使用几乎相同的 C++ 标准库 API。这就是为什么我们应该学习
C++11 并重构 SRS 中类似的智能指针。</p>
<p>智能指针在仅涉及内存管理时可能看起来很简单，但当你深入到继承、复制、比较、性能、循环引用、指针转换、创建以及 "no naked new" 的纯粹主义时，
它们的功能变得显著丰富。实际上，C++ 程序的主要问题源于程序员的胡搞乱搞，而这种纯粹主义和各种语法糖使得在公司中很难注意到这些问题，
大量代码被提交，使用各种新特性，并且时间紧迫。</p>
<p>C++ 的真正地狱之门不是 C 的有限旧特性，而是它大量的新特性。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="shared-ptr">Shared Ptr<a href="https://ossrs.io/lts/zh-cn/blog/smart-pointer#shared-ptr" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>我们实现了一个简单的Shared Ptr，支持了引用计数和自动释放，参考 <a href="https://github.com/ossrs/srs/commit/6834ec208d67fa47c21536d1f1041bb6d60c1834" target="_blank" rel="noopener noreferrer" class="">#6834ec2</a></p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">template</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">T</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">SrsSharedPtr</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">private</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// The pointer to the object.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    T</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> ptr_</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// The reference count of the object.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">uint32_t</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> ref_count_</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>使用时，和std::shared_ptr差不多，不过支持的接口更少：</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">SrsSharedPtr</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">MyClass</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ptr</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">MyClass</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ptr</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token function" style="color:#d73a49">do_something</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">SrsSharedPtr</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">MyClass</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> cp </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> ptr</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cp</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token function" style="color:#d73a49">do_something</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>实际上还涉及到一些拷贝构造、赋值和移动构造，以及一些操作符重载，详细可以参考代码和utest的例子，总体上讲这部分是比较简单的实现。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="shared-resource">Shared Resource<a href="https://ossrs.io/lts/zh-cn/blog/smart-pointer#shared-resource" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>除了Shared Ptr智能指针，我们还支持了Shared Resource，主要实现了ISrsResource接口，可以被ResourceManager释放，
参考 <a href="https://github.com/ossrs/srs/commit/6834ec208d67fa47c21536d1f1041bb6d60c1834" target="_blank" rel="noopener noreferrer" class="">#6834ec2</a></p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">template</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token keyword" style="color:#00009f">typename</span><span class="token plain"> </span><span class="token class-name">T</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">SrsSharedResource</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token base-clause keyword" style="color:#00009f">public</span><span class="token base-clause"> </span><span class="token base-clause class-name">ISrsResource</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">private</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    SrsSharedPtr</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">T</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> ptr_</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>实际上，Shared Resource和Shared Ptr拥有完全一样的接口，不过我们没有使用继承，而是组合的方式。使用起来和Shared Ptr也是一样，
不过可以使用Manager管理它：</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">SrsSharedResource</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">MyClass</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> ptr </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token generic-function function" style="color:#d73a49">SrsSharedResource</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name">MyClass</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">MyClass</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">*</span><span class="token plain">ptr</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token function" style="color:#d73a49">do_something</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ISrsResourceManager</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> manager </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">manager</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token function" style="color:#d73a49">remove</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">ptr</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>在实际的应用场景中，往往Resource是由一个coroutine管理，比如GB SIP连接，会启动一个独立的coroutine服务这个连接。类似的还有GB
Media连接，GB Session会话，RTC TCP连接等。我们创建了一个Executor实现这个通用逻辑：</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token class-name">SrsExecutorCoroutine</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">SrsExecutorCoroutine</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">ISrsResourceManager</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> m</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> ISrsResource</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> r</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    resource_ </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> r</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    manager_ </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> m</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    trd_ </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">SrsSTCoroutine</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"ar"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> resource_</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token function" style="color:#d73a49">get_id</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">SrsExecutorCoroutine</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token operator" style="color:#393A34">~</span><span class="token function" style="color:#d73a49">SrsExecutorCoroutine</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    manager_</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token function" style="color:#d73a49">remove</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">resource_</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">srs_freep</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">trd_</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">srs_error_t </span><span class="token class-name">SrsExecutorCoroutine</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">cycle</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    srs_error_t err </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> handler_</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token function" style="color:#d73a49">cycle</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    manager_</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token function" style="color:#d73a49">remove</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> err</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>因此我们可以很方便的使用Executor管理这类Resource：</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">SrsGbSipTcpConn</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> raw_conn </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">SrsGbSipTcpConn</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">SrsSharedResource</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">SrsGbSipTcpConn</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> conn </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token generic-function function" style="color:#d73a49">SrsSharedResource</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name">SrsGbSipTcpConn</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">raw_conn</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">SrsExecutorCoroutine</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> executor </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">SrsExecutorCoroutine</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">_srs_gb_manager</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> conn</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> raw_conn</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> raw_conn</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">err </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> executor</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token function" style="color:#d73a49">start</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">!=</span><span class="token plain"> srs_success</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">srs_freep</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">executor</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">srs_error_wrap</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">err</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"gb sip"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>值得强调的是，Execuctor和Smart Ptr本身没有关联，只是为了解决一类通用的场景而设计的机制。否则多个地方都需要实现重复的逻辑，
相反会更复杂。此外，由于Executor引用的是ISrsResource，因此我们使用Resource Ptr指针对象，而不是直接使用Shared Ptr指针。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="gb28181">GB28181<a href="https://ossrs.io/lts/zh-cn/blog/smart-pointer#gb28181" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>GB28181的SIP和Media是两个独立的协议，也是两个独立的传输通道，因此涉及到对象的独立生命周期和引用和管理，参考 <a href="https://github.com/ossrs/srs/pull/4080" target="_blank" rel="noopener noreferrer" class="">#4080</a>
的说明，如下图所示：</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2024-06-15-01-1de19ee49c969c84a2b46d45daf83f5a.png" width="700" height="357" class="img_ev3q"></p>
<p>SIPTcpConn就是GB的SIP对象，一般侦听的是TCP 5060端口，负责设备注册和信息收集。MediaTcpConn是GB的媒体传输对象，传输的是PS流。
GB Session是由SIPTcpConn或MediaTcpConn对象创建，管理GB会话。</p>
<p>实际上，Session、SIPTcpConn、MediaTcpConn都是Shared Resource管理的对象。Session使用Shared Resource引用SIPTcpConn和MediaTcpConn。
但是SIPTcpConn和MediaTcpConn引用的是Session的裸指针，而不是Shared Resource。这是因为我们没有实现Weak Ptr，不支持循环引用。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="webrtc-over-tcp">WebRTC over TCP<a href="https://ossrs.io/lts/zh-cn/blog/smart-pointer#webrtc-over-tcp" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>WebRTC over UDP是默认的传输方式，由于UDP是没有连接，因此SRS只需要一个RTC Connection对象管理RTC会话。而WebRTC over TCP
则新增了一个TCP连接，我们使用SrsRtcTcpConn管理这个Tcp连接。参考 <a href="https://github.com/ossrs/srs/pull/4083" target="_blank" rel="noopener noreferrer" class="">#4083</a></p>
<p>SrsRtcConnection使用Shared Resource引用SrsRtcTcpConn对象，而SrsRtcTcpConn直接引用SrsRtcConnection的裸指针，
因为SrsRtcConnection的生命周期是更长的。</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">SrsRtcTcpConn</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">private</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// Because session references to this object, so we should directly use the session ptr.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    SrsRtcConnection</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> session_</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">SrsRtcTcpNetwork</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token base-clause keyword" style="color:#00009f">public</span><span class="token base-clause"> </span><span class="token base-clause class-name">ISrsRtcNetwork</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">private</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    SrsSharedResource</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">SrsRtcTcpConn</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> owner_</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>由于我们没有实现shared_from_this，所以我们需要把Shared Resource传递给SrsRtcTcpConn，最终是由Executor和SrsRtcConnection管理这个指针。
由于SrsRtcTcpConn是启动了协程服务这个对象，所以我们使用Executor管理它：</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">resource </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">SrsRtcTcpConn</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">SrsTcpConnection</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">stfd2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> ip</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> port</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">SrsRtcTcpConn</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> raw_conn </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token generic-function function" style="color:#d73a49">dynamic_cast</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name">SrsRtcTcpConn</span><span class="token generic-function generic class-name operator" style="color:#393A34">*</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">resource</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">SrsSharedResource</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">SrsRtcTcpConn</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> conn </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token generic-function function" style="color:#d73a49">SrsSharedResource</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name">SrsRtcTcpConn</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">raw_conn</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">SrsExecutorCoroutine</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> executor </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">SrsExecutorCoroutine</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">_srs_rtc_manager</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> conn</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> raw_conn</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> raw_conn</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">err </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> executor</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token function" style="color:#d73a49">start</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">!=</span><span class="token plain"> srs_success</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">srs_freep</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">executor</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">srs_error_wrap</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">err</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"start executor"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>在使用Smart Ptr之前，我们需要在SrsRtcConnection和SrsRtcTcpConn对象释放时，释放对方。而使用Smart Ptr之后，这个逻辑就没有了，
而是只需要释放SrsRtcTcpConn即可，SrsRtcTcpConn是会自动释放的。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="srt-source">SRT Source<a href="https://ossrs.io/lts/zh-cn/blog/smart-pointer#srt-source" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>SRT的Source也涉及到如何清理的问题，但相对比较简单，只需要修改为Shared Ptr即可，详细参考 <a href="https://github.com/ossrs/srs/pull/4084" target="_blank" rel="noopener noreferrer" class="">#4084</a></p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">SrsSrtSourceManager</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">virtual</span><span class="token plain"> srs_error_t </span><span class="token function" style="color:#d73a49">fetch_or_create</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">SrsRequest</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> r</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> SrsSharedPtr</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">SrsSrtSource</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain"> pps</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">virtual</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">eliminate</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">SrsRequest</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> r</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">SrsSharedPtr</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">SrsSrtSource</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> srt</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">err </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> _srs_srt_sources</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token function" style="color:#d73a49">fetch_or_create</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">r</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> srt</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">!=</span><span class="token plain"> srs_success</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">srs_error_wrap</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">err</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"create source"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>值得注意的是，Source实际上管理了Consumer，所以在Consumer中我们使用的是Source的裸指针：</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">SrsSrtConsumer</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">private</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// Because source references to this object, so we should directly use the source ptr.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    SrsSrtSource</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> source_</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>在没有推流和播放时，释放Source对象：</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token class-name">SrsSrtSource</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">on_consumer_destroy</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">SrsSrtConsumer</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> consumer</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// Destroy and cleanup source when no publishers and consumers.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">can_publish_ </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> consumers</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">empty</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        _srs_srt_sources</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token function" style="color:#d73a49">eliminate</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">req</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token class-name">SrsSrtSource</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">on_unpublish</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// Destroy and cleanup source when no publishers and consumers.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">can_publish_ </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> consumers</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">empty</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        _srs_srt_sources</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token function" style="color:#d73a49">eliminate</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">req</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>释放Live Source的逻辑稍微有所不同(未来会改成一样)，不过智能指针的使用是一致的。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="webrtc-source">WebRTC Source<a href="https://ossrs.io/lts/zh-cn/blog/smart-pointer#webrtc-source" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>和SRT类似，WebRTC的Source也比较简单，只需要修改为Shared Ptr即可，详细参考 <a href="https://github.com/ossrs/srs/pull/4085" target="_blank" rel="noopener noreferrer" class="">#4085</a></p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">SrsRtcSourceManager</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">virtual</span><span class="token plain"> srs_error_t </span><span class="token function" style="color:#d73a49">fetch_or_create</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">SrsRequest</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> r</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> SrsSharedPtr</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">SrsRtcSource</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain"> pps</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">virtual</span><span class="token plain"> SrsSharedPtr</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">SrsRtcSource</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">fetch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">SrsRequest</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> r</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">virtual</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">eliminate</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">SrsRequest</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> r</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>值得注意的是，Source实际上管理了Consumer，所以在Consumer中我们使用的是Source的裸指针：</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">SrsRtcConsumer</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">private</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// Because source references to this object, so we should directly use the source ptr.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    SrsRtcSource</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> source_</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>WebRTC Source Manager支持了一个<code>fetch</code>的API，它可能会返回空的指针，例如：</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">SrsSharedPtr</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">SrsRtcSource</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> source </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> _srs_rtc_sources</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token function" style="color:#d73a49">fetch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">ruc</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">req_</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">is_rtc_stream_active </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">source</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">!</span><span class="token plain">source</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token function" style="color:#d73a49">can_publish</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>在没有推流和播放时，释放Source对象：</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token class-name">SrsRtcSource</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">on_consumer_destroy</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">SrsRtcConsumer</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> consumer</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// Destroy and cleanup source when no publishers and consumers.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">is_created_ </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> consumers</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">empty</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        _srs_rtc_sources</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token function" style="color:#d73a49">eliminate</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">req</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token class-name">SrsRtcSource</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">on_unpublish</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// Destroy and cleanup source when no publishers and consumers.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">is_created_ </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> consumers</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">empty</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        _srs_rtc_sources</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token function" style="color:#d73a49">eliminate</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">req</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>释放Live Source的逻辑稍微有所不同(未来会改成一样)，不过智能指针的使用是一致的。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="live-source">Live Source<a href="https://ossrs.io/lts/zh-cn/blog/smart-pointer#live-source" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>Live Source是最复杂的改进，主要是因为HTTP Streaming中也使用到了Source，详细参考 <a href="https://github.com/ossrs/srs/pull/4089" target="_blank" rel="noopener noreferrer" class="">#4089</a>。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2024-06-15-02-13e3ab7f95118dfbe40010d4b5e554b7.png" width="1024" height="506" class="img_ev3q"></p>
<p>因此我们需要先删除一些不必要的对Source的引用，而改成从manager获取：</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">srs_error_t </span><span class="token class-name">SrsLiveStream</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">do_serve_http</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">ISrsHttpResponseWriter</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> w</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> ISrsHttpMessage</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> r</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    SrsSharedPtr</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">SrsLiveSource</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> live_source </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> _srs_sources</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token function" style="color:#d73a49">fetch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">req</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">live_source</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">srs_error_new</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">ERROR_NO_SOURCE</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"no source for %s"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> req</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token function" style="color:#d73a49">get_stream_url</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">c_str</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>Manager的定义如下，值得注意的是它使用一个Timer检查和释放Source，这个逻辑和SRT/RTC不一致，未来会修改成一致的：</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">SrsLiveSourceManager</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token base-clause keyword" style="color:#00009f">public</span><span class="token base-clause"> </span><span class="token base-clause class-name">ISrsHourGlass</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">virtual</span><span class="token plain"> srs_error_t </span><span class="token function" style="color:#d73a49">fetch_or_create</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">SrsRequest</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> r</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> ISrsLiveSourceHandler</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> h</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> SrsSharedPtr</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">SrsLiveSource</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain"> pps</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">virtual</span><span class="token plain"> SrsSharedPtr</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">SrsLiveSource</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">fetch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">SrsRequest</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> r</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>值得注意的是，Source实际上管理了Consumer/OriginHub/Edge等对象，所以在Consumer等对象中我们使用的是Source的裸指针：</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">SrsEdgeIngester</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token base-clause keyword" style="color:#00009f">public</span><span class="token base-clause"> </span><span class="token base-clause class-name">ISrsCoroutineHandler</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">private</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// Because source references to this object, so we should directly use the source ptr.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    SrsLiveSource</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> source_</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">SrsEdgeForwarder</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token base-clause keyword" style="color:#00009f">public</span><span class="token base-clause"> </span><span class="token base-clause class-name">ISrsCoroutineHandler</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">private</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// Because source references to this object, so we should directly use the source ptr.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    SrsLiveSource</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> source_</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">SrsLiveConsumer</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token base-clause keyword" style="color:#00009f">public</span><span class="token base-clause"> </span><span class="token base-clause class-name">ISrsWakable</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">private</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// Because source references to this object, so we should directly use the source ptr.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    SrsLiveSource</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> source_</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">SrsOriginHub</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token base-clause keyword" style="color:#00009f">public</span><span class="token base-clause"> </span><span class="token base-clause class-name">ISrsReloadHandler</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">private</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// Because source references to this object, so we should directly use the source ptr.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    SrsLiveSource</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> source_</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>Manager使用定时器检查和释放Source：</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">srs_error_t </span><span class="token class-name">SrsLiveSourceManager</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">notify</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> event</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> srs_utime_t interval</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> srs_utime_t tick</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    srs_error_t err </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> srs_success</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    std</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token plain">map</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> std</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token plain">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> SrsSharedPtr</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">SrsLiveSource</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token plain">iterator it</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">it </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> pool</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">begin</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> it </span><span class="token operator" style="color:#393A34">!=</span><span class="token plain"> pool</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">end</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        SrsSharedPtr</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">SrsLiveSource</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain"> source </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> it</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">second</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">source</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token function" style="color:#d73a49">stream_is_dead</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> SrsContextId</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain"> cid </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> source</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token function" style="color:#d73a49">source_id</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token function" style="color:#d73a49">srs_trace</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"cleanup die source, id=[%s], total=%d"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cid</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">c_str</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">int</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">pool</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">size</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            pool</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">erase</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">it</span><span class="token operator" style="color:#393A34">++</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token operator" style="color:#393A34">++</span><span class="token plain">it</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> err</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>这个释放的逻辑和SRT/RTC不一致，未来会修改成一致的，不过智能指针的使用是一致的。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://ossrs.io/lts/zh-cn/blog/smart-pointer#conclusion" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>SRS为了简单处理，最初并没有释放Source对象，通过引入Smart Ptr，终于解决了这个问题。由于我们通过业务上的限制，结合裸指针和Smart Ptr，
避免了复杂的Smart Ptr功能，避免支持多种不同的Smart Ptr，总体上这个修改引入的复杂度是可控的，未来的维护性也很好。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.net/gif/v1/sls.gif?site=ossrs.net&amp;path=/lts/blog-zh/24-06-15-SRS-Smart-Pointer" alt="" class="img_ev3q"></p>]]></content:encoded>
            <category>srs</category>
            <category>memory</category>
            <category>smart-pointer</category>
        </item>
        <item>
            <title><![CDATA[Oryx - 基于AI的视频流的OCR和对象识别]]></title>
            <link>https://ossrs.io/lts/zh-cn/blog/ocr-video-streams</link>
            <guid>https://ossrs.io/lts/zh-cn/blog/ocr-video-streams</guid>
            <pubDate>Mon, 20 May 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Introduction]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="introduction">Introduction<a href="https://ossrs.io/lts/zh-cn/blog/ocr-video-streams#introduction" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>在当今的数字世界中，视频无处不在。从社交媒体片段到直播，我们每天都在大量消费视频内容。但你是否想过我们如何理解这些视频中的所有信息？
这就是人工智能的作用。有了人工智能的帮助，我们现在可以识别文字、识别物体，甚至描述视频流中的场景。</p>
<!-- -->
<p>一个强大的工具使这个过程变得简单，那就是Oryx。在这篇博客中，我们将探讨Oryx如何帮助你在视频流上执行OCR（光学字符识别），
让你能够实时提取有价值的信息。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-1-create-oryx-by-one-click">Step 1: Create Oryx by One Click<a href="https://ossrs.io/lts/zh-cn/blog/ocr-video-streams#step-1-create-oryx-by-one-click" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>创建 Oryx 很简单，只需点击一下，如果您使用 Digital Ocean droplet，就可以完成。
请参阅<a class="" href="https://ossrs.io/lts/zh-cn/blog/Oryx-Tutorial">如何通过 1-Click 设置视频流服务</a>了解详细信息。</p>
<p>您还可以使用 Docker 通过单个命令行创建 Oryx：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">docker run --restart always -d -it --name oryx -v $HOME/data:/data \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -p 80:2022 -p 443:2443 -p 1935:1935 -p 8000:8000/udp -p 10080:10080/udp \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  registry.cn-hangzhou.aliyuncs.com/ossrs/oryx:5</span><br></div></code></pre></div></div>
<p>创建 Oryx 后，您可以通过 <code>http://your-server-ip/mgmt</code> 访问它。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-2-publish-a-live-stream-to-oryx">Step 2: Publish a Live Stream to Oryx<a href="https://ossrs.io/lts/zh-cn/blog/ocr-video-streams#step-2-publish-a-live-stream-to-oryx" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>您可以使用 OBS 或 FFmpeg 将直播流发布到 Oryx。您还可以设置 HTTPS 并通过 WebRTC 发布。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2024-05-20-11-cc048d41ddeaa4e1970f1649b0ded739.png" width="720" height="640" class="img_ev3q"></p>
<p>发布流后，您可以使用 H5 播放器或 VLC 预览它。
请参阅<a class="" href="https://ossrs.io/lts/zh-cn/blog/Oryx-Tutorial">如何通过 1-Click 设置视频流服务</a>了解详细信息。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-3-setup-openai-secret-key-for-ocr">Step 3: Setup OpenAI Secret Key for OCR<a href="https://ossrs.io/lts/zh-cn/blog/ocr-video-streams#step-3-setup-openai-secret-key-for-ocr" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>要使用 Whisper ASR，您必须从 OpenAI 获取一个密钥。请在您的浏览器中打开 <a href="https://platform.openai.com/api-keys" target="_blank" rel="noopener noreferrer" class="">API 密钥</a>
页面，然后点击 <code>创建新的密钥</code> 按钮。密钥创建后，复制它并在 Oryx 中设置。然后，如下图所示，点击 <code>测试OpenAI服务可用性</code>
按钮。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2024-05-20-12-822965fb3eff708208360eda5317018e.png" width="720" height="548" class="img_ev3q"></p>
<p>如果测试成功，你可以点击 <code>开始OCR</code> 按钮来启动OCR过程。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-4-setup-ai-instructions-for-ocr">Step 4: Setup AI Instructions for OCR<a href="https://ossrs.io/lts/zh-cn/blog/ocr-video-streams#step-4-setup-ai-instructions-for-ocr" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>配置好你的GPT AI助手后，你可以在设置网页上更新以下提示<code>服务设置 &gt; AI模型配置 &gt; 提示词</code>。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2024-05-20-13-14bbe391fcfa1780c0302b008165a3e8.png" width="720" height="589" class="img_ev3q"></p>
<p>要在视频流中识别文本，你可以使用以下指令：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">Recognize the text in the image. Output the identified text directly.</span><br></div></code></pre></div></div>
<p>请记得在更新AI设置后重新启动OCR。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-5-view-ocr-results-by-callback">Step 5: View OCR Results by Callback<a href="https://ossrs.io/lts/zh-cn/blog/ocr-video-streams#step-5-view-ocr-results-by-callback" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>一旦OCR过程完成，你可以通过在Oryx中设置回调URL来查看结果。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2024-05-20-14-333f935d1b7e5bfeec73d100b8bcec7c.png" width="720" height="301" class="img_ev3q"></p>
<p>你也可以在仪表板中查看最新的OCR结果。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2024-05-20-15-bceb7058bc7dbecbfe4d6b852357071b.png" width="720" height="496" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://ossrs.io/lts/zh-cn/blog/ocr-video-streams#conclusion" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>总之，使用AI识别视频流中的文本和物体是一个改变游戏规则的技术。它帮助我们快速准确地从视频中提取有价值的信息。
像Oryx这样的工具使这个过程变得简单高效，让你能够轻松发布直播并获得实时OCR结果。无论你是想识别人、读取文本还是描述场景，
AI驱动的OCR都可以改变你与视频内容的互动方式。通过利用这些技术，你可以从每天接触到的视频中解锁新的可能性和见解。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.net/gif/v1/sls.gif?site=ossrs.net&amp;path=/lts/blog-zh/24-05-20-OCR-Video-Streams" alt="" class="img_ev3q"></p>]]></content:encoded>
            <category>ocr</category>
            <category>ai</category>
            <category>gpt</category>
            <category>srs</category>
            <category>oryx</category>
        </item>
        <item>
            <title><![CDATA[Oryx - 基于AI的视频多语言翻译和配音]]></title>
            <link>https://ossrs.io/lts/zh-cn/blog/dubbing-translating</link>
            <guid>https://ossrs.io/lts/zh-cn/blog/dubbing-translating</guid>
            <pubDate>Wed, 21 Feb 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Introduction]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="introduction">Introduction<a href="https://ossrs.io/lts/zh-cn/blog/dubbing-translating#introduction" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>在当今全球化的世界中，内容创作不再受地理范围的限制。因此，吸引多元、国际化的受众对视频创作者越来越重要。无论您是一名YouTuber、
电影制片人还是电子学习内容提供商，能够让您的内容用多种语言呈现，都会大大提高其影响力。这时Oryx的作用就显现出来了 -
通过OpenAI驱动的先进多语言配音和翻译服务，打破语言障碍现在变得更加简单、经济。</p>
<!-- -->
<p>在这篇博客中，我们将讨论Oryx如何支持将视频文件从一种语言配音和翻译成另一种语言，例如将一段英语演讲的视频转换成中文字幕和演讲。
我们将探讨这项技术如何帮助您吸引更广泛的受众，发掘内容的全部潜力，同时使用起来非常简单，对您的钱包友好。所以，让我们一起深入了解
多语言视频内容的Oryx!</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-1-create-oryx-by-one-click">Step 1: Create Oryx by One Click<a href="https://ossrs.io/lts/zh-cn/blog/dubbing-translating#step-1-create-oryx-by-one-click" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>创建 Oryx 很简单，只需点击一下，如果您使用 Digital Ocean droplet，就可以完成。
请参阅<a class="" href="https://ossrs.io/lts/zh-cn/blog/Oryx-Tutorial">如何通过 1-Click 设置视频流服务</a>了解详细信息。</p>
<p>您还可以使用 Docker 通过单个命令行创建 Oryx：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">docker run --restart always -d -it --name oryx -v $HOME/data:/data \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -p 80:2022 -p 443:2443 -p 1935:1935 -p 8000:8000/udp -p 10080:10080/udp \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  registry.cn-hangzhou.aliyuncs.com/ossrs/oryx:5</span><br></div></code></pre></div></div>
<p>创建 Oryx 后，您可以通过 <code>http://your-server-ip/mgmt</code> 访问它。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-2-upload-video-source-file">Step 2: Upload Video Source File<a href="https://ossrs.io/lts/zh-cn/blog/dubbing-translating#step-2-upload-video-source-file" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>首先，上传视频源文件，选择 <code>视频翻译 &gt; 视频源 &gt; 上传本地文件 &gt; 上传文件</code> 上传文件：</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2024-02-21-21-9bb64fcaa6d4c14e559a485463eab5b2.png" width="830" height="410" class="img_ev3q"></p>
<blockquote>
<p>Note: 你也可以使用其他工具，将视频文件上传到 <code>/data</code> 目录，然后选择 <code>指定服务器文件</code> 直接使用文件。</p>
</blockquote>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-3-setup-openai-secret-key-for-dubbing">Step 3: Setup OpenAI Secret Key for Dubbing<a href="https://ossrs.io/lts/zh-cn/blog/dubbing-translating#step-3-setup-openai-secret-key-for-dubbing" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>要使用AI的各种服务，您必须从 OpenAI 获取一个密钥。请在您的浏览器中打开 <a href="https://platform.openai.com/api-keys" target="_blank" rel="noopener noreferrer" class="">API 密钥</a>
页面，然后点击 <code>创建新的密钥</code> 按钮。密钥创建后，复制它并在 Oryx 中设置。</p>
<p>然后，在<code>视频翻译设置 &gt; 语音识别设置</code>中设置OpenAI的密钥，如下图所示。然后点击 <code>测试OpenAI服务可用性</code>按钮，如果测试通过，
没有任何错误，点击<code>更新</code>按钮。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2024-02-21-22-f9eebec7880fd4cc9ac6913d26a50583.png" width="830" height="653" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-4-setup-the-language-to-translate">Step 4: Setup the Language to Translate<a href="https://ossrs.io/lts/zh-cn/blog/dubbing-translating#step-4-setup-the-language-to-translate" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>设置视频源的语言，请打开 <code>视频翻译设置 &gt; 语音识别设置 &gt; 语言</code> ，然后设置翻译的目标语言，设置AI的提示词
<code>视频翻译设置 &gt; 多语言翻译设置 &gt; 提示词</code> ，点击<code>更新</code>按钮。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2024-02-21-23-a03d8cd119713987dd92dccbf8819f9f.png" width="830" height="706" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-5-start-dubbing-and-download-translated-video">Step 5: Start Dubbing and Download Translated Video<a href="https://ossrs.io/lts/zh-cn/blog/dubbing-translating#step-5-start-dubbing-and-download-translated-video" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>点击 <code>开始翻译</code> 按钮，如下图所示。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2024-02-21-24-418fdee8b1725d79d980e5921c83eda9.png" width="830" height="628" class="img_ev3q"></p>
<p>如果翻译后的视频，比原始视频长，可以点击 <code>改进翻译</code> 或者 <code>合并到下一组</code> 按钮，让翻译后的语音更短，如下图所示。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2024-02-21-25-e1cb525e53949fd285dd715ba178f3b6.png" width="830" height="342" class="img_ev3q"></p>
<p>如果所有的音频分段都没有问题，也就是没有红色背景的分段，你可以点击按钮 <code>下载翻译视频</code> 下载。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2024-02-21-26-ada60b19a4f1ddf164324f7782943878.png" width="830" height="540" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://ossrs.io/lts/zh-cn/blog/dubbing-translating#conclusion" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>总之，Oryx 支持将视频文件配音和翻译成多种语言，包括将英语语音转换为中文字幕和语音，这对于希望吸引更多观众的内容创作
者来说是一个改变游戏规则的解决方案。通过利用 OpenAI 服务的先进功能，Oryx 确保视频本地化的高效、经济实惠和用户友好。
这项了不起的技术不仅打破了语言障碍，还促进了文化交流和全球沟通，推动您的内容进入新领域，为无限可能打开大门。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.net/gif/v1/sls.gif?site=ossrs.net&amp;path=/lts/blog-zh/2024-02-21-dubbing-translating" alt="" class="img_ev3q"></p>]]></content:encoded>
            <category>dubbing</category>
            <category>translating</category>
            <category>ai</category>
            <category>gpt</category>
            <category>voice</category>
            <category>srs</category>
            <category>oryx</category>
            <category>multilingual</category>
        </item>
        <item>
            <title><![CDATA[Oryx - 基于浏览器的语音驱动的GPT-AI助手]]></title>
            <link>https://ossrs.io/lts/zh-cn/blog/browser-voice-driven-gpt</link>
            <guid>https://ossrs.io/lts/zh-cn/blog/browser-voice-driven-gpt</guid>
            <pubDate>Wed, 31 Jan 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[想象一下仅通过语音在浏览器中与GPT AI互动，与朋友分享这种功能，或从任何地方访问它。设想一个使学习英语口语变得愉快而简单的助手，]]></description>
            <content:encoded><![CDATA[<p>想象一下仅通过语音在浏览器中与GPT AI互动，与朋友分享这种功能，或从任何地方访问它。设想一个使学习英语口语变得愉快而简单的助手，
或者通过实时翻译所有内容，让您和说不同语言的朋友进行无缝对话的助手。探索如何将这些激动人心的可能性变为现实！</p>
<!-- -->
<p>向您介绍一种突破性的互动工具：一个可以快捷构建的、基于浏览器的语音驱动的GPT AI助手。你可以使用简单易用的Oryx快捷构建，
仅需点击一下即可轻松启用HTTPS，可以在任何配备浏览器的设备上使用，包括PC和手机。它的便利性使您可以在任何时候、任何地方、使用语音
轻松的与您的私人GPT AI助手进行交流。无论是用于提高您的英语口语、充当实时翻译工具，还是作为智能伴侣，这款语音驱动的GPT AI助手都可以
通过简单的对话实现。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-1-create-oryx-by-one-click">Step 1: Create Oryx by One Click<a href="https://ossrs.io/lts/zh-cn/blog/browser-voice-driven-gpt#step-1-create-oryx-by-one-click" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>创建 Oryx 很简单，只需点击一下，如果您使用 Digital Ocean droplet，就可以完成。
请参阅<a class="" href="https://ossrs.io/lts/zh-cn/blog/Oryx-Tutorial">如何通过 1-Click 设置视频流服务</a>了解详细信息。</p>
<p>您还可以使用 Docker 通过单个命令行创建 Oryx：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">docker run --restart always -d -it --name oryx -v $HOME/data:/data \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -p 80:2022 -p 443:2443 -p 1935:1935 -p 8000:8000/udp -p 10080:10080/udp \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  registry.cn-hangzhou.aliyuncs.com/ossrs/oryx:5</span><br></div></code></pre></div></div>
<p>创建 Oryx 后，您可以通过 <code>http://your-server-ip/mgmt</code> 访问它。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-2-setup-https-for-voice-driven-gpt">Step 2: Setup HTTPS for Voice-Driven GPT<a href="https://ossrs.io/lts/zh-cn/blog/browser-voice-driven-gpt#step-2-setup-https-for-voice-driven-gpt" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>在将语音功能集成到基于浏览器的 GPT AI助手中时，安全性至关重要。浏览器要求在访问麦克风以捕获语音输入时使用 HTTPS，
作为其安全策略的一部分。这听起来可能很复杂，但使用 Oryx，让您的网站启用 HTTPS 变得简单而轻松。以下是如何使用
HTTPS 保护您的语音驱动助手的方法：</p>
<ol>
<li class="">
<p><strong>DNS 配置</strong>：首先为您的域名添加 DNS A 记录。此步骤将您的域名指向您的 Oryx 服务器。要验证 DNS 设置是否正确，请尝试通过 http 使用您的域名访问您的 Oryx，如 <code>http://your_domain_name</code>。如果设置正确，这应该可以正常工作。</p>
</li>
<li class="">
<p><strong>启用 HTTPS</strong>：导航到 Oryx 仪表板中的 <code>系统配置 &gt; HTTPS &gt; 自动HTTPS证书</code> 部分。在这里，您只需输入您的域名并点击 <code>提交</code> 按钮。此过程启动为您的域名自动生成和安装 Let's Encrypt SSL 证书，使 HTTPS 设置如同点击一下鼠标按钮一样简单。</p>
</li>
<li class="">
<p><strong>验证结果</strong>：启用 HTTPS 后，您现在可以通过 "https://your_domain_name" 安全地访问您的 Oryx 站点。此安全策略提高了与 GPT AI助手互动的安全性。</p>
</li>
</ol>
<p>有关更多详细信息，请参阅<a class="" href="https://ossrs.io/lts/zh-cn/blog/Oryx-HTTPS">设置 Oryx 的 HTTPS</a>。按照这些步骤操作，您将确保您的语音驱动
GPT AI助手不仅创新且有用，而且安全且符合浏览器安全标准。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-3-setup-openai-secret-key-in-live-room">Step 3: Setup OpenAI Secret Key in Live Room<a href="https://ossrs.io/lts/zh-cn/blog/browser-voice-driven-gpt#step-3-setup-openai-secret-key-in-live-room" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>要使用AI的各种服务，您必须从 OpenAI 获取一个密钥。请在您的浏览器中打开 <a href="https://platform.openai.com/api-keys" target="_blank" rel="noopener noreferrer" class="">API 密钥</a>
页面，然后点击 <code>创建新的密钥</code> 按钮。密钥创建后，复制它并在 Oryx 中设置。</p>
<p>接下来，如下图所示，导航至<code>应用场景 &gt; 直播间 &gt; 创建直播间</code>，然后按下<code>创建</code>按钮以创建一个与GPT AI助手交谈的直播间。或者，
选择链接加入现有的直播间。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2024-01-31-21-e698d7c7e2087c6d182820089b96ee2d.png" width="820" height="456" class="img_ev3q"></p>
<p>然后，在<code>直播间 &gt; AI助手 &gt; AI服务商</code>中设置OpenAI的密钥，如下图所示。然后点击 <code>测试OpenAI服务可用性</code>按钮，如果测试通过，
没有任何错误，点击<code>更新助手</code>按钮。</p>
<blockquote>
<p>Remark: 如果你的服务器在中国，一定要设置 <code>OpenAI服务接入地址</code>，也就是经过代理访问OpenAI的服务，因为中国区域无法直接访问<code>api.openai.com</code>这个域名。</p>
</blockquote>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2024-01-31-22-9d73d4626f87c0fa56dab5bab4e964e2.png" width="820" height="600" class="img_ev3q"></p>
<p>设置完成了，非常简单!</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-4-open-gpt-ai-assistant-in-browser">Step 4: Open GPT AI Assistant in Browser<a href="https://ossrs.io/lts/zh-cn/blog/browser-voice-driven-gpt#step-4-open-gpt-ai-assistant-in-browser" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>现在，点击 <code>Assistant</code> 生成基于浏览器的语音驱动 GPT AI助手的链接，可以直接点击打开。或者右键复制链接，将网址分享给其他设备或朋友。
你也可以在手机上访问它。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2024-01-31-23-bb292d239bffd9447932bb54f938804c.png" width="820" height="602" class="img_ev3q"></p>
<p>在打开助手网页时，按<code>允许</code>按钮授权麦克风访问权限给助手。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2024-01-31-24-caf69e53ebf11d2dac0a18fc77442231.png" width="500" height="165" class="img_ev3q"></p>
<p>然后点击<code>开始聊天</code>开始对话。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2024-01-31-25-66a606d688d046a525e5a6d40608413d.png" width="820" height="291" class="img_ev3q"></p>
<p>现在，你的助手就准备好了，接下来让我们看如何和她对话。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-5-how-to-interact-with-gpt-ai-assistant">Step 5: How to Interact with GPT AI Assistant<a href="https://ossrs.io/lts/zh-cn/blog/browser-voice-driven-gpt#step-5-how-to-interact-with-gpt-ai-assistant" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>当在电脑上（如Apple Mac或Windows PC）使用基于浏览器的语音驱动GPT AI助手时，点击网页上的麦克风图标。按住<code>空格键</code>或<code>R</code>键开始讲话，
松开键停止讲话。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2024-01-31-26-857e5676116186aed58a1f055e269615.png" width="820" height="485" class="img_ev3q"></p>
<p>在移动设备浏览器上使用助手时，比如 iPhone 或 Android，按住麦克风键进行讲话，松开即可完成讲话。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2024-01-31-27-e232bbf3019f0d4b51b4d95e55d632b6.png" width="360" height="640" class="img_ev3q"></p>
<p>一旦您向助手提交了您的消息，请稍等片刻。助手将以文字和语音的形式回复您。</p>
<blockquote>
<p>Note: 此外，还有一个文本输入功能，允许您通过键入或从剪贴板粘贴来输入文本。使用语音输入时，输入文本框将自动填充，使您能够编辑并重新发送给助手。</p>
</blockquote>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2024-01-31-28-07ee3ce49be4c928d16bd2f1168853fd.png" width="820" height="485" class="img_ev3q"></p>
<p>好的！接下来，让我展示一些引人入胜且实用的现实世界示例，以及如何通过基于浏览器的语音驱动的GTP助手来实现它们。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-to-create-an-english-speaking-coach-with-a-voice-driven-gpt-ai-assistant">How to Create an English Speaking Coach with a Voice-Driven GPT AI Assistant<a href="https://ossrs.io/lts/zh-cn/blog/browser-voice-driven-gpt#how-to-create-an-english-speaking-coach-with-a-voice-driven-gpt-ai-assistant" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>一旦您配置好了您的语音驱动的GPT AI助手，你可以在 <code>AI助手 &gt; AI模型配置 &gt; 提示词</code> 中，更新为下面的提示词。你就可以获得一个非常好的
口语教练了，它不眠不休、不骄不躁、不会发脾气，非常耐心的陪你训练口语。我使用了一个月之后，从最初的一个词一个词的说，能做到一句话
一句话的说了。</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">I want you to act as a spoken English teacher and improver. </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">I will speak to you in English and you will reply to me in English to practice my spoken English. </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">I want you to strictly correct my grammar mistakes, typos, and factual errors. </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">I want you to ask me a question in your reply. </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Now let's start practicing, you could ask me a question first. </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Remember, I want you to strictly correct my grammar mistakes, typos, and factual errors.</span><br></div></code></pre></div></div>
<blockquote>
<p>Note: 更多提示词，可以参考 <a href="https://github.com/f/awesome-chatgpt-prompts?#perform-as-a-spoken-english-instructor-and-enhancer" target="_blank" rel="noopener noreferrer" class="">awesome-chatgpt-prompts</a> 这个站点。</p>
</blockquote>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-to-create-a-simultaneous-translator-for-multilingual-users">How to Create a Simultaneous Translator for Multilingual Users<a href="https://ossrs.io/lts/zh-cn/blog/browser-voice-driven-gpt#how-to-create-a-simultaneous-translator-for-multilingual-users" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>通过将您的语音激活的GPT AI助手分享给多个用户，使他们可以与同一个AI助手进行交流，那么您将同时获得一名同声传译。你需要将提示词设置为
翻译为多种语言。</p>
<p>请将下面提示词中的语言更改为您需要翻译的语言，请在 <code>AI助手 &gt; AI模型配置 &gt; 提示词</code> 中更新提示词：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">I want you to act as a language translator.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">I want you to translate my text in conversational tone.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">I want you to strictly translate to English and Chinese.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Keep in mind that you must translate to English and Chinese.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Remember, never answer questions but only translate.</span><br></div></code></pre></div></div>
<blockquote>
<p>Note: 更多提示词，可以参考 <a href="https://github.com/f/awesome-chatgpt-prompts" target="_blank" rel="noopener noreferrer" class="">awesome-chatgpt-prompts</a> 这个站点。</p>
</blockquote>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://ossrs.io/lts/zh-cn/blog/browser-voice-driven-gpt#conclusion" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>总结一下，使用Oryx创建个人的、基于浏览器的、语音驱动的GPT AI助手的过程非常简单。从设置HTTPS进行安全通信，到集成OpenAI GPT，
每个步骤都设计非常容易使用。无论是为了提高语言能力、实现多语言对话，还是简单地享受便利的语音驱动的GPT AI助手，它为直播间和主播提供了
许多可能性。将来，还将支持将实时观众聊天连接到AI助手。您可以在真实场景中发现更多有益的GPT AI助手用例。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.net/gif/v1/sls.gif?site=ossrs.net&amp;path=/lts/blog-zh/2024-01-31-browser-voice-driven-gpt" alt="" class="img_ev3q"></p>]]></content:encoded>
            <category>ai</category>
            <category>gpt</category>
            <category>voice</category>
            <category>srs</category>
            <category>oryx</category>
            <category>streaming</category>
        </item>
        <item>
            <title><![CDATA[Oryx - 如何实现5秒HLS低延迟]]></title>
            <link>https://ossrs.io/lts/zh-cn/blog/hls-5s-low-latency</link>
            <guid>https://ossrs.io/lts/zh-cn/blog/hls-5s-low-latency</guid>
            <pubDate>Sat, 06 Jan 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Introduction]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="introduction">Introduction<a href="https://ossrs.io/lts/zh-cn/blog/hls-5s-low-latency#introduction" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>在动态的直播世界中，延迟是一个关键因素，它可以决定观众体验的成败。传统上，实现低延迟一直是一个挑战，
特别是在努力实现跨设备和平台的广泛兼容性时。这就是HLS发挥作用的地方，它是一种因其可靠性和兼容性而广受欢迎的格式。
然而，HLS通常与较高的延迟（约30秒）相关联，这对于实时互动可能是一个缺点。</p>
<!-- -->
<p>进入低延迟HLS流媒体的领域，这对于现场广播来说是一个游戏规则改变者。在这篇博客中，我们将探讨如何将HLS流延迟降低到最低5秒。
最好的部分？这可以通过使用常见的、高度兼容的技术来实现，无需专门的设备。我们将深入研究Oryx的使用，这是一个功能强大而简单的工具，
可以简化流程，仅需点击一下即可实现超低延迟HLS流媒体。</p>
<p>如果您需要更低的延迟并可以在兼容性上妥协，还有其他选择。对于1到3秒之间的延迟，HTTP-FLV是一个很好的选择。对于大约0.5到1秒的超低延迟，
WebRTC是理想的选择。每种技术都适用于不同的需求和内容类型。</p>
<p>在这篇博客中，我们的目标是为您提供一个关于如何为您的业务选择合适的流媒体技术的全面指南，重点关注HLS，
以实现低延迟和高兼容性之间的最佳平衡。无论您是在进行现场体育赛事、互动网络研讨会还是实时游戏会话的直播，了解这些技术将使您能够为观众提供最佳的直播体验。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="key-points">Key Points<a href="https://ossrs.io/lts/zh-cn/blog/hls-5s-low-latency#key-points" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>为了实现最广泛的兼容性，我们使用最常见的HLS协议，而不是HTTP-FLV、WebRTC或LLHLS协议，而是最标准的HLS协议。</p>
<p>然而，我们需要在关键点上更改一些设置，例如：</p>
<ul>
<li class="">对于OBS编码器，选择x264编码器，在高级设置中，将<code>GOP（关键帧间隔）</code>设置为<code>1 s</code>。选择<code>CPU使用预设</code>为<code>fast</code>，<code>配置 (Profile)</code>为<code>baseline</code>，<code>微调 (Tune)</code>为<code>zerolatency</code>。这些设置允许OBS在保持兼容性的同时生成较短的片段。</li>
<li class="">对于Oryx，启用HLS低延迟模式。这将生成尽可能短的HLS片段，每个片段约2秒。HLS的最小延迟大约是两个片段，允许大约5秒的延迟。</li>
<li class="">对于HLS播放器，如hls.js，将其设置为从最后一个片段开始播放，并配置最大缓冲时间。当累积延迟达到一定阈值时，启用加速播放以保持稳定的低延迟。</li>
</ul>
<p>整个工作流程，从流媒体到服务器到播放器，都需要优化以实现5秒的低延迟。在此过程中的常见错误包括：
*</p>
<ul>
<li class="">无法将编码器（如 OBS）设置为较大的 GOP（如 10 秒），或者编码器缓冲区过大，导致整体延迟显著增加。</li>
<li class="">Oryx 未设置为低延迟模式。在正常模式下，生成的片段持续时间较长，或者某些服务器可能无法生成准确持续时间的片段，而是更喜欢较大的片段。</li>
<li class="">使用不正确的播放器，如 VLC，无论使用哪种协议，都会有显著的延迟。并非所有播放器都适用；我们已经测试过 hls.js 和 mpegts.js 播放器具有低延迟。将来，我们将测试并确保与更多播放器兼容。</li>
</ul>
<p>让我们通过一些简单的设置步骤和点击来实现 5 秒的 HLS 延迟。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-1-create-oryx-by-one-click">Step 1: Create Oryx by One Click<a href="https://ossrs.io/lts/zh-cn/blog/hls-5s-low-latency#step-1-create-oryx-by-one-click" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>创建 Oryx 很简单，只需点击一下，如果您使用 Digital Ocean droplet，就可以完成。
请参阅<a class="" href="https://ossrs.io/lts/zh-cn/blog/Oryx-Tutorial">如何通过 1-Click 设置视频流服务</a>了解详细信息。</p>
<p>您还可以使用 Docker 通过单个命令行创建 Oryx：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">docker run --restart always -d -it --name oryx -v $HOME/data:/data \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -p 80:2022 -p 443:2443 -p 1935:1935 -p 8000:8000/udp -p 10080:10080/udp \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  registry.cn-hangzhou.aliyuncs.com/ossrs/oryx:5</span><br></div></code></pre></div></div>
<p>创建 Oryx 后，您可以通过 <code>http://your-server-ip/mgmt</code> 访问它。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-2-setup-obs-for-hls-low-latency">Step 2: Setup OBS for HLS Low Latency<a href="https://ossrs.io/lts/zh-cn/blog/hls-5s-low-latency#step-2-setup-obs-for-hls-low-latency" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>我建议使用OBS发布流。这是一个受欢迎且功能强大的流媒体工具，易于设置。 您应按照以下方式配置OBS：</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2024-01-06-11-c8ff5d8e7919344435b8df748bce6a6e.png" width="720" height="861" class="img_ev3q"></p>
<p>点击<code>设置</code>按钮，然后转到<code>输出</code>选项卡并应用以下设置：</p>
<ul>
<li class="">将<code>输出模式</code>设置为<code>高级</code>。<code>简单</code>模式不适用于低延迟HLS。</li>
<li class="">将<code>视频编码器</code>设置为<code>x264</code>。请注意，硬件编码器可能具有较大的延迟。</li>
<li class="">将<code>关键帧间隔</code>设置为<code>1 s</code>。请注意，这是实现低延迟的最关键设置。</li>
<li class="">将<code>CPU使用预设</code>设置为<code>fast</code>。此设置有助于减少延迟。</li>
<li class="">将<code>配置 (Profile)</code>设置为<code>baseline</code>。此设置有助于减少延迟。</li>
<li class="">将<code>微调 (Tune)</code>设置为<code>zerolatency</code>。此设置有助于减少延迟。</li>
</ul>
<p>接下来，打开<code>直播</code>选项卡并按照Oryx提供的说明设置服务器和流密钥以发布流。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-3-setup-oryx-in-hls-low-latency-mode">Step 3: Setup Oryx in HLS Low Latency Mode<a href="https://ossrs.io/lts/zh-cn/blog/hls-5s-low-latency#step-3-setup-oryx-in-hls-low-latency-mode" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>打开Oryx，导航至<code>系统配置 &gt; HLS</code>。启用HLS低延迟模式，然后点击<code>提交</code>按钮。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2024-01-06-12-f9845d56e3f99034b8c016e14d4dcc9d.png" width="576" height="449" class="img_ev3q"></p>
<p>在此之后，您可以获取发布服务器和流密钥，以便将OBS流传输到Oryx。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2024-01-06-13-cc048d41ddeaa4e1970f1649b0ded739.png" width="720" height="640" class="img_ev3q"></p>
<p>请配置OBS并开始将RTMP流发布到Oryx。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-4-setup-the-hls-player">Step 4: Setup the HLS Player<a href="https://ossrs.io/lts/zh-cn/blog/hls-5s-low-latency#step-4-setup-the-hls-player" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>在浏览器中打开 Oryx 的 <code>简易播放器</code>，您可以看到具有5秒延迟的 HLS 流。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2024-01-06-04-4458f5f2e3d9e6283f61c2a4d7474ea9.png" width="720" height="411" class="img_ev3q"></p>
<p>Oryx已使用hls.js为低延迟模式配置了HLS播放器。我们已经应用了以下设置。如果您需要使用自己的HLS播放器，请进行类似的配置：</p>
<ul>
<li class="">通过将其设置为<code>true</code>来启用<code>enableWorker</code>。这可以提高性能，避免卡顿或丢帧。</li>
<li class="">通过将其设置为<code>true</code>来激活<code>lowLatencyMode</code>。这将启用低延迟HLS部分播放列表和片段加载。</li>
<li class="">将<code>liveSyncDurationCount</code>设置为<code>0</code>，从最后一个片段开始播放。</li>
<li class="">将<code>maxBufferLength</code>设置为<code>5</code>，以秒为单位设置最大缓冲长度。</li>
<li class="">将<code>maxLiveSyncPlaybackRate</code>设置为<code>2</code>，以便在延迟较大时追赶。</li>
</ul>
<p>有关详细信息，请参阅<a href="https://github.com/ossrs/oryx/commit/a6b709f516da3c7f36f5c3c599142296148187ee#diff-06095ca53f7d88e4f592f1a432030f541adf2060cb2dfc6c4efd86cd9f074820R40" target="_blank" rel="noopener noreferrer" class="">此提交</a>。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://ossrs.io/lts/zh-cn/blog/hls-5s-low-latency#conclusion" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>利用Oryx、OBS和hls.js，我们实现了5秒延迟的HLS流媒体直播，打破了直播低延迟和兼容性的障碍。
这一进步标志着互动和引人入胜的现场活动的新时代，无需专门的设备，所有人都可以使用，为流媒体观众带来了新的体验。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.net/gif/v1/sls.gif?site=ossrs.net&amp;path=/lts/blog-zh/2024-01-06-HLS-5s-Low-Latency" alt="" class="img_ev3q"></p>]]></content:encoded>
            <category>hls</category>
            <category>llhls</category>
            <category>live-streaming</category>
            <category>low-latency-streaming</category>
            <category>low-latency-hls</category>
        </item>
        <item>
            <title><![CDATA[SRS十周年纪念和2023年终回顾]]></title>
            <link>https://ossrs.io/lts/zh-cn/blog/srs-ten-years</link>
            <guid>https://ossrs.io/lts/zh-cn/blog/srs-ten-years</guid>
            <pubDate>Fri, 15 Dec 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[又到2023年底了，每年写个总结，几年后可以嘲笑自己当年的不成熟。]]></description>
            <content:encoded><![CDATA[<p>又到2023年底了，每年写个总结，几年后可以嘲笑自己当年的不成熟。</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="srs-server">SRS Server<a href="https://ossrs.io/lts/zh-cn/blog/srs-ten-years#srs-server" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>SRS 5.0将在这两周正式发布稳定版，经过一年的功能冻结，半年的稳定性提升，现在5.0已经可以在生产环境使用。</p>
<p>5.0是从2021年3月份开始开发，重要变更如下：</p>
<ul>
<li class="">ST(State-Threads)：支持Windows/RISCV/LOONGARCH/MIPS/AppleM1等芯片，支持多线程能力。</li>
<li class="">SRT：基于ST重写，对齐API和回调等完善的能力，支持直接IP推流，升级libsrt，改进延迟，补全配置项。</li>
<li class="">WebRTC：支持WHIP和WHEP协议，支持TCP传输，支持Unity，改进错误提升，支持MP3转OPUS，支持FFmpeg原生OPUS。</li>
<li class="">WHIP：支持WHIP协议，适配Larix，适配OBS WHIP，安全改进，支持删除资源。</li>
<li class="">GB28181：支持2016/TCP协议，支持压测工具，支持回归测试。</li>
<li class="">Live: 解决RBSP解析问题，兼容FFmpeg timecode，忽略空NALU，支持HLS伪流，支持踢HLS客户端，解决DASH崩溃问题。</li>
</ul>
<p>还有一些bugfix，详细的变更清单，请参考官网的Changelog吧。</p>
<p>一盘点，两年好像也没干啥事。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="oryx">Oryx<a href="https://ossrs.io/lts/zh-cn/blog/srs-ten-years#oryx" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>Oryx就是一体化的视频云，里面包含多个音视频项目，以音视频应用场景为中心，开箱即用的方案。</p>
<p>今年Oryx重新做了，主要变更如下：</p>
<ul>
<li class="">从微服务架构改成单体应用，镜像大小减少90%，开发速度提高10倍，最坑人的莫过于微服务架构了。</li>
<li class="">支持Docker和脚本安装，DigitalOcean和Lighthouse镜像，BT和aaPanel插件安装，HELM安装。</li>
<li class="">测试覆盖所有安装方式，覆盖所有功能和API。</li>
<li class="">支持虚拟直播、AI自动字幕、转码、回调、HLS集群、拉流转推等新场景。</li>
</ul>
<p>如果说SRS是很简单易用，Oryx就是可以真正简单易用的构建音视频业务。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="community">Community<a href="https://ossrs.io/lts/zh-cn/blog/srs-ten-years#community" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>SRS是2013年开始做的开源项目，从2020年才正式开始做开源社区，2022年开始做全球社区，今年社区发展非常快，已经可以独立生长了。</p>
<p>今年我们也通过了中国电子技术标准化研究院，开源成熟度评估。经过两年的孵化和导师的指导，今年年底，SRS也从木兰开源社区顺利毕业了。</p>
<p>今年海外的每月付费人数，OpenCollective的订阅人数，从5人左右增加到了41人，预计三到五年左右，可以投入专门的时间支持社区的发展。</p>
<p>国内星球在200人左右，每年可以支持我们参加一次国内的会议的差旅，社区也可以正常发展了。</p>
<p>今年也开始给社区提供付费支持，海外5美元一个月，国内5人民币一个月，更好的支持了用户的业务，得到了用户的广泛好评。</p>
<p>最初星球是10人民币一个月，现在调整为5人民币一个月，和海外保持对齐（虽然海外是美元但人家赚的也是美元）。</p>
<p>在中国，一般是越涨价就越要付钱，越降价越没人付钱，总是套路得人心。所以我们降价后，希望大家都跑路了，我们需要花的时间也更少一些。</p>
<p>国内付费习惯和海外差得还挺远，海外的付费习惯成熟些，我想还是因为国内总觉得占用别人时间是免费的，实际上最昂贵的不就是人的时间吗？不过大家也不用担心，只要项目活着，国内的付费支持通道不会关闭。</p>
<p>我们维护开源项目，也同时受益于其他音视频开源项目，因此我们会在年底将一半费用捐给其他的我们依赖的音视频的开源项目，比如FFmpeg和OBS等。</p>
<p>同时，我们还会继续增强社区的AI能力。比如我们使用GPT自动翻译社区的Issues和PullRequest，降低交流的门槛。比如我们在官网部署了AI Talk，方便大家体验音视频和AI结合的新能力。</p>
<p>感谢全球开发者对SRS的支持和认可，我们的发展会越来越好。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://ossrs.io/lts/zh-cn/blog/srs-ten-years#conclusion" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>无论开源的风怎么吹，弄清楚我们所做的事情，到底在提供什么样的价值，就可以长长久久。</p>
<p>众多开源项目为全球软件生态，提供了生生不熄火的基础，能够参与到整个系统中，成为贡献者是程序员作为程序员的骄傲。</p>
<p>为用户提供付费支持是有价值的，或许国内不太认可那就少提供一些这种服务，目前海外更认可这种形式那就多提供一些服务。</p>
<p>至于职业化开源，提供定制开发，我们社区有些开发者在upwork上已经在做了，灵活就业也是不错的工作。</p>
<p>最后就是商业化，至少SRS是不会做的，SRS的目标是成为全球广泛使用的音视频基础开源项目，商业化会妨碍这个目标。</p>
<p>在开源社区，看不到冬天。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.net/gif/v1/sls.gif?site=ossrs.net&amp;path=/lts/blog-zh/2023-12-15-SRS-Ten-Years" alt="" class="img_ev3q"></p>]]></content:encoded>
            <category>srs</category>
            <category>community</category>
        </item>
        <item>
            <title><![CDATA[Oryx - 为OBS快速构建公网WHIP服务]]></title>
            <link>https://ossrs.io/lts/zh-cn/blog/obs-whip-internet-service</link>
            <guid>https://ossrs.io/lts/zh-cn/blog/obs-whip-internet-service</guid>
            <pubDate>Tue, 12 Dec 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[Introduction]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="introduction">Introduction<a href="https://ossrs.io/lts/zh-cn/blog/obs-whip-internet-service#introduction" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>您是否厌倦了在尝试为OBS创建公共互联网WHIP服务时与复杂设置和技术术语作斗争？再也不用寻找了！在本综合指南中，
我们将引导您通过使用Oryx一键轻松构建自己的WHIP服务的过程。告别安全性、身份验证和WebRTC的复杂性，
拥抱亚秒级直播和无缝OBS-RTC房间连接的未来。</p>
<!-- -->
<p>加入我们，打破在线流媒体的障碍，帮助您充分利用OBS的WHIP支持。我们易于理解的、分步教程将使您能够创建一个安全高效的WHIP服务，
彻底改变您的在线会议和直播体验。不要再让技术挑战阻碍您前进 - 深入了解我们的指南，从今天开始像专业人士一样进行流媒体！</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-1-create-oryx-by-one-click">Step 1: Create Oryx by One Click<a href="https://ossrs.io/lts/zh-cn/blog/obs-whip-internet-service#step-1-create-oryx-by-one-click" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h3>
<p>如果您使用腾讯云轻量服务器，只需点击一下即可创建Oryx。请参考 <a class="" href="https://ossrs.io/lts/zh-cn/blog/Oryx-Tutorial">Oryx - 起步、购买和入门</a> 这个博客。</p>
<p>您还可以使用Docker通过单个命令行创建Oryx：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">docker run --rm -it -p 80:2022 -p 443:2443 -p 1935:1935 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -p 8080:8080 -p 8000:8000/udp -p 10080:10080/udp --name oryx \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -v $HOME/data:/data registry.cn-hangzhou.aliyuncs.com/ossrs/oryx:5</span><br></div></code></pre></div></div>
<p>创建Oryx后，您可以通过 <code>http://your-server-ip/mgmt</code> 访问它。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-2-get-the-whip-url-from-oryx">Step 2: Get the WHIP URL from Oryx<a href="https://ossrs.io/lts/zh-cn/blog/obs-whip-internet-service#step-2-get-the-whip-url-from-oryx" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>请从<a href="https://github.com/obsproject/obs-studio/releases" target="_blank" rel="noopener noreferrer" class="">此链接</a>下载 OBS 30 或更高版本，并继续进行安装。</p>
<p>打开 Oryx，选择<code>场景 &gt; 推拉直播流 &gt; WebRTC：WHIP OBS</code>，并操作步骤，获取一个WHIP的推流地址。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-12-12-01-c5794d74912fcd34ee2add46162f792e.png" width="720" height="614" class="img_ev3q"></p>
<p>请复制 WHIP URL，因为我们将在 OBS 中使用它。请注意，可以使用 WHEP 播放器播放 WHIP 流或将其嵌入到您的
WordPress 网站中。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-3-publish-whip-via-obs-to-oryx">Step 3: Publish WHIP via OBS to Oryx<a href="https://ossrs.io/lts/zh-cn/blog/obs-whip-internet-service#step-3-publish-whip-via-obs-to-oryx" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>接下来，启动 OBS 并选择<code>设置 &gt; 流</code>。从<code>服务</code>下拉菜单中选择<code>WHIP</code>，并将 WHIP URL 设置到<code>服务器</code>字段中。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-12-12-02-67cffb90b54f2c770d920ecc6306cdd2.png" width="720" height="431" class="img_ev3q"></p>
<p>现在，您可以点击<code>开始直播</code>按钮将 WHIP 流发布到 Oryx。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-4-use-whep-to-view-the-stream">Step 4: Use WHEP to View the Stream<a href="https://ossrs.io/lts/zh-cn/blog/obs-whip-internet-service#step-4-use-whep-to-view-the-stream" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>在发布流之后，您可以使用WebRTC HTML5播放器查看它。从Oryx管理后台访问WHEP播放器。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-12-12-03-0cf70d9f6a2a23ff73c204ee5944c11a.png" width="720" height="329" class="img_ev3q"></p>
<p>此外，将WHEP播放器集成到您的WordPress网站中。请遵循Oryx管理后台上提供的指南。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://ossrs.io/lts/zh-cn/blog/obs-whip-internet-service#conclusion" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>总之，我们的全面指南为您提供了一种简单高效的方法，使用Oryx为OBS创建公共互联网WHIP服务。通过遵循我们易于理解的分步教程，
您现在可以毫不费力地仅通过单击一下即可构建自己的WHIP服务，无需应对复杂的安全性、认证和WebRTC问题。有了这个新发现的知识，
您可以彻底改变您的在线会议和直播体验，充分利用OBS的WHIP支持实现亚秒级流媒体和无缝OBS-RTC房间连接。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.net/gif/v1/sls.gif?site=ossrs.net&amp;path=/lts/blog-zh/2023-12-12-Oryx-OBS-WHIP-Service" alt="" class="img_ev3q"></p>]]></content:encoded>
            <category>live</category>
            <category>obs</category>
            <category>whip</category>
            <category>streaming</category>
        </item>
        <item>
            <title><![CDATA[Oryx - 直播流AI自动字幕]]></title>
            <link>https://ossrs.io/lts/zh-cn/blog/live-streams-transcription</link>
            <guid>https://ossrs.io/lts/zh-cn/blog/live-streams-transcription</guid>
            <pubDate>Tue, 28 Nov 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[Introduction]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="introduction">Introduction<a href="https://ossrs.io/lts/zh-cn/blog/live-streams-transcription#introduction" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>在这篇博客中，我们将探讨一种正在改变直播体验的创新方法：使用自动语音识别（ASR）来创建实时字幕。您是否曾想过如何使
直播对听力障碍者或说不同语言的人更具包容性？答案在于一项正在重塑我们体验直播内容的创新技术。</p>
<!-- -->
<p>我们的重点是ASR领域的一个颠覆性工具——OpenAI的Whisper。这不仅仅是一项技术；它是一个强大的AI服务，能够理解世界上
几乎所有的语言，并以惊人的准确度转录语音。忘掉过去需要昂贵专业人士进行现场翻译和转录的日子。有了OpenAI的Whisper，
这个过程变得自动化、高效且经济。</p>
<p>这个为初学者设计的指南将带您了解如何将Whisper AI整合到您的直播中，实时识别和转录语音。然后，我们将向您展示如何
使用FFmpeg具，将这些字幕无缝叠加到您的直播上。所有这些都通过Oryx轻松实现，该技术将这些技术无缝连接，
只需点击一下。</p>
<p>我们一起迈入以AI为动力的直播未来，其中无障碍和包容性至关重要，使您的内容更加愉快，且能触及更广泛的观众。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-1-create-oryx-by-one-click">Step 1: Create Oryx by One Click<a href="https://ossrs.io/lts/zh-cn/blog/live-streams-transcription#step-1-create-oryx-by-one-click" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h3>
<p>如果您使用腾讯云轻量服务器，只需点击一下即可创建Oryx。请参考 <a class="" href="https://ossrs.io/lts/zh-cn/blog/Oryx-Tutorial">Oryx - 起步、购买和入门</a> 这个博客。</p>
<p>您还可以使用Docker通过单个命令行创建Oryx：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">docker run --rm -it -p 80:2022 -p 443:2443 -p 1935:1935 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -p 8080:8080 -p 8000:8000/udp -p 10080:10080/udp --name oryx \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -v $HOME/data:/data registry.cn-hangzhou.aliyuncs.com/ossrs/oryx:5</span><br></div></code></pre></div></div>
<p>创建Oryx后，您可以通过 <code>http://your-server-ip/mgmt</code> 访问它。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-2-publish-a-live-stream-to-oryx">Step 2: Publish a Live Stream to Oryx<a href="https://ossrs.io/lts/zh-cn/blog/live-streams-transcription#step-2-publish-a-live-stream-to-oryx" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>您可以使用 OBS 或 FFmpeg 将直播流发布到 Oryx。您还可以设置 HTTPS 并通过 WebRTC 发布。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-11-28-02-cc048d41ddeaa4e1970f1649b0ded739.png" width="720" height="640" class="img_ev3q"></p>
<p>发布流后，您可以使用 H5 播放器或 VLC 预览它。
请参阅<a class="" href="https://ossrs.io/lts/zh-cn/blog/Oryx-Tutorial">如何通过 1-Click 设置视频流服务</a>了解详细信息。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-3-setup-openai-secret-key-for-whisper-asr">Step 3: Setup OpenAI Secret Key for Whisper ASR<a href="https://ossrs.io/lts/zh-cn/blog/live-streams-transcription#step-3-setup-openai-secret-key-for-whisper-asr" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>要使用 Whisper ASR，您必须从 OpenAI 获取一个密钥。请在您的浏览器中打开 <a href="https://platform.openai.com/api-keys" target="_blank" rel="noopener noreferrer" class="">API 密钥</a>
页面，然后点击 <code>创建新的密钥</code> 按钮。密钥创建后，复制它并在 Oryx 中设置。然后，如下图所示，点击 <code>测试OpenAI服务可用性</code>
按钮。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-11-28-04-b2aed71fdf52c019f5b841b73dac8a92.png" width="720" height="677" class="img_ev3q"></p>
<p>如果测试成功，您可以点击 <code>开启AI字幕</code> 按钮以开始直播自动加字幕。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-4-view-live-stream-with-subtitles">Step 4: View Live Stream with Subtitles<a href="https://ossrs.io/lts/zh-cn/blog/live-streams-transcription#step-4-view-live-stream-with-subtitles" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>当生成HLS片段时，Oryx使用FFmpeg将TS片段转码为音频MP4文件。然后，它利用OpenAI的Whisper服务将其转换为SRT字幕。
接下来，将字幕覆盖到原始TS文件上，从而创建一个新的直播流。</p>
<p>页面中有链接可以播放带有字幕的新生成的直播流。您可以直接在浏览器中打开此链接，如下图所示。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-11-28-06-035bb34dc84aceb931ac4a86214e1f08.png" width="720" height="588" class="img_ev3q"></p>
<p>在浏览器中打开HLS流链接，以看到带有字幕的直播。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-11-28-07-4fddafac5c9c470aa8f4c8770c2657ff.png" width="576" height="333" class="img_ev3q"></p>
<p>您还可以使用HTTP API获取每个HLS片段的ASR结果，并执行诸如翻译或与您的AI系统集成等操作。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="hls-with-webvtt">HLS with WebVTT<a href="https://ossrs.io/lts/zh-cn/blog/live-streams-transcription#hls-with-webvtt" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>您可以为 HLS 启用 Web Video Text Tracks (WebVTT)。首先，在 <code>AI字幕 &gt; 服务设置 &gt; WebVTT字幕</code> 中启用 WebVTT，
勾选 <code>是否开启WebVTT字幕</code> 复选框。</p>
<p>然后，打开 <code>直播流管理操作</code> 标签页，您将获得一个带有 WebVTT 字幕的 HLS 流。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://ossrs.io/lts/zh-cn/blog/live-streams-transcription#conclusion" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>Oryx将OpenAI的Whisper和FFmpeg整合在一起，彻底改变了直播方式，使观众体验更佳，通过提供包容性的AI驱动字幕。
这种从手动转录到自动化转录的转变既节约成本又扩大了全球可及性，克服了语言和听力障碍。我们正在进入一个AI增强数字包容性
的未来，丰富了我们在线分享和消费内容的方式。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.net/gif/v1/sls.gif?site=ossrs.net&amp;path=/lts/blog-zh/23-11-28-Oryx-Live-Streams-Transcription" alt="" class="img_ev3q"></p>]]></content:encoded>
            <category>live</category>
            <category>ai</category>
            <category>transcription</category>
            <category>asr</category>
            <category>subtitles</category>
        </item>
        <item>
            <title><![CDATA[SRS - 用FFmpeg推送RTMP HEVC流]]></title>
            <link>https://ossrs.io/lts/zh-cn/blog/unlock-the-power-of-hevc-via-rtmp</link>
            <guid>https://ossrs.io/lts/zh-cn/blog/unlock-the-power-of-hevc-via-rtmp</guid>
            <pubDate>Thu, 26 Oct 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[Introduction]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="introduction">Introduction<a href="https://ossrs.io/lts/zh-cn/blog/unlock-the-power-of-hevc-via-rtmp#introduction" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>HEVC（或H.265）与广泛使用的H.264编码相比，可以将带宽使用量减少约50%，而H.264具有最佳的兼容性。在过去的10年里，
HEVC的发展速度较慢，因为新的编码需要一个生态系统来支持它，包括解码器和设备硬件。现在，OBS和FFmpeg都支持RTMP和FLV的HEVC，
这些都是直播行业的标准工具。</p>
<!-- -->
<p>在直播中，所有必要的工具都已准备好支持HEVC。对于编码，FFmpeg和OBS是最常用的直播工具。OBS 29+支持带有HEVC的RTMP，
而FFmpeg 6支持带有HEVC的RTMP。对于HTML5播放器，mpegts.js 1.7.3已经通过HTTP-FLV或HTTP-TS支持HEVC。
VLC和ffplay还通过HTTP-TS、SRT和HLS支持HEVC。对于媒体服务器，SRS 6通过RTMP、FLV、TS、HLS、SRT、WebRTC等支持HEVC。</p>
<p>在本教程中，我们介绍了几个月前刚添加了HEVC支持的FFmpeg 6。这是一个重要的发展，因为许多使用FFmpeg的工具现在可以通过
RTMP无需任何补丁就可以使用HEVC。</p>
<blockquote>
<p>Note: 如果您有兴趣了解 OBS 通过 RTMP 支持 HEVC，请阅读
<a class="" href="https://ossrs.io/lts/zh-cn/blog/push-hevc-via-rtmp-by-obs">如何通过 OBS 推送 RTMP 的 HEVC</a>。</p>
</blockquote>
<blockquote>
<p>Note: 请注意，SRS 6.0 已经支持 RTMP、HTTP-FLV、SRT、HTTP-TS、HLS、MPEG-DASH
和 WebRTC（Safari）的 HEVC（H.265），请参考 <a class="" href="https://ossrs.io/lts/zh-cn/blog/lets-do-h265-live-streaming">H.265 直播节省 50% 成本</a>。</p>
</blockquote>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-1-run-srs-media-server">Step 1: Run SRS Media Server<a href="https://ossrs.io/lts/zh-cn/blog/unlock-the-power-of-hevc-via-rtmp#step-1-run-srs-media-server" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>如果您需要创建自己的直播平台，可以使用支持通过RTMP使用HEVC的SRS媒体服务器。</p>
<p>要运行SRS，您可以使用Docker并使用以下命令：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">docker run --rm -it -p 1935:1935 -p 8080:8080 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  registry.cn-hangzhou.aliyuncs.com/ossrs/srs:6 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ./objs/srs -c conf/docker.conf</span><br></div></code></pre></div></div>
<p>可以打开链接，检查是否正常启动：<a href="http://localhost:8080/" target="_blank" rel="noopener noreferrer" class="">http://localhost:8080</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-2-publish-by-ffmpeg-6">Step 2: Publish by FFmpeg 6<a href="https://ossrs.io/lts/zh-cn/blog/unlock-the-power-of-hevc-via-rtmp#step-2-publish-by-ffmpeg-6" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>如果您按照此<a class="" href="https://ossrs.io/lts/zh-cn/docs/v6/doc/hevc#ffmpeg-tools">帖子</a>中的说明使用源代码编译了FFmpeg 6，
现在您可以使用FFmpeg发布RTMP HEVC流：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">ffmpeg -stream_loop -1 -re -i doc/source.flv -acodec copy \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -vcodec libx265 -f flv rtmp://localhost/live/livestream</span><br></div></code></pre></div></div>
<p>请注意，需要确认你的代码，需要更新到这个Commit之后，才支持HEVC via RTMP
<a href="https://github.com/FFmpeg/FFmpeg/commit/637c761be1bf9c3e1f0f347c5c3a390d7c32b282" target="_blank" rel="noopener noreferrer" class="">637c761b</a>:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">commit 637c761be1bf9c3e1f0f347c5c3a390d7c32b282</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Author: Steven Liu &lt;liuqi05@kuaishou.com&gt;</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Date:   Mon Aug 28 09:59:24 2023 +0800</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    avformat/rtmpproto: support enhanced rtmp</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    add option named rtmp_enhanced_codec,</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    it would support hvc1,av01,vp09 now,</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    the fourcc is using Array of strings.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Signed-off-by: Steven Liu &lt;lq@chinaffmpeg.org&gt;</span><br></div></code></pre></div></div>
<p>SRS为FFmpeg 4和5版本提供了Docker支持，这使得可以通过RTMP实现HEVC直播。您可以方便地使用Docker直接发布您的实时流。</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># For macOS</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">docker run --rm -it registry.cn-hangzhou.aliyuncs.com/ossrs/srs:encoder \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  ffmpeg -stream_loop -1 -re -i doc/source.flv -acodec copy \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    -vcodec libx265 -f flv rtmp://host.docker.internal/live/livestream</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># For Linux</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">docker run --net=host --rm -it registry.cn-hangzhou.aliyuncs.com/ossrs/srs:encoder \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  ffmpeg -stream_loop -1 -re -i doc/source.flv -acodec copy \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    -vcodec libx265 -f flv rtmp://127.0.0.1/live/livestream</span><br></div></code></pre></div></div>
<blockquote>
<p>Note: 如果要使用OBS，请从<a href="https://github.com/obsproject/obs-studio/releases" target="_blank" rel="noopener noreferrer" class="">这里</a>下载OBS 29+，
选择HEVC编解码器，请参阅<a class="" href="https://ossrs.io/lts/zh-cn/blog/push-hevc-via-rtmp-by-obs">如何通过OBS推送HEVC RTMP直播</a>了解详细信息。</p>
</blockquote>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-3-play-by-html5-player">Step 3: Play by HTML5 Player<a href="https://ossrs.io/lts/zh-cn/blog/unlock-the-power-of-hevc-via-rtmp#step-3-play-by-html5-player" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>要在您的网络浏览器中播放HEVC流，您可以使用mpegts.js 1.7.3+版本播放HTTP-FLV或HTTP-TS。</p>
<p>SRS播放器已集成了mpegts.js，因此您只需打开URL即可播放HEVC流：</p>
<ul>
<li class="">HTTP-FLV(by H5):  <a href="http://localhost:8080/players/srs_player.html?autostart=true" target="_blank" rel="noopener noreferrer" class="">http://localhost:8080/live/livestream.flv</a></li>
</ul>
<p>对于HLS流，hls.js不支持通过TS的HEVC。因此，您应该使用VLC或ffplay播放HLS流：</p>
<ul>
<li class="">HLS(by VLC or fflay): <code>http://localhost:8080/live/livestream.m3u8</code></li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://ossrs.io/lts/zh-cn/blog/unlock-the-power-of-hevc-via-rtmp#conclusion" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>由于OBS、FFmpeg和SRS媒体服务器等关键工具的支持，使用HEVC进行直播变得更加容易，使用户更容易从这种编解码器提供的带宽节省中受益。
按照本指南中的步骤，您可以使用HEVC和RTMP创建自己的直播平台，并使用像mpegts.js这样的HTML5播放器播放流，或者使用VLC和ffplay进行
HLS流播放。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.net/gif/v1/sls.gif?site=ossrs.net&amp;path=/lts/blog-zh/23-10-26-Unlock-the-Power-of-HEVC-via-RTMP" alt="" class="img_ev3q"></p>]]></content:encoded>
            <category>hevc</category>
            <category>rtmp</category>
            <category>obs</category>
            <category>ffmpeg</category>
            <category>live</category>
        </item>
        <item>
            <title><![CDATA[Oryx - 直播转码降低带宽并节约成本]]></title>
            <link>https://ossrs.io/lts/zh-cn/blog/Live-Transcoding</link>
            <guid>https://ossrs.io/lts/zh-cn/blog/Live-Transcoding</guid>
            <pubDate>Sat, 21 Oct 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[Introduction]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="introduction">Introduction<a href="https://ossrs.io/lts/zh-cn/blog/Live-Transcoding#introduction" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>在当今的数字世界中，直播流已成为企业、内容创作者和个人的必备工具。随着越来越多的观众收看直播，优化直播流体验和成本变得至关重要，
无论观众的网络速度或设备性能如何。实现这一目标的有效方法之一是通过直播转码，这个过程可以在不影响视频质量的情况下降低带宽并节省成本。
在这篇博客中，我们将探讨使用 Oryx 进行高效直播转码的好处，以及它如何带来显著的成本节省。</p>
<!-- -->
<p>直播转码涉及将 Oryx 使用 FFmpeg 转换的直播流转换为不同的比特率和分辨率，然后将其推送回 Oryx。这个过程通过降低流的
比特率来降低带宽，同时保持相同的质量。因此，整体观看带宽减少，为流媒体提供者和观众节省成本。</p>
<p>例如，考虑一个有 10,000 名观众观看相同 2Mbps 比特率流的直播场景。通过将流转码为 1Mbps，所需带宽减少到 10Gbps，节省了 50% 的成本。
这不仅使内容提供商受益，还确保了具有不同网络速度和设备的观众获得更流畅的观看体验。</p>
<p>请继续关注我们对直播转码世界的深入探讨，并学习如何利用 Oryx 的力量优化您的直播体验并节省成本。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-1-create-oryx-by-one-click">Step 1: Create Oryx by One Click<a href="https://ossrs.io/lts/zh-cn/blog/Live-Transcoding#step-1-create-oryx-by-one-click" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>创建 Oryx 很简单，只需点击一下，如果您使用 Digital Ocean droplet，就可以完成。
请参阅<a class="" href="https://ossrs.io/lts/zh-cn/blog/Oryx-Tutorial">如何通过 1-Click 设置视频流服务</a>了解详细信息。</p>
<p>您还可以使用 Docker 通过单个命令行创建 Oryx：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">docker run --restart always -d -it --name oryx -v $HOME/data:/data \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -p 80:2022 -p 443:2443 -p 1935:1935 -p 8000:8000/udp -p 10080:10080/udp \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  registry.cn-hangzhou.aliyuncs.com/ossrs/oryx:5</span><br></div></code></pre></div></div>
<p>创建 Oryx 后，您可以通过 <code>http://your-server-ip/mgmt</code> 访问它。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-2-publish-a-live-stream-to-oryx">Step 2: Publish a Live Stream to Oryx<a href="https://ossrs.io/lts/zh-cn/blog/Live-Transcoding#step-2-publish-a-live-stream-to-oryx" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>您可以使用 OBS 或 FFmpeg 将直播流发布到 Oryx。您还可以设置 HTTPS 并通过 WebRTC 发布。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-10-21-04-fbe9a7bec920b5675b7f6536eb6ed180.png" width="720" height="621" class="img_ev3q"></p>
<p>发布流后，您可以使用 H5 播放器或 VLC 预览它。
请参阅<a class="" href="https://ossrs.io/lts/zh-cn/blog/Oryx-Tutorial">如何通过 1-Click 设置视频流服务</a>了解详细信息。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-3-transcode-the-live-stream-to-lower-bitrate">Step 3: Transcode the Live Stream to Lower Bitrate<a href="https://ossrs.io/lts/zh-cn/blog/Live-Transcoding#step-3-transcode-the-live-stream-to-lower-bitrate" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>假设您使用 OBS 将 8Mbps 流发送到 Oryx，并且您无法在 OBS 中调整比特率。这可能是因为流是由您无法控制的供应商发布的，
或者您需要记录原始高分辨率流，或者某些设备（如 4K/8K 电视）需要高分辨率流。</p>
<p>然而，您的大多数观众在移动设备上观看直播，他们不需要 8Mbps 流。对于移动设备来说，2Mbps 流就足够了，他们的带宽可能只支持
2Mbps 比特率。在这种情况下，您可以使用转码将 8Mbps 流转换为 2Mbps 直播流。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-10-21-05-220f500e29778ab6f11934c8c49376aa.png" width="720" height="830" class="img_ev3q"></p>
<p>转码流后，您可以预览 2Mbps 版本或将其转发到另一个直播平台。
请参阅<a class="" href="https://ossrs.io/lts/zh-cn/blog/Stream-IP-Camera-Events">如何做RTSP监控摄像头直播</a>
了解更多信息。您还可以从 Oryx 拉取 RTMP 流并将其转发到其他地方。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="check-transcoding-status">Check Transcoding Status<a href="https://ossrs.io/lts/zh-cn/blog/Live-Transcoding#check-transcoding-status" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>您可以在 Oryx 仪表板中检查转码状态。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-10-21-06-1fe88df6096b9883cbffaf15c7a0ee72.png" width="720" height="353" class="img_ev3q"></p>
<p>您可以点击预览链接检查转码流，或将其转发到另一个直播平台。
请参阅<a class="" href="https://ossrs.io/lts/zh-cn/blog/Stream-IP-Camera-Events">如何做RTSP监控摄像头直播</a>
了解更多信息。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://ossrs.io/lts/zh-cn/blog/Live-Transcoding#conclusion" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>总之，我们讨论了使用 Oryx 和 FFmpeg 进行直播转码的好处。转码优化了具有不同网络速度和设备的观众的流媒体观看体验，
减少了带宽使用并节省了成本。我们介绍了设置 Oryx 和 FFmpeg、创建配置文件以及将转码流推送回 Oryx 的方法。
监控和调整设置对于实现最佳观众体验至关重要，转码还可以将高分辨率流转换为适用于移动设备的较低分辨率。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.net/gif/v1/sls.gif?site=ossrs.net&amp;path=/lts/blog-zh/2023-10-21-Live-Transcoding" alt="" class="img_ev3q"></p>]]></content:encoded>
            <category>live streaming</category>
            <category>transcode</category>
            <category>srs</category>
            <category>ffmpeg</category>
        </item>
        <item>
            <title><![CDATA[Oryx - 如何做RTSP监控摄像头直播]]></title>
            <link>https://ossrs.io/lts/zh-cn/blog/Stream-IP-Camera-Events</link>
            <guid>https://ossrs.io/lts/zh-cn/blog/Stream-IP-Camera-Events</guid>
            <pubDate>Wed, 11 Oct 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[Introduction]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="introduction">Introduction<a href="https://ossrs.io/lts/zh-cn/blog/Stream-IP-Camera-Events#introduction" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>您是否拥有一台仅支持 RTSP 协议的 IP 摄像头，并希望将其流式传输到视频号直播、B站和快手等各种直播平台？最简单的解决方案是使用
Oryx。只需点击一下，您就可以将 IP 摄像头流式传输到这些平台，实现 24/7 不间断直播。</p>
<!-- -->
<p>如何将IP摄像头的RTSP流转换为RTMP/RTMPS以用于直播平台？您可以使用OBS或Oryx。 OBS需要一个设备，而Oryx则在云服务器
上运行并在后端工作。请参阅下面的工作流程。</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">IP Camera ---RTSP---&gt; OBS or Oryx ---RTMP/RTMPS---&gt; 视频号、B站和快手</span><br></div></code></pre></div></div>
<p>Oryx 可帮助您连接多个 IP 摄像头并在各种平台上进行实时直播，使您的直播体验更加强大。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-1-create-oryx-by-one-click">Step 1: Create Oryx by One Click<a href="https://ossrs.io/lts/zh-cn/blog/Stream-IP-Camera-Events#step-1-create-oryx-by-one-click" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h3>
<p>如果您使用腾讯云轻量服务器，只需点击一下即可创建Oryx。请参考 <a class="" href="https://ossrs.io/lts/zh-cn/blog/Oryx-Tutorial">Oryx - 起步、购买和入门</a> 这个博客。</p>
<p>您还可以使用Docker通过单个命令行创建Oryx：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">docker run --rm -it -p 80:2022 -p 443:2443 -p 1935:1935 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -p 8080:8080 -p 8000:8000/udp -p 10080:10080/udp --name oryx \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -v $HOME/data:/data registry.cn-hangzhou.aliyuncs.com/ossrs/oryx:5</span><br></div></code></pre></div></div>
<p>创建Oryx后，您可以通过 <code>http://your-server-ip/mgmt</code> 访问它。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-2-pull-rtsp-stream-from-ip-camera">Step 2: Pull RTSP Stream from IP Camera<a href="https://ossrs.io/lts/zh-cn/blog/Stream-IP-Camera-Events#step-2-pull-rtsp-stream-from-ip-camera" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>创建Oryx后，打开后台，点击<code>应用场景 &gt; 虚拟直播 &gt; 视频号直播</code>，然后点击<code>拉流转推</code>，输入RTSP流地址，然后点击<code>确认</code>。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-10-11-21-3fb0e40251d48c8f03ba032b0b94ff25.png" width="720" height="364" class="img_ev3q"></p>
<p>转发RTSP流时，Oryx会自动为您生成一个静音音轨。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-21-optional-enable-extra-silent-audio-track">Step 2.1: (Optional) Enable Extra Silent Audio Track<a href="https://ossrs.io/lts/zh-cn/blog/Stream-IP-Camera-Events#step-21-optional-enable-extra-silent-audio-track" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>如果您的摄像头仅提供视频流，则必须启用额外的静音音轨，否则，发布到像视频号这样的直播平台将失败。
Oryx可以为您自动生成静音音轨。请选择<code>静音音频流</code>选项。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-10-11-29-b7f97f41474a11b60ae31cebb743d714.png" width="720" height="434" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-3-stream-ip-camera-to-wechat">Step 3: Stream IP Camera to WeChat<a href="https://ossrs.io/lts/zh-cn/blog/Stream-IP-Camera-Events#step-3-stream-ip-camera-to-wechat" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>若需要虚拟直播到视频号直播，请先在<a href="https://channels.weixin.qq.com/platform/live/liveBuild" target="_blank" rel="noopener noreferrer" class="">视频号直播</a>后台，创建直播。
然后，复制服务器地址和密钥。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-10-11-22-b2d4258b792bae4563e96a57aa582210.png" width="1280" height="654" class="img_ev3q"></p>
<p>请打开Oryx仪表板，然后单击<code>应用场景 &gt; 虚拟直播 &gt; 视频号直播</code>，然后在Oryx中单击<code>开始直播</code>。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-10-11-23-e50280130b07aba773b76a58a5044c98.png" width="720" height="561" class="img_ev3q"></p>
<p>您的流现在将在视频号直播上发布。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-10-11-24-c91345324509d4923e61e93081aeaa39.png" width="720" height="345" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-4-stream-ip-camera-to-bilibili">Step 4: Stream IP Camera to Bilibili<a href="https://ossrs.io/lts/zh-cn/blog/Stream-IP-Camera-Events#step-4-stream-ip-camera-to-bilibili" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h3>
<p>若需要虚拟直播到B站直播，请先在<a href="https://link.bilibili.com/p/center/index#/my-room/start-live" target="_blank" rel="noopener noreferrer" class="">B站直播</a>后台，创建直播。
然后，复制服务器地址和密钥。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-10-11-25-0e3bf32af3fd257a03c97f898de63377.png" width="720" height="406" class="img_ev3q"></p>
<p>请打开Oryx仪表板，然后单击<code>应用场景 &gt; 虚拟直播 &gt; B站直播</code>，然后在Oryx中单击<code>开始直播</code>。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-10-11-26-6bd2b0565dfc797837816543d39a25ab.png" width="720" height="530" class="img_ev3q"></p>
<p>您的流现在将在B站直播上发布。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-10-11-27-28497cd92f55071294af6ea1b55592f1.png" width="720" height="408" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-5-stream-ip-camera-to-custom">Step 5: Stream IP Camera to Custom<a href="https://ossrs.io/lts/zh-cn/blog/Stream-IP-Camera-Events#step-5-stream-ip-camera-to-custom" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h3>
<p>你也可以将流转给任意平台，甚至可以转给Oryx自己，在<code>应用场景 &gt; 私人直播间</code>中复制服务器地址和密钥。</p>
<p>请打开Oryx仪表板，然后单击<code>应用场景 &gt; 虚拟直播 &gt; 自定义平台</code>，然后在Oryx中单击<code>开始直播</code>。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-10-11-28-5df1d47fa6f671286ab5d5162bc56518.png" width="720" height="705" class="img_ev3q"></p>
<p>您的流现在将在自定义平台上发布。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://ossrs.io/lts/zh-cn/blog/Stream-IP-Camera-Events#conclusion" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>总之，通过Oryx，将您的RTSP IP摄像头流式传输到视频号直播、B站和快手等热门平台从未如此简单。只需几个简单的步骤，
您就可以在这些平台上为您的IP摄像头设置连续24/7的流式传输。通过使用Oryx，您还可以连接多个IP摄像头并实时流式传输到各种平台，
从而增强您的实时流式传输体验。所以，请尝试使用Oryx，并享受它为您的IP摄像头流式传输需求提供的便利和灵活性。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.net/gif/v1/sls.gif?site=ossrs.net&amp;path=/lts/blog-zh/2023-10-11-Stream-IP-Camera-Events" alt="" class="img_ev3q"></p>]]></content:encoded>
            <category>live streaming</category>
            <category>virual live events</category>
            <category>srs</category>
            <category>ip camera</category>
            <category>rtsp</category>
        </item>
        <item>
            <title><![CDATA[Oryx - 虚拟直播和无人直播间]]></title>
            <link>https://ossrs.io/lts/zh-cn/blog/Virtual-Live-Events</link>
            <guid>https://ossrs.io/lts/zh-cn/blog/Virtual-Live-Events</guid>
            <pubDate>Mon, 11 Sep 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[Introduction]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="introduction">Introduction<a href="https://ossrs.io/lts/zh-cn/blog/Virtual-Live-Events#introduction" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>虚拟直播是指将录制的视频文件，或者设备，或者网络流，转成直播推送到直播平台。比如在电商直播中，可以先录制好直播内容，商品的讲解。
比如在教育直播中，可以预先录制课程，在直播间播放课程。比如在线演讲和分享，可以将提前录制的内容在直播间播放。</p>
<p>虚拟直播让主播可以有充分的准备时间，让直播内容更加精美，可以避免经验不足的主播的焦虑，可以避免主播网络问题，可以7x24小时在
直播间做直播，可以触达更多的观众，可以让直播有更多的可能性。</p>
<!-- -->
<p>Oryx使您只需点击一次即可创建虚拟直播，并将其广播到多个平台，如视频号直播、B站和快手等各种直播平台。在这篇博客文章中，
我们将指导您如何使用Oryx创建虚拟直播。</p>
<p>在如今快节奏的世界中，由于所提供的便利性，虚拟直播正变得越来越受欢迎。无论是音乐会、足球比赛还是在线课程，您现在都可以使用视频文件创建虚拟直播，使其更具互动性并能触及更广泛的受众。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-1-create-oryx-by-one-click">Step 1: Create Oryx by One Click<a href="https://ossrs.io/lts/zh-cn/blog/Virtual-Live-Events#step-1-create-oryx-by-one-click" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h3>
<p>如果您使用腾讯云轻量服务器，只需点击一下即可创建Oryx。请参考 <a class="" href="https://ossrs.io/lts/zh-cn/blog/Oryx-Tutorial">Oryx - 起步、购买和入门</a> 这个博客。</p>
<p>您还可以使用Docker通过单个命令行创建Oryx：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">docker run --rm -it -p 80:2022 -p 443:2443 -p 1935:1935 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -p 8080:8080 -p 8000:8000/udp -p 10080:10080/udp --name oryx \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -v $HOME/data:/data registry.cn-hangzhou.aliyuncs.com/ossrs/oryx:5</span><br></div></code></pre></div></div>
<p>创建Oryx后，您可以通过 <code>http://your-server-ip/mgmt</code> 访问它。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-2-upload-your-video-file">Step 2: Upload your video file<a href="https://ossrs.io/lts/zh-cn/blog/Virtual-Live-Events#step-2-upload-your-video-file" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>创建Oryx后，打开后台，点击<code>应用场景 &gt; 虚拟直播 &gt; 视频号直播</code>，然后点击<code>Choose File</code>，选择您的视频文件，然后点击<code>上传文件</code>。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-09-11-21-985937babcd7ed9929037b7361ef101e.png" width="720" height="708" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-3-stream-file-to-wechat">Step 3: Stream file to WeChat<a href="https://ossrs.io/lts/zh-cn/blog/Virtual-Live-Events#step-3-stream-file-to-wechat" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>若需要虚拟直播到视频号直播，请先在<a href="https://channels.weixin.qq.com/platform/live/liveBuild" target="_blank" rel="noopener noreferrer" class="">视频号直播</a>后台，创建直播。
然后，复制服务器地址和密钥。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-09-11-22-b2d4258b792bae4563e96a57aa582210.png" width="1280" height="654" class="img_ev3q"></p>
<p>请打开Oryx仪表板，然后单击<code>应用场景 &gt; 虚拟直播 &gt; 视频号直播</code>，然后在Oryx中单击<code>开始直播</code>。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-09-11-23-b77f7d8b68776f35a33ff96c44edb279.png" width="720" height="704" class="img_ev3q"></p>
<p>您的流现在将在视频号直播上发布。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-09-11-24-5555d815f8a8768c9e769cc2d48b3406.png" width="480" height="367" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-4-stream-file-to-bilibili">Step 4: Stream file to Bilibili<a href="https://ossrs.io/lts/zh-cn/blog/Virtual-Live-Events#step-4-stream-file-to-bilibili" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h3>
<p>若需要虚拟直播到B站直播，请先在<a href="https://link.bilibili.com/p/center/index#/my-room/start-live" target="_blank" rel="noopener noreferrer" class="">B站直播</a>后台，创建直播。
然后，复制服务器地址和密钥。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-09-11-25-0e3bf32af3fd257a03c97f898de63377.png" width="720" height="406" class="img_ev3q"></p>
<p>请打开Oryx仪表板，然后单击<code>应用场景 &gt; 虚拟直播 &gt; B站直播</code>，然后在Oryx中单击<code>开始直播</code>。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-09-11-26-26e11abaa6a96c0a90e5d92c88335e8c.png" width="720" height="711" class="img_ev3q"></p>
<p>您的流现在将在B站直播上发布。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-09-11-27-28497cd92f55071294af6ea1b55592f1.png" width="720" height="408" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-5-stream-file-to-custom">Step 5: Stream file to Custom<a href="https://ossrs.io/lts/zh-cn/blog/Virtual-Live-Events#step-5-stream-file-to-custom" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h3>
<p>你也可以将流转给任意平台，甚至可以转给Oryx自己，在<code>应用场景 &gt; 私人直播间</code>中复制服务器地址和密钥。</p>
<p>请打开Oryx仪表板，然后单击<code>应用场景 &gt; 虚拟直播 &gt; 自定义平台</code>，然后在Oryx中单击<code>开始直播</code>。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-09-11-28-6dde31e05f6ce2fe61e2e19a25dd079f.png" width="720" height="711" class="img_ev3q"></p>
<p>您的流现在将在自定义平台上发布。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="optional-upload-video-file-by-other-tools">(Optional) Upload Video File by Other Tools<a href="https://ossrs.io/lts/zh-cn/blog/Virtual-Live-Events#optional-upload-video-file-by-other-tools" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>您还可以使用 FTP 或 SCP 等工具将视频文件上传到 <code>/data/upload</code> 文件夹。然后选择 <code>Use server file</code>，
输入视频文件的路径，并将其用作虚拟直播源。</p>
<p>这种方法使您能够上传非常大的文件，尤其是当基于网页的上传失败时。通过使用专业的上传工具，您可以继续上传或
通过多线程等功能加快上传过程。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://ossrs.io/lts/zh-cn/blog/Virtual-Live-Events#conclusion" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>总之，虚拟直播活动为在各种平台上播放预先录制的内容提供了便捷高效的方式，使其更加精致且触及更广泛的受众。通过减轻对于新手
直播者的焦虑并实现7x24直播，虚拟直播活动为各行各业带来了诸多可能性。Oryx 简化了创建和播放这些活动的过程，
满足了当今快节奏世界对这种互动体验的日益增长的需求。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.net/gif/v1/sls.gif?site=ossrs.net&amp;path=/lts/blog-zh/2023-09-11-Virtual-Live-Events" alt="" class="img_ev3q"></p>]]></content:encoded>
            <category>live streaming</category>
            <category>virual live events</category>
            <category>srs</category>
        </item>
        <item>
            <title><![CDATA[Oryx - 如何录制直播流为MP4文件和对接云存储]]></title>
            <link>https://ossrs.io/lts/zh-cn/blog/Record-Live-Streaming</link>
            <guid>https://ossrs.io/lts/zh-cn/blog/Record-Live-Streaming</guid>
            <pubDate>Sun, 10 Sep 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[Introduction]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="introduction">Introduction<a href="https://ossrs.io/lts/zh-cn/blog/Record-Live-Streaming#introduction" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>使用Oryx，您可以轻松录制直播流并将其发布到网页上供观众观看。在这篇博客中，我们将指导您如何使用Oryx将直播流录制为MP4文件。</p>
<!-- -->
<p>直播流越来越受欢迎，许多内容创作者希望录制他们的直播流以供日后使用或为观众提供视频点播（VoD）内容。虽然有多种方法可以录制直播流，
例如使用OBS，但一些嵌入式设备可能不支持录制或可能难以控制。在这种情况下，服务器端录制可能是一个更有效的解决方案。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-1-create-oryx-by-one-click">Step 1: Create Oryx by One Click<a href="https://ossrs.io/lts/zh-cn/blog/Record-Live-Streaming#step-1-create-oryx-by-one-click" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h3>
<p>如果您使用腾讯云轻量服务器，只需点击一下即可创建Oryx。请参考 <a class="" href="https://ossrs.io/lts/zh-cn/blog/Oryx-Tutorial">Oryx - 起步、购买和入门</a> 这个博客。</p>
<p>您还可以使用Docker通过单个命令行创建Oryx：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">docker run --rm -it -p 80:2022 -p 443:2443 -p 1935:1935 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -p 8080:8080 -p 8000:8000/udp -p 10080:10080/udp --name oryx \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -v $HOME/data:/data registry.cn-hangzhou.aliyuncs.com/ossrs/oryx:5</span><br></div></code></pre></div></div>
<p>创建Oryx后，您可以通过 <code>http://your-server-ip/mgmt</code> 访问它。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-2-publish-a-live-stream-to-oryx">Step 2: Publish a live stream to Oryx<a href="https://ossrs.io/lts/zh-cn/blog/Record-Live-Streaming#step-2-publish-a-live-stream-to-oryx" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h3>
<p>您可以使用OBS或FFmpeg将直播发布到Oryx。您还可以设置HTTPS并通过WebRTC发布。发布流后，您可以使用H5播放器或VLC预览它。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-09-09-13-cc048d41ddeaa4e1970f1649b0ded739.png" width="720" height="640" class="img_ev3q"></p>
<p>推流到Oryx后，你可以用网页预览它，也可以用VLC播放。
请参考 <a class="" href="https://ossrs.io/lts/zh-cn/blog/Oryx-Tutorial">Oryx - 起步、购买和入门</a> 这个博客。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-3-record-the-live-stream-by-oryx">Step 3: Record the Live Stream by Oryx<a href="https://ossrs.io/lts/zh-cn/blog/Record-Live-Streaming#step-3-record-the-live-stream-by-oryx" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>发布直播流后，您可以使用Oryx开始录制。为此，请打开<code>Scenarios &gt; Record &gt; Setup Record Rules</code>部分，
然后点击<code>Start Record</code>按钮。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-09-10-04-633149565f06f65593df7f6202b0d76a.png" width="720" height="479" class="img_ev3q"></p>
<p>录制过程将开始，您可以监控录制任务的进度。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-09-10-05-f2c1dd61ad9c3a37382010ff7081dbe2.png" width="720" height="404" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-4-stop-and-download-mp4-file">Step 4: Stop and Download MP4 File<a href="https://ossrs.io/lts/zh-cn/blog/Record-Live-Streaming#step-4-stop-and-download-mp4-file" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>当您想要停止录制时，请在<code>Setup Record Rules</code>部分点击<code>Stop Record</code>按钮。等待几秒钟，让录制停止。如果直播流不再发布，
Oryx将在几分钟后（例如5分钟）自动停止录制任务。</p>
<p>录制停止后，Oryx将把录制的文件转换为MP4格式。然后，您可以预览并下载MP4文件以供进一步使用或分发。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-09-10-03-1e27aadc1e7fac9a3804d89cca567bfa.png" width="720" height="363" class="img_ev3q"></p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-09-10-03-1e27aadc1e7fac9a3804d89cca567bfa.png" width="720" height="363" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-to-record-specific-streams">How to Record Specific Streams?<a href="https://ossrs.io/lts/zh-cn/blog/Record-Live-Streaming#how-to-record-specific-streams" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>参考 <a class="" href="https://ossrs.io/lts/zh-cn/faq-oryx#how-to-record-a-specific-stream">如何录制特定的流</a></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-to-record-to-s3-cloud-storage">How to Record to S3 Cloud Storage?<a href="https://ossrs.io/lts/zh-cn/blog/Record-Live-Streaming#how-to-record-to-s3-cloud-storage" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>参考 <a class="" href="https://ossrs.io/lts/zh-cn/faq-oryx#how-to-record-to-s3-cloud-storage">如何录制到S3云存储</a></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-to-merge-to-one-mp4-file">How to Merge to One Mp4 File?<a href="https://ossrs.io/lts/zh-cn/blog/Record-Live-Streaming#how-to-merge-to-one-mp4-file" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>参考 <a class="" href="https://ossrs.io/lts/zh-cn/faq-oryx#recording-doesnt-stop-when-the-stream-is-stopped">为何不能在停止推流时停止录制</a>
和 <a class="" href="https://ossrs.io/lts/zh-cn/faq-oryx#how-to-quickly-generate-a-recorded-file">如何快速生成录制文件</a></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://ossrs.io/lts/zh-cn/blog/Record-Live-Streaming#conclusion" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>将直播流录制为MP4文件对于希望为观众提供视频点播内容的内容创作者来说是非常有价值的功能。使用Oryx，录制、停止和
下载直播流的过程得到了简化，使您更容易管理和分发录制的内容。按照本博客中概述的步骤，您可以快速高效地录制直播流，
并使观众随时观看。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.net/gif/v1/sls.gif?site=ossrs.net&amp;path=/lts/blog-zh/2023-09-10-Record-Live-Streaming" alt="" class="img_ev3q"></p>]]></content:encoded>
            <category>live streaming</category>
            <category>record</category>
            <category>dvr</category>
            <category>srs</category>
        </item>
        <item>
            <title><![CDATA[Oryx - 如何实现多平台转播]]></title>
            <link>https://ossrs.io/lts/zh-cn/blog/Multi-Platform-Streaming</link>
            <guid>https://ossrs.io/lts/zh-cn/blog/Multi-Platform-Streaming</guid>
            <pubDate>Sat, 09 Sep 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[在当今的数字世界中，直播已成为企业、内容创作者和个人与受众互动的重要工具。随着视频号直播、B站和快手等各种直播平台的日益普及，同时在多个平台上播放内容已变得至关重要，以便触及更广泛的受众。本博客将指导您使用Oryx在多个平台上进行直播。]]></description>
            <content:encoded><![CDATA[<p>在当今的数字世界中，直播已成为企业、内容创作者和个人与受众互动的重要工具。随着视频号直播、B站和快手等各种直播平台的日益普及，同时在多个平台上播放内容已变得至关重要，以便触及更广泛的受众。本博客将指导您使用Oryx在多个平台上进行直播。</p>
<!-- -->
<p>Oryx是一种功能强大且易于使用的解决方案，只需点击几下鼠标即可在多个平台上进行直播。它还允许您将内容流式传输到自己的平台，甚至在公司内部设置内部网直播。让我们深入了解如何使用Oryx在多个平台上设置直播。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-1-create-oryx-by-one-click">Step 1: Create Oryx by One Click<a href="https://ossrs.io/lts/zh-cn/blog/Multi-Platform-Streaming#step-1-create-oryx-by-one-click" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h3>
<p>如果您使用腾讯云轻量服务器，只需点击一下即可创建Oryx。请参考 <a class="" href="https://ossrs.io/lts/zh-cn/blog/Oryx-Tutorial">Oryx - 起步、购买和入门</a> 这个博客。</p>
<p>您还可以使用Docker通过单个命令行创建Oryx：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">docker run --rm -it -p 80:2022 -p 443:2443 -p 1935:1935 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -p 8080:8080 -p 8000:8000/udp -p 10080:10080/udp --name oryx \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -v $HOME/data:/data registry.cn-hangzhou.aliyuncs.com/ossrs/oryx:5</span><br></div></code></pre></div></div>
<p>创建Oryx后，您可以通过 <code>http://your-server-ip/mgmt</code> 访问它。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-2-publish-a-live-stream-to-oryx">Step 2: Publish a live stream to Oryx<a href="https://ossrs.io/lts/zh-cn/blog/Multi-Platform-Streaming#step-2-publish-a-live-stream-to-oryx" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h3>
<p>您可以使用OBS或FFmpeg将直播发布到Oryx。您还可以设置HTTPS并通过WebRTC发布。发布流后，您可以使用H5播放器或VLC预览它。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-09-09-13-cc048d41ddeaa4e1970f1649b0ded739.png" width="720" height="640" class="img_ev3q"></p>
<p>推流到Oryx后，你可以用网页预览它，也可以用VLC播放。
请参考 <a class="" href="https://ossrs.io/lts/zh-cn/blog/Oryx-Tutorial">Oryx - 起步、购买和入门</a> 这个博客。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-3-forward-to-wechat">Step 3: Forward to WeChat<a href="https://ossrs.io/lts/zh-cn/blog/Multi-Platform-Streaming#step-3-forward-to-wechat" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h3>
<p>要将流转发到视频号直播，请先在<a href="https://channels.weixin.qq.com/platform/live/liveBuild" target="_blank" rel="noopener noreferrer" class="">视频号直播</a>后台，创建直播。
然后，复制服务器地址和密钥。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-09-09-14-b2d4258b792bae4563e96a57aa582210.png" width="1280" height="654" class="img_ev3q"></p>
<p>请打开Oryx仪表板，然后单击<code>应用场景 &gt; 多平台转播 &gt; 视频号直播</code>，然后在Oryx中单击<code>开始转播</code>。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-09-09-15-5ebcbe932436ba50a3f3b8de1069c1df.png" width="720" height="777" class="img_ev3q"></p>
<p>您的流现在将在视频号直播上发布。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-09-09-16-5555d815f8a8768c9e769cc2d48b3406.png" width="480" height="367" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-4-forward-to-bilibili">Step 4: Forward to Bilibili<a href="https://ossrs.io/lts/zh-cn/blog/Multi-Platform-Streaming#step-4-forward-to-bilibili" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h3>
<p>要将流转发到B站直播，请先在<a href="https://link.bilibili.com/p/center/index#/my-room/start-live" target="_blank" rel="noopener noreferrer" class="">B站直播</a>后台，创建直播。
然后，复制服务器地址和密钥。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-09-09-17-0e3bf32af3fd257a03c97f898de63377.png" width="720" height="406" class="img_ev3q"></p>
<p>请打开Oryx仪表板，然后单击<code>应用场景 &gt; 多平台转播 &gt; B站直播</code>，然后在Oryx中单击<code>开始转播</code>。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-09-09-18-b01077520fb474d66d4ff63e49875eff.png" width="720" height="581" class="img_ev3q"></p>
<p>您的流现在将在B站直播上发布。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-09-09-19-28497cd92f55071294af6ea1b55592f1.png" width="720" height="408" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-5-forward-to-custom">Step 5: Forward to Custom<a href="https://ossrs.io/lts/zh-cn/blog/Multi-Platform-Streaming#step-5-forward-to-custom" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h3>
<p>你也可以将流转给任意平台，甚至可以转给Oryx自己，在<code>应用场景 &gt; 私人直播间</code>中复制服务器地址和密钥。</p>
<p>请打开Oryx仪表板，然后单击<code>应用场景 &gt; 多平台转播 &gt; 自定义平台</code>，然后在Oryx中单击<code>开始转播</code>。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-09-09-20-1b49d47b731c57cef387eb0f004a3161.png" width="720" height="779" class="img_ev3q"></p>
<p>您的流现在将在自定义平台上发布。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-6-check-multiple-streaming-status">Step 6: Check Multiple Streaming Status<a href="https://ossrs.io/lts/zh-cn/blog/Multi-Platform-Streaming#step-6-check-multiple-streaming-status" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h3>
<p>在所有平台上发布流后，您可以在Oryx仪表板中检查多个流媒体状态。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-09-09-21-a67c2fa35320e09322f69523f9bf7e87.png" width="720" height="844" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://ossrs.io/lts/zh-cn/blog/Multi-Platform-Streaming#conclusion" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h3>
<p>在多个平台上进行直播是触及更广泛受众和提高参与度的有效方法。Oryx使此过程变得简单高效，让您专注于创建高质量内容，而它负责处理技术方面的问题。通过遵循本博客中概述的步骤，您可以轻松地在视频号、B站、快手等多个平台上设置直播，并将您的内容提升到一个新的水平。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.net/gif/v1/sls.gif?site=ossrs.net&amp;path=/lts/blog-zh/2023-09-09-Multi-Platform-Streaming" alt="" class="img_ev3q"></p>]]></content:encoded>
            <category>live streaming</category>
            <category>multi-platform streaming</category>
            <category>restreaming</category>
        </item>
        <item>
            <title><![CDATA[Oryx - 如何实现直播推流鉴权和安全]]></title>
            <link>https://ossrs.io/lts/zh-cn/blog/Ensuring-Authentication-in-Live-Streaming-Publishing</link>
            <guid>https://ossrs.io/lts/zh-cn/blog/Ensuring-Authentication-in-Live-Streaming-Publishing</guid>
            <pubDate>Tue, 29 Aug 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[在当今的数字时代，直播变得越来越受欢迎，像视频号和抖音这样的平台为用户提供了实时直播内容的能力。然而，随着这种越来越受]]></description>
            <content:encoded><![CDATA[<p>在当今的数字时代，直播变得越来越受欢迎，像视频号和抖音这样的平台为用户提供了实时直播内容的能力。然而，随着这种越来越受
欢迎的需求，加强安全性和认证措施以保护播放者和观众变得尤为重要。在这篇全面的指南中，我们将深入探讨直播中安全性和认证的重要性，
讨论Oryx解决方案以实现安全发布，并提供一步一步的指南来为您自己的直播服务设置Oryx。</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-importance-of-authentication-in-live-streaming">The Importance of Authentication in Live Streaming<a href="https://ossrs.io/lts/zh-cn/blog/Ensuring-Authentication-in-Live-Streaming-Publishing#the-importance-of-authentication-in-live-streaming" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>在视频号和抖音等平台上发布直播时，用户需要获取一个流密钥，并使用像OBS将流推送到直播平台。保持流密钥的私密性至关重要，
因为任何有权访问它的人都可以代表您发布流，触发违规行为。</p>
<p>对于那些希望建立自己的直播服务的人来说，确保安全性和认证变得更加关键。这就是Oryx的作用所在，通过使用Publish Secret
来提供安全发布的解决方案。</p>
<p>然而，过于复杂的安全设计也可能导致用户感到困惑和困难，使得流媒体平台难以使用。因此，实施一种安全且简单的解决方案对于
实时流媒体发布至关重要。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-oryx-solution-for-secure-publishing">The Oryx Solution for Secure Publishing<a href="https://ossrs.io/lts/zh-cn/blog/Ensuring-Authentication-in-Live-Streaming-Publishing#the-oryx-solution-for-secure-publishing" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>Oryx是一个强大的工具，帮助用户建立自己的直播服务，并增强安全性和认证功能。通过使用Publish Secret，Oryx
确保只有授权用户才能发布流，防止未经授权的访问并保护您的内容。</p>
<p>要设置Oryx以实现安全发布，请按照以下步骤操作：</p>
<ol>
<li class="">
<p>一键创建Oryx。有关详细说明，请访问<a class="" href="https://ossrs.io/lts/zh-cn/blog/Oryx-Tutorial">Oryx：起步、购买和入门</a></p>
</li>
<li class="">
<p>创建后，Oryx将自动生成一个Publish Secret，例如<code>5181a08ee6eab86597e913e1f9e4c294</code>。您可以从<code>System / Authentication / Update Stream Secret</code>设置它。</p>
</li>
<li class="">
<p>从<code>Scenarios / Streaming</code>复制OBS设置，包括<code>Server</code>和<code>StreamKey</code>。例如，<code>Server</code>可能是<code>rtmp://135.98.31.15/live/</code>，<code>StreamKey</code>可能是<code>livestream?secret=5181a08ee6eab86597e913e1f9e4c294</code>。</p>
</li>
</ol>
<p>打开HLS播放器播放流，例如 <code>http://135.98.31.15/live/livestream.m3u8</code></p>
<p>例如，您将获得以下网址：</p>
<ul>
<li class="">Publish URL: <code>rtmp://135.98.31.15/live/livestream?secret=5181a08ee6eab86597e913e1f9e4c294</code></li>
<li class="">Play URL: <code>http://135.98.31.15/live/livestream.m3u8</code></li>
</ul>
<p>请注意，播放流网址中不包含Publish Secret，防止观众知道Publish Secret。这样观众只能观看流，而不能发布。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="supporting-multiple-streams">Supporting Multiple Streams<a href="https://ossrs.io/lts/zh-cn/blog/Ensuring-Authentication-in-Live-Streaming-Publishing#supporting-multiple-streams" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>Oryx允许用户通过根据需要简单地更改资源名称（流名称）来支持多个流。例如，将流名称从<code>livestream</code>更改为<code>movie</code>：</p>
<ul>
<li class="">Publish URL: <code>rtmp://135.98.31.15/live/movie?secret=5181a08ee6eab86597e913e1f9e4c294</code></li>
<li class="">Play URL: <code>http://135.98.31.15/live/movie.m3u8</code></li>
</ul>
<p>或者您可以将<code>livestream</code>更改为<code>sport</code>：</p>
<ul>
<li class="">Publish URL: <code>rtmp://135.98.31.15/live/sport?secret=5181a08ee6eab86597e913e1f9e4c294</code></li>
<li class="">Play URL: <code>http://135.98.31.15/live/sport.m3u8</code></li>
</ul>
<p>您可以使用任何您喜欢的名称，例如，<code>the-10-years-anually-for-you</code> ：</p>
<ul>
<li class="">Publish URL: <code>rtmp://135.98.31.15/live/the-10-years-anually-for-you?secret=5181a08ee6eab86597e913e1f9e4c294</code></li>
<li class="">Play URL: <code>http://135.98.31.15/live/the-10-years-anually-for-you.m3u8</code></li>
</ul>
<blockquote>
<p>Note: 请注意这些流的Secret都是一样的。</p>
</blockquote>
<p>Oryx允许无限数量的同时流，唯一的限制是您的服务器带宽容量。此外，您可以自由选择任何所需的流名称。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="limitations-of-the-oryx">Limitations of the Oryx<a href="https://ossrs.io/lts/zh-cn/blog/Ensuring-Authentication-in-Live-Streaming-Publishing#limitations-of-the-oryx" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>然而，Oryx也有一些局限性。</p>
<p>截至目前，只支持全局的Publish Secret，也就是所有推流的Secret是一样的。这是为了保持简单和易用。目前不支持每个流
使用单独的Secret，这需要每次推流都需要生成密钥，并且需要考虑密钥的管理和过期。</p>
<p>此外，与YouTube和Twitch不同，Oryx不支持更改流名称，也就是在发布和播放时使用不同的流名称。这可能会令人困惑，
整体的复杂性很高， 因为它需要一个额外的系统来管理推流和播放流名称的映射。</p>
<p>最后，Oryx目前尚未支持播放流的认证，使流视图对所有人公开和可访问。如果您希望限制流的播放，请告诉我们。这个
功能已经在里规划中了，但没有具体的实施时间表。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://ossrs.io/lts/zh-cn/blog/Ensuring-Authentication-in-Live-Streaming-Publishing#conclusion" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>总之，安全性和认证是直播的重要方面，Oryx为那些建立自己的流媒体服务的人提供了一个简单的解决方案。
通过遵循本指南中概述的步骤，您可以确保您的直播服务保持安全并仅对授权用户可访问。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.net/gif/v1/sls.gif?site=ossrs.net&amp;path=/lts/blog-zh/2023-08-29-Ensuring-Authentication-for-Live-Streaming-Publishing" alt="" class="img_ev3q"></p>]]></content:encoded>
            <category>live streaming</category>
            <category>security</category>
            <category>authentication</category>
        </item>
        <item>
            <title><![CDATA[SRS - 体验OBS WHIP超低延迟直播！]]></title>
            <link>https://ossrs.io/lts/zh-cn/blog/Experience-Ultra-Low-Latency-Live-Streaming-with-OBS-WHIP</link>
            <guid>https://ossrs.io/lts/zh-cn/blog/Experience-Ultra-Low-Latency-Live-Streaming-with-OBS-WHIP</guid>
            <pubDate>Thu, 15 Jun 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[OBS现在支持WHIP功能，最近已经合并了这个补丁。这使得OBS WHIP具有各种新功能和可能性，]]></description>
            <content:encoded><![CDATA[<p>OBS现在支持WHIP功能，最近已经合并了这个补丁。这使得OBS WHIP具有各种新功能和可能性，
因为延迟从1秒降低到200毫秒。</p>
<p>在没有OBS WHIP的情况下，您可以使用RTMP+WebRTC进行直播，这将导致大约500ms的延迟。
然而，通过使用OBS WHIP，您可以实现低延迟直播，延迟大约为200ms。</p>
<!-- -->
<p>此外，即使在网络连接不佳或通过互联网进行流媒体传输的情况下，OBS WHIP也能保持稳定的
低延迟。</p>
<p>在这个视频中，我将演示如何轻松地将OBS WHIP与SRS结合使用，只需三个简单的步骤。</p>
<p>Oryx还支持OBS WHIP，使您只需点击一下即可建立WHIP服务。
请参考<a class="" href="https://ossrs.io/lts/zh-cn/blog/obs-whip-internet-service">为OBS快速构建公网WHIP服务</a>。</p>
<p>You can also watch the video on YouTube: <a href="https://youtu.be/SqrazCPWcV0" target="_blank" rel="noopener noreferrer" class="">Ultra Low Latency Streaming with OBS WHIP</a></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="prerequisites">Prerequisites<a href="https://ossrs.io/lts/zh-cn/blog/Experience-Ultra-Low-Latency-Live-Streaming-with-OBS-WHIP#prerequisites" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>请在继续操作之前安装以下软件：</p>
<ul>
<li class=""><a href="https://obsproject.com/download" target="_blank" rel="noopener noreferrer" class="">OBS Studio</a></li>
</ul>
<blockquote>
<p>注意：OBS WHIP已经合并到主分支，将在OBS 30版本中支持该功能。
您可以从<a href="https://github.com/obsproject/obs-studio/releases/tag/30.0.0-rc1" target="_blank" rel="noopener noreferrer" class="">这里</a>下载。</p>
</blockquote>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-1-run-srs">Step 1: Run SRS<a href="https://ossrs.io/lts/zh-cn/blog/Experience-Ultra-Low-Latency-Live-Streaming-with-OBS-WHIP#step-1-run-srs" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>运行以下命令以启动SRS：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">CANDIDATE="192.168.1.10"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">docker run --rm -it -p 1935:1935 -p 1985:1985 -p 8080:8080 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    --env CANDIDATE=$CANDIDATE -p 8000:8000/udp \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ossrs/srs:5 ./objs/srs -c conf/rtmp2rtc.conf</span><br></div></code></pre></div></div>
<blockquote>
<p>Note: 请将 CANDIDATE 设置为你的 IP 地址。关于如何设置CANDIDATE, 请参考<a class="" href="https://ossrs.io/lts/zh-cn/docs/v5/doc/webrtc#config-candidate">CANDIDATE</a></p>
</blockquote>
<p>有关配置详细信息，请参考<a class="" href="https://ossrs.io/lts/zh-cn/docs/v5/doc/getting-started#webrtc-for-live-streaming">这里</a>。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-2-run-obs">Step 2: Run OBS<a href="https://ossrs.io/lts/zh-cn/blog/Experience-Ultra-Low-Latency-Live-Streaming-with-OBS-WHIP#step-2-run-obs" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>打开OBS并单击<code>Settings</code>以进行以下配置：</p>
<ol>
<li class="">打开OBS并单击<strong>Settings</strong>。</li>
<li class="">单击左侧边栏上的<strong>Stream</strong>。</li>
<li class="">选择<code>WHIP</code>作为<strong>Service</strong>。</li>
<li class="">将<strong>Server</strong>设置为<code>http://localhost:1985/rtc/v1/whip/?app=live&amp;stream=livestream</code>。</li>
<li class="">单击<strong>OK</strong>以保存设置。</li>
<li class="">单击<strong>Start Streaming</strong>以开始直播。</li>
</ol>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-06-15-011-deacec98d951b217c462e98045fe9d88.png" width="576" height="159" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-3-play-the-stream">Step 3: Play the Stream<a href="https://ossrs.io/lts/zh-cn/blog/Experience-Ultra-Low-Latency-Live-Streaming-with-OBS-WHIP#step-3-play-the-stream" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>在浏览器中打开以下网址以播放流媒体：</p>
<p><a href="http://localhost:8080/players/whep.html" target="_blank" rel="noopener noreferrer" class="">http://localhost:8080/players/whep.html</a></p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-06-15-012-abe1b2c571cf5b9ebb287d0565d89d7a.png" width="720" height="450" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="cloud-service-and-support">Cloud Service and Support<a href="https://ossrs.io/lts/zh-cn/blog/Experience-Ultra-Low-Latency-Live-Streaming-with-OBS-WHIP#cloud-service-and-support" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>我测试了 TRTC 云服务，它与 OBS WHIP 配合得非常好。如果您正在寻找一个提供 24/7 支持的
WHIP 云服务，我强烈建议尝试 TRTC。要查看演示，请点击<a href="https://tencent-rtc.github.io/obs-trtc/" target="_blank" rel="noopener noreferrer" class="">这里</a>。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://ossrs.io/lts/zh-cn/blog/Experience-Ultra-Low-Latency-Live-Streaming-with-OBS-WHIP#conclusion" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>在本教程中，我们探讨了 OBS WHIP 的超低延迟直播功能，并演示了如何在仅需三个简单步骤的
情况下将其与 SRS 配置。OBS WHIP 显著降低了延迟，使其成为低延迟直播的绝佳选择。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.net/gif/v1/sls.gif?site=ossrs.net&amp;path=/lts/blog-zh/2023-06-15-Experience-Ultra-Low-Latency-Live-Streaming-with-OBS-WHIP" alt="" class="img_ev3q"></p>]]></content:encoded>
            <category>srs</category>
            <category>obs</category>
            <category>whip</category>
        </item>
        <item>
            <title><![CDATA[SRS - 解锁SRS真实应用场景]]></title>
            <link>https://ossrs.io/lts/zh-cn/blog/unlock-the-power-of-srs-real-world-use-cases</link>
            <guid>https://ossrs.io/lts/zh-cn/blog/unlock-the-power-of-srs-real-world-use-cases</guid>
            <pubDate>Mon, 22 May 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[发掘SRS服务器的能力，这是一款全能的开源媒体服务器解决方案，可以实现无缝的直播流媒体、内容创作和AI等系统集成，]]></description>
            <content:encoded><![CDATA[<p>发掘SRS服务器的能力，这是一款全能的开源媒体服务器解决方案，可以实现无缝的直播流媒体、内容创作和AI等系统集成，
支持视频号、抖音、B站和快手等平台上的多平台直播。</p>
<!-- -->
<p>You can also watch the video on YouTube: <a href="https://youtu.be/WChYr6z7EpY" target="_blank" rel="noopener noreferrer" class="">Unlock the Power of SRS: Real-World Use Cases and Boosting Your Business with Simple Realtime Server.</a></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="introduction">Introduction<a href="https://ossrs.io/lts/zh-cn/blog/unlock-the-power-of-srs-real-world-use-cases#introduction" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-05-22-001-da3c07638ea6857d97435f0c7583d0d4.png" width="1280" height="720" class="img_ev3q"></p>
<p>你好，我是 Winlin！</p>
<p>我创建了 SRS，即简单实时服务器，简称“SARS”。</p>
<p>SRS 是一款易于使用、高效的实时视频服务器，支持多种协议，如 RTMP、WebRTC、HLS、HTTP-FLV、SRT、MPEG-DASH和GB28181。</p>
<p>在这个视频中，我将介绍一些常见的 SRS 使用方法。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="project-compare-an-open-source-media-gateway-server">Project Compare, an open-source media gateway server.<a href="https://ossrs.io/lts/zh-cn/blog/unlock-the-power-of-srs-real-world-use-cases#project-compare-an-open-source-media-gateway-server" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-05-22-002-87ade753517e7ea0390c98aa62c388aa.png" width="1280" height="720" class="img_ev3q"></p>
<p>市面上有几个知名的开源媒体服务器，如用于直播的 NginxRTMP，用于 WebRTC 的 Janus 和 Mediasoup，当然还有 SRS，它涵盖了所有功能。</p>
<p>我们在 2013 年开始了 SRS 项目，最初支持 RTMP 和 HLS，延迟分别为 1-3 秒和 5-10 秒。SRS 还支持 HTTP-FLV 和 HTTP-TS，它们与 RTMP 类似。</p>
<p>2020 年，我们扩大了社区，并增加了对 WebRTC 和 SRT 的支持，实现了亚秒级延迟。SRT 延迟约为 300-500 毫秒，而 WebRTC 延迟在 80-200 毫秒之间。</p>
<p>SRS 充当媒体网关，在 RTMP、SRT 和 WebRTC 之间进行转换，因此您不需要三个单独的服务器。</p>
<p>我们还更新了文档和网站，您可以在 ossrs.net 上查看。SRS 取得了很大进展，但仍有更多工作要做。我们正在 Discord 上建立全球社区，帮助许多开发者并赢得他们的赞赏。</p>
<p>现在，让我向您介绍一些人们使用 SRS 的方法。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="live-origin-cluter-converting-streams-is-essential">Live Origin Cluter, converting streams is essential.<a href="https://ossrs.io/lts/zh-cn/blog/unlock-the-power-of-srs-real-world-use-cases#live-origin-cluter-converting-streams-is-essential" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-05-22-003-de69950c66117cf1b7d5068021558809.png" width="1280" height="720" class="img_ev3q"></p>
<p>第一个用例是Origin集群，它是一组Origin服务器。</p>
<p>Origin服务器是一种基本且必不可少的服务器，作为 SRS 网关，接收并转换来自发布者的流。</p>
<p>与扩展Origin服务器的边缘或代理服务器不同，Origin服务器至关重要。默认情况下，SRS 服务器充当Origin服务器，充当从各种发布者收集流的流中心。</p>
<p>您可以通过 RTMP、SRT 或 WebRTC 将实时流发送到Origin服务器，然后将它们转换为 HLS、HTTP-FLV、RTMP、SRT 和 WebRTC。</p>
<p>您还可以从Origin服务器拉取流，转码、DVR 或将它们转发到其他服务器，甚至将它们交付给 CDN 或使用 SRS 创建 CDN。</p>
<p>简而言之，这是 SRS 的一个关键功能。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="vrtual-live-streaming-boosting-business-with-virtual-live-streaming">Vrtual Live Streaming, boosting business with virtual live streaming.<a href="https://ossrs.io/lts/zh-cn/blog/unlock-the-power-of-srs-real-world-use-cases#vrtual-live-streaming-boosting-business-with-virtual-live-streaming" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-05-22-004-532a8a3cecd249d56ac279bf0fe94c9f.png" width="1280" height="720" class="img_ev3q"></p>
<p>你是一个拥有大量高质量视频的视频博主吗？你是否考虑过建立一个直播间来发展你的业务？</p>
<p>通过 Oryx，您可以轻松地将视频文件转换为直播流，无需亲自直播就可以吸引观众。</p>
<p>Oryx让您只需三个步骤就可以创建 24/7 虚拟直播：上传视频、设置直播间（如 视频号和抖音直播间），然后复制粘贴流密钥开始直播。</p>
<p>这很简单，不需要任何媒体流专业知识，而且 Oryx甚至可以免费将您的直播流重新发送到其他平台，因为它是开源的。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="video-blogger-empower-video-bloggers-with-live-streaming">Video Blogger, empower video bloggers with live streaming.<a href="https://ossrs.io/lts/zh-cn/blog/unlock-the-power-of-srs-real-world-use-cases#video-blogger-empower-video-bloggers-with-live-streaming" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-05-22-005-109ac59d77750e9f7fae89c354f88fa7.png" width="1280" height="720" class="img_ev3q"></p>
<p>如果您拥有一个 WordPress 网站，您可能考虑过添加直播功能，但由于 WordPress 的限制，以前无法实现。</p>
<p>但现在，有了 SRS 播放器 WordPress 插件，您可以使用 HTTP-FLV、HLS 和 WebRTC 进行直播，以及通过 HTTP-MP4 进行点播流。</p>
<p>只需使用 WordPress 短代码将直播播放器嵌入，您可以在 Oryx控制台中找到它。</p>
<p>这个强大的插件让每个人都可以使用直播，甚至在 WooCommerce（一款广泛使用的 WordPress 电子商务插件）中，展示了开源技术的影响力。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="unity-webrtc-streaming-make-unity-work-with-webrtc-sfu">Unity WebRTC Streaming, make Unity work with WebRTC SFU.<a href="https://ossrs.io/lts/zh-cn/blog/unlock-the-power-of-srs-real-world-use-cases#unity-webrtc-streaming-make-unity-work-with-webrtc-sfu" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-05-22-006-f04344b2a4d626b46538da8bb3990097.png" width="1280" height="720" class="img_ev3q"></p>
<p>SRS Unity 展示了 Unity 开发者如何使用与 SRS 兼容的 WebRTC SDK 集成直播。</p>
<p>您可以将 Unity 摄像头画面发送到 SRS，并在浏览器中播放流，从 SRS 检索流并在 Unity 游戏中显示，或者使用 WebRTC 使多个 Unity 游戏互动。</p>
<p>在这种情况下，SRS 充当 WebRTC SFU 服务器，这对生产环境中的 WebRTC Unity 客户端至关重要。</p>
<p>WebRTC P2P 在实际情况中并不可靠，但 SFU 服务器提供了更好的网络质量、可扩展性以及对 WebRTC-RTMP 转换的支持。</p>
<p>此外，您可以将 WebRTC 流记录为点播文件，SRS 与 Unity WebRTC SDK、Unity AR 和 VR 一起工作。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="remote-broadcasting--content-creator-enables-remote-content-creation-in-broadcasting">Remote Broadcasting &amp; Content Creator, enables remote content creation in broadcasting.<a href="https://ossrs.io/lts/zh-cn/blog/unlock-the-power-of-srs-real-world-use-cases#remote-broadcasting--content-creator-enables-remote-content-creation-in-broadcasting" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-05-22-007-f4f3cbef84ab1629c45b8cbea945234a.png" width="1280" height="720" class="img_ev3q"></p>
<p>SRS 可以应用于广播行业，开发远程内容创作系统。</p>
<p>Origin摄像头画面发送到 SRS，然后由远程编辑访问，编辑在编辑后的流上添加水印和徽标。</p>
<p>使用 SRT，延迟约为 300-500 毫秒，实现实时编辑和在摄像头画面之间切换。</p>
<p>低延迟确保所有流同步，使其成为远程内容创作的强大工具。</p>
<p>您可以在远离现场的地方进行编辑，并同时生成多个流，甚至使用 HEVC 或 AV1 生成 HDR 内容。</p>
<p>通过 SRS，您可以实现更高效的远程内容创作和实时编辑，从而提高广播行业的生产力和灵活性。这种技术的应用将有助于降低成本、提高效率，并为观众带来更丰富的视听体验。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="video--audio-ai-process-real-time-ai-processing-makes-more-possibilities">Video &amp; Audio AI Process, real-time AI processing makes more possibilities.<a href="https://ossrs.io/lts/zh-cn/blog/unlock-the-power-of-srs-real-world-use-cases#video--audio-ai-process-real-time-ai-processing-makes-more-possibilities" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-05-22-008-9dc2b5529391c5ea553e772c19cc6d3d.png" width="1280" height="720" class="img_ev3q"></p>
<p>SRS在AI领域的视频和音频处理方面也很有用。从SRS接收流，然后用AI模型处理它们，比如使用deepfake进行人脸替换。</p>
<p>SRS与音频处理的AI模型兼容，srs-k2项目就是一个例子，它演示了如何将SRS与k2-fsa一起用于ASR（Kaldi 2.0，一款流行的开源ASR工具包）。</p>
<p>srs-k2的端到端延迟约为400-800毫秒，可用于WebRTC多语言实时通信系统。这使得与不同语言的人进行对话以及与AIGC系统集成成为可能。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="hevcav1-for-avar8k-reduce-the-cost-significantly">HEVC/AV1 for AV/AR/8K, reduce the cost significantly.<a href="https://ossrs.io/lts/zh-cn/blog/unlock-the-power-of-srs-real-world-use-cases#hevcav1-for-avar8k-reduce-the-cost-significantly" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-05-22-009-75998bf2d4be942d3c0b8af8443a834e.png" width="1280" height="720" class="img_ev3q"></p>
<p>想要将直播费用减半，请考虑使用HEVC或AV1。</p>
<p>AV1是一种新的、开源的、免版税的视频编解码器，但其硬件解码器并不像HEVC那样普及。然而，它正在迅速获得关注，并对未来充满希望。</p>
<p>HEVC是业界广泛采用的编解码器，通过OBS支持RTMP和SRT。将HEVC流通过OBS发送到SRS，然后使用H5播放器、mpegjs.js、VLC或ffplay播放流。</p>
<p>HEVC或AV1对于8K直播至关重要，并在VR/AR领域变得越来越流行。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="restream-to-multiple-platforms-restream-to-multiple-platforms-without-extra-cost">Restream to Multiple Platforms, restream to multiple platforms without extra cost.<a href="https://ossrs.io/lts/zh-cn/blog/unlock-the-power-of-srs-real-world-use-cases#restream-to-multiple-platforms-restream-to-multiple-platforms-without-extra-cost" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-05-22-010-356af7c3c5c366acb960ec46829babf3.png" width="1280" height="720" class="img_ev3q"></p>
<p>想要在视频号、抖音、B站和快手等多个平台上直播吗？</p>
<p>Oryx简化了这个任务，而且不会占用你的带宽，因为它会为你处理重新推流。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="srs-prometheus-exporter-make-srs-an-operatable-online-product">SRS Prometheus Exporter, make SRS an operatable online product.<a href="https://ossrs.io/lts/zh-cn/blog/unlock-the-power-of-srs-real-world-use-cases#srs-prometheus-exporter-make-srs-an-operatable-online-product" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-05-22-011-06f22497bcc6b4af8cf48dee95b2fa7c.png" width="1280" height="720" class="img_ev3q"></p>
<p>Prometheus是一个著名的开源监控系统，通过其导出器，SRS可以原生支持它，让你可以密切关注SRS服务器。</p>
<p>使用Grafana可视化指标，并期待Prometheus和Grafana将来被整合到Oryx中。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="support-contributions-and-donations-are-welcome">Support, contributions and donations are welcome.<a href="https://ossrs.io/lts/zh-cn/blog/unlock-the-power-of-srs-real-world-use-cases#support-contributions-and-donations-are-welcome" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-05-22-012-42ee2d44cd9265f8bc014565d00bbff5.png" width="1280" height="720" class="img_ev3q"></p>
<p>如果想要支持SRS这个项目，请考虑加入SRS付费星球支持我们。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.net/gif/v1/sls.gif?site=ossrs.net&amp;path=/lts/blog-zh/2023-05-22-Unlock-the-Power-of-SRS-Real-World-Use-Cases" alt="" class="img_ev3q"></p>]]></content:encoded>
            <category>srs</category>
            <category>use-case</category>
        </item>
        <item>
            <title><![CDATA[SRS - 如何用浏览器做YouTube直播]]></title>
            <link>https://ossrs.io/lts/zh-cn/blog/how-to-stream-youtube-using-a-web-browser</link>
            <guid>https://ossrs.io/lts/zh-cn/blog/how-to-stream-youtube-using-a-web-browser</guid>
            <pubDate>Tue, 16 May 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[Written by Winlin and GPT4]]></description>
            <content:encoded><![CDATA[<blockquote>
<p>Written by <a href="https://github.com/winlinvip" target="_blank" rel="noopener noreferrer" class="">Winlin</a> and GPT4</p>
</blockquote>
<p>虽然Open Broadcaster Software（OBS）是通过RTMP或RTMPS向YouTube进行直播的广泛使用的解决方案，但还有一种利用网络浏览器的替代方法。</p>
<p>这种方法涉及在网页中使用WebRTC直播您的摄像头，然后使用Simple Realtime Server（SRS）将WebRTC转换为RTMP，并用FFmpeg将RTMP流发布到YouTube。对于那些更喜欢RTMPS的人，可以使用FFmpeg从SRS获取流，将RTMP转为RTMPS，然后发布到YouTube。</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-1-setting-up-srs">Step 1: Setting Up SRS<a href="https://ossrs.io/lts/zh-cn/blog/how-to-stream-youtube-using-a-web-browser#step-1-setting-up-srs" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>首先，从GitHub仓库克隆SRS：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">git clone https://github.com/ossrs/srs.git</span><br></div></code></pre></div></div>
<p>然后，执行以下命令编译SRS：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">./configure &amp;&amp; make</span><br></div></code></pre></div></div>
<p>最后，使用以下命令启动SRS：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">./objs/srs -c conf/rtc2rtmp.conf</span><br></div></code></pre></div></div>
<p>要确认成功安装，请在网络浏览器中访问 <a href="http://localhost:8080/" target="_blank" rel="noopener noreferrer" class="">http://localhost:8080</a></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-2-streaming-webrtc-to-srs">Step 2: Streaming WebRTC to SRS<a href="https://ossrs.io/lts/zh-cn/blog/how-to-stream-youtube-using-a-web-browser#step-2-streaming-webrtc-to-srs" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>打开网页 <a href="http://localhost:8080/players/whip.html" target="_blank" rel="noopener noreferrer" class="">http://localhost:8080/players/whip.html</a> ，通过WebRTC将您的摄像头流传输到SRS。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-05-16-001-2d0c7f99e59339f83f8d9efafb9c4d77.png" width="720" height="400" class="img_ev3q"></p>
<p>要预览RTMP流，请使用VLC播放<code>rtmp://localhost/live/livestream</code></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-3-routing-rtmp-to-youtube">Step 3: Routing RTMP to YouTube<a href="https://ossrs.io/lts/zh-cn/blog/how-to-stream-youtube-using-a-web-browser#step-3-routing-rtmp-to-youtube" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>访问YouTube直播流控制台，网址为 <a href="https://youtube.com/livestreaming/dashboard" target="_blank" rel="noopener noreferrer" class="">https://youtube.com/livestreaming/dashboard</a></p>
<p>获取流服务器（例如，<code>rtmp://a.rtmp.youtube.com/live2</code>）和流密钥（例如，<code>9xxx-8yyy-3zzz-3iii-7jjj</code>）。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-05-16-002-18ec54002497e911a0df182b58f978d3.png" width="720" height="447" class="img_ev3q"></p>
<p>使用FFmpeg从SRS提取RTMP流并将其转发到YouTube，命令如下：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">ffmpeg -i rtmp://localhost/live/livestream -c copy \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -f flv rtmp://a.rtmp.youtube.com/live2/9xxx-8yyy-3zzz-3iii-7jjj</span><br></div></code></pre></div></div>
<p><img decoding="async" loading="lazy" src="https://ossrs.io/lts/zh-cn/assets/images/blog-2023-05-16-003-5d6cb0bf2548f1b78da0b79920c33548.png" width="720" height="515" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-4-routing-rtmps-to-youtube">Step 4: Routing RTMPS to YouTube<a href="https://ossrs.io/lts/zh-cn/blog/how-to-stream-youtube-using-a-web-browser#step-4-routing-rtmps-to-youtube" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>要通过RTMPS传输流，请将RTMP URL从 <code>rtmp://a.rtmp.youtube.com/live2/9xxx-8yyy-3zzz-3iii-7jjj</code> 修改为RTMPS URL，例如 <code>rtmps://a.rtmp.youtube.com:443/live2/9xxx-8yyy-3zzz-3iii-7jjj</code></p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">ffmpeg -i rtmp://localhost/live/livestream -c copy \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -f flv rtmps://a.rtmp.youtube.com:443/live2/9xxx-8yyy-3zzz-3iii-7jjj</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://ossrs.io/lts/zh-cn/blog/how-to-stream-youtube-using-a-web-browser#conclusion" class="hash-link" aria-label="Direct link to heading" title="Direct link to heading" translate="no">​</a></h2>
<p>通过遵循这些说明，您可以使用网络浏览器有效地通过RTMP或RTMPS进行YouTube直播。这种技术为OBS提供了一种实用的替代方案，使您能够利用WebRTC、SRS和FFmpeg的功能，实现流畅高效的直播体验。</p>
<p><img decoding="async" loading="lazy" src="https://ossrs.net/gif/v1/sls.gif?site=ossrs.net&amp;path=/lts/blog-zh/2023-05-16-Stream-YouTube-Using-Web-Browser" alt="" class="img_ev3q"></p>]]></content:encoded>
            <category>youtube</category>
            <category>rtmp</category>
            <category>rtmps</category>
            <category>webrtc</category>
            <category>srs</category>
            <category>ffmpeg</category>
        </item>
    </channel>
</rss>