【GStreamer 】5-4-USB相机转RTSP网络视频流优化转发

        我们使用gstreamer-rtsp-server ,实现了USB相机转RTSP网络流的基本功能,但是效果很一般,接下来我们需要做优化,以提升其整体性能。

        我自己的测试硬件环境在文章《【GStreamer 】USB相机 Jeston TX1平台测试环境说明_机器人虎哥的博客-CSDN博客》有说明,请必要的时候参考。

1、test-launch 测试,使用videotestsrc 为视频源

一直以来我们测试的命令为:使用videotestsrc 做为源,可以同时并发链接多路

./test-launch "( videotestsrc ! x264enc ! rtph264pay name=pay0 pt=96 )"

 

2、test-launch 测试,使用v4l2src device=/dev/video0 为视频源

./test-launch --gst-debug-level=3 "( v4l2src device=/dev/video0 ! videoconvert! videoscale ! video/x-raw, width=640, height=480, framerate=25/1 ! queue ! x264enc bitrate=2048 !  rtph264pay name=pay0 pt=96 )"

 

        发现使用USB相机做为视频源,链接第二路就会出现报错。

错误信息为:

Call to S_FMT failed for YUYV @ 640x480: Device or resource busy)
0:00:45.254816029 21038   0x55b0381590 WARN               rtspmedia rtsp-media.c:2573:wait_preroll: failed to preroll pipeline
0:00:45.254838113 21038   0x55b0381590 WARN               rtspmedia rtsp-media.c:2877:gst_rtsp_media_prepare: failed to preroll pipeline
0:00:45.259095810 21038   0x55b0381590 ERROR             rtspclient rtsp-client.c:767:find_media: client 0x55b0566d60: can't prepare media
0:00:45.259610808 21038   0x55b0381590 ERROR             rtspclient rtsp-client.c:2041:handle_setup_request: client 0x55b0566d60: media '/test' not found

        所以,我们其实可以理解为,这个测试代码,每次一个链接,都会从视频源开始到最后的封装,全部都重新建立一次,1中我们使用了videotestsrc 做为测试源,支持复用,2中我们的USB设备,就不支持复用了,所以报了Device or resource busy 的信息。

3、修改代码,USB相机源时支持多路复用转发

        上面我们测试,发现USB源测试时,不支持并发复用,无法支持多个客户端链接,如何修改,可以实现呢?仔细阅读官方给的示例代码后发现有这样的描述:

默认情况下,工厂将为每个客户机创建一个新管道。如果要在客户端之间共享管道,请使用 `gst_rtsp_media_factory_set_shared()`。

仔细阅读test-readme.c 代码:

/* GStreamer
​
 */
​
#include <gst/gst.h>
​
#include <gst/rtsp-server/rtsp-server.h>
​
int
main (int argc, char *argv[])
{
  GMainLoop *loop;
  GstRTSPServer *server;
  GstRTSPMountPoints *mounts;
  GstRTSPMediaFactory *factory;
​
  gst_init (&argc, &argv);
​
  loop = g_main_loop_new (NULL, FALSE);
​
  /* create a server instance */
  server = gst_rtsp_server_new ();
​
  /* get the mount points for this server, every server has a default object
   * that be used to map uri mount points to media factories */
  mounts = gst_rtsp_server_get_mount_points (server);
​
  /* make a media factory for a test stream. The default media factory can use
   * gst-launch syntax to create pipelines. 
   * any launch line works as long as it contains elements named pay%d. Each
   * element with pay%d names will be a stream */
  factory = gst_rtsp_media_factory_new ();
  gst_rtsp_media_factory_set_launch (factory,
      "( videotestsrc is-live=1 ! x264enc ! rtph264pay name=pay0 pt=96 )");
​
  gst_rtsp_media_factory_set_shared (factory, TRUE);
​
  /* attach the test factory to the /test url */
  gst_rtsp_mount_points_add_factory (mounts, "/test", factory);
​
  /* don't need the ref to the mapper anymore */
  g_object_unref (mounts);
​
  /* attach the server to the default maincontext */
  gst_rtsp_server_attach (server, NULL);
​
  /* start serving */
  g_print ("stream ready at rtsp://127.0.0.1:8554/test\n");
  g_main_loop_run (loop);
​
  return 0;
}

然后再阅读test-launch.c 代码

/* GStreamer
 */
​
#include <gst/gst.h>
​
#include <gst/rtsp-server/rtsp-server.h>
​
#define DEFAULT_RTSP_PORT "8554"
​
static char *port = (char *) DEFAULT_RTSP_PORT;
​
static GOptionEntry entries[] = {
  {"port", 'p', 0, G_OPTION_ARG_STRING, &port,
      "Port to listen on (default: " DEFAULT_RTSP_PORT ")", "PORT"},
  {NULL}
};
​
int
main (int argc, char *argv[])
{
  GMainLoop *loop;
  GstRTSPServer *server;
  GstRTSPMountPoints *mounts;
  GstRTSPMediaFactory *factory;
  GOptionContext *optctx;
  GError *error = NULL;
​
  optctx = g_option_context_new ("<launch line> - Test RTSP Server, Launch\n\n"
      "Example: \"( videotestsrc ! x264enc ! rtph264pay name=pay0 pt=96 )\"");
  g_option_context_add_main_entries (optctx, entries, NULL);
  g_option_context_add_group (optctx, gst_init_get_option_group ());
  if (!g_option_context_parse (optctx, &argc, &argv, &error)) {
    g_printerr ("Error parsing options: %s\n", error->message);
    g_option_context_free (optctx);
    g_clear_error (&error);
    return -1;
  }
  g_option_context_free (optctx);
​
  loop = g_main_loop_new (NULL, FALSE);
​
  /* create a server instance */
  server = gst_rtsp_server_new ();
  g_object_set (server, "service", port, NULL);
​
  /* get the mount points for this server, every server has a default object
   * that be used to map uri mount points to media factories */
  mounts = gst_rtsp_server_get_mount_points (server);
​
  /* make a media factory for a test stream. The default media factory can use
   * gst-launch syntax to create pipelines.
   * any launch line works as long as it contains elements named pay%d. Each
   * element with pay%d names will be a stream */
  factory = gst_rtsp_media_factory_new ();
  gst_rtsp_media_factory_set_launch (factory, argv[1]);
​
  gst_rtsp_media_factory_set_shared (factory, TRUE);
  
  /* attach the test factory to the /test url */
  gst_rtsp_mount_points_add_factory (mounts, "/test", factory);
​
  /* don't need the ref to the mapper anymore */
  g_object_unref (mounts);
​
  /* attach the server to the default maincontext */
  gst_rtsp_server_attach (server, NULL);
​
  /* start serving */
  g_print ("stream ready at rtsp://127.0.0.1:%s/test\n", port);
  g_main_loop_run (loop);
​
  return 0;
}
 

发现差别和描述是一致的:

    /* test-readme.c */
  factory = gst_rtsp_media_factory_new ();
  gst_rtsp_media_factory_set_launch (factory,
      "( videotestsrc is-live=1 ! x264enc ! rtph264pay name=pay0 pt=96 )");
​
  gst_rtsp_media_factory_set_shared (factory, TRUE);
​
  gst_rtsp_mount_points_add_factory (mounts, "/test", factory);
​
​
    /* test-launch.c  */
  factory = gst_rtsp_media_factory_new ();
  gst_rtsp_media_factory_set_launch (factory, argv[1]);
​
  gst_rtsp_mount_points_add_factory (mounts, "/test", factory);

发现这个区别和描述,我们再看看这个描述

默认情况下,工厂将为每个客户机创建一个新管道。如果要在客户端之间共享管道,请使用 `gst_rtsp_media_factory_set_shared()`。

我们修改test-launch.c 代码,重新命名一个新文件:test-launch2.c 修改后的代码:

/* GStreamer
 */
​
#include <gst/gst.h>
​
#include <gst/rtsp-server/rtsp-server.h>
​
#define DEFAULT_RTSP_PORT "8554"
​
static char *port = (char *) DEFAULT_RTSP_PORT;
​
static GOptionEntry entries[] = {
  {"port", 'p', 0, G_OPTION_ARG_STRING, &port,
      "Port to listen on (default: " DEFAULT_RTSP_PORT ")", "PORT"},
  {NULL}
};
​
int
main (int argc, char *argv[])
{
  GMainLoop *loop;
  GstRTSPServer *server;
  GstRTSPMountPoints *mounts;
  GstRTSPMediaFactory *factory;
  GOptionContext *optctx;
  GError *error = NULL;
​
  optctx = g_option_context_new ("<launch line> - Test RTSP Server, Launch\n\n"
      "Example: \"( videotestsrc ! x264enc ! rtph264pay name=pay0 pt=96 )\"");
  g_option_context_add_main_entries (optctx, entries, NULL);
  g_option_context_add_group (optctx, gst_init_get_option_group ());
  if (!g_option_context_parse (optctx, &argc, &argv, &error)) {
    g_printerr ("Error parsing options: %s\n", error->message);
    g_option_context_free (optctx);
    g_clear_error (&error);
    return -1;
  }
  g_option_context_free (optctx);
​
  loop = g_main_loop_new (NULL, FALSE);
​
  /* create a server instance */
  server = gst_rtsp_server_new ();
  g_object_set (server, "service", port, NULL);
​
  /* get the mount points for this server, every server has a default object
   * that be used to map uri mount points to media factories */
  mounts = gst_rtsp_server_get_mount_points (server);
​
  /* make a media factory for a test stream. The default media factory can use
   * gst-launch syntax to create pipelines.
   * any launch line works as long as it contains elements named pay%d. Each
   * element with pay%d names will be a stream */
  factory = gst_rtsp_media_factory_new ();
  gst_rtsp_media_factory_set_launch (factory, argv[1]);
​
   //新增加 客户端之间共享管道 不用重新建立
  gst_rtsp_media_factory_set_shared (factory, TRUE);
  
  /* attach the test factory to the /test url */
  gst_rtsp_mount_points_add_factory (mounts, "/test", factory);
​
  /* don't need the ref to the mapper anymore */
  g_object_unref (mounts);
​
  /* attach the server to the default maincontext */
  gst_rtsp_server_attach (server, NULL);
​
  /* start serving */
  g_print ("stream ready at rtsp://127.0.0.1:%s/test\n", port);
  g_main_loop_run (loop);
​
  return 0;
}
 

编译:

gcc test-launch2.c -o test-launch2 $(pkg-config --cflags --libs gstreamer-rtsp-server-1.0 gstreamer-1.0)

 

测试:

./test-launch2 --gst-debug-level=3 "( v4l2src device=/dev/video0 ! videoconvert! videoscale ! video/x-raw, width=640, height=480, framerate=25/1 ! queue ! x264enc bitrate=2048 !  rtph264pay name=pay0 pt=96 )"

 

  

这样修改就实现了一个可以多路复用的USB转RTSP服务器

4、测试硬件加速的效果

./test-launch2 --gst-debug-level=3 "( v4l2src device=/dev/video0 ! video/x-raw,format=YUY2,width=640, height=480, framerate=25/1 ! nvvidconv ! video/x-raw(memory:NVMM), format=(string)I420, width=640, height=480, framerate=25/1  ! queue ! omxh264enc bitrate=2048 ! rtph264pay name=pay0 pt=96 )"

虽然感觉图像质量变差了,但是资源占用真心有很大优化。而且延时也有一定的优化。

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

机器人虎哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值