gmyth-stream/server/plugins/media/mencoder.py
branchtrunk
changeset 565 ed34b1dab103
parent 564 1b897f699097
child 566 25f194cfa60b
     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()