GStreamer播放RTMP流
rtmp-decodebin.py
#!/usr/bin/env python3
import sys
import gi
import datetime
gi.require_version('GLib', '2.0')
gi.require_version('GObject', '2.0')
gi.require_version('Gst', '1.0')
from gi.repository import Gst, GObject, GLib
# demuxer.connect("pad-added",cb_demuxer_newpad,queuev,queuea)
def cb_decode_newpad(decode,new_pad,_convv,_queuea):
__FUN__ = sys._getframe().f_code.co_name
pad_name = new_pad.get_property("template").name_template
pad_current_caps = new_pad.get_current_caps()
src_name = pad_current_caps.get_structure(0).get_name()
print("src_name=",src_name)
# ---->src_pad_name video/x-raw
# ---->src_pad_name audio/x-raw
if src_name == "video/x-raw":
convv_pad = _convv.get_static_pad("sink")
ret = new_pad.link(convv_pad)
print(__FUN__,sys._getframe().f_lineno,"decode src",pad_name ,"link convv sink. ret=", ret)
pass
elif src_name == "audio/x-raw":
queuea_pad = _queuea.get_static_pad("sink")
ret = new_pad.link(queuea_pad)
print(__FUN__,sys._getframe().f_lineno,"decode src",pad_name ,"link queuev sink. ret=", ret)
pass
else:
print(__FUN__,sys._getframe().f_lineno,"add a unknown new pad:",pad_name,"src_name:",src_name)
pass
# if pad_name == "video":
# queuev_pad = _queuev.get_static_pad("sink")
# ret = new_pad.link(queuev_pad)
# print(__FUN__,sys._getframe().f_lineno,"demuxer src",pad_name ,"link queuev sink. ret=", ret)
# elif pad_name == "audio":
# queuea_pad = _queuea.get_static_pad("sink")
# ret = new_pad.link(queuea_pad)
# print(__FUN__,sys._getframe().f_lineno,"demuxer src",pad_name ,"link queuev sink. ret=", ret)
# else:
# print(__FUN__,sys._getframe().f_lineno,"add a unknown new pad:",pad_name)
def cb_bus_message(_bus,new_msg,_custom_data):
__FUN__ = sys._getframe().f_code.co_name
if new_msg:
msg_src_name = new_msg.src.get_name()
msg_type = new_msg.type
# print(__FUN__,sys._getframe().f_lineno,msg_src_name, msg_type)
if msg_type == Gst.MessageType.ERROR:
err, debug_info = new_msg.parse_error()
print(__FUN__,sys._getframe().f_lineno,"Error received from element %s:%s" % (msg_src_name,err.message))
_custom_data["pipeline"].set_state(Gst.State.READY)
_custom_data["loop"].quit()
elif msg_type == Gst.MessageType.EOS:
print(__FUN__,sys._getframe().f_lineno,"End-Of-Stream reached.")
_custom_data["pipeline"].set_state(Gst.State.READY)
_custom_data["loop"].quit()
elif msg_type == Gst.MessageType.BUFFERING:
print("----------------------Gst.MessageType.BUFFERING-------------------------------------")
pass
elif msg_type == Gst.MessageType.CLOCK_LOST:
print("----------------------Gst.MessageType.CLOCK_LOST-------------------------------------")
pass
elif msg_type == Gst.MessageType.STATE_CHANGED:
pass
else:
# Unhandled message
pass
else:
print(__FUN__,sys._getframe().f_lineno,"Error new_msg=",new_msg)
def run():
__FUN__ = sys._getframe().f_code.co_name
rtmp_url = "rtmp://103.229.149.171/myapp/GoProCut"
# 初始化 GStreamer
Gst.init(sys.argv[1:])
# 创建elements
pipeline = Gst.Pipeline.new("RTMP-Play")
src = Gst.ElementFactory.make("rtmpsrc","src")
decode = Gst.ElementFactory.make("decodebin","decode")
convv = Gst.ElementFactory.make("videoconvert","convv") #视频转换元素
sinkv = Gst.ElementFactory.make("xvimagesink","sinkv") #图像接收器
queuea = Gst.ElementFactory.make("queue","queuea")
conva = Gst.ElementFactory.make("audioconvert","conva") #视频转换元素
sinka = Gst.ElementFactory.make("autoaudiosink","sinka") #自动音频接收器 autoaudiosink
# 设置播放地址
src.set_property("location",rtmp_url)
#设置queuev、queuea
# queuev.set_property("max-size-buffers",0) # Default: 200
# queuev.set_property("max-size-bytes",0) # Default: 10485760
# queuev.set_property("max-size-time",0) # Default: 1000000000 ns
queuea.set_property("max-size-buffers",0) # Default: 200
queuea.set_property("max-size-bytes",0) # Default: 10485760
queuea.set_property("max-size-time",0) # Default: 1000000000 ns
# 向管道中添加元件
pipeline.add(src)
pipeline.add(decode)
pipeline.add(convv)
pipeline.add(sinkv)
pipeline.add(queuea)
pipeline.add(conva)
pipeline.add(sinka)
# 连接elements
src.link(decode)
decode.connect("pad-added",cb_decode_newpad,convv,queuea)
convv.link(sinkv)
queuea.link(queuea)
queuea.link(conva)
conva.link(sinka)
ret = pipeline.set_state(Gst.State.PLAYING)
if ret is Gst.StateChangeReturn.FAILURE:
print(__FUN__,sys._getframe().f_lineno,"Unable to set the pipeline to the playing state.")
return
elif ret is Gst.StateChangeReturn.NO_PREROLL:
print(__FUN__,sys._getframe().f_lineno,"is_live")
else:
print(__FUN__,sys._getframe().f_lineno,"pipeline set state playing. ret=",ret)
main_loop = GLib.MainLoop()
bus = pipeline.get_bus()
bus.add_signal_watch()
custom_data = {
"pipeline":pipeline,
"loop":main_loop
}
bus.connect("message",cb_bus_message,custom_data)
main_loop.run()
# Free resources
main_loop.unref()
Gst.Object.unref(bus)
pipeline.set_state(Gst.State.NULL)
if __name__ == "__main__":
run()
'''
# 输出视频
gst-launch-1.0 --gst-debug-level=3 rtmpsrc location=rtmp://103.229.149.171/myapp/GoProCut ! decodebin ! videoconvert ! autovideosink
gst-launch-1.0 --gst-debug-level=3 rtmpsrc location=rtmp://103.229.149.171/myapp/GoProCut ! decodebin ! videoconvert ! xvimagesink
# 输出音频
gst-launch-1.0 rtmpsrc name=rtmpsrc location=rtmp://103.229.149.171/myapp/GoProCut ! decodebin ! queue ! audioconvert ! autoaudiosink
#输出音视频
'''
play-rtmp.py
#!/usr/bin/env python3
import sys
import gi
gi.require_version('GLib', '2.0')
gi.require_version('GObject', '2.0')
gi.require_version('Gst', '1.0')
from gi.repository import Gst, GObject, GLib
def cb_demuxer_newpad(demux, new_pad, queue_v,queue_a):
if new_pad.get_property("template").name_template == "video":
vdec_pad = queue_v.get_static_pad("sink")
new_pad.link(vdec_pad)
elif new_pad.get_property("template").name_template == "audio":
adec_pad = queue_a.get_static_pad("sink")
new_pad.link(adec_pad)
else:
pass
def run():
pipeline = None
bus = None
message = None
rtmp_url = "rtmp://103.229.149.171/myapp/GoProCut"
# 初始化 GStreamer
Gst.init(sys.argv[1:])
# 创建elements
pipeline = Gst.Pipeline.new("RTMP-Play")
src = Gst.ElementFactory.make("rtmpsrc","src")
demuxer = Gst.ElementFactory.make("flvdemux","demux")
# 创建视频队列element 视频缓存
queuev = Gst.ElementFactory.make("queue","queuev")
parsev = Gst.ElementFactory.make("h264parse","parsev")
decodebinv = Gst.ElementFactory.make("avdec_h264","decodev") #ffmpeg插件avdec_h264
convv = Gst.ElementFactory.make("videoconvert","convv") #视频转换元素
sinkv = Gst.ElementFactory.make("xvimagesink","sinkv") #图像接收器
# 创建音频队列element
queuea = Gst.ElementFactory.make("queue","queuea")
decodebina = Gst.ElementFactory.make("faad","decodea") #ffmpeg插件faad
conva = Gst.ElementFactory.make("audioconvert","conva") #视频转换元素
sinka = Gst.ElementFactory.make("autoaudiosink","sinka") #自动音频接收器
#设置队列缓存
queuev.set_property("max-size-buffers",4294967295)
queuev.set_property("max-size-bytes",4294967295)
queuev.set_property("max-size-time",18446744073709551615)
queuea.set_property("max-size-buffers",4294967295)
queuea.set_property("max-size-bytes",4294967295)
queuea.set_property("max-size-time",18446744073709551615)
#设置播放地址
src.set_property("location",rtmp_url)
#向管道中添加元件
pipeline.add(src)
pipeline.add(demuxer)
pipeline.add(queuev)
pipeline.add(parsev)
pipeline.add(decodebinv)
pipeline.add(convv)
pipeline.add(sinkv)
pipeline.add(queuea)
pipeline.add(decodebina)
pipeline.add(conva)
pipeline.add(sinka)
demuxer.connect("pad-added",cb_demuxer_newpad,queuev,queuea)
#连接elements
src.link(demuxer)
queuev.link(parsev)
parsev.link(decodebinv)
decodebinv.link(convv)
convv.link(sinkv)
queuea.link(decodebina)
decodebina.link(conva)
conva.link(sinka)
ret = pipeline.set_state(Gst.State.PLAYING)
if ret is Gst.StateChangeReturn.FAILURE:
print("Unable to set the pipeline to the playing state.")
return
elif ret is Gst.StateChangeReturn.NO_PREROLL:
print("is_live")
else:
print("ret=",ret)
# mainloop = GLib.MainLoop()
# mainloop.run()
bus = pipeline.get_bus()
msg = bus.timed_pop_filtered(Gst.CLOCK_TIME_NONE, Gst.MessageType.ERROR | Gst.MessageType.EOS)
if msg:
if msg.type == Gst.MessageType.ERROR:
err, debug_info = msg.parse_error()
print(f"Error received from element {msg.src.get_name()}: {err.message}")
print(f"Debugging information: {debug_info if debug_info else 'none'}")
elif msg.type == Gst.MessageType.EOS:
print("End-Of-Stream reached.")
else:
print(msg.type)
print("Unexpected message received.")
pipeline.set_state(Gst.State.NULL)
if __name__ == "__main__":
run()
pass
'''
GStreamer播放RTMP的命令行如下:
gst-launch-1.0 --gst-debug-level=3 \
rtmpsrc location=rtmp://103.229.149.171/myapp/GoProCut ! flvdemux name=demux \
demux.audio ! queue max-size-buffers=4294967295 max-size-bytes=4294967295 max-size-time=18446744073709551615 ! faad ! audioconvert ! autoaudiosink \
demux.video ! queue max-size-buffers=4294967295 max-size-bytes=4294967295 max-size-time=18446744073709551615 ! h264parse ! avdec_h264 ! videoconvert ! xvimagesink
'''
rtmp-flvdemux-queue.py
#!/usr/bin/env python3
import sys
import gi
import datetime
gi.require_version('GLib', '2.0')
gi.require_version('GObject', '2.0')
gi.require_version('Gst', '1.0')
from gi.repository import Gst, GObject, GLib
# demuxer.connect("pad-added",cb_demuxer_newpad,queuev,queuea)
def cb_demuxer_newpad(_demuxer,new_pad,_queuev,_queuea):
__FUN__ = sys._getframe().f_code.co_name
pad_name = new_pad.get_property("template").name_template
ret = new_pad.get_pad_template()
# print("ret=",ret)
if pad_name == "video":
queuev_pad = _queuev.get_static_pad("sink")
ret = new_pad.link(queuev_pad)
print(__FUN__,sys._getframe().f_lineno,"demuxer src",pad_name ,"link queuev sink. ret=", ret)
elif pad_name == "audio":
queuea_pad = _queuea.get_static_pad("sink")
ret = new_pad.link(queuea_pad)
print(__FUN__,sys._getframe().f_lineno,"demuxer src",pad_name ,"link queuev sink. ret=", ret)
else:
print(__FUN__,sys._getframe().f_lineno,"add a unknown new pad:",pad_name)
def cb_bus_message(_bus,new_msg,_custom_data):
__FUN__ = sys._getframe().f_code.co_name
if new_msg:
msg_src_name = new_msg.src.get_name()
msg_type = new_msg.type
# print(__FUN__,sys._getframe().f_lineno,msg_src_name, msg_type)
if msg_type == Gst.MessageType.ERROR:
err, debug_info = new_msg.parse_error()
print(__FUN__,sys._getframe().f_lineno,"Error received from element %s:%s" % (msg_src_name,err.message))
_custom_data["pipeline"].set_state(Gst.State.READY)
_custom_data["loop"].quit()
elif msg_type == Gst.MessageType.EOS:
print(__FUN__,sys._getframe().f_lineno,"End-Of-Stream reached.")
_custom_data["pipeline"].set_state(Gst.State.READY)
_custom_data["loop"].quit()
elif msg_type == Gst.MessageType.BUFFERING:
print("----------------------Gst.MessageType.BUFFERING-------------------------------------")
pass
elif msg_type == Gst.MessageType.CLOCK_LOST:
print("----------------------Gst.MessageType.CLOCK_LOST-------------------------------------")
pass
elif msg_type == Gst.MessageType.STATE_CHANGED:
pass
else:
# Unhandled message
pass
else:
print(__FUN__,sys._getframe().f_lineno,"Error new_msg=",new_msg)
def cb_queuev_underrun(_queuev):
print(datetime.datetime.now(),"---------------cb_queuev_underrun")
# _queuev.set_state(Gst.State.PAUSED)
ret = _queuev.get_state(Gst.CLOCK_TIME_NONE)
print("ret =",ret)
def cb_queuev_overrun(_queuev):
print(datetime.datetime.now(),"---------------cb_queuev_overrun")
# _queuev.set_state(Gst.State.PLAYING)
ret = _queuev.get_state(Gst.CLOCK_TIME_NONE)
print("ret =",ret)
def cb_queuev_running(_queuev):
print(datetime.datetime.now(),"---------------cb_queuev_running")
# _queuev.set_state(Gst.State.PLAYING)
ret = _queuev.get_state(Gst.CLOCK_TIME_NONE)
print("ret =",ret)
def cb_queuev_pushing(_queuev):
print(datetime.datetime.now(),"---------------cb_queuev_pushing")
ret = _queuev.get_state(Gst.CLOCK_TIME_NONE)
print("ret =",ret)
def cb_queuea_underrun(_queuea):
print(datetime.datetime.now(),"---------------cb_queuea_underrun")
# _queuea.set_state(Gst.State.PAUSED)
ret = _queuea.get_state(Gst.CLOCK_TIME_NONE)
print("ret =",ret)
def cb_queuea_overrun(_queuea):
print(datetime.datetime.now(),"---------------cb_queuea_overrun")
# _queuea.set_state(Gst.State.PLAYING)
ret = _queuea.get_state(Gst.CLOCK_TIME_NONE)
print("ret =",ret)
def cb_queuea_running(_queuea):
print(datetime.datetime.now(),"---------------cb_queuea_running")
# _queuea.set_state(Gst.State.PLAYING)
ret = _queuea.get_state(Gst.CLOCK_TIME_NONE)
print("ret =",ret)
def cb_queuea_pushing(_queuea):
print(datetime.datetime.now(),"---------------cb_queuea_pushing")
ret = _queuea.get_state(Gst.CLOCK_TIME_NONE)
print("ret =",ret)
def run():
__FUN__ = sys._getframe().f_code.co_name
rtmp_url = "rtmp://103.229.149.171/myapp/GoProCut"
# 初始化 GStreamer
Gst.init(sys.argv[1:])
# 创建elements
pipeline = Gst.Pipeline.new("RTMP-Play")
src = Gst.ElementFactory.make("rtmpsrc","src")
demuxer = Gst.ElementFactory.make("flvdemux","demux")
queuev = Gst.ElementFactory.make("queue","queuev")
h264parse = Gst.ElementFactory.make("h264parse","parsev")
decodebinv = Gst.ElementFactory.make("avdec_h264","decodev") #ffmpeg插件avdec_h264
convv = Gst.ElementFactory.make("videoconvert","convv") #视频转换元素
sinkv = Gst.ElementFactory.make("xvimagesink","sinkv") #图像接收器
queuea = Gst.ElementFactory.make("queue","queuea")
decodebina = Gst.ElementFactory.make("faad","decodea") #ffmpeg插件faad
conva = Gst.ElementFactory.make("audioconvert","conva") #视频转换元素
sinka = Gst.ElementFactory.make("autoaudiosink","sinka") #自动音频接收器 autoaudiosink
# 设置播放地址
src.set_property("location",rtmp_url)
# max-size-buffers : Max. number of buffers in the queue (0=disable)
# flags: 可读, 可写, 可以在NULL、READY、PAUSED或PLAYING状态下改变
# Unsigned Integer. Range: 0 - 4294967295 Default: 200
# max-size-bytes : Max. amount of data in the queue (bytes, 0=disable)
# flags: 可读, 可写, 可以在NULL、READY、PAUSED或PLAYING状态下改变
# Unsigned Integer. Range: 0 - 4294967295 Default: 10485760
# max-size-time : Max. amount of data in the queue (in ns, 0=disable)
# flags: 可读, 可写, 可以在NULL、READY、PAUSED或PLAYING状态下改变
# Unsigned Integer64. Range: 0 - 18446744073709551615 Default: 1000000000
# min-threshold-buffers: Min. number of buffers in the queue to allow reading (0=disable)
# flags: 可读, 可写, 可以在NULL、READY、PAUSED或PLAYING状态下改变
# Unsigned Integer. Range: 0 - 4294967295 Default: 0
# min-threshold-bytes : Min. amount of data in the queue to allow reading (bytes, 0=disable)
# flags: 可读, 可写, 可以在NULL、READY、PAUSED或PLAYING状态下改变
# Unsigned Integer. Range: 0 - 4294967295 Default: 0
# min-threshold-time : Min. amount of data in the queue to allow reading (in ns, 0=disable)
# flags: 可读, 可写, 可以在NULL、READY、PAUSED或PLAYING状态下改变
# Unsigned Integer64. Range: 0 - 18446744073709551615 Default: 0
#设置queuev、queuea
queuev.set_property("max-size-buffers",0) # Default: 200
queuev.set_property("max-size-bytes",0) # Default: 10485760
queuev.set_property("max-size-time",0) # 1s Default: 1000000000 ns
queuea.set_property("max-size-buffers",0) # Default: 200
queuea.set_property("max-size-bytes",0) # Default: 10485760
queuea.set_property("max-size-time",0) # 1s Default: 1000000000 ns
# queuev.connect("underrun",cb_queuev_underrun)
# queuev.connect("overrun",cb_queuev_overrun)
# queuev.connect("running",cb_queuev_running)
# queuev.connect("pushing",cb_queuev_pushing)
# queuea.connect("underrun",cb_queuea_underrun)
# queuea.connect("overrun",cb_queuea_overrun)
# queuea.connect("running",cb_queuea_running)
# queuea.connect("pushing",cb_queuea_pushing)
# 向管道中添加元件
pipeline.add(src)
pipeline.add(demuxer)
pipeline.add(queuev)
pipeline.add(h264parse)
pipeline.add(decodebinv)
pipeline.add(convv)
pipeline.add(sinkv)
pipeline.add(queuea)
pipeline.add(decodebina)
pipeline.add(conva)
pipeline.add(sinka)
# 连接elements
src.link(demuxer)
demuxer.connect("pad-added",cb_demuxer_newpad,queuev,queuea)
queuev.link(h264parse)
h264parse.link(decodebinv)
decodebinv.link(convv)
convv.link(sinkv)
queuea.link(decodebina)
decodebina.link(conva)
conva.link(sinka)
ret = pipeline.set_state(Gst.State.PLAYING)
if ret is Gst.StateChangeReturn.FAILURE:
print(__FUN__,sys._getframe().f_lineno,"Unable to set the pipeline to the playing state.")
return
elif ret is Gst.StateChangeReturn.NO_PREROLL:
print(__FUN__,sys._getframe().f_lineno,"is_live")
else:
print(__FUN__,sys._getframe().f_lineno,"pipeline set state playing. ret=",ret)
main_loop = GLib.MainLoop()
bus = pipeline.get_bus()
bus.add_signal_watch()
custom_data = {
"pipeline":pipeline,
"loop":main_loop
}
bus.connect("message",cb_bus_message,custom_data)
main_loop.run()
# Free resources
main_loop.unref()
Gst.Object.unref(bus)
pipeline.set_state(Gst.State.NULL)
if __name__ == "__main__":
run()
'''
gst-launch-1.0 --gst-debug-level=3 \
rtmpsrc location=rtmp://103.229.149.171/myapp/GoProCut ! \
flvdemux name=demux \
demux.audio ! queue max-size-time=0 max-size-bytes=0 max-size-buffers=0 ! faad ! audioconvert ! autoaudiosink \
demux.video ! queue max-size-time=0 max-size-bytes=0 max-size-buffers=0 ! h264parse ! avdec_h264 ! videoconvert ! xvimagesink
'''
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库