1.1 --- a/gmyth-stream/server/plugins/media/mencoder.py Wed Apr 18 15:47:40 2007 +0100
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,411 +0,0 @@
1.4 -from __future__ import division
1.5 -
1.6 -import os
1.7 -import sys
1.8 -import lib
1.9 -import time
1.10 -import shlex
1.11 -import signal
1.12 -import socket
1.13 -import ConfigParser
1.14 -import logging as log
1.15 -
1.16 -from select import *
1.17 -from subprocess import *
1.18 -
1.19 -class Media(object):
1.20 -
1.21 - def __init__(self, config):
1.22 -
1.23 - self.config = config
1.24 - self.do_cleanup()
1.25 -
1.26 - # __init__()
1.27 -
1.28 -
1.29 - def do_cleanup(self):
1.30 - self.path = ""
1.31 - self.args = []
1.32 - self.language = None
1.33 - self.subtitle = None
1.34 - self.mpegopts = None
1.35 - self.socket = None
1.36 - self.child_pid = None
1.37 - self.mplayer = None
1.38 - self.mencoder_pid = None
1.39 - self.mplayer_pid = None
1.40 - self.audio_opts = None
1.41 - self.video_opts = None
1.42 - self.gst_pipe = None
1.43 - self.gst_pid = None
1.44 - self.transcode_local = None
1.45 -
1.46 - # do_cleanup()
1.47 -
1.48 -
1.49 - def setup_opts(self, options):
1.50 -
1.51 - for opt in options:
1.52 -
1.53 - if opt == "local":
1.54 - self.mplayer = lib.which("mplayer")
1.55 -
1.56 - elif opt.find("language=") >= 0:
1.57 - try:
1.58 - lan = opt.split("=")[1]
1.59 - if len(lan) < 2:
1.60 - self.language = lan
1.61 - except Exception, e:
1.62 - log.error("Bad language option: %s" % opt)
1.63 -
1.64 - elif opt.find("subtitle=") >= 0:
1.65 - try:
1.66 - sub = opt.split("=")[1]
1.67 - if len(sub) < 2:
1.68 - self.language = sub
1.69 - except Exception, e:
1.70 - log.error("Bad subtitle option: %s" % opt)
1.71 -
1.72 - elif opt.find("format=") >= 0:
1.73 - try:
1.74 - self.mpegopts = opt.split("=")[1]
1.75 - except Exception, e:
1.76 - log.error("Bad format option: %s" % opt)
1.77 -
1.78 - elif opt.find("outfile=") >= 0:
1.79 - try:
1.80 - self.transcode_local = opt.split("=")[1]
1.81 - except Exception, e:
1.82 - log.error("Bad outfile option: %s" % opt)
1.83 -
1.84 - # setup_opts()
1.85 -
1.86 -
1.87 - def run_mplayer(self):
1.88 - msg = self.filename
1.89 -
1.90 - if self.kind == "dvd":
1.91 - msg = "dvd://" + msg
1.92 -
1.93 - self.mplayer_pid = Popen([self.mplayer, self.filename, "1> %s" % os.devnull,\
1.94 - "2> %s" % os.devnull], stdout=PIPE, close_fds=True)
1.95 -
1.96 - # run_mplayer()
1.97 -
1.98 -
1.99 - def setup_mencoder(self):
1.100 - self.path = self.config.get("Mencoder", "path")
1.101 - mp = Popen([self.path], stdout=PIPE, close_fds=True)
1.102 -
1.103 - version = mp.stdout.read().split("MEncoder ")[1].split(" (C)")[0].split("-")[-1]
1.104 -
1.105 - if version > "4.1.1": self.mencoder_old = False
1.106 - else: self.mencoder_old = True
1.107 -
1.108 - os.kill(mp.pid, signal.SIGKILL)
1.109 - log.info("Mencoder version: %s" % version)
1.110 -
1.111 - if self.mencoder_old:
1.112 - try:
1.113 - self.fifo = self.config.get("Mencoder", "fifo_path")
1.114 - os.mkfifo(self.fifo)
1.115 - except Exception, e:
1.116 - log.info("Fifo: %s" % e)
1.117 - else:
1.118 - self.fifo = "-"
1.119 -
1.120 - # setup_mencoder()
1.121 -
1.122 -
1.123 - def setup_audio(self):
1.124 -
1.125 - if self.acodec == "mp3lame":
1.126 - return "-oac mp3lame -lameopts cbr:br=%s vol=5" % self.abitrate
1.127 - else:
1.128 - return "-oac lavc -lavcopts acodec=%s:abitrate=%s" % (\
1.129 - self.acodec, self.abitrate)
1.130 -
1.131 - # setup_audio()
1.132 -
1.133 -
1.134 - def setup_video(self):
1.135 -
1.136 - video = ""
1.137 -
1.138 - video += " -of %s" % self.mux
1.139 - video += " -ofps %s" % self.fps
1.140 -
1.141 - if self.vcodec == "nuv" or self.vcodec == "xvid"\
1.142 - or self.vcodec == "qtvideo" or self.vcodec == "copy":
1.143 - video += " -ovc %s" % self.vcodec
1.144 - else:
1.145 - video += " -ovc lavc -lavcopts vcodec=%s:vbitrate=%s" % (
1.146 - self.vcodec, self.vbitrate)
1.147 -
1.148 - if self.mux == "mpeg" and self.mpegopts is not None:
1.149 - video += " -mpegopts format=%s" % self.mpegopts
1.150 -
1.151 - video += " -vf scale=%s:%s" % (self.width, self.height)
1.152 -
1.153 - return video
1.154 -
1.155 - # setup_video()
1.156 -
1.157 -
1.158 - def arg_append(self, args, options):
1.159 - l = shlex.split(options)
1.160 - for i in l:
1.161 - args.append(i)
1.162 -
1.163 - # arg_append()
1.164 -
1.165 -
1.166 - def setup_args(self, args):
1.167 -
1.168 - args.append(self.path)
1.169 -
1.170 - #args.append(self.filename)
1.171 - args.append("-")
1.172 -
1.173 - if self.language != None:
1.174 - self.arg_append(args, "-alang %s" % self.language)
1.175 -
1.176 - if self.subtitle != None:
1.177 - self.arg_append(args, "-slang %s" % self.subtitle)
1.178 - self.arg_append(args, "-subfps %s" % self.fps)
1.179 -
1.180 - self.arg_append(args, "-idx")
1.181 - self.arg_append(args, self.audio_opts)
1.182 - self.arg_append(args, self.video_opts)
1.183 -
1.184 - self.arg_append(args, "-really-quiet")
1.185 - self.arg_append(args, "-o %s" % self.fifo)
1.186 - self.arg_append(args, "2> %s" % os.devnull)
1.187 -
1.188 - # setup_args()
1.189 -
1.190 -
1.191 - def setup_filename(self, filename):
1.192 - try:
1.193 - self.kind, self.filename = filename.split("://")
1.194 - except:
1.195 - return (False, "Wrong filename protocol")
1.196 -
1.197 - if self.kind == "file":
1.198 - if not os.path.exists(self.filename):
1.199 - msg = "File requested does not exist. SETUP failed."
1.200 - log.error(msg)
1.201 - return (False, msg)
1.202 -
1.203 - elif self.kind == "dvd":
1.204 - self.filename = "dvd://" + filename
1.205 -
1.206 - elif self.kind == "myth":
1.207 - self.filename = filename
1.208 - self.gst_pipe = os.pipe()
1.209 - print self.gst_pipe[0]
1.210 - print self.gst_pipe[1]
1.211 -
1.212 - return (True, "")
1.213 -
1.214 - # setup_filename()
1.215 -
1.216 -
1.217 - def setup_socket(self):
1.218 - if self.socket != None:
1.219 - self.socket = None
1.220 -
1.221 - self.socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
1.222 - self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
1.223 -
1.224 - try:
1.225 - self.socket.bind( ('', self.port) )
1.226 - self.socket.listen(1)
1.227 - except Exception, e:
1.228 - log.error("Could not create socket: %s" % e)
1.229 - return (False, e)
1.230 -
1.231 - return (True, "")
1.232 -
1.233 - # setup_socket()
1.234 -
1.235 -
1.236 - '''
1.237 - MENCODER SETUP DESCRIPTION
1.238 - ===========================
1.239 -
1.240 - -> mux, vcodecs and acodecs
1.241 - |-> mencoder (-of | -ovc | -oac) help
1.242 -
1.243 - -> if used mpeg as mux:
1.244 - |-> to setup format: format=%s as an option at the end
1.245 -
1.246 - '''
1.247 -
1.248 -
1.249 - # good one: /tmp/dvb.mpg avi mpeg4 400 25 mp3lame 192 320 240
1.250 - # file:///tmp/dvb.mpg mpeg mpeg1video 400 25 mp2 192 320 240 format=mpeg1
1.251 - # dvd://4 mpeg mpeg1video 400 25 mp3lame 192 400 240 language=en local
1.252 - # file:///tmp/mpg/bad_day.mpg avi mpeg4 400 25 mp3 192 320 240
1.253 -
1.254 - def setup(self, filename, mux, vcodec, vbitrate,\
1.255 - fps, acodec, abitrate, width, height, port, options):
1.256 -
1.257 - if self.args != []:
1.258 - self.do_cleanup()
1.259 -
1.260 - self.mux = mux
1.261 - self.vcodec = vcodec
1.262 - self.vbitrate = vbitrate
1.263 - self.fps = fps
1.264 - self.acodec = acodec
1.265 - self.abitrate = abitrate
1.266 - self.width = width
1.267 - self.height = height
1.268 - self.port = int(port)
1.269 -
1.270 - self.setup_mencoder()
1.271 -
1.272 - ret_val = self.setup_filename(filename)
1.273 -
1.274 - if not ret_val[0]:
1.275 - return ret_val
1.276 -
1.277 - self.setup_opts(options)
1.278 - self.audio_opts = self.setup_audio()
1.279 - self.video_opts = self.setup_video()
1.280 - self.setup_args(self.args)
1.281 -
1.282 - ret_val = self.setup_socket()
1.283 - return ret_val
1.284 -
1.285 - # setup()
1.286 -
1.287 - def play_loop(self, conn):
1.288 - data = self.pout.read(4096)
1.289 -
1.290 - conn.settimeout(5)
1.291 - retry = 0
1.292 -
1.293 - if not self.transcode_local:
1.294 - while data != "" and retry < 5:
1.295 - try:
1.296 - conn.send(data)
1.297 - r, w, x = select([conn], [], [], 0)
1.298 - if conn in r:
1.299 - back = conn.recv(1024)
1.300 - if back == "OK" and self.mplayer and not self.mplayer_pid:
1.301 - self.run_mplayer()
1.302 -
1.303 - except socket.error, e:
1.304 - log.error("Socket error: %s" % e)
1.305 - retry += 1
1.306 -
1.307 - data = self.pout.read(4096)
1.308 -
1.309 - else:
1.310 - local = open(self.transcode_local, "w")
1.311 - total = os.path.getsize(self.filename)
1.312 - partial = 4096
1.313 -
1.314 - while data != "":
1.315 - try:
1.316 - local.write(data)
1.317 - except Exception, e:
1.318 - log.error("Write error: %s" % e)
1.319 -
1.320 - data = self.pout.read(4096)
1.321 - partial += len(data)
1.322 - conn.send("%.2f\n" % (partial * 100 / total) )
1.323 -
1.324 - local.close()
1.325 - conn.send("DONE\n")
1.326 -
1.327 - return retry
1.328 -
1.329 - # play_loop()
1.330 -
1.331 -
1.332 - def play(self):
1.333 -
1.334 - if self.gst_pipe:
1.335 - try:
1.336 - gst = [ lib.which("gst-launch-0.10"), "--gst-debug-level=0" ]
1.337 - self.arg_append(gst, "mythtvsrc location=%s" % self.filename)
1.338 - self.arg_append(gst, "! fdsink fd=2")
1.339 - self.gst_pid = Popen(gst, close_fds=True)
1.340 - log.info("Running Gstreamer: %s" % gst);
1.341 - except Exception, e:
1.342 - msg = "Could not init Gstreamer: %s" % e
1.343 - log.error(msg)
1.344 - return (False, msg)
1.345 -
1.346 -
1.347 - log.info("Starting Mencoder: %s" % self.args )
1.348 - try:
1.349 - if not self.gst_pipe:
1.350 - self.stdin = open(self.filename)
1.351 - else:
1.352 - self.stdin = self.gst_pid.stdout
1.353 -
1.354 - self.mencoder_pid = Popen(self.args, stdin=self.stdin, stdout=PIPE, close_fds=True)
1.355 - except Exception, e:
1.356 - msg = "Could not init Mencoder: %s" % e
1.357 - log.error(msg)
1.358 - return (False, msg)
1.359 -
1.360 - if self.mencoder_old: self.pout = open(self.fifo)
1.361 - else: self.pout = self.mencoder_pid.stdout
1.362 -
1.363 - self.child_pid = os.fork()
1.364 -
1.365 - if self.child_pid == 0:
1.366 - conn, addr = self.socket.accept()
1.367 -
1.368 - log.info("Sending Data to client: %s" % addr[0])
1.369 - retry = self.play_loop(conn)
1.370 -
1.371 - if retry < 5:
1.372 - log.info("Finished sending Data to client: %s" % addr[0])
1.373 - else:
1.374 - log.error("Client timed out, retried more than %s times" % retry)
1.375 -
1.376 - os.kill(self.mencoder_pid.pid, signal.SIGKILL)
1.377 - sys.exit(0)
1.378 -
1.379 - return (True, "")
1.380 -
1.381 - # play()
1.382 -
1.383 -
1.384 - def stop(self):
1.385 - try:
1.386 -
1.387 - if self.mencoder_pid:
1.388 - os.kill(self.mencoder_pid.pid, signal.SIGTERM)
1.389 - self.mencoder_pid = None
1.390 -
1.391 - if self.mplayer_pid:
1.392 - os.kill(self.mplayer_pid.pid, signal.SIGTERM)
1.393 - self.mplayer_pid = None
1.394 -
1.395 - if self.socket:
1.396 - self.socket.close()
1.397 - self.socket = None
1.398 -
1.399 - if self.child_pid:
1.400 - os.kill(self.child_pid, signal.SIGTERM)
1.401 - self.child_pid = None
1.402 -
1.403 - if self.gst_pid:
1.404 - os.kill(self.gst_pid.pid, signal.SIGTERM)
1.405 - self.gst_pid = None
1.406 -
1.407 - self.do_cleanup()
1.408 -
1.409 - os.wait()
1.410 -
1.411 - except Exception, e:
1.412 - log.error("Stop error: %s" % e)
1.413 -
1.414 - # stop()