当前位置: 首页 > 工具软件 > GStreamer SDK > 使用案例 >

在 Node.js 中使用 GStreamer

扶文光
2023-12-01

GStreamer 是一个用于创建流媒体应用程序的框架。使用 GStreamer 框架,可以设计和构建可以处理任何类型的流数据流的低延迟应用程序,包括音频和视频功能。

GStreamer 核心为插件、数据流和媒体类型处理提供了一个框架。它还提供了一个 API 来使用各种插件编写应用程序。

基于插件的框架提供了各种编解码器和其他功能,这些功能可以链接和排列在管道中,它定义了数据的流向。但是,在撰写本文时,还没有针对 GStreamer 应用程序的官方 Node.js 端口/绑定。

在这篇文章中,我们将通过以下部分讨论 GStreamer 的功能以及使用 Node 进行设置:

  • 功能和用例

  • GStreamer 插件架构

  • GStreamer 安装

  • 使用 Node.js 设置 GStreamer

  • 一些 GStreamer 限制

功能和用例

GStreamer 的主要用例之一是构建媒体播放器。作为开发人员,您可以使用大量强大的工具来创建媒体管道,而无需编写任何代码。

默认情况下,GStreamer 包含用于构建支持多种格式的媒体播放器的组件,包括 MP3、Ogg/Vorbis、MPEG-1/2、AVI、QuickTime、mod 等。

然而,GStreamer 提供的功能比其他媒体播放器要多得多。它的主要优点是可插入组件可以混合到任意管道中,以便编写视频或音频编辑应用程序。具体来说,GStreamer 提供:

  • 多媒体应用程序的 API

  • 插件架构

  • 管道架构

  • 一种媒体类型处理/协商机制

GStreamer 插件架构

通过插件,GStreamer 可以桥接到其他多媒体框架以重用现有组件(例如编解码器)和其他平台输入/输出机制。

GStreamer 的核心本质上与媒体无关。它只知道字节和块,并且只包含基本元素。所有的媒体处理功能都由内核外部的插件提供。这些告诉核心如何处理特定类型的媒体。

GStreamer 插件可以分为以下几组:

  • 协议处理

  • 来源:音频和视频(涉及协议插件)

  • 格式:解析器、格式化程序、复用器、解复用器、元数据、字幕

  • 编解码器:编码器和解码器

  • 过滤器:转换器、混音器、效果器

  • sinks:用于音频和视频(涉及协议插件)

GStreamer 安装

要安装 GStreamer,文档提供了多种方法供您选择,具体取决于您选择的操作系统。

对于 macOS X,我们需要安装 OSX Snow Leopard (10.6) 或更高版本以及 XCode 3.2.6 或更高版本。但是,推荐的系统版本是带有 XCode 8 的 macOS Sierra。我们可以从 GStreamer 下载页面安装运行时和开发安装程序,我们可以在这里找到。

对于其他操作系统/环境,包括 Windows、iOS、Android 和 Linux,我们可以查看文档中的下载页面,其中包含所有支持的生态系统列表以及为开发目的构建 GStreamer SDK 的方法。

我们可以导航到/Library/Frameworks/GStreamer.framework/Commands系统路径上的 以查看可用的命令来使用 GStreamer。一些流行的命令包括gst-launch-1.0, gst-inspect-1.0, gst-play-1.0.

使用 Node.js 设置 GStreamer

安装后,我们可以继续使用 Node.js 运行时来使用 GStreamer 管道并将结果输出到 Web 浏览器。


超过 20 万开发人员使用 LogRocket 来创造更好的数字体验了解更多 →


让我们创建一个我们选择的文件夹并使用 npm 或 Yarn 安装 Express.js,然后按照说明设置一个带有package.json文件的基本项目:

npm install express or yarn add express

然后继续创建一个index.js文件来保存我们使用 GStreamer 的流式传输示例的 JavaScript 代码。请参阅index.js下面的文件:

const express = require('express')
const http = require('http')
const net = require('net');
const child = require('child_process');
​
const app = express();
app.use(express.static(__dirname + '/'));
​
const httpServer = http.createServer(app);
const port = 3000;  
​
//send the html page which holds the video tag
app.get('/', function (req, res) {
    res.send('index.html');
});
​
//stop the connection
app.post('/stop', function (req, res) {
    console.log('Connection closed using /stop endpoint.');
    if (gstMuxer != undefined) {
        gstMuxer.kill();    //kill the GStreamer Pipeline
    }
    gstMuxer = undefined;
    res.end();
});
​
//send the video stream
app.get('/stream', function (req, res) {
    res.writeHead(200, {
        'Content-Type': 'video/webm',
    });
​
    const tcpServer = net.createServer(function (socket) {
        socket.on('data', function (data) {
            res.write(data);
        });
        socket.on('close', function () {
            console.log('Socket closed.');
            res.end();
        });
    });
​
    tcpServer.maxConnections = 1;
​
    tcpServer.listen(function () {
        console.log("Connection started.");
        if (gstMuxer == undefined) {
            console.log("inside gstMuxer == undefined");
            const cmd = 'gst-launch-1.0';
            const args = getGstPipelineArguments(this);
            const gstMuxer = child.spawn(cmd, args);
            gstMuxer.stderr.on('data', onSpawnError);
            gstMuxer.on('exit', onSpawnExit);
        }
        else {
            console.log("New GST pipeline rejected because gstMuxer != undefined.");
        }
    });
});
​
httpServer.listen(port);
console.log(`Camera Streaming App listening at http://localhost:${port}`)
​
process.on('uncaughtException', function (err) {
    console.log(err);
});
​
//functions
function onSpawnError(data) {
    console.log(data.toString());
}
​
function onSpawnExit(code) {
    if (code != null) {
        console.log('GStreamer error, exit code ' + code);
    }
}
​
function getGstPipelineArguments(tcpServer) {
    const args =
        ['/Users/alexandernnakwue/Downloads/samplevideo.mp4', 'pattern=ball',
            '!', 'video/x-raw,width=320,height=240,framerate=100/1',
            '!', 'vpuenc_h264', 'bitrate=2000',
            '!', 'mp4mux', 'fragment-duration=10',
            '!', 'tcpclientsink', 'host=localhost',
            'port=' + tcpServer.address().port];
    return args;
}

正如我们在上面的文件中看到的,我们有三个端点:

  1. 用于发送 HTML 页面的端点,其中包含视频标签

  2. 发送视频流的端点

  3. 结束连接的端点

接下来,创建 HTML 页面 ( index.html),其中包含视频标签,如下所示。

<!DOCTYPE html>
<head>
    <title>GStreamer with NodeJS Demo</title>
    <meta name="viewport" content="width=device-width, initial-scale=0.9">
    <style>
        html,
        body {
            overflow: hidden;
        }
    </style> 
    <script>
        function buffer() {
            //Start playback as soon as possible to minimize latency at startup 
            const dStream = document.getElementById('vidStream');
            try {
                dStream.play();
            } catch (error) {
                console.log(error);
            }
​
        }
    </script>
</head>
​
<body οnlοad="buffer();">
    <video id="vidStream" width="640" height="480" muted>
        <source src="/stream" type="video/mp4" />
        <source src="/stream" type="video/webm" />
        <source src="/stream" type="video/ogg" />
        <!-- fallback -->
        Your browser does not support the video element. </video> </body>

正如我在介绍中提到的,目前没有针对 Node.js 的官方端口或绑定。上面的代码改编自这个Stack Overflow 帖子。

我们可以继续使用gst-launch-1.0命令启动流式应用程序和参数,其中包括用于流式传输的视频或音频源、TCP 端口和地址、设置等。随着页面加载,我们正在使用该方法尽快播放视频流play()。

注意:这仅适用于基于 Chromium 的浏览器。我将在下面解释更多。l

一些 Gstreamer 限制

目前针对 Node.js 的 GStreamer 实现是非标准化的并且仍然缺乏。例如,当前的实现并不完全兼容浏览器,并且仅适用于基于 Chromium 的实现,因为 Chrome 中加载资源所需的一些 HTTP 标头不可用。漫画帮追番App,解锁VIP限制无广告,动漫画质清晰度超高!此外,在某些系统架构上构建 GStreamer 仍然是一项艰巨的任务,因为它仍然包含大量错误。

GStreamer 尚不直接支持多种不同编程语言的端口。这意味着打算在 Node.js 应用程序中使用 GStreamer 的开发人员需要直接从 Nodenode-addon-api调用代码。但是,此方法需要大量工作,并且在使用node-gypC构建时尤其容易出错。

结论

我们可能已经注意到,目前 Node.js 的 GStreamer 绑定有限。

还有其他可用的绑定,例如node-gstreamer-superficial,但根据文档,它不会尝试成为 GStreamer 的完整 JS 绑定,并且希望有一天会被替换为(或实现为)node-gir。

其他可用的绑定或 hack 无法按预期工作、未标准化或容易出错。这确实是一个巨大的挑战,在不久的将来,需要构建一个标准化的、行业范围的 Node.js 绑定端口。

 类似资料: