Deepstream实现rtmp推流

网页播放rtmp流转http流比rtsp流转rtmp流再转http流的效率高很多哦,资源占用也很低,我边缘机可以做到九路直播。操作也不麻烦,直接修改sink_bin就行。

1,在/opt/nvidia/deepstream/deepstream/sources/apps/apps-common/includes/deepstream_sinks.h中添加SINK_RTMP

2,在/opt/nvidia/deepstream/deepstream/sources/apps/apps-common/src/deepstream_sink_bin.c中添加create_rtmpsink_bin

static gboolean
create_rtmpsink_bin (NvDsSinkEncoderConfig * config, NvDsSinkBinSubBin * bin)
{
  GstCaps *caps = NULL;
  gboolean ret = FALSE;
  gchar elem_name[50];
  gchar encode_name[50];
 
  uid++;
 
  g_snprintf (elem_name, sizeof (elem_name), "sink_sub_bin%d", uid);
  bin->bin = gst_bin_new (elem_name);
  if (!bin->bin) {
    NVGSTDS_ERR_MSG_V ("Failed to create '%s'", elem_name);
    goto done;
  }
 
  g_snprintf (elem_name, sizeof (elem_name), "sink_sub_bin_queue%d", uid);
  bin->queue = gst_element_factory_make (NVDS_ELEM_QUEUE, elem_name);
  if (!bin->queue) {
    NVGSTDS_ERR_MSG_V ("Failed to create '%s'", elem_name);
    goto done;
  }
 
  g_snprintf (elem_name, sizeof (elem_name), "sink_sub_bin_transform%d", uid);
  bin->transform = gst_element_factory_make (NVDS_ELEM_VIDEO_CONV, elem_name);
  if (!bin->transform) {
    NVGSTDS_ERR_MSG_V ("Failed to create '%s'", elem_name);
    goto done;
  }
 
  g_snprintf (elem_name, sizeof (elem_name), "sink_sub_bin_cap_filter_%d", uid);
  bin->cap_filter = gst_element_factory_make (NVDS_ELEM_CAPS_FILTER, elem_name);
  if (!bin->cap_filter) {
    NVGSTDS_ERR_MSG_V ("Failed to create '%s'", elem_name);
    goto done;
  }
 
  if (config->enc_type == NV_DS_ENCODER_TYPE_SW)
    caps = gst_caps_from_string ("video/x-raw, format=I420");
  else
    caps = gst_caps_from_string ("video/x-raw(memory:NVMM), format=I420");
 
  g_object_set (G_OBJECT (bin->cap_filter), "caps", caps, NULL);
 
  g_snprintf (encode_name, sizeof (encode_name), "sink_sub_bin_encoder%d", uid);
 
  switch (config->codec) {
    case NV_DS_ENCODER_H264:
      bin->codecparse = gst_element_factory_make ("h264parse", "h264-parser");
      bin->encoder = gst_element_factory_make (NVDS_ELEM_ENC_H264_HW, encode_name);
      if (config->enc_type == NV_DS_ENCODER_TYPE_SW)
        bin->encoder = gst_element_factory_make (NVDS_ELEM_ENC_H264_SW, encode_name);
      else
        bin->encoder = gst_element_factory_make (NVDS_ELEM_ENC_H264_HW, encode_name);
      break;
    case NV_DS_ENCODER_H265:
      bin->codecparse = gst_element_factory_make ("h265parse", "h265-parser");
      if (config->enc_type == NV_DS_ENCODER_TYPE_SW)
        bin->encoder = gst_element_factory_make (NVDS_ELEM_ENC_H265_SW, encode_name);
      else
        bin->encoder = gst_element_factory_make (NVDS_ELEM_ENC_H265_HW, encode_name);
      break;
    default:
      goto done;
  }
 
  if (!bin->encoder) {
    NVGSTDS_ERR_MSG_V ("Failed to create '%s'", encode_name);
    goto done;
  }
 
  if (config->enc_type  == NV_DS_ENCODER_TYPE_SW) {
    //bitrate is in kbits/sec for software encoder x264enc and x265enc
    g_object_set (G_OBJECT (bin->encoder), "bitrate", config->bitrate/1000, NULL);
  } else {
      g_object_set (G_OBJECT (bin->encoder), "bitrate", config->bitrate, NULL);
      g_object_set (G_OBJECT (bin->encoder), "profile", config->profile, NULL);
      g_object_set (G_OBJECT (bin->encoder), "iframeinterval", config->iframeinterval, NULL);
  }
 
#ifdef IS_TEGRA
  g_object_set (G_OBJECT (bin->encoder), "preset-level", 1, NULL);
  g_object_set (G_OBJECT (bin->encoder), "insert-sps-pps", 1, NULL);
  //g_object_set (G_OBJECT (bin->encoder), "bufapi-version", 1, NULL);
#else
  g_object_set (G_OBJECT (bin->transform), "gpu-id", config->gpu_id, NULL);
#endif
 
  bin->mux = gst_element_factory_make ("flvmux", "sink_sub_bin_mux");
  if (!bin->mux) {
    NVGSTDS_ERR_MSG_V ("Failed to create '%s'", "sink_sub_bin_mux");
    goto done;
  }
  g_object_set (G_OBJECT (bin->mux), "name", "mux",  "streamable", TRUE, NULL);
 
  bin->sink = gst_element_factory_make ("rtmpsink", elem_name);
  if (!bin->sink) {
    NVGSTDS_ERR_MSG_V ("Failed to create '%s'", elem_name);
    goto done;
  }

  char url[128] = {0};
  sprintf(url, "rtmp://127.0.0.1:%d/road/%d", config->udp_port, config->rtsp_port);//自己修改ip和路径
  
  g_object_set (G_OBJECT (bin->sink), "location", url, NULL);//"rtmp://10.1.1.101/live/livestream"
  g_print ("%s: DEBUGGER create_rtmp_sink \n", url);//"rtmp://10.1.1.101/live/livestream"
 
  gst_bin_add_many (GST_BIN (bin->bin), bin->queue, bin->transform,
      bin->encoder, bin->codecparse, bin->mux, bin->sink, NULL);

  NVGSTDS_LINK_ELEMENT (bin->queue, bin->transform);
  NVGSTDS_LINK_ELEMENT (bin->transform, bin->encoder);
  NVGSTDS_LINK_ELEMENT (bin->encoder, bin->codecparse);
  NVGSTDS_LINK_ELEMENT (bin->codecparse, bin->mux);
  NVGSTDS_LINK_ELEMENT (bin->mux, bin->sink);
  NVGSTDS_BIN_ADD_GHOST_PAD (bin->bin, bin->queue, "sink");
 
  ret = TRUE;
 
  if (ret != TRUE) {
    g_print ("%s: start_rtmp_straming function failed\n", __func__);
  }
  g_print ("%s: Started streaming RTMP\n", __func__);
 
done:
  if (caps) {
    gst_caps_unref (caps);
  }
  if (!ret) {
    NVGSTDS_ERR_MSG_V ("%s failed", __func__);
  }
  return ret;
}

3,在/opt/nvidia/deepstream/deepstream/sources/apps/apps-common/src/deepstream_sink_bin.c中查找“case NV_DS_SINK_MSG_CONV_BROKER:”在后面加上“case SINK_RTMP:”(一共有两处)

      case NV_DS_SINK_MSG_CONV_BROKER:
        config_array[i].msg_conv_broker_config.sync = config_array[i].sync;
        if (!create_msg_conv_broker_bin (&config_array[i].
                msg_conv_broker_config, &bin->sub_bins[i]))
          goto done;
        break;
      case SINK_RTMP:
        if (!create_rtmpsink_bin (&config_array[i].encoder_config,
                &bin->sub_bins[i]))
          goto done;
        break;

4,去目标app源码目录下执行“sudo make install”

5,在config文件中修改“type=7”,“rtsp-port”和“udp-port”参数在uri上有用到,最后推流的地址是“rtmp://127.0.0.1:{udp-port}/road/{rtsp-port}”,有其他改动需求自己修代码。

[sink]
enable=0
source-id=11
type=7
codec=1
enc-type=0
sync=1
bitrate=4000000
profile=0
rtsp-port=8565
udp-port=1935

6,Enjoy it!

### 使用 DeepStream SDK 实现和拉 #### 操作 为了使用 DeepStream SDK 将视频送至 RTMP 或其他服务器,通常会采用 GStreamer 插件来构建管道。GStreamer 是一个强大的多媒体框架,允许创建复杂的音频/视频处理水线。 对于功能而言,`nvv4l2h264enc` 编码器与 `rtph264pay` 支付负载插件组合起来非常有用。下面是一个简单的 Python 脚本例子,展示了如何配置并启动一个向指定 URL 发送 H.264 编码 RTP 数据包的程[^1]: ```python import gi gi.require_version('Gst', '1.0') from gi.repository import Gst, GObject def create_pipeline(): pipeline_str = ( "v4l2src device=/dev/video0 ! " "videoconvert ! nvvidconv ! nvh264enc bitrate=8000000 ! h264parse ! rtph264pay config-interval=1 pt=96 ! udpsink host=localhost port=5000" ) return Gst.parse_launch(pipeline_str) if __name__ == "__main__": # Initialize GStreamer Gst.init(None) # Create the pipeline pipeline = create_pipeline() # Start playing pipeline.set_state(Gst.State.PLAYING) try: loop = GObject.MainLoop() loop.run() except KeyboardInterrupt: pass # Clean up pipeline.set_state(Gst.State.NULL) ``` 此脚本设置了一个从摄像头读取原始帧并通过 UDP 协议发送编码后的 H.264 的过程。实际应用中可能还需要调整参数以适应特定需求,比如改变源地址、目标 IP 地址以及端口号等。 #### 拉操作 当涉及到接收远程媒体资源时,则需要用到不同的组件集。例如,可以通过 `rtspsrc` 来连接到 RTSP 服务器获取实时音视频内容;而如果要直接对接 RTMP ,则有专门为此目的设计的 gstreamer 插件如 `flvmux` 和 `rtmpsink` 可供选用[^2]。 这里给出一段基于上述提到的技术栈编写的小程序片段,它能够监听来自网络上的 RTSP 链接并将接收到的画面展示出来: ```python import gi gi.require_version('Gst', '1.0') from gi.repository import Gst, Gtk, GdkX11, GstVideo def build_player_pipeline(uri): player_factory = """ rtspsrc location={} latency=0 ! decodebin ! videoconvert ! autovideosink sync=false """.format(uri).strip().replace('\n', '') return Gst.parse_launch(player_factory) if __name__ == '__main__': uri = "rtsp://example.com/stream" # 初始化环境变量 Gst.init([]) window = Gtk.Window(title="RTSP Player") drawing_area = Gtk.DrawingArea() window.add(drawing_area) window.connect("destroy", lambda w: Gtk.main_quit()) window.show_all() pipeline = build_player_pipeline(uri) bus = pipeline.get_bus() bus.enable_sync_message_emission() bus.connect("sync-message::element", on_sync_message, drawing_area) pipeline.set_state(Gst.State.PLAYING) Gtk.main() def on_sync_message(bus, message, drawing_area): if not message.structure is None and message.structure.has_field("xwindow_id"): win_id = drawing_area.get_property("window").get_xid() imagesink = message.src imagesink.set_window_handle(win_id) ``` 这段代码实现了基本的功能——打开给定 URI 所指向的服务,并在一个 GTK+ 应用窗口内呈现所获得的数据画面。需要注意的是,在生产环境中应当考虑错误处理机制和服务稳定性保障措施等问题。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值