python gstreamer play multiple video streams - python

I'm participating in an art project which includes remotely playing videos. I've implemented a simple python application with a HTTP server and a gstreamer video player. I'm able to catch a http request and change the video which is currently playing, but I'd like to just add the new video in the same window and continue playing two videos simultaniously.
I've used playbin2 to play videos, but I think it can only play one uri at the time. I've tried to find other solutions which could play several videos at the same time, but no use...
Could anyone please post a simple example of playing multiple streams at the same time, or give me some pointers to the documentation or other resources??
Thanks in advance!!
PS. Here's the code I wrote: the VideoPlayer class initializes the stream and the the playCurrent function switches the currently played video - I'd like that function just to add the new video to the stream.
#!/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()

Here is a simple example of code that plays multiple video streams at the same time.
It works with Python 2 and 3 and it uses the standard Python GUI (Tk) and Gstreamer 1.0. It should therefore be portable, but I only tested it under Ubuntu 16.04.
(The ffmpeg fork libav created problems under Ubuntu 14.04, which seem to be solved under 16.04. Note that you need the package gstreamer1.0-libav in addition to gstreamer1.0-plugins-*.)
The code is configured to create eight frames in a column, and to associate a Gstreamer player with each of them. You are required to give a list of (up to eight) valid local video file names as arguments to the file into which you saved it (say multivid.py), like this:
$ python3 multivid.py video1.webm video2.mp4
The sound channels are simply mixed together. You probably want to change this.
My solution does not address remote playing, but you have already solved that part.
I previously posted the same code in an answer to another question on video files in tkinter, where the question did not ask for simultaneous streams. It is therefore more appropriate here.
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()
If you save the handles to the players (say in player_list), you can later change the uri that it is playing in one of them like this:
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)

Related

Where are Gstreamer bus log messages?

I am trying to stream a .mp4 to a RTSP server using Gstreamer in python
import sys
import gi
gi.require_version('Gst', '1.0')
gi.require_version('GstRtspServer', '1.0')
gi.require_version('GstRtsp', '1.0')
from gi.repository import Gst, GstRtspServer, GObject, GLib, GstRtsp
loop = GLib.MainLoop()
Gst.init(None)
file_path = "test.mp4"
class TestRtspMediaFactory(GstRtspServer.RTSPMediaFactory):
def __init__(self):
GstRtspServer.RTSPMediaFactory.__init__(self)
def do_create_element(self, url):
src_demux = f"filesrc location={file_path} ! qtdemux name=demux"
h264_transcode = "demux.video_0"
pipeline = "{0} {1} ! queue ! rtph264pay name=pay0 config-interval=1 pt=96".format(src_demux, h264_transcode)
print ("Element created: " + pipeline)
self._pipeline = Gst.parse_launch(pipeline)
def bus_handler(bus, message):
print(message)
self.bus = self._pipeline.get_bus()
self.bus.connect('message', bus_handler)
self.bus.add_signal_watch_full(1)
return self._pipeline
class GstreamerRtspServer():
def __init__(self):
self.rtspServer = GstRtspServer.RTSPServer()
factory = TestRtspMediaFactory()
factory.set_shared(True)
mountPoints = self.rtspServer.get_mount_points()
self.address = '127.0.0.1' #my RPi's local IP
self.port = '8553'
self.rtspServer.set_address(self.address)
self.rtspServer.set_service(self.port)
urlstr = "/user=&password=.sdp"
url = GstRtsp.RTSPUrl.parse(urlstr)
mountPoints.add_factory(urlstr, factory)
self.rtspServer.attach(None)
if __name__ == '__main__':
s = GstreamerRtspServer()
loop.run()
However I am trying to understand how to use Gstreamer bus to log messages like eos or errors and warnings but I don't see any, even when I send eos events and the streaming effectively stops
s.rtspServer._pipeline._end_stream_event.set()
s.rtspServer._pipeline.send_event(Gst.Event.new_eos())
Am I using it properly? If not, what can I fix to properly log bus messages?
Following solution is based on this accepted but somehow incomplete answer.
I found out the way that does not require "manual" creation of pipeline elements but instead it keeps (in this scenario) convenient Gst.parse_launch(pipelineCmd) method and extends Gst.Bin to enable message debugging.
Here is full example source code (check out commented lines for some explanations):
#!/usr/bin/env python
import sys
import gi
gi.require_version('Gst', '1.0')
gi.require_version('GstRtspServer', '1.0')
from gi.repository import Gst, GstRtspServer, GObject, GLib
Gst.init(None)
loop = GLib.MainLoop()
# extended Gst.Bin that overrides do_handle_message and adds debugging
class ExtendedBin(Gst.Bin):
def do_handle_message(self,message):
if message.type == Gst.MessageType.ERROR:
error, debug = message.parse_error()
print("ERROR:", message.src.get_name(), ":", error.message)
if debug:
print ("Debug info: " + debug)
elif message.type == Gst.MessageType.EOS:
print ("End of stream")
elif message.type == Gst.MessageType.STATE_CHANGED:
oldState, newState, pendingState = message.parse_state_changed()
print ("State changed -> old:{}, new:{}, pending:{}".format(oldState,newState,pendingState))
else :
print("Some other message type: " + str(message.type))
#call base handler to enable message propagation
Gst.Bin.do_handle_message(self,message)
class TestRtspMediaFactory(GstRtspServer.RTSPMediaFactory):
def __init__(self):
GstRtspServer.RTSPMediaFactory.__init__(self)
def do_create_element(self, url):
#set mp4 file path to filesrc's location property
src_demux = "filesrc location=/path/to/dir/test.mp4 ! qtdemux name=demux"
h264_transcode = "demux.video_0"
#uncomment following line if video transcoding is necessary
#h264_transcode = "demux.video_0 ! decodebin ! queue ! x264enc"
pipelineCmd = "{0} {1} ! queue ! rtph264pay name=pay0 config-interval=1 pt=96".format(src_demux, h264_transcode)
self.pipeline = Gst.parse_launch(pipelineCmd)
print ("Pipeline created: " + pipelineCmd)
# creates extended Gst.Bin with message debugging enabled
extendedBin = ExtendedBin("extendedBin")
# Gst.pipeline inherits Gst.Bin and Gst.Element so following is possible
extendedBin.add(self.pipeline)
# creates new Pipeline and adds extended Bin to it
self.extendedPipeline = Gst.Pipeline.new("extendedPipeline")
self.extendedPipeline.add(extendedBin)
return self.extendedPipeline
class GstreamerRtspServer(GstRtspServer.RTSPServer):
def __init__(self):
self.rtspServer = GstRtspServer.RTSPServer()
self.factory = TestRtspMediaFactory()
self.factory.set_shared(True)
mountPoints = self.rtspServer.get_mount_points()
mountPoints.add_factory("/stream", self.factory)
self.rtspServer.attach(None)
print ("RTSP server is ready")
if __name__ == '__main__':
s = GstreamerRtspServer()
loop.run()
Please note that Gst.Pipeline actually inherists/extends Gst.Bin (and Gst.Element) so it is possible (no matter how strange it sounds) to add pipeline to bin.
This little "trick" saves time for us "lazy" programmers to keep using parsing of command line syntax to create pipeline elements.
In some more complex scenarios, where parsing of command line syntax is not applicable, solution would be following:
create ExtendedBin,
"manually" create elements with Gst.ElementFactory.make method (and set necessary properties)
add created elements to ExtendedBean
link elements
create new pipeline and add bin to it
use pipeline where it is needed.

Keep Python COM local server listening open in paralallel while the main code runs

I am trying to build a COM server to get real time information. The problem is that all other functionalities stop while localserver is opened. The rest of the code just runs when the localserver is closed.
I have searched for solutions and failed trying multiprocessing, not because this wouldn't work, I guess because I suck. Anyway, I am stuck in this part.
import pythoncom
import win32com
from win32com.server import localserver
from multiprocessing import Process
class PythonUtilities(object):
_reg_clsid_ = '{D9C54599-9011-4678-B1EB-A07FD272F0AF}'
_reg_desc_ = "Change information between programs"
_reg_progid_ = "Python.LetsTalk"
_public_attrs_ = ['speech', 'roger']
_readonly_attrs_ = ['roger']
_public_methods_ = ['talktome']
def __init__(self):
self.roger = 'roger'
self.speech = None
def talktome(self,speech):
self.speech = speech
print ('New speech received: ' + self.speech)
return self.roger
### ___ ###
def runserver(mess):
print(mess)
localserver.serve(['{D9C54599-9011-4678-B1EB-A07FD272F0AF}'])
if __name__=='__main__':
pu = PythonUtilities
print ("Registering COM Server ")
win32com.server.register.UseCommandLine(pu)
# Fine so far.
# The problem starts here:
localserver.serve(['{D9C54599-9011-4678-B1EB-A07FD272F0AF}'])
#... rest of the code waiting for localserver be closed
# Experiment... Doesnt work:
#proc = Process(target=runserver, args = ('starting process',))
#proc.start()
#proc.join()
It's important to say that all messages sent from the client seem to be correctly displayed BUT ONLY AFTER I close the local server manually. I want to receive it in real time like a chat app. I mean, I want to keep the localserver opened and being able to work with the information received along the rest of the code.
My problem was solved rewriting the localserver.serve() function and starting it in a new thread as the code below.
import pythoncom
from win32com.client import Dispatch # to get attributes
from win32com.server import register, factory
from threading import Thread
from queue import Queue
class PythonUtilities(object):
_reg_clsid_ = '{D9C54599-9011-4678-B1EB-A07FD272F0AF}'
_reg_desc_ = "Change information between programs"
_reg_progid_ = "Python.LetsTalk"
_public_attrs_ = ['speech']
_public_methods_ = ['talktome']
queue_speech = Queue()
def talktome(self,speech):
self.queue_speech.put(speech)
print ('New speech received: ' + speech)
return 'roger'
### ___ ###
# use instead localserver.serve()
def runserver():
# added - multithread support
pythoncom.CoInitialize()
clsids = ['{D9C54599-9011-4678-B1EB-A07FD272F0AF}']
infos = factory.RegisterClassFactories(clsids)
# commented - from original localserver.serve() method
#pythoncom.EnableQuitMessage(win32api.GetCurrentThreadId())
pythoncom.CoResumeClassObjects()
pythoncom.PumpMessages()
factory.RevokeClassFactories( infos )
pythoncom.CoUninitialize()
if __name__=='__main__':
#use this
server_thread = Thread(target=runserver) # Process works as well
server_thread.start()
#instead this
#localserver.serve(['{D9C54599-9011-4678-B1EB-A07FD272F0AF}'])
#... rest of the code now works in parallel
Also I have made some improvements like Queue to get data later. I hope it can help others.

How to use gst along with pyqt to stream video on pyqt widget

Am using gst along with my pyqt. I want to display the video stream in my widget. While doing so my application starts streaming the video and then crashes. What am I doing wrong ?
Camera Code
from PyQt4 import QtCore
import gst
class camThread(QtCore.QThread):
updateImage = QtCore.pyqtSignal(str)
flag = None
def __init__(self,windowId):
QtCore.QThread.__init__(self)
self.windowId =windowId
self.player = gst.parse_launch("udpsrc port=5000 ! application/x-rtp, encoding-name=H264, payload=96 ! rtph264depay ! h264parse ! ffdec_h264 ! autovideosink")
bus = self.player.get_bus()
bus.add_signal_watch()
bus.enable_sync_message_emission()
bus.connect("sync-message::element", self.on_sync_message)
self.bus = bus
def on_sync_message(self, bus, message):
print "akash 123"
if message.structure is None:
return
message_name = message.structure.get_name()
if message_name == "prepare-xwindow-id":
win_id = self.windowId
assert win_id
imagesink = message.src
imagesink.set_property("force-aspect-ratio", True)
imagesink.set_xwindow_id(win_id)
def run(self):
print "akash"
self.player.set_state(gst.STATE_PLAYING)
msg = self.bus.timed_pop_filtered(gst.CLOCK_TIME_NONE,
gst.MESSAGE_ERROR | gst.MESSAGE_EOS)
self.flag = True
while(True):
if(self.flag==False):
break
def quit(self):
self.flag = false
self.player.set_state(gst.STATE_NULL)
#self.cap.release()
Calling code
def stopCam(self):
if(self.cam!=None):
self.cam.quit()
self.cam = None
def startCam(self):
if(self.cam==None):
self.cam = camThread(self.pic.winId())
self.cam.start()
elif(self.cam.isRunning()):
pass
What am I doing wrong ? Here is the entire code on paste bin
PasteBin file 1
PasteBin file 2
Edit:
I opened the python in debugger. The application becomes unresponsive/fails, when I start the gst playing i.e. it fails after gst bus timed pop.
One of the possible reason I could see was that a thread relating to the video streaming stops or exits after it is started in the application. After which the application goes black/unresponsive/crashes.
I think you forgot to initialise the threading system.
import gobject
gobject.threads_init()
import gst
Your run() function also does not need the while loop and the flag self.flag. According to the documentation here, the call to timed_pop_filtered(gst.CLOCK_TIME_NONE, ...) will block until it receives the specified message. When you click on the "Stop Cam" button, you terminate the playback. The flag is never used.
I also had to change self.cam = camThread(self.pic.winId()) to self.cam = camThread(int(self.pic.winId())) and comment out imagesink.set_property("force-aspect-ratio", True)
-- I am using Mac OS X.
Hope this helps.

GStreamer: textoverlay is not dynamically updated during play

I wanted to see the current CPU load on top of the video image (source is /dev/video0), and I thought textoverlay element would be perfect for this.
I have constructed a (seemingly) working pipeline, except that the textoverlay keeps showing the value originally set to it.
The pipeline is currently like this:
v4l2src > qtdemux > queue > ffmpegcolorspace > textoverlay > xvimagesink
And code looks like this (I have removed bunch of gtk window, thread handling code and some other signal handling, and only left the relevant part):
#!/usr/bin/env python
import sys, os, time, signal
import pygtk, gtk, gobject
import pygst
pygst.require("0.10")
import gst
# For cpu load stats
import psutil
from multiprocessing import Process, Value, Lock # For starting threads
class Video:
def __init__(self):
window = gtk.Window(gtk.WINDOW_TOPLEVEL)
vbox = gtk.VBox()
window.add(vbox)
self.movie_window = gtk.DrawingArea()
vbox.add(self.movie_window)
window.show_all()
# Set up the gstreamer pipeline
self.pipeline = gst.Pipeline("pipeline")
self.camera = gst.element_factory_make("v4l2src","camera")
self.camera.set_property("device","""/dev/video0""")
self.pipeline.add(self.camera)
# Demuxer
self.demuxer = gst.element_factory_make("qtdemux","demuxer")
# Create a dynamic callback for the demuxer
self.demuxer.connect("pad-added", self.demuxer_callback)
self.pipeline.add(self.demuxer)
# Demuxer doesnt have static pads, but they are created at runtime, we will need a callback to link those
self.videoqueue = gst.element_factory_make("queue","videoqueue")
self.pipeline.add(self.videoqueue)
self.videoconverter = gst.element_factory_make("ffmpegcolorspace","videoconverter")
self.pipeline.add(self.videoconverter)
## Text overlay stuff
self.textoverlay = gst.element_factory_make("textoverlay","textoverlay")
self.overlay_text = "cpu load, initializing"
self.textoverlay.set_property("text",self.overlay_text)
self.textoverlay.set_property("halign", "left")
self.textoverlay.set_property("valign", "top")
self.textoverlay.set_property("shaded-background","true")
self.pipeline.add(self.textoverlay)
self.videosink = gst.element_factory_make("xvimagesink","videosink")
self.pipeline.add(self.videosink)
self.camera.link(self.videoqueue)
gst.element_link_many(self.videoqueue, self.videoconverter, self.textoverlay, self.videosink)
bus = self.pipeline.get_bus()
bus.add_signal_watch()
bus.enable_sync_message_emission()
# Start stream
self.pipeline.set_state(gst.STATE_PLAYING)
# CPU stats calculator thread
cpu_load_thread = Process(target=self.cpu_load_calculator, args=())
cpu_load_thread.start()
def demuxer_callback(self, dbin, pad):
if pad.get_property("template").name_template == "video_%02d":
print "Linking demuxer & videopad"
qv_pad = self.videoqueue.get_pad("sink")
pad.link(qv_pad)
def cpu_load_calculator(self):
cpu_num = len( psutil.cpu_percent(percpu=True))
while True:
load = psutil.cpu_percent(percpu=True)
self.parsed_load = ""
for i in range (0,cpu_num):
self.parsed_load = self.parsed_load + "CPU%d: %s%% " % (i, load[i])
print self.textoverlay.get_property("text") # Correctly prints previous cycle CPU load
self.textoverlay.set_property("text",self.parsed_load)
time.sleep(2)
c = Video()
gtk.threads_init()
gtk.main()
The cpu_load_calculator keeps running in the background, and before I set the new value, I print out the previous using the get_property() function, and it is set properly. However on the actual video outputwindow, it keeps to the initial value..
How can I make the textoverlay to update properly also to the video window ?
The problem is that you are trying to update textoverlay from different Process. And processes unlike threads run in separate address space.
You can switch to threads:
from threading import Thread
...
# CPU stats calculator thread
cpu_load_thread = Thread(target=self.cpu_load_calculator, args=())
cpu_load_thread.start()
Or you can run cpu_load_calculator loop from the main thread. This will work because self.pipeline.set_state(gst.STATE_PLAYING) starts it's own thread in background.
So this will be enough:
# Start stream
self.pipeline.set_state(gst.STATE_PLAYING)
# CPU stats calculator loop
self.cpu_load_calculator()

How To : Create Video chat using gst and python and show initiators and accepter's video, in single gtk window

I am developing video chat using gst and python.
where, I would like to view end user's webcam and also want to view my own webcam in one gtk window (similar to empathy video chat).
for that, I have used gst.Tee object and created 2 queues, one would link result to local gtk window and second queue would link same video stream to session object.
gst.Tee have done the task but also decrease the speed of video chat and Video comes later than Audio. (I have used different stream for Audio session)
here, the code snippet :
self.pipeline = gst.Pipeline()
bus = self.pipeline.get_bus()
bus.add_signal_watch()
bus.connect('message', self._on_gst_message)
self.src_bin = gst.element_factory_make("autovideosrc", "src")
autovideosinkLocal = gst.element_factory_make("autovideosink", "autovideosinkLocal")
tee = gst.element_factory_make('tee', "tee")
queueLocal = gst.element_factory_make("queue", "queueLocal")
queueSend = gst.element_factory_make("queue", "queueSend")
self.pipeline.add(self.src_bin, tee, queueLocal, autovideosinkLocal, queueSend)
gst.element_link_many(self.src_bin, tee)
tee.link(queueLocal)
queueLocal.link(autovideosinkLocal)
tee.link(queueSend)
queueSend.get_pad('src').link(self.p2psession.get_property('sink-pad'))
self.pipeline.set_state(gst.STATE_PLAYING)
How would I speedup the video chat (like, If I would use single sink and display only accepter's video it works great)?
Is there any other way to do the same?
Thanks!
I was holding off on answering, but as no one else has weighed in, I'll take a shot at it.
I'm not sure if this would tie in with webcam (though it probably would), but you could create two drawing areas (gtk.DrawingArea) in PyGTK for your two screens. Then, you can hook your video up to those.
I'm doing something similar in my code for playing video. This may require you to create two separate sinks, but frankly, I'm not sure. (If anyone can further expand on this idea, please feel free to do so in comments.)
Here's the piece of code I'm using right now (taken from def __ init __. I am dealing with a small glitch with it in Ubuntu (it has to do with JACK I think), but I'm pretty sure that's computer specific. Note, I have a predefined path.
def __init__(self):
def on_message(bus, message):
if message.type == gst.MESSAGE_EOS:
# End of Stream
player.set_state(gst.STATE_NULL)
elif message.type == gst.MESSAGE_ERROR:
player.set_state(gst.STATE_NULL)
(err, debug) = message.parse_error()
print "Error: %s" % err, debug
def on_sync_message(bus, message):
if message.structure is None:
return False
if message.structure.get_name() == "prepare-xwindow-id":
if sys.platform == "win32":
win_id = videowidget.window.handle
else:
win_id = videowidget.window.xid
assert win_id
imagesink = message.src
imagesink.set_property("force-aspect-ratio", True)
imagesink.set_xwindow_id(win_id)
win = gtk.Window()
win.set_resizable(False)
win.set_has_frame(False)
win.set_position(gtk.WIN_POS_CENTER)
fixed = gtk.Fixed()
win.add(fixed)
fixed.show()
videowidget = gtk.DrawingArea()
fixed.put(videowidget, 0, 0)
videowidget.set_size_request(640, 480)
videowidget.show()
# Setup GStreamer
player = gst.element_factory_make("playbin", "MultimediaPlayer")
bus = player.get_bus()
bus.add_signal_watch()
bus.enable_sync_message_emission()
#used to get messages that GStreamer emits
bus.connect("message", on_message)
#used for connecting video to your application
bus.connect("sync-message::element", on_sync_message)
player.set_property("uri", "file://" + os.getcwd() + "/VID/SEQ-GAME-OPEN.ogv")
player.set_state(gst.STATE_PLAYING)
win.show()
Here's hoping that helps you out, some.

Categories