在python中为rtsp流设置自定义gstreamer appsrc

jfewjypa  于 2024-01-05  发布在  Python
关注(0)|答案(1)|浏览(201)

我想设置一个appsrc来流式传输自定义数据,例如使用python中的gstreamer管道传输任意图像,如numpy矩阵。为此,我使用了推送模式的GstAppSrc。这对于使用autovideosink显示数据很好,但似乎不适用于任何编码器,例如将jpeg写入为.avi或将h264流式传输为rtsp流。
由于完整的应用程序太复杂了,我试着做了一个小例子,在numpy中创建了一个100 x100的RGB矩阵,并使用自定义的GstAppSrc推送它。
我尝试遵循this example(它是用C编写的)并将其解析为Python代码。
只要我不需要对数据进行编码并使用autovideosink直接显示它,管道就可以工作。使用任何类型的编码器都会导致管道阻塞或抛出错误,如:
(python:178667):GStreamer-Video-CRITICAL**:15:50:56.078:gst_pad_set_caps:Assert'caps!= NULL && gst_caps_is_fixed(caps)'失败
这是没有意义的,因为我设置和固定上限的缓冲区和我的GstAppSrc。
对于设置rtsp流,我遵循以下答案:https://stackoverflow.com/a/73186851/20580911
下面是我的演示程序,用于测试管道:

  1. import time
  2. from dataclasses import dataclass
  3. import numpy as np
  4. import gi
  5. gi.require_version('Gst', '1.0')
  6. gi.require_version('GstVideo', '1.0')
  7. gi.require_version('GstApp', '1.0')
  8. gi.require_version('GLib', '2.0')
  9. from gi.repository import Gst, GstVideo, GstApp, GLib
  10. Gst.init()
  11. @dataclass
  12. class AppSrcSharedData:
  13. pipeline: Gst.Pipeline
  14. app_src: GstApp.AppSrc
  15. source_id: int
  16. main_loop: GLib.MainLoop
  17. frame_ctr: int
  18. color_val: int
  19. def create_color_tile(hue_val):
  20. red = 1
  21. green = 1
  22. blue = 1
  23. if hue_val <= 120:
  24. red = 1 - (hue_val / 120)
  25. green = hue_val / 120
  26. blue = 0
  27. elif hue_val <= 240:
  28. red = 0
  29. green = 1 - ((hue_val-120) / 120)
  30. blue = ((hue_val-120) / 120)
  31. elif hue_val <= 360:
  32. red = ((hue_val-240) / 120)
  33. green = 0
  34. blue = 1 - ((hue_val-240) / 120)
  35. return np.full((100, 100, 3), (255 * np.asarray([red, green, blue])), dtype=np.uint8)
  36. def _push_data(data: AppSrcSharedData):
  37. buffer = Gst.Buffer.new_wrapped(create_color_tile(data.color_val).tobytes())
  38. buffer.add_reference_timestamp_meta(data.app_src.get_caps(), data.app_src.get_current_running_time(), Gst.CLOCK_TIME_NONE)
  39. buffer.pts = data.app_src.get_current_running_time()
  40. buffer.dts = Gst.CLOCK_TIME_NONE
  41. buffer.duration = Gst.CLOCK_TIME_NONE
  42. buffer.offset = data.frame_ctr
  43. data.frame_ctr += 1
  44. ret = data.app_src.push_buffer(buffer)
  45. data.color_val += 1
  46. time.sleep(0.03)
  47. if data.color_val > 360:
  48. data.app_src.end_of_stream()
  49. data.pipeline.send_event(Gst.Event.new_eos())
  50. data.pipeline.set_state(Gst.State.NULL)
  51. data.main_loop.quit()
  52. return False
  53. if ret != Gst.FlowReturn.OK:
  54. return True
  55. else:
  56. return False
  57. def _start_feed(appsrc, length, udata):
  58. udata.source_id = GLib.idle_add(_push_data, udata)
  59. def _stop_feed(appsrc, udata):
  60. GLib.source_remove(udata.appsrc_data.source_id)
  61. udata.appsrc_data.source_id = 0
  62. if __name__ == '__main__':
  63. pipe_str = "appsrc name=source ! videoconvert ! autovideosink"
  64. # pipe_str = ("appsrc name=source format=time is_live=True ! videoconvert ! openh264enc ! rtspclientsink location=rtsp://localhost:8554/test")
  65. # pipe_str = "appsrc name=source format=time is_live=True ! videoconvert ! jpegenc ! avimux ! filesink location=output.avi"
  66. pipeline = Gst.parse_launch(pipe_str)
  67. src = None
  68. for element in pipeline.children:
  69. if element.name == "source":
  70. src = element
  71. # configure appsrc
  72. src.set_stream_type(GstApp.AppStreamType.STREAM)
  73. src.set_live(True)
  74. src.set_do_timestamp(False)
  75. src.set_format(Gst.Format.TIME)
  76. # set caps
  77. video_info = GstVideo.VideoInfo()
  78. video_info.set_format(GstVideo.VideoFormat.RGB, 100, 100)
  79. video_caps = video_info.to_caps()
  80. video_caps.fixate()
  81. src.set_caps(video_caps)
  82. main_loop = GLib.MainLoop()
  83. appsrc_data = AppSrcSharedData(pipeline, src, 0, main_loop, 0, 0)
  84. # connect callbacks
  85. src.connect("need-data", _start_feed, appsrc_data)
  86. src.connect("enough-data", _stop_feed, appsrc_data)
  87. ret = pipeline.set_state(Gst.State.PLAYING)
  88. main_loop.run()

字符串
有人能帮我弄清楚我是否缺少了一个参数设置或配置,以使编码正常工作吗?

chhkpiq4

chhkpiq41#

pipe_str更改为

  1. pipe_str = """
  2. appsrc name="source" ! tee name=video_tee
  3. video_tee. ! queue name=display_queue ! videoconvert ! autovideosink
  4. video_tee. ! queue name=enc_queue ! videoconvert ! video/x-raw,format=I420 ! x264enc bitrate=1000 byte-stream=true key-int-max=30 bframes=0 aud=true pass=cbr speed-preset=superfast threads=8 analyse=i8x8 sliced-threads=true ! h264parse ! mpegtsmux ! filesink location=output.ts
  5. """

字符串
可以与您的代码(Ubuntu 22.04,GStreamer 1.22.6)一起开箱即用。管道将来自appsrc的输入分支到autovideosink中用于显示,另一个分支用于编码和存储在TS文件中。这些编码器设置可以帮助您设置RTSP客户端接收器。
output.ts可以使用VLC打开,例如,编解码器统计数据如下所示:


的数据
您可能需要添加一些内容:

  • 设置输入视频的帧速率,以便编码器正常工作:
  1. # set caps
  2. video_info = GstVideo.VideoInfo()
  3. video_info.set_format(GstVideo.VideoFormat.RGB, 100, 100)
  4. video_info.fps_n = 30 # or whatever value from your app
  5. video_info.fps_d = 1 # same

  • 当管道即将停止时,刷新appsrc元素,以便任何下游元素完成其工作。我注意到,如果没有这个,我在output.ts文件中获得了大约6秒的视频,而不是预期的12秒。
  1. def _push_data(data: AppSrcSharedData):
  2. buffer = Gst.Buffer.new_wrapped(create_color_tile(data.color_val).tobytes())
  3. buffer.add_reference_timestamp_meta(data.app_src.get_caps(), data.app_src.get_current_running_time(), Gst.CLOCK_TIME_NONE)
  4. buffer.pts = data.app_src.get_current_running_time()
  5. buffer.dts = Gst.CLOCK_TIME_NONE
  6. buffer.duration = Gst.CLOCK_TIME_NONE
  7. buffer.offset = data.frame_ctr
  8. data.frame_ctr += 1
  9. ret = data.app_src.push_buffer(buffer)
  10. data.color_val += 1
  11. time.sleep(0.03)
  12. if data.color_val > 360:
  13. data.app_src.end_of_stream()
  14. data.app_src.send_event(Gst.Event.new_flush_start())
  15. data.app_src.send_event(Gst.Event.new_eos())
  16. data.pipeline.set_state(Gst.State.NULL)
  17. data.main_loop.quit()
  18. return False
  19. if ret != Gst.FlowReturn.OK:
  20. return True
  21. else:
  22. return False


有了这个,output.ts视频的统计数据看起来像:


展开查看全部

相关问题