gmyth-stream/server/plugins/media/mencoder.py
author morphbr
Wed Apr 04 23:30:44 2007 +0100 (2007-04-04)
branchtrunk
changeset 504 2b5355061b66
parent 499 9900800a8dd6
child 511 16312d0021cb
permissions -rw-r--r--
[svn r509] - GMyth-Streamer:
* default port changed to 50000
* increase port used for streaming when SETUP
* changed SETUP protocol
* switch command CLOSE to QUIT
renatofilho@484
     1
import os
renatofilho@484
     2
import sys
renatofilho@484
     3
import lib
renatofilho@484
     4
import time
renatofilho@484
     5
import signal
renatofilho@484
     6
import socket
renatofilho@484
     7
import ConfigParser
renatofilho@484
     8
renatofilho@484
     9
from select import *
renatofilho@484
    10
from subprocess import *
renatofilho@484
    11
morphbr@497
    12
class Media(object):
renatofilho@484
    13
renatofilho@484
    14
    def __init__(self, config):
renatofilho@484
    15
renatofilho@484
    16
        self.config = config
morphbr@504
    17
        self.args = ""
renatofilho@484
    18
        self.language = "en"
renatofilho@484
    19
        self.socket = None
renatofilho@484
    20
        self.child_pid = None
renatofilho@484
    21
        self.mplayer = None
renatofilho@484
    22
        self.mencoder_pid = None
renatofilho@484
    23
        self.mplayer_pid = None
renatofilho@484
    24
        signal.signal(signal.SIGABRT, self.kill_handler)
renatofilho@484
    25
renatofilho@484
    26
    def kill_handler(self, sig, frame):
renatofilho@484
    27
        try:
renatofilho@484
    28
            os.kill(self.mplayer_pid.pid + 1, signal.SIGKILL)
renatofilho@484
    29
            sys.exit(0)
renatofilho@484
    30
        except:
renatofilho@484
    31
            lib.log("Problems closing child")
renatofilho@484
    32
renatofilho@484
    33
    def set_args(self, options):
renatofilho@484
    34
renatofilho@484
    35
        for opt in options:
renatofilho@484
    36
morphbr@504
    37
            if opt == "local":
renatofilho@484
    38
                self.mplayer = os.popen("which mplayer").read().strip()
renatofilho@484
    39
morphbr@497
    40
            elif opt.find("language=") >= 0:
renatofilho@484
    41
                try:
renatofilho@484
    42
                    self.language = opt.split("=")[1]
renatofilho@484
    43
                except:
renatofilho@484
    44
                    lib.log("Bad language option")
renatofilho@484
    45
morphbr@497
    46
            elif opt.find("format=") >= 0:
morphbr@497
    47
                try:
morphbr@497
    48
                    self.mux += " -mpegopts format=%s" % opt.split("=")[1]
morphbr@497
    49
                except:
morphbr@497
    50
                    lib.log("Bad format option")
morphbr@497
    51
renatofilho@484
    52
renatofilho@484
    53
    def run_mplayer(self):
renatofilho@484
    54
        msg = "%s 1>/dev/null 2>/dev/null" % self.filename
morphbr@497
    55
morphbr@498
    56
        if self.kind == "dvd":
renatofilho@484
    57
            msg = "dvd://" + msg
renatofilho@484
    58
renatofilho@484
    59
        self.mplayer += " " + msg
renatofilho@484
    60
        self.mplayer_pid = Popen(self.mplayer, shell=True)
renatofilho@484
    61
morphbr@504
    62
    def setup_mencoder(self):
morphbr@499
    63
        self.path = self.config.get("Mencoder", "path")
morphbr@499
    64
        a, b = os.popen2(self.path)
morphbr@499
    65
        version = b.read().split("MEncoder ")[1].split(" (C)")[0].split("-")[-1]
morphbr@499
    66
morphbr@499
    67
        if version > "4.1.1": self.mencoder_old = False
morphbr@499
    68
        else: self.mencoder_old = True
morphbr@499
    69
morphbr@504
    70
        lib.log("Mencoder version: %s" % version)
morphbr@504
    71
morphbr@499
    72
        a.close()
morphbr@499
    73
        b.close()
morphbr@499
    74
morphbr@499
    75
        if self.mencoder_old:
morphbr@499
    76
            self.fifo = self.config.get("Mencoder", "fifo_path")
morphbr@499
    77
        else:
morphbr@499
    78
            self.fifo = "-"
renatofilho@484
    79
morphbr@504
    80
    def setup_filename(self, filename):
morphbr@504
    81
        try:
morphbr@504
    82
            self.kind, self.filename = filename.split("://")
morphbr@504
    83
        except:
morphbr@504
    84
            return (False, "Wrong filename protocol")
morphbr@504
    85
morphbr@504
    86
        if self.acodec == "mp3lame":
morphbr@504
    87
            audio = "-oac mp3lame -lameopts cbr:br=%s vol=5" % self.abitrate
morphbr@504
    88
        else:
morphbr@504
    89
            audio = "-oac lavc -lavcopts acodec=%s:abitrate=%s" % (\
morphbr@504
    90
                    self.acodec, self.abitrate)
morphbr@504
    91
morphbr@504
    92
        if self.kind == "file":
morphbr@504
    93
            if not os.path.exists(self.filename):
morphbr@504
    94
                msg = "File requested does not exist. SETUP failed."
morphbr@504
    95
                lib.log(msg)
morphbr@504
    96
                return (False, msg)
morphbr@504
    97
morphbr@504
    98
            self.args += " %s -mf fps=%s -of %s %s"\
morphbr@504
    99
                         " -ovc lavc -lavcopts vcodec=%s:vbitrate=%s -vf scale=%s:%s"\
morphbr@504
   100
                         " -really-quiet -o %s 2>/dev/null" % (
morphbr@504
   101
                self.filename, self.fps, self.mux, audio, self.vcodec,
morphbr@504
   102
                self.vbitrate, self.width, self.height, self.fifo)
morphbr@504
   103
morphbr@504
   104
        elif self.kind == "dvd":
morphbr@504
   105
            self.args += " dvd://%s -alang %s -vf scale=%s:%s %s"\
morphbr@504
   106
                         " -of %s -ovc lavc -lavcopts vcodec=%s:vbitrate=%s"\
morphbr@504
   107
                         " -ofps %s -really-quiet -o %s 2>/dev/null" % (
morphbr@504
   108
                self.filename, self.language, self.width, self.height, audio,
morphbr@504
   109
                self.mux, self.vcodec, self.vbitrate, self.fps, self.fifo)
morphbr@504
   110
morphbr@504
   111
        return (True, "")
morphbr@504
   112
morphbr@504
   113
    '''
morphbr@504
   114
    MENCODER SETUP DESCRIPTION
morphbr@504
   115
    ===========================
morphbr@504
   116
morphbr@504
   117
    -> mux, vcodecs and acodecs
morphbr@504
   118
     |-> mencoder (-of | -ovc | -oac) help
morphbr@504
   119
morphbr@504
   120
    -> if used mpeg as mux:
morphbr@504
   121
     |-> to setup format: format=%s as an option at the end
morphbr@504
   122
morphbr@504
   123
    '''
morphbr@504
   124
morphbr@504
   125
    def setup(self, filename, mux, vcodec, vbitrate,\
morphbr@504
   126
              fps, acodec, abitrate, width, height, port, options):
morphbr@504
   127
morphbr@504
   128
        self.mux = mux
morphbr@504
   129
        self.vcodec = vcodec
morphbr@504
   130
        self.vbitrate = vbitrate
morphbr@504
   131
        self.fps = fps
morphbr@504
   132
        self.acodec = acodec
morphbr@504
   133
        self.abitrate = abitrate
morphbr@504
   134
        self.width = width
morphbr@504
   135
        self.height = height
morphbr@504
   136
        self.port = int(port)
morphbr@504
   137
morphbr@504
   138
        self.setup_mencoder()
morphbr@504
   139
        ret_val = self.setup_filename(filename)
morphbr@504
   140
morphbr@504
   141
        if not ret_val[0]:
morphbr@504
   142
            return ret_val[1]
morphbr@504
   143
renatofilho@484
   144
        self.set_args(options)
renatofilho@484
   145
morphbr@498
   146
        # good one: /tmp/dvb.mpg avi mpeg4 400 25 mp3lame 192 320 240 5000 file
morphbr@504
   147
        # /tmp/dvb.mpg mpeg mpeg1video 400 25 mp2 192 320 240 5000 format=mpeg1 file
morphbr@497
   148
        #4 mpeg mpeg1video 400 25 mp3lame 192 400 240 5000 language=en local dvd
morphbr@498
   149
        if self.socket != None:
renatofilho@484
   150
            del(self.socket)
renatofilho@484
   151
renatofilho@484
   152
        self.socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
renatofilho@484
   153
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
renatofilho@484
   154
        self.socket.bind( ('', self.port) )
renatofilho@484
   155
        self.socket.listen(1)
renatofilho@484
   156
renatofilho@484
   157
        return 0
renatofilho@484
   158
renatofilho@484
   159
renatofilho@484
   160
    def play(self):
renatofilho@484
   161
morphbr@499
   162
        if self.mencoder_old:
morphbr@499
   163
            try:
morphbr@499
   164
                os.mkfifo(self.fifo)
morphbr@499
   165
            except:
morphbr@499
   166
                lib.log("Fifo already exists")
morphbr@499
   167
renatofilho@484
   168
renatofilho@484
   169
        lib.log("Starting Mencoder: %s %s" % (self.path, self.args) )
renatofilho@484
   170
        # exec Mencoder
morphbr@499
   171
        if self.mencoder_old:
morphbr@499
   172
            self.mencoder_pid = Popen(self.path + self.args, shell=True)
morphbr@504
   173
            self.pout = open(self.fifo)
morphbr@499
   174
        else:
morphbr@499
   175
            self.path += self.args
morphbr@499
   176
            pin, self.pout = os.popen2(self.path)
renatofilho@484
   177
renatofilho@484
   178
        self.child_pid = os.fork()
renatofilho@484
   179
morphbr@498
   180
        if self.child_pid == 0:
renatofilho@484
   181
            conn,addr= self.socket.accept()
renatofilho@484
   182
            lib.log("Sending Data to client: %s" % addr[0])
renatofilho@484
   183
morphbr@499
   184
            data = self.pout.read(1024)
morphbr@499
   185
renatofilho@484
   186
            conn.settimeout(5)
renatofilho@484
   187
            retry = 0
renatofilho@484
   188
morphbr@498
   189
            while data != "" and retry < 5:
renatofilho@484
   190
                try:
renatofilho@484
   191
                    conn.send(data)
renatofilho@484
   192
                    r, w, x = select([conn], [], [], 0)
renatofilho@484
   193
                    if conn in r:
renatofilho@484
   194
                        back = conn.recv(1024)
morphbr@498
   195
                        if back == "OK" and self.mplayer and not self.mplayer_pid:
renatofilho@484
   196
                            self.run_mplayer()
renatofilho@484
   197
renatofilho@484
   198
                except socket.error:
renatofilho@484
   199
                    lib.log("Socket error (maybe timeout ?)")
renatofilho@484
   200
                    retry += 1
renatofilho@484
   201
morphbr@499
   202
                data = self.pout.read(1024)
renatofilho@484
   203
morphbr@497
   204
            if retry < 5:
renatofilho@484
   205
                lib.log("Finished sending Data to client: %s" % addr[0])
renatofilho@484
   206
            else:
renatofilho@484
   207
                lib.log("Client timed out")
renatofilho@484
   208
renatofilho@484
   209
            sys.exit(0)
renatofilho@484
   210
renatofilho@484
   211
renatofilho@484
   212
    def stop(self):
renatofilho@484
   213
        try:
morphbr@499
   214
            if self.mplayer_old:
morphbr@499
   215
                os.kill(self.mencoder_pid.pid + 1, signal.SIGKILL)
morphbr@499
   216
            else:
morphbr@499
   217
                self.pout.close()
renatofilho@484
   218
            self.mplayer = None
renatofilho@484
   219
        except:
renatofilho@484
   220
            lib.log("Trying to stop before playing...")
renatofilho@484
   221
morphbr@498
   222
        if self.socket != None:
renatofilho@484
   223
            lib.log("Closing socket")
renatofilho@484
   224
            self.socket.close()
renatofilho@484
   225
renatofilho@484
   226
            lib.log("Trying to stop Mencoder process")
morphbr@498
   227
            if self.child_pid != None:
renatofilho@484
   228
                os.kill(self.child_pid, signal.SIGABRT)