[英]python gstreamer play multiple video streams
我正在參與一個包括遠程播放視頻的藝術項目。 我已經實現了一個帶有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, bus, 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, bus, 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
聲道簡單地混合在一起。 你可能想改變它。
我的解決方案不涉及遠程播放,但您已經解決了這個問題。
我之前在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)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.