2013-02-23 237 views
3

我参与了一个包含远程播放视频的艺术项目。我已经使用HTTP服务器和gstreamer视频播放器实现了一个简单的python应用程序。我能够抓住一个http请求并更改当前正在播放的视频,但是我只想在同一个窗口中添加新视频,并同时继续播放两个视频。python gstreamer播放多个视频流

我用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() 
+0

我不完全得到在同一窗口中同时播放它们意味着什么。你想让其中一个在另一个上面或者在一个小盒子里(图片中)或其他什么东西玩到半透明? – mreithub 2013-07-11 15:21:47

+0

这听起来更像是一个“请别人修正我的代码”的问题,而不是一个会让他人受益的通用问题。或者我只是不明白。 – 2015-10-02 14:02:03

回答

0

这是一个简单的代码示例,可以同时播放多个视频流。

它适用于Python 2和3,它使用标准的Python GUI(Tk)和Gstreamer 1.0。因此它应该是可移植的,但我只在Ubuntu 16.04下进行了测试。

(FFmpeg的叉libav产生问题的Ubuntu 14.04,这似乎16.04下要解决下。需要注意的是你需要的包gstreamer1.0-libav除了gstreamer1.0-插件 - *。)

该代码被配置为在一列中创建八个帧,并将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)