Exemplo n.º 1
0
    def get(self):
        lat, long = config.get_list('web', 'map.position')
        options = {
            'latitude': lat,
            'longitude': long,
            'zoomlevel': config.getint('web', 'map.zoom'),
            'traffic_layer':
            js_bool(config.getboolean('web', 'map.traffic_layer')),
            'api_key': config.get('web', 'map.api_key'),
        }

        view = loader.load('map.html').generate(**options)
        self.finish(view)
Exemplo n.º 2
0
    def get(self):
        lat, long = config.get_list('web', 'map.position')
        options = {
            'latitude': lat,
            'longitude': long,
            'zoomlevel': config.getint('web', 'map.zoom'),
            'traffic_layer': js_bool(
                config.getboolean('web', 'map.traffic_layer')),
            'api_key': config.get('web', 'map.api_key'),
        }

        view = loader.load('map.html').generate(**options)
        self.finish(view)
Exemplo n.º 3
0
def main():
    client = pymongo.MongoClient()
    database_name = 'dss_script'
    collection_name = 'mobile_send'
    db = storage.KeyValueStorage(collection_name, client[database_name])

    try:
        file = sys.argv[1]
    except IndexError:
        print('Missing file/stream name as first argument.')
        print('Usage:\n\t', './mobile_send', 'FILE_NAME',
              '[SERVER_IP_ADDRESS]')
        sys.exit(-1)

    try:
        addr = sys.argv[2]
    except IndexError:
        addr = None

    tmp = tempfile.mkdtemp()
    video_file = join(tmp, 'video.ts')
    audio_file = join(tmp, 'audio.ts')

    cmd = ffmpeg.cmd_outputs(
        '-re',
        file,
        '-f mpegts',
        ['-an -c:v libx264', '-vn -c:a libfdk_aac'],
        [video_file, audio_file],
        add_probe=False,
    )
    #print(' '.join(cmd))

    if addr is None:
        addr = config['local']['addr']
    port = config.getint('local', 'tcp_port')

    sender = Sender((addr, port)).start()
    watcher = Watcher(cmd).start()
    try:
        stream_id = db.stream_id
    except AttributeError:
        stream_id = ''

    sender.insert(ContentType.meta, {'id': stream_id}, as_metadata=True)
    with sender.cond:
        sender.cond.wait()
    type, data = sender.handler.read_data()
    type, data = DataProc.decode_data(data)
    if 'id' in data:
        db.stream_id = data['id']

    print('Transmission started')
    print('ID:', db.stream_id)
    time.sleep(2)

    try:
        # Run loop on other thread because it will block!
        _ = thread.Thread(read_loop,
                          args=(audio_file, video_file, sender,
                                watcher)).start()

        with watcher.cond:
            watcher.cond.wait()
    except KeyboardInterrupt:
        watcher.stop()
        sender.stop()

    print('Exiting...')
Exemplo n.º 4
0
def main():
    client = pymongo.MongoClient()
    database_name = 'dss_script'
    collection_name = 'mobile_send'
    db = storage.KeyValueStorage(collection_name, client[database_name])

    try:
        file = sys.argv[1]
    except IndexError:
        print('Missing file/stream name as first argument.')
        print('Usage:\n\t', './mobile_send', 'FILE_NAME', '[SERVER_IP_ADDRESS]')
        sys.exit(-1)

    try:
        addr = sys.argv[2]
    except IndexError:
        addr = None

    tmp = tempfile.mkdtemp()
    video_file = join(tmp, 'video.ts')
    audio_file = join(tmp, 'audio.ts')

    cmd = ffmpeg.cmd_outputs(
        '-re', file, '-f mpegts',
        ['-an -c:v libx264', '-vn -c:a libfdk_aac'],
        [video_file, audio_file],
        add_probe=False,
    )
    #print(' '.join(cmd))

    if addr is None:
        addr = config['local']['addr']
    port = config.getint('local', 'tcp_port')

    sender = Sender((addr, port)).start()
    watcher = Watcher(cmd).start()
    try:
        stream_id = db.stream_id
    except AttributeError:
        stream_id = ''

    sender.insert(ContentType.meta, {'id': stream_id}, as_metadata=True)
    with sender.cond:
        sender.cond.wait()
    type, data = sender.handler.read_data()
    type, data = DataProc.decode_data(data)
    if 'id' in data:
        db.stream_id = data['id']

    print('Transmission started')
    print('ID:', db.stream_id)
    time.sleep(2)

    try:
        # Run loop on other thread because it will block!
        _ = thread.Thread(
            read_loop,
            args=(audio_file, video_file, sender, watcher)
        ).start()

        with watcher.cond:
            watcher.cond.wait()
    except KeyboardInterrupt:
        watcher.stop()
        sender.stop()

    print('Exiting...')
Exemplo n.º 5
0
class MediaHandler(socketserver.BaseRequestHandler, object):
    """  Packet header description

        The packet header will provide the type of payload data, and the size.

        [ T | S | S | S | S | D | D | ... ]

        T - 1st byte              - Type of message
        S - 2nd to 5th bytes      - Size of payload
        D - Data payload

        Currently we envision just 4 types of messages:
        Metadata, Video, Audio and User generated data.
    """

    provider_prefix = 'M'
    _handlers = set()
    _handlers_lock = thread.Lock()
    _time_limit = config.getint('mobile', 'time_limit')

    def setup(self):
        self._id = None
        self.run = True
        self.proc = None
        self.video = None
        self.audio = None
        self.destination_url = None
        self.data_processing = None
        self.thumbnail_path = None
        self.buffer = buffer.Buffer(self.request)
        self.data_queue = queue.Queue()
        self.tmpdir = tempfile.mkdtemp(dir=config['mobile']['dir'])
        self._timer_alarm = False
        self.timer = thread.Timer(self._time_limit, self.timer_alarm) \
            if self._time_limit else None
        self._error = []
        self.__cleanup_executed = False

    def add_handler(self):
        with self._handlers_lock:
            self._handlers.add(self)

    def remove_handler(self):
        with self._handlers_lock:
            self._handlers.remove(self)

    @property
    def error(self):
        return self._error

    @error.setter
    def error(self, value):
        self._error.append(value)

    @classmethod
    def wait_handlers(cls):
        while cls._handlers:
            time.sleep(0.1)

    def timer_alarm(self):
        self._timer_alarm = True

    def file(self, name, open_options=None):
        """ Return the name of a file in the temp dir.
            If open_options is supplied, the file will
            be opened and returned.
        """
        fname = os.path.join(self.tmpdir, name)
        if open_options is None:
            return fname
        return open(fname, open_options)

    def cleanup(self):
        """ Close pipes, remove files and temp dir and
            kills the transcoding process.
        """
        if self.__cleanup_executed:
            return

        s = Suppress(Exception)

        # Stop timer if any
        if self.timer is not None:
            self.timer.cancel()

        # Stop all threads
        with s: self.audio.stop()
        with s: self.video.stop()
        with s: self.data_processing.stop()

        # Remove entry from database
        if self._id:
            db.mobile.update({'_id': self._id}, {'$set': {'active': False}})

        # Remove temp directory and thumbnail
        with s: shutil.rmtree(self.tmpdir)
        with s: os.remove(self.thumbnail_path)

        WebsocketBroadcast.select('mobile_location').cls.broadcast_message({
            'name': self.get_stream_name(),
            'info': 'finished'
        })

        self.__cleanup_executed = True
        if s.errors:
            show.warn('Errors during cleanup:', *s.errors, sep='\n', end='\n\n')
        show('Mobile stream "{0}" has ended'.format(self._id))

    def finish(self):
        try:
            self.cleanup()
        except Exception as e:
            show.error('Exception while cleaning:', repr(e))
        finally:
            self.remove_handler()

    def handle(self):
        try:
            self._handle()
        except BaseException:
            show.error(traceback.format_exc())
            raise

    def _handle(self):
        self.request.settimeout(WAIT_TIMEOUT)
        self.add_handler()
        db_data = {'start': datetime.datetime.utcnow(),
                   'active': True}

        # Read the first data block.
        # It should have complete metadata information with at least the
        # provided id, if it is known (or falsy value otherwise)
        typ, payload = self.read_data()
        typ = DataContent[typ]
        if typ is DataContent.metadata:
            action, payload = DataProc.decode_data(payload)
            try:
                self._id = ObjectId(payload['id'])
            except Exception:
                pass
        else:
            show.error('Received first data block of type {0.name!r}({0.value}).\n'
                       'Expected {1.name!r}({1.value})', typ, DataContent.metadata)
            return

        response = db.mobile.update({'_id': self._id}, db_data, upsert=True)
        self._id = response.get('upserted', self._id)
        self.send_data(ContentType.meta, {'id': str(self._id)})
        self.destination_url = os.path.join(
            rtmpconf['addr'], rtmpconf['app'], self.get_stream_name()
        )
        show('New mobile stream:', self.destination_url)

        audio_filename = self.file('audio.ts')
        video_filename = self.file('video.ts')
        try:
            os.mkfifo(audio_filename)
            os.mkfifo(video_filename)
        except OSError as e:
            show.error('Failed to create FIFO:', e)
            return

        audio_pipe = os.open(audio_filename, os.O_RDWR)
        video_pipe = os.open(video_filename, os.O_RDWR)
        set_pipe_max_size(audio_pipe, video_pipe)

        self.audio = Media(audio_pipe, self, 'audio').start()
        self.video = Media(video_pipe, self, 'video').start()
        self.data_processing = DataProc(self).start()

        thumb = config['thumbnail']
        self.thumbnail_path = os.path.join(
            thumb['dir'], self.get_stream_name()
        ) + '.' + thumb['format']

        thumb_rate = str(1. / int(thumb['mobile_interval']))

        args = ffmpeg.cmd_inputs_outputs(
            '-y -re', [audio_filename, video_filename], '',
            ['-c:v copy -c:a copy -bsf:a aac_adtstoasc -f flv',
             '-r ' + thumb_rate + ' -update 1 -an'],
            [self.destination_url, self.thumbnail_path]
        )

        # Start the timer for alarm
        if self.timer is not None:
            self.timer.start()

        with self.file('proc_output', 'w') as out:
            with self.file('proc_err', 'w') as err:
                self.handle_proc_loop(args, out, err)

    def handle_proc_loop(self, proc_args, stdout, stderr):
        """ Open transcoding process and read data from buffer
            until the client stops sending data.
        """
        with process.Popen(proc_args, stdout=stdout, stderr=stderr) as self.proc:
            while self.server.is_running \
                    and not self._timer_alarm \
                    and not self.error \
                    and self.proc.poll() is None:
                try:
                    type, payload = self.read_data()
                except Exception:
                    show.warn('Timeout')
                    break

                if not self.run or type is None:
                    break

                self.handle_content(type, payload)

            if self._timer_alarm:
                show('Stream finished due to time limit: {0} seconds'.format(self._time_limit))

    def handle_content(self, type, payload):
        try:
            type = DataContent[type]
        except KeyError:
            show.warn('Invalid header type "%s"' % type)

        if type in (DataContent.metadata, DataContent.userdata):
            self.data_queue.put((type, payload))
        elif type is DataContent.video:
            self.video.add_data(payload)
        elif type is DataContent.audio:
            self.audio.add_data(payload)
        else:
            show.warn('Unknown content received: ' +
                      'Type: {0}, Payload: {1!r}'.format(type, payload))

    def process_header(self, data):
        """ Strips out the header
            Takes away the header data and returns it as a tuple of values.
        """
        size = struct.unpack('!I', data[1:])
        return data[0], size[0]

    def read_data(self):
        """ Read next packet from buffer.
            Refer to the "MediaHandler" doc for the packet description.
        """
        buff = self.buffer.read(HEADER_SIZE)
        if not buff:
            return None, None
        typ, size = self.process_header(buff)
        payload = self.buffer.read(size)
        if not payload:
            return None, None
        return typ, payload

    @classmethod
    def build_metadata(cls, type, content):
        data = {'type': type.name, 'content': content}
        return json.dumps(data).encode('utf-8')

    def send_data(self, type, content):
        # Deprecated. Use write_data directly
        self.write_data(type, content, as_metadata=True)

    def write_data(self, data_type, data, as_metadata=False):
        if as_metadata:
            data = self.build_metadata(data_type, data)
            data_type = DataContent.metadata

        header = struct.pack('!BI', data_type.value, len(data))
        self.request.sendall(header + data)

    def get_stream_name(self):
        return self.stream_name(self._id)

    @classmethod
    def stream_name(cls, id):
        return cls.provider_prefix + '_' + str(id)
Exemplo n.º 6
0
 def __init__(self):
     self.host = config.get('local', 'addr')
     self.port = config.getint('local', 'tcp_port')
     self.cond = thread.Condition()
     self._server = None
Exemplo n.º 7
0
 def __init__(self):
     self.host = config.get('local', 'addr')
     self.port = config.getint('local', 'tcp_port')
     self.cond = thread.Condition()
     self._server = None