gmyth-stream/server/plugins/media/mencoder.py
author rosfran
Thu Apr 12 14:58:13 2007 +0100 (2007-04-12)
branchtrunk
changeset 530 ad51640dd2cd
parent 514 b5352888e3c2
child 533 e55310730feb
permissions -rw-r--r--
[svn r535] Fixed to the older GMythFileTransfer revision (no GObject inheritance).
renatofilho@484
     1
import os
renatofilho@484
     2
import sys
renatofilho@484
     3
import lib
renatofilho@484
     4
import time
morphbr@516
     5
import shlex
renatofilho@484
     6
import signal
renatofilho@484
     7
import socket
renatofilho@484
     8
import ConfigParser
morphbr@516
     9
import logging as log
renatofilho@484
    10
renatofilho@484
    11
from select import *
renatofilho@484
    12
from subprocess import *
renatofilho@484
    13
morphbr@497
    14
class Media(object):
renatofilho@484
    15
renatofilho@484
    16
    def __init__(self, config):
renatofilho@484
    17
renatofilho@484
    18
        self.config = config
morphbr@516
    19
        self.path = ""
morphbr@516
    20
        self.args = []
morphbr@516
    21
        self.language = None
morphbr@516
    22
        self.subtitle = None
morphbr@516
    23
        self.mpegopts = None
renatofilho@484
    24
        self.socket = None
renatofilho@484
    25
        self.child_pid = None
renatofilho@484
    26
        self.mplayer = None
renatofilho@484
    27
        self.mencoder_pid = None
renatofilho@484
    28
        self.mplayer_pid = None
renatofilho@484
    29
morphbr@514
    30
    # __init__
morphbr@514
    31
morphbr@516
    32
    def setup_opts(self, options):
renatofilho@484
    33
renatofilho@484
    34
        for opt in options:
renatofilho@484
    35
morphbr@504
    36
            if opt == "local":
morphbr@511
    37
                self.mplayer = lib.which("mplayer")
renatofilho@484
    38
morphbr@497
    39
            elif opt.find("language=") >= 0:
renatofilho@484
    40
                try:
morphbr@516
    41
                    lan = opt.split("=")[1]
morphbr@516
    42
                    if len(lan) < 2:
morphbr@516
    43
                        self.language = lan
morphbr@516
    44
                except Exception, e:
morphbr@516
    45
                    log.error("Bad language option: %s" % e)
morphbr@516
    46
morphbr@516
    47
            elif opt.find("subtitle=") >= 0:
morphbr@516
    48
                try:
morphbr@516
    49
                    sub = opt.split("=")[1]
morphbr@516
    50
                    if len(sub) < 2:
morphbr@516
    51
                        self.language = sub
morphbr@516
    52
                except Exception, e:
morphbr@516
    53
                    log.error("Bad subtitle option: %s" % e)
renatofilho@484
    54
morphbr@497
    55
            elif opt.find("format=") >= 0:
morphbr@497
    56
                try:
morphbr@516
    57
                    self.mpegopts = opt.split("=")[1]
morphbr@516
    58
                except Exception, e:
morphbr@516
    59
                    log.error("Bad format option: %s" % e)
morphbr@497
    60
morphbr@516
    61
    # setup_opts
renatofilho@484
    62
renatofilho@484
    63
    def run_mplayer(self):
morphbr@514
    64
        msg = self.filename
morphbr@497
    65
morphbr@498
    66
        if self.kind == "dvd":
renatofilho@484
    67
            msg = "dvd://" + msg
renatofilho@484
    68
morphbr@514
    69
        self.mplayer_pid = Popen([self.mplayer, self.filename, "1> %s" % os.devnull,\
morphbr@514
    70
                                  "2> %s" % os.devnull], stdout=PIPE, close_fds=True)
morphbr@514
    71
morphbr@514
    72
    # run_mplayer
morphbr@514
    73
morphbr@504
    74
    def setup_mencoder(self):
morphbr@499
    75
        self.path = self.config.get("Mencoder", "path")
morphbr@514
    76
        mp = Popen([self.path], stdout=PIPE, close_fds=True)
morphbr@514
    77
morphbr@514
    78
        version = mp.stdout.read().split("MEncoder ")[1].split(" (C)")[0].split("-")[-1]
morphbr@499
    79
morphbr@499
    80
        if version > "4.1.1": self.mencoder_old = False
morphbr@499
    81
        else: self.mencoder_old = True
morphbr@499
    82
morphbr@514
    83
        os.kill(mp.pid, signal.SIGKILL)
morphbr@514
    84
        log.info("Mencoder version: %s" % version)
morphbr@499
    85
morphbr@499
    86
        if self.mencoder_old:
morphbr@516
    87
            try:
morphbr@516
    88
                self.fifo = self.config.get("Mencoder", "fifo_path")
morphbr@516
    89
                os.mkfifo(self.fifo)
morphbr@516
    90
            except Exception, e:
morphbr@516
    91
                log.info("Fifo: %s" % e)
morphbr@499
    92
        else:
morphbr@499
    93
            self.fifo = "-"
renatofilho@484
    94
morphbr@514
    95
    # setup_mencoder
morphbr@514
    96
morphbr@516
    97
    def setup_audio(self):
morphbr@514
    98
morphbr@516
    99
        if self.acodec == "mp3lame":
morphbr@514
   100
            return "-oac mp3lame -lameopts cbr:br=%s vol=5" % self.abitrate
morphbr@514
   101
        else:
morphbr@516
   102
            return "-oac lavc -lavcopts acodec=%s:abitrate=%s" % (\
morphbr@514
   103
                self.acodec, self.abitrate)
morphbr@514
   104
morphbr@516
   105
    # setup_audio
morphbr@516
   106
morphbr@516
   107
morphbr@516
   108
    def setup_video(self):
morphbr@516
   109
morphbr@516
   110
        video = ""
morphbr@516
   111
morphbr@516
   112
        video += " -of %s" % self.mux
morphbr@516
   113
        video += " -ofps %s" % self.fps
morphbr@516
   114
morphbr@516
   115
        if self.vcodec == "nuv" or self.vcodec == "xvid"\
morphbr@516
   116
               or self.vcodec == "qtvideo" or self.vcodec == "copy":
morphbr@516
   117
            video += " -ovc %s" % self.vcodec
morphbr@516
   118
        else:
morphbr@516
   119
            video += " -ovc lavc -lavcopts vcodec=%s:vbitrate=%s" % (
morphbr@516
   120
                self.vcodec, self.vbitrate)
morphbr@516
   121
morphbr@516
   122
        if self.mux == "mpeg" and self.mpegopts is not None:
morphbr@516
   123
            video += " -mpegopts format=%s" % self.mpegopts
morphbr@516
   124
morphbr@516
   125
        video += " -vf scale=%s:%s" % (self.width, self.height)
morphbr@516
   126
morphbr@516
   127
        return video
morphbr@516
   128
morphbr@516
   129
    # setup_video
morphbr@516
   130
morphbr@516
   131
morphbr@516
   132
    def arg_append(self, args, options):
morphbr@516
   133
        l = shlex.split(options)
morphbr@516
   134
        for i in l:
morphbr@516
   135
            args.append(i)
morphbr@516
   136
morphbr@516
   137
    # arg_append
morphbr@516
   138
morphbr@516
   139
    def setup_args(self, args):
morphbr@516
   140
morphbr@516
   141
        args.append(self.path)
morphbr@516
   142
        args.append(self.filename)
morphbr@516
   143
morphbr@516
   144
        if self.language != None:
morphbr@516
   145
            self.arg_append(args, "-alang %s" % self.language)
morphbr@516
   146
morphbr@516
   147
        if self.subtitle != None:
morphbr@516
   148
            self.arg_append(args, "-slang %s" % self.subtitle)
morphbr@516
   149
            self.arg_append(args, "-subfps %s" % self.fps)
morphbr@516
   150
morphbr@516
   151
        self.arg_append(args, "-idx")
morphbr@516
   152
        self.arg_append(args, self.audio_opts)
morphbr@516
   153
        self.arg_append(args, self.video_opts)
morphbr@516
   154
morphbr@516
   155
        self.arg_append(args, "-really-quiet")
morphbr@516
   156
        self.arg_append(args, "-o %s" % self.fifo)
morphbr@516
   157
        self.arg_append(args, "2> %s" % os.devnull)
morphbr@516
   158
morphbr@516
   159
    # setup_args
morphbr@516
   160
morphbr@504
   161
    def setup_filename(self, filename):
morphbr@504
   162
        try:
morphbr@504
   163
            self.kind, self.filename = filename.split("://")
morphbr@504
   164
        except:
morphbr@504
   165
            return (False, "Wrong filename protocol")
morphbr@504
   166
morphbr@504
   167
        if self.kind == "file":
morphbr@504
   168
            if not os.path.exists(self.filename):
morphbr@504
   169
                msg = "File requested does not exist. SETUP failed."
morphbr@514
   170
                log.error(msg)
morphbr@504
   171
                return (False, msg)
morphbr@504
   172
morphbr@504
   173
        elif self.kind == "dvd":
morphbr@516
   174
            self.filename = "dvd://" + filename
morphbr@504
   175
morphbr@504
   176
        return (True, "")
morphbr@504
   177
morphbr@514
   178
    # setup_filename
morphbr@514
   179
morphbr@516
   180
    def setup_socket(self):
morphbr@516
   181
        if self.socket != None:
morphbr@516
   182
            del(self.socket)
morphbr@514
   183
morphbr@516
   184
        self.socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
morphbr@516
   185
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
morphbr@514
   186
morphbr@514
   187
        try:
morphbr@516
   188
            self.socket.bind( ('', self.port) )
morphbr@516
   189
            self.socket.listen(1)
morphbr@514
   190
        except Exception, e:
morphbr@514
   191
            log.error("Could not create socket: %s" % e)
morphbr@514
   192
            return (False, e)
morphbr@514
   193
morphbr@514
   194
        return (True, "")
morphbr@514
   195
morphbr@516
   196
    # setup_socket
morphbr@516
   197
morphbr@504
   198
    '''
morphbr@504
   199
    MENCODER SETUP DESCRIPTION
morphbr@504
   200
    ===========================
morphbr@504
   201
morphbr@504
   202
    -> mux, vcodecs and acodecs
morphbr@504
   203
     |-> mencoder (-of | -ovc | -oac) help
morphbr@504
   204
morphbr@504
   205
    -> if used mpeg as mux:
morphbr@504
   206
     |-> to setup format: format=%s as an option at the end
morphbr@504
   207
morphbr@504
   208
    '''
morphbr@504
   209
morphbr@516
   210
morphbr@516
   211
    # good one: /tmp/dvb.mpg avi mpeg4 400 25 mp3lame 192 320 240
morphbr@516
   212
    # file:///tmp/dvb.mpg mpeg mpeg1video 400 25 mp2 192 320 240 format=mpeg1
morphbr@516
   213
    # dvd://4 mpeg mpeg1video 400 25 mp3lame 192 400 240 language=en local
morphbr@516
   214
    # file:///tmp/mpg/bad_day.mpg avi mpeg4 400 25 mp3 192 320 240
morphbr@516
   215
morphbr@504
   216
    def setup(self, filename, mux, vcodec, vbitrate,\
morphbr@504
   217
              fps, acodec, abitrate, width, height, port, options):
morphbr@504
   218
morphbr@504
   219
        self.mux = mux
morphbr@504
   220
        self.vcodec = vcodec
morphbr@504
   221
        self.vbitrate = vbitrate
morphbr@504
   222
        self.fps = fps
morphbr@504
   223
        self.acodec = acodec
morphbr@504
   224
        self.abitrate = abitrate
morphbr@504
   225
        self.width = width
morphbr@504
   226
        self.height = height
morphbr@504
   227
        self.port = int(port)
morphbr@504
   228
morphbr@504
   229
        self.setup_mencoder()
morphbr@516
   230
morphbr@504
   231
        ret_val = self.setup_filename(filename)
morphbr@504
   232
        if not ret_val[0]:
morphbr@504
   233
            return ret_val[1]
morphbr@504
   234
morphbr@516
   235
        self.setup_opts(options)
morphbr@516
   236
        self.audio_opts = self.setup_audio()
morphbr@516
   237
        self.video_opts = self.setup_video()
morphbr@516
   238
        self.setup_args(self.args)
renatofilho@484
   239
morphbr@516
   240
        ret_val = self.setup_socket()
morphbr@514
   241
        if not ret_val[0]:
morphbr@514
   242
            return ret_val[1]
renatofilho@484
   243
morphbr@514
   244
        return True
renatofilho@484
   245
morphbr@514
   246
    # setup
renatofilho@484
   247
renatofilho@484
   248
    def play(self):
renatofilho@484
   249
morphbr@516
   250
        log.info("Starting Mencoder: %s" % self.args )
morphbr@499
   251
morphbr@516
   252
        try:
morphbr@516
   253
            self.mencoder_pid = Popen(self.args, stdout=PIPE, close_fds=True)
morphbr@516
   254
        except Exception, e:
morphbr@516
   255
            msg = "Could not init Mencoder: %s" % e
morphbr@516
   256
            log.error(msg)
morphbr@516
   257
            return msg
renatofilho@484
   258
morphbr@516
   259
        if self.mencoder_old: self.pout = open(self.fifo)
morphbr@516
   260
        else: self.pout = self.mencoder_pid.stdout
renatofilho@484
   261
renatofilho@484
   262
        self.child_pid = os.fork()
renatofilho@484
   263
morphbr@498
   264
        if self.child_pid == 0:
morphbr@516
   265
            conn, addr = self.socket.accept()
morphbr@516
   266
            log.info("Sending Data to client: %s" % addr[0])
renatofilho@484
   267
morphbr@516
   268
            data = self.pout.read(4096)
morphbr@499
   269
renatofilho@484
   270
            conn.settimeout(5)
renatofilho@484
   271
            retry = 0
renatofilho@484
   272
morphbr@498
   273
            while data != "" and retry < 5:
renatofilho@484
   274
                try:
renatofilho@484
   275
                    conn.send(data)
renatofilho@484
   276
                    r, w, x = select([conn], [], [], 0)
renatofilho@484
   277
                    if conn in r:
renatofilho@484
   278
                        back = conn.recv(1024)
morphbr@498
   279
                        if back == "OK" and self.mplayer and not self.mplayer_pid:
renatofilho@484
   280
                            self.run_mplayer()
renatofilho@484
   281
morphbr@516
   282
                except socket.error, e:
morphbr@516
   283
                    log.error("Socket error: %s" % e)
renatofilho@484
   284
                    retry += 1
renatofilho@484
   285
morphbr@516
   286
                data = self.pout.read(4096)
renatofilho@484
   287
morphbr@497
   288
            if retry < 5:
morphbr@516
   289
                log.info("Finished sending Data to client: %s" % addr[0])
renatofilho@484
   290
            else:
morphbr@516
   291
                log.error("Client timed out, retried more than %s times" % retry)
renatofilho@484
   292
morphbr@516
   293
            os.kill(self.mencoder_pid.pid, signal.SIGKILL)
renatofilho@484
   294
            sys.exit(0)
renatofilho@484
   295
morphbr@516
   296
        return True
morphbr@516
   297
morphbr@516
   298
        # play
morphbr@516
   299
renatofilho@484
   300
renatofilho@484
   301
    def stop(self):
renatofilho@484
   302
        try:
renatofilho@484
   303
morphbr@516
   304
            if self.mencoder_pid:
morphbr@516
   305
                os.kill(self.mencoder_pid.pid, signal.SIGKILL)
morphbr@516
   306
                self.mencoder_pid = None
renatofilho@484
   307
morphbr@516
   308
            if self.mplayer_pid:
morphbr@516
   309
                os.kill(self.mplayer_pid.pid, signal.SIGKILL)
morphbr@516
   310
                self.mplayer_pid = None
morphbr@516
   311
morphbr@516
   312
            if self.socket != None:
morphbr@516
   313
                self.socket.close()
morphbr@516
   314
morphbr@498
   315
            if self.child_pid != None:
morphbr@516
   316
                os.kill(self.child_pid, signal.SIGKILL)
morphbr@516
   317
morphbr@516
   318
        except Exception, e:
morphbr@516
   319
            log.error("Stop error: %s" % e)
morphbr@516
   320
morphbr@516
   321
    # stop