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

'''



posted @   陈执象  阅读(1179)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
点击右上角即可分享
微信分享提示