renderer.py 5.18 KB
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Author: Erickson Silva
E-Mail: erickson.silva@lavid.ufpb.br

Author: Jonathan Lincoln Brilhante
E-Mail: jonathan.lincoln.brilhante@gmail.com

Author: Wesnydy Lima Ribeiro
E-Mail: wesnydy@lavid.ufpb.br
"""

import json
import os
import pika
import PikaManager
import signal
import socket
import subprocess

from pyvirtualdisplay import Display
from thread import start_new_thread
from time import sleep

#Temporary
from shutil import rmtree

# Manager of queues connections.
manager = PikaManager.PikaManager("localhost")

TCP_IP = '0.0.0.0'
TCP_PORT = 5555

CONTROL_MESSAGE = "FINALIZE"
DEFAULT_PTS = "#-1"

PATH_LIBRAS = os.getenv("VLIBRAS_VIDEO_LIBRAS")
VIDEO_CREATOR = os.getenv("VLIBRAS_VIDEO_CREATOR")

#Temporary
PATH_SCREENS = "/storage/frames/"

# Status of renderer to process new requests. Answer one request at a time.
worker_available = True
# Path of libras video.
libras_video = None
# pyvirtualdisplay instance
display = None
# ffmpeg process instance
ffmpeg = None

def start_video_creator(id):
    """
    Start video creator server.

    Parameters
    ----------
    id : string
        Identification of request.
    """
    global display, ffmpeg
    # logger.info("Starting video creator server")
    display = Display(visible=0, size=(800,600))
    display.start()
    subprocess.call(
        [
            VIDEO_CREATOR,
            id,
            "0",
            "30",
            "20",
            "25",
            "-screen-fullscreen", "1",
            "-screen-quality", "Fantastic",
            "-force-opengl"
        ],
        shell=False
    )
    ffmpeg.send_signal(signal.SIGQUIT)
    ffmpeg.communicate()
    display.stop()

def start_ffmpeg(id):
    """
    Start FFmpeg to capture the video creator display.

    Parameters
    ----------
    id : string
        Identification of request.
    """
    global ffmpeg, display, libras_video
    # logger.info("Starting ffmpeg")
    libras_video = os.path.join(PATH_LIBRAS, id + ".mp4")
    ffmpeg = subprocess.Popen(
        [
            "ffmpeg",
            "-y",
            "-loglevel", "quiet",
            "-video_size", "800x600",
            "-r", "30",
            "-f", "x11grab",
            "-draw_mouse", "0",
            "-i", str(display.cmd_param[-1]) + ".0+nomouse",
            "-vcodec", "libx264",
            "-pix_fmt", "yuv420p",
            "-an",
            libras_video
        ],
        shell=False
    )

def open_socket_connection():
    """
    Create a new socket TCP connection with video creator server.

    Returns
    -------
    socket object
        Connection with video creator server.
    """
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # logger.info("Opening connection with video creator")
    while True:
        try:
            s.connect((TCP_IP, TCP_PORT))
            break
        except:
            sleep(2)
    return s

def send_to_video_creator(id, message):
    # Stablishes connection with video creator server.
    socket = open_socket_connection()
    # Send gloss to video creator.
    socket.send(str(message)+DEFAULT_PTS)
    # Receive a response from the video creator
    socket.recv(3)
    # Send the control message to video creator
    socket.send(CONTROL_MESSAGE+DEFAULT_PTS)
    # Start ffmpeg to capture the video creator display.
    start_ffmpeg(id)
    # Close the connection with video creator server.
    socket.close()

def run(ch, method, properties, body):
    """
    Execute the worker.

    Parameters
    ----------
    ch : object
        Channel of communication.
    method : function
        Callback method.
    properties : object
        Message containing a set of 14 properties.
    body : string
        Json string containing the necessary arguments for workers.
    """
    global worker_available

    if worker_available:
        worker_available = False
        start_new_thread(send_to_video_creator, (properties.correlation_id, body))
        start_video_creator(properties.correlation_id)

        try:
            filesize = os.path.getsize(libras_video)
        except:
            filesize = 0

        body = {"file": properties.correlation_id+".mp4", "size": filesize}
        json.dumps(body)

        manager.send_to_queue("videos", body, properties)

        clean(properties.correlation_id)
        worker_available = True
    else:
        ch.basic_reject(delivery_tag=method.delivery_tag, requeue=True)

#Temporary
def clean(id):
    # logger.info("Cleaning screens files")
    path = os.path.join(PATH_SCREENS, id)
    rmtree(path, ignore_errors=True)

def keep_alive(conn_send, conn_receive):
    """
    Keep the connection alive.

    Parameters
    ----------
    conn_send : object
        Connection of writer.
    conn_receive : object
        Connection of receiver.
    """
    while  True:
        sleep(30)
        try:
            conn_send.process_data_events()
            conn_receive.process_data_events()
        except:
            continue

# start_new_thread(keep_alive, (manager.get_conn_send(), manager.get_conn_receive()))

print("Renderer listening...")
while True:
    try:
        manager.receive_from_queue("glosses", run)
    except KeyboardInterrupt:
        manager.close_connections()
        os._exit(0)