python gstreamer播放多个视频流
我正在参与一个包括远程播放视频的艺术项目.我已经实现了一个带有HTTP服务器和gstreamer视频播放器的简单
python应用程序.我能够捕获一个http请求并更改当前正在播放的视频,但我想在同一窗口中添加新视频并继续同时播放两个视频.
我用playbin2来播放视频,但我认为它当时只能玩一个uri.我试图找到可以同时播放多个视频的其他解决方案,但没有用… 任何人都可以发布一个同时播放多个流的简单示例,或者给我一些指向文档或其他资源的指针? 提前致谢!! PS.这是我写的代码:VideoPlayer类初始化流,playCurrent函数切换当前播放的视频 – 我希望该功能只是将新视频添加到流中. #!/usr/bin/python import threading import time import BaseHTTPServer from BaseHTTPServer import HTTPServer from urlparse import urlparse,parse_qs from os import path import gst import gtk HOST_NAME = 'localhost' # !!!REMEMBER TO CHANGE THIS!!! PORT_NUMBER = 9000 # Maybe set this to 9000. ################################################################# # VIDEO DICTIONARY # Manages the video database ################################################################# # VideoDictionary class ################################################################# # This class allows to access the video database # used by the video player - for best performance,it's a native # python dictionary class VideoDictionary(): # declaring filenames filename = path.join(path.dirname(path.abspath(__file__)),'large.mp4') filename_02 = path.join(path.dirname(path.abspath(__file__)),'01.avi') # declaring uris uri = 'file://' + filename uri_02 = 'file://' + filename_02 # combining it all into a dictionary videoDict = {} videoDict["01"] = uri videoDict["02"] = uri_02 # setting the current video currentVideo = "01" ################################################################# # VIDEO DICTIONARY END ################################################################# ################################################################# # VIDEO PLAYER # Manages all the video playing ################################################################# # VideoPlayer class ################################################################# # This class initializes the GST pipe context and it # handles different events related to video stream playing class VideoPlayer(object,VideoDictionary): VideoDictionary = "" def __init__(self,VideoDictionary): self.VideoDictionary = VideoDictionary self.window = gtk.Window() self.window.connect('destroy',self.quit) self.window.set_default_size(1024,768) self.drawingarea = gtk.DrawingArea() self.window.add(self.drawingarea) # Create GStreamer pipeline self.pipeline = gst.Pipeline() # Create bus to get events from GStreamer pipeline self.bus = self.pipeline.get_bus() # This is needed to make the video output in our DrawingArea: self.bus.enable_sync_message_emission() self.bus.connect('sync-message::element',self.on_sync_message) # Create GStreamer elements self.playbin = gst.element_factory_make('playbin2') # Add playbin2 to the pipeline self.pipeline.add(self.playbin) self.window.show_all() self.xid = self.drawingarea.window.xid print('DEBUG INFO: player initialization finished') def playCurrent(self): print('DEBUG INFO: getting running video ') print(self.VideoDictionary.currentVideo) self.pipeline.set_state(gst.STATE_READY) self.playbin.set_property('uri',self.VideoDictionary.videoDict[self.VideoDictionary.currentVideo]) self.pipeline.set_state(gst.STATE_PLAYING) def quit(self,window): print('DEBUG INFO: quitting player') self.pipeline.set_state(gst.STATE_NULL) gtk.main_quit() def on_sync_message(self,bus,msg): if msg.structure.get_name() == 'prepare-xwindow-id': msg.src.set_property('force-aspect-ratio',True) msg.src.set_xwindow_id(self.xid) def on_eos(self,msg): print('DEBUG INFO: EOS detected') print('on_eos(): seeking to start of video') self.pipeline.seek_simple( gst.FORMAT_TIME,gst.SEEK_FLAG_FLUSH | gst.SEEK_FLAG_KEY_UNIT,0L ) def on_error(self,msg): print('DEBUG INFO: error detected') print('on_error():',msg.parse_error()) ################################################################# # VIDEO PLAYER END ################################################################# ################################################################# # HTTP SERVER # implements the http listener in a separate thread # the listener plays the videos depending on the # received parameters in the GET request ################################################################# # HttpHandler class ################################################################# # uses global variables to operate videos class HttpHandler(BaseHTTPServer.BaseHTTPRequestHandler): def do_GET(self): # initialize the currently played video global VideoDictionary print('DEBUG INFO: GET running playCurrent') if VideoDictionary.currentVideo == "01": VideoDictionary.currentVideo = "02" else: VideoDictionary.currentVideo = "01" # play the video we have just set global player player.playCurrent() # HttpThread class ################################################################# # initializes the http listener in a separate thread class HttpThread (threading.Thread): def __init__(self): threading.Thread.__init__(self) def run(self): gtk.gdk.threads_enter() server_class = BaseHTTPServer.HTTPServer httpd = server_class((HOST_NAME,PORT_NUMBER),HttpHandler) print time.asctime(),"Server Starts - %s:%s" % (HOST_NAME,PORT_NUMBER) try: httpd.serve_forever() except KeyboardInterrupt: pass httpd.server_close() print time.asctime(),"Server Stops - %s:%s" % (HOST_NAME,PORT_NUMBER) gtk.gdk.threads_leave() return ################################################################# # HTTP SERVER END ################################################################# if __name__ == '__main__': VideoDictionary = VideoDictionary() player = VideoPlayer(VideoDictionary) gtk.gdk.threads_init() thread2 = HttpThread() thread2.run() gtk.gdk.threads_enter() gtk.main() gtk.gdk.threads_leave() 解决方法
这是一个同时播放多个视频流的代码的简单示例.
它适用于Python 2和3,它使用标准的Python GUI(Tk)和Gstreamer 1.0.因此它应该是可移植的,但我只在Ubuntu 16.04下进行了测试. (ffmpeg fork libav在Ubuntu 14.04下创建了问题,这似乎是在16.04下解决的.请注意,除了gstreamer1.0-plugins- *之外,还需要gstreamer1.0-libav包.) 代码配置为在列中创建八个帧,并将Gstreamer播放器与它们中的每一个相关联.您需要提供一个(最多八个)有效本地视频文件名列表作为您保存它的文件的参数(比如multivid.py),如下所示: $python3 multivid.py video1.webm video2.mp4 声道简单地混合在一起.你可能想改变它. 我的解决方案不涉及远程播放,但您已经解决了这个问题. 我之前在video files in tkinter的另一个问题的答案中发布了相同的代码,其中问题没有要求同时流.因此,这里更合适. import sys import os if sys.version_info[0] < 3: import Tkinter as tkinter else: import tkinter import gi gi.require_version('Gst','1.0') from gi.repository import Gst,GObject # Needed for set_window_handle(): gi.require_version('GstVideo','1.0') from gi.repository import GstVideo def set_frame_handle(bus,message,frame_id): if not message.get_structure() is None: if message.get_structure().get_name() == 'prepare-window-handle': display_frame = message.src display_frame.set_property('force-aspect-ratio',True) display_frame.set_window_handle(frame_id) NUMBER_OF_FRAMES = 8 # with more frames than arguments,videos are repeated relative_height = 1 / float(NUMBER_OF_FRAMES) # Only argument number checked,not validity. number_of_file_names_given = len(sys.argv) - 1 if number_of_file_names_given < 1: print('Give at least one video file name.') sys.exit() if number_of_file_names_given < NUMBER_OF_FRAMES: print('Up to',NUMBER_OF_FRAMES,'video file names can be given.') file_names = list() for index in range(number_of_file_names_given): file_names.append(sys.argv[index + 1]) window = tkinter.Tk() window.title("Multiple videos in a column using Tk and GStreamer 1.0") window.geometry('480x960') Gst.init(None) GObject.threads_init() for number in range(NUMBER_OF_FRAMES): display_frame = tkinter.Frame(window,bg='') relative_y = number * relative_height display_frame.place(relx = 0,rely = relative_y,anchor = tkinter.NW,relwidth = 1,relheight = relative_height) frame_id = display_frame.winfo_id() player = Gst.ElementFactory.make('playbin',None) fullname = os.path.abspath(file_names[number % len(file_names)]) player.set_property('uri','file://%s' % fullname) player.set_state(Gst.State.PLAYING) bus = player.get_bus() bus.enable_sync_message_emission() bus.connect('sync-message::element',set_frame_handle,frame_id) window.mainloop() 如果将句柄保存到播放器(例如在player_list中),您可以稍后更改其中一个播放的uri,如下所示: player_list[index].set_state(Gst.State.NULL) player_list[index].set_property('uri','file://%s' % fileName) player_list[index].set_state(Gst.State.PLAYING) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |