使用 C++ 和 GStreamer 将 RTMP 推流到本地

之前文章《使用GStreamer将网络摄像头数据传输到RTMP服务器》展示了如何将本地网络摄像头流式传输到 RTMP 服务器,这次我将向您展示如何使用 C++ 和 GStreamer 播放上述示例(或任何其他 RTMP 流)。

要求

  • C++知识
  • GStreamer基础知识
  • 安装了 GStreamer 开发库

编写程序

导入,打开一个名为“main.cpp”的文件并添加以下一行以导入 GStreamer:

#include <gst/gst.h>

接下来我们需要添加一个回调方法来监听 “on_pad_added “事件,与发送流不同的是,当你接收流时,你不会立即得到流,这将给你在尝试链接元素时带来链接器问题。

当接收时,最好添加一个回调,当流被实际接收时运行。像这样:

static void on_pad_added(GstElement *element, GstPad* pad, gpointer user_data)
{
  GstPad *sinkpad;
  GstElement *decoder = (GstElement *)user_data;

  sinkpad = gst_element_get_static_pad(decoder, "sink");
  gst_pad_link(pad, sinkpad);
  gst_object_unref(sinkpad);
}

以上将在添加 pad 时运行,并将元素添加到另一个元素 sinkpad(在本例中为 h264parse)。

接下来我们将创建一个主要方法并创建管道所需的元素等:

int main(int argc, char *argv[])
{
  GstElement *pipeline;
  GstElement *source;
  GstElement *demuxer;
  GstElement *parser;
  GstElement *decoder;
  GstElement *converter;
  GstElement *sink;
  GstBus *bus;
  GstMessage *message;
  GstStateChangeReturn ret;

上面只是创建了元素,接下来需要通过以下方式初始化 GStreamer:

gst_init(&argc, &argv);

最好在尝试初始化和其他 GStreamer 元素之前调用上面的方法。

接下来我们将通过以下方式初始化其他元素和管道:

source = gst_element_factory_make("rtmpsrc", NULL);
demuxer = gst_element_factory_make("flvdemux", NULL);
parser = gst_element_factory_make("h264parse", NULL);
decoder = gst_element_factory_make("avdec_h264", NULL);
converter = gst_element_factory_make("videoconvert", NULL);
sink = gst_element_factory_make("autovideosink", NULL);

pipeline = gst_pipeline_new("pipeline");

接下来我们将检查元素是否已正确创建,这是通过以下 if 语句完成的,如果无法创建元素,我们将结束程序:

if (!pipeline || !source || !demuxer || !parser || !decoder || !sink)
{
	g_printerr("Not all elements could be created.\n");

	return -1; 
}

接下来我们通过以下方式将元素添加到管道中:

gst_bin_add_many(GST_BIN(pipeline), source, demuxer, parser, decoder, converter, sink, NULL);

最后,我们现在可以通过以下方式将所有元素链接在一起:

if (!gst_element_link(source, demuxer))
{
	g_printerr("Elements could not be linked\n");
    gst_object_unref(pipeline);

    return -1;
}

if (!gst_element_link_many(parser, decoder, converter, sink, NULL))
{
    g_printerr("Element could not be linked\n");
    gst_object_unref(pipeline);

    return -1;
}

分离器和解析器将通过“on_pad_added”方法链接,所以我们不在这里做,在这里做可能会导致链接器错误,因为还没有流。

接下来我们将上面的“on_pad_added”回调添加到解复用器:

g_signal_connect(demuxer, "pad-added", G_CALLBACK(on_pad_added), parser);

使用以下内容设置 rtmpsrc url(注意,确保将 RTMP url 替换为您自己的)

g_object_set(source, "location", "rtmp://localhost:1935/stream/video", NULL);

最后,通过将其设置为播放状态来启动 GStreamer 管道:

ret = gst_element_set_state(pipeline, GST_STATE_PLAYING);

要检查更改是否成功,我们可以使用以下 if 语句:

if (ret == GST_STATE_CHANGE_FAILURE)
{
    g_printerr("Unable to set pipeline to the playing state\n");
    gst_object_unref(pipeline);

    return -1;
}

如果失败,程序将停止。

接下来我们还需要监听任何错误消息和/或 EOS 消息,这可以通过以下方式完成:

bus = gst_element_get_bus(pipeline);
message = gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, GstMessageType(GST_MESSAGE_ERROR | GST_MESSAGE_EOS));

if (message != NULL)
{
    GError * error;
    gchar *debug_info;

    switch (GST_MESSAGE_TYPE(message))
    {
	    case GST_MESSAGE_ERROR:
	        gst_message_parse_error(message, &error, &debug_info);
	        g_printerr("Error received from element %s: %s\n", GST_OBJECT_NAME(message->src), error->message);
	        g_printerr("Debugging information: %s\n", debug_info ? debug_info : "none");
	        g_clear_error(&error);
	        g_free(debug_info);
	        break;
	    case GST_MESSAGE_EOS:
	        g_print("End of stream");
	        break;
	    default:
	        g_printerr("Unknown message received\n");
	        break;
    }
    gst_message_unref(message);
  }

上面只是监听任何错误和/或 EOS 消息并显示日志信息,根据您要完成的任务,您可能需要实现更多逻辑。例如,如果您想将 RTMP 保存到视频文件。

最后我们通过以下方式清理代码:

gst_object_unref(bus);
gst_element_set_state(pipeline, GST_STATE_NULL);
gst_object_unref(pipeline);

return 0;

完毕!😃 现在我们需要构建项目,我将向您展示如何通过 CMakeLists 来构建项目。

创建 CMakeLists 文件

要构建项目,需要创建一个 CMakeLists.txt 文件,创建该文件并添加以下内容:

cmake_minimum_required(VERSION 3.10)
project(rtmprecv)

set(CMAKE_CXX_STANDARD 14) 

find_package(PkgConfig REQUIRED)
pkg_check_modules(GST REQUIRED gstreamer-1.0)

include_directories(${GST_INCLUDE_DIRS})

add_executable(rtmprecv main.cpp)
target_link_libraries(rtmprecv ${GST_LIBRARIES})

上面只是将代码与开发GStreamer依赖项链接起来,现在我们可以真正构建项目了!

这可以通过以下命令完成:

mkdir build && cd build
cmake ..
make

运行 make 后,会在构建目录中看到“rtmprecv”可执行文件。😆

运行示例

要运行该示例,需要一个 RTMP 源,这可以是我之前写的示例或你自己的 RTMP 源。请注意,如果您使用我之前的示例,则需要将 url 更改为以下“rtmp://localhost:1935/stream/video”。

./rtmprecv

如果一切顺利,应该能够在本地看到 RTMP 流。😎


结论

在本教程中,我向您展示了如何创建接收和显示 RTMP 流的 GStreamer/C++ 程序。我希望它对你有帮助,就像我制作它的乐趣一样。

如果您有任何问题或改进等,请在评论中告诉我,一如既往,你可以在我的存储库中找到示例代码:https://github.com/ethand91/rtmp-to-local

作者:Ethan Denvir

版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。

(0)

相关推荐

发表回复

登录后才能评论