1.1 --- a/gmyth-stream/plugins/media/gstreamer.py Tue Mar 27 23:57:42 2007 +0100
1.2 +++ b/gmyth-stream/plugins/media/gstreamer.py Tue Apr 03 16:42:04 2007 +0100
1.3 @@ -2,59 +2,174 @@
1.4 pygst.require("0.10")
1.5 import gst
1.6 import gobject
1.7 +import socket
1.8
1.9 class Media:
1.10 + class StreamData:
1.11 + stream_count = 0
1.12 +
1.13 + def __init__ (self, pipe, abin, vbin, sink):
1.14 +
1.15 + self.stream_count += 1
1.16 + self.Id = self.stream_count
1.17 + self.Pipe = pipe
1.18 + self.Abin = abin
1.19 + self.Vbin = vbin
1.20 + self.Sink = sink
1.21 + self.Loop = gobject.MainLoop()
1.22 + self.ACaps = ""
1.23 + self.VCaps = ""
1.24 + self.Ready = False
1.25 +
1.26
1.27 def __init__(self, config):
1.28 -
1.29 # set gstreamer basic options
1.30 self.config = config
1.31 - self.pipe = ""
1.32 + self.pipe = None
1.33 + self.streams = []
1.34 + self.socket = None
1.35 + self.connection = None
1.36 + self.addr = None
1.37
1.38
1.39 - def setup(self, filename, mux, vcodec, vbitrate,\
1.40 - fps, acodec, abitrate, width, height, port):
1.41 -
1.42 - self.filename = filename
1.43 - self.mux = mux
1.44 - self.vcodec = vcodec
1.45 - self.vbitrate = int(vbitrate)
1.46 - self.fps = int(fps)
1.47 - self.acodec = acodec
1.48 - self.abitrate = int(abitrate)
1.49 - self.width = int(width)
1.50 - self.height = int(height)
1.51 -
1.52 - self.port = int(port)
1.53 + def setup(self, filename, mux, vcodec, vbitrate,
1.54 + fps, acodec, abitrate, width, height, port, options):
1.55
1.56 ## Pipelines
1.57 + self.pipe = gst.Pipeline ()
1.58 + uri = "file://" + filename
1.59 + print "Opening Uri:" + uri
1.60 + src = gst.element_make_from_uri (gst.URI_SRC, uri, "src")
1.61 + if (src is None):
1.62 + return None
1.63 +
1.64 + decode = gst.element_factory_make ("decodebin", "decode")
1.65 + if (decode is None):
1.66 + return None
1.67
1.68 - #queue ! videoscale ! video/x-raw-yuv,width=240,height=144\
1.69 - #! videorate ! ffenc_h263p bitrate=256000 me-method=2 \
1.70 - #! rtph263ppay ! udpsink host=224.0.0.1 port=5000
1.71 + mux = gst.element_factory_make ("avimux", "mux")
1.72 + if (mux is None):
1.73 + return None
1.74
1.75 + sink = gst.element_factory_make ("fdsink", "sink")
1.76 + if (sink is None):
1.77 + return None
1.78
1.79 - #audio/x-raw-int ! queue ! audioconvert ! faac ! rtpmp4gpay\
1.80 - #! udpsink name=upd_audio host=224.0.0.1 port=5002
1.81 + #Create socket
1.82 + self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
1.83 + self.socket.bind(('', int (port)))
1.84 +
1.85 + #video encode
1.86 + #queue ! videoscale ! video/x-raw-yuv,width=240,height=144 ! videorate ! ffenc_h263p bitrate=256000 me-method=2 ! rtph263ppay ! udpsink host=224.0.0.1 port=5000
1.87 + vbin = gst.Bin ()
1.88 + vqueue = gst.element_factory_make ("queue", "vqueue")
1.89 + vscale = gst.element_factory_make ("videoscale", "vscale")
1.90 + vrate = gst.element_factory_make ("videorate", "vrate")
1.91 + vencode = gst.element_factory_make ("ffenc_h263p", "vencode")
1.92
1.93 - self.pipe = "filesrc location=%s ! decodebin name=d ! queue ! videoscale !"\
1.94 - "video/x-raw-yuv,width=(int)%d,height=(int)%d ! ffenc_h263p bitrate=%d"\
1.95 - " me-method=2 ! rtph263ppay ! udpsink host=224.0.0.1 port=%d d. ! "\
1.96 - "queue ! audioconvert ! faac ! rtpmp4gpay ! udpsink name=udp_audio "\
1.97 - "host=224.0.0.1 port=%d" % (self.filename, self.width, self.height,\
1.98 - self.vbitrate, self.port, self.port+2)
1.99 + if (None in [vbin, vqueue, vscale, vrate, vencode]):
1.100 + print "Fail to create video encode elements."
1.101 + return None
1.102
1.103 - #self.pipe = "filesrc location=/tmp/mpg/cpm.mpg ! decodebin ! ffmpegcolorspace ! ximagesink"
1.104 + vscale_pad = vscale.get_pad("sink")
1.105 + if (vscale_pad is None):
1.106 + print "Fail to get vscale sink pad."
1.107 + return None
1.108
1.109 - self.pipeline = gst.parse_launch(self.pipe)
1.110 + vscale_caps = gst.caps_from_string ("video/x-raw-yuv, width=%s, height=%s" % (width, height))
1.111 + if (vscale_caps is None):
1.112 + print "Fail to create video caps"
1.113 + return None
1.114
1.115 + if (not vscale_pad.set_caps (vscale_caps)):
1.116 + print "Fail to set video output caps"
1.117 + return None
1.118 +
1.119 + vbin.add (vqueue, vscale, vrate, vencode)
1.120 + if (not gst.element_link_many (vqueue, vscale, vrate, vencode)):
1.121 + print "Fail to link video elements"
1.122 + return None
1.123 +
1.124 + vbin.add_pad (gst.GhostPad ("sink", vqueue.get_pad ("sink")))
1.125 + vbin.add_pad (gst.GhostPad ("src", vencode.get_pad ("src")))
1.126 +
1.127 + #audio encode
1.128 + #audio/x-raw-int ! queue ! audioconvert ! faac ! rtpmp4gpay ! udpsink name=upd_audio host=224.0.0.1 port=5002
1.129 + abin = gst.Bin ()
1.130 + aqueue = gst.element_factory_make ("queue", "vqueue")
1.131 + aconvert = gst.element_factory_make ("audioconvert", "aconvert")
1.132 + aencode = gst.element_factory_make ("ffenc_ac3", "aencode")
1.133 +
1.134 + if (None in [abin, aqueue, aconvert, aencode]):
1.135 + print "Fail to create video encode elements."
1.136 + return None
1.137 +
1.138 + abin.add (aqueue, aconvert, aencode)
1.139 + if (not gst.element_link_many (aqueue, aconvert, aencode)):
1.140 + print "Fail to link video elements"
1.141 + return None
1.142 +
1.143 + abin.add_pad (gst.GhostPad ("sink", aqueue.get_pad ("sink")))
1.144 + abin.add_pad (gst.GhostPad ("src", aencode.get_pad ("src")))
1.145 +
1.146 + #Finish Pipeline
1.147 +
1.148 + self.pipe.add (src, decode, abin, vbin, mux, sink)
1.149 + gst.element_link_many (src, decode)
1.150 + gst.element_link_many (mux, sink)
1.151 +
1.152 + #Linking decode with mux
1.153 + mux_audio = mux.get_pad ("audio_0")
1.154 + mux_video = mux.get_pad ("video_0")
1.155 +
1.156 + audio_pad = abin.get_pad ("src")
1.157 + video_pad = vbin.get_pad ("src")
1.158 +
1.159 + if (audio_pad.link (mux_audio) != gst.PAD_LINK_OK):
1.160 + print "Fail to link audio with mux"
1.161 + return None
1.162 +
1.163 + if (video_pad.link (mux_video) != gst.PAD_LINK_OK):
1.164 + print "Fail to link audio with mux"
1.165 + return None
1.166 +
1.167 + stream_data = self.StreamData (self.pipe, abin, vbin, sink)
1.168 +
1.169 + bus = self.pipe.get_bus()
1.170 + bus.add_signal_watch()
1.171 + bus.connect("message", self.__on_bus_message, stream_data)
1.172 +
1.173 + decode.connect("new-decoded-pad", self.__on_decode_new_pad, stream_data)
1.174 + decode.connect("unknown-type", self.__on_decode_unknown_type, stream_data)
1.175 +
1.176 +
1.177 + self.pipe.set_state (gst.STATE_PAUSED)
1.178 + print "Running Pipe"
1.179 + stream_data.Loop.run ()
1.180 + print "End run"
1.181 +
1.182 + a_caps = stream_data.ACaps
1.183 + v_caps = stream_data.VCaps
1.184 + stream_id = stream_data.Id
1.185 +
1.186 + self.streams.append (stream_data)
1.187
1.188 def play(self):
1.189
1.190 print "Trying to play pipeline: %s" % self.pipe
1.191 try:
1.192 - if (self.pipeline):
1.193 - self.pipeline.set_state(gst.STATE_PLAYING)
1.194 + if (self.pipe):
1.195 + print "Waiting for connection"
1.196 + self.socket.listen(1)
1.197 + print "Connection Requested"
1.198 + #Create socket
1.199 + self.connection, self.addr = self.socket.accept ()
1.200 +
1.201 + stream_data = self.streams[0]
1.202 + stream_data.Sink.set_property ("fd", self.connection.fileno());
1.203 + print "Connected"
1.204 +
1.205 + self.pipe.set_state(gst.STATE_PLAYING)
1.206 except gobject.GError, e:
1.207 print "Error: " + str(e)
1.208
1.209 @@ -64,7 +179,57 @@
1.210 print "Trying to stop pipeline: %s" % self.pipe
1.211 try:
1.212 if (self.pipeline):
1.213 + self.connection.close ()
1.214 self.pipeline.set_state(gst.STATE_NULL)
1.215 except gobject.GError, e:
1.216 print "Error: " + str(e)
1.217
1.218 + def __on_bus_message (self, bus, message, stream_data):
1.219 +
1.220 + t = message.type
1.221 + if (t == gst.MESSAGE_STATE_CHANGED):
1.222 + oldstate = -1
1.223 + newstate = -1
1.224 + pending = -1
1.225 + oldstate, newstate, pending = message.parse_state_changed ()
1.226 + if ((oldstate == gst.STATE_READY) and \
1.227 + (newstate == gst.STATE_PAUSED) and \
1.228 + (pending == gst.STATE_VOID_PENDING) and \
1.229 + (stream_data.Ready == False)):
1.230 + state_changed_status, current_state, pending_state = stream_data.Pipe.get_state ()
1.231 + if ((current_state == gst.STATE_PAUSED) and \
1.232 + (pending_state == gst.STATE_VOID_PENDING)):
1.233 + print "Pipe paused"
1.234 + stream_data.Loop.quit ()
1.235 + stream_data.Ready = True
1.236 + elif (t == gst.MESSAGE_ERROR):
1.237 + err, debug = message.parse_error()
1.238 + print "Error: %s" % err, debug
1.239 + stream_data.Loop.quit ()
1.240 + stream_data.Ready = False
1.241 +
1.242 + return True
1.243 +
1.244 + def __on_decode_unknown_type (self, decode, pad, caps, stream_data):
1.245 +
1.246 + print "Unknown Type"
1.247 + return None
1.248 +
1.249 + def __on_decode_new_pad (self, decode, pad, arg1, stream_data):
1.250 +
1.251 + caps = pad.get_caps().to_string()
1.252 + print "New pad " + caps
1.253 + if (caps.rfind ("audio") != -1):
1.254 + apad = stream_data.Abin.get_pad ("sink")
1.255 + if (pad.link (apad) != gst.PAD_LINK_OK):
1.256 + print "Error on link audio pad"
1.257 + return None
1.258 + elif (caps.rfind ("video") != -1):
1.259 + vpad = stream_data.Vbin.get_pad ("sink")
1.260 + if (pad.link (vpad) != gst.PAD_LINK_OK):
1.261 + print "Error on link video pad"
1.262 + return None
1.263 + else:
1.264 + print "Invalid caps"
1.265 +
1.266 +