renderer.cpp 4.94 KB
#include "renderer.h"

Renderer::Renderer(char* path_Contents, char* id) {
	this->pathOutVideo = path_Contents;
	this->userID = id;
	cSocket = new StreamSocket();
	listeners = new list<ListenerRenderer*>();
	PRINTL(util::_DEBUG, "Renderer Done!\n");
}

Renderer::~Renderer() {
	listeners->clear(); 
    delete listeners;
    if(cSocket) delete cSocket;
    PRINTL(util::_DEBUG, "Renderer finalized!\n");
}

void Renderer::addListener(ListenerRenderer* listener) {
    listeners->push_back(listener);
}

void Renderer::notifyListeners() {
    PRINTL(util::_DEBUG, "Renderização finalizada!\n");
    for (list<ListenerRenderer*>::iterator i = listeners->begin(); i != listeners->end(); i++) {
        (*i)->notifyEndOfRenderization();
    }
}

void Renderer::executeServerScript() {
	PRINTL(util::_DEBUG, "Executando o Script de inicialização do servidor\n");

	string command = "cd ";

	char* renderPath;
	renderPath = getenv("RENDERER");
	if(renderPath != NULL)
		command.append(renderPath);
	else
		command.append(PATH_RENDERER);

	command.append(" && ").append("python render.py ")
	.append(userID).append(" >/dev/null 2>&1 &");

	system(command.c_str());
	sleep(4); //tempo para inicializar o player
}

void Renderer::connectToUnityPlayer() {
	try{
        static InetAddress* addr = InetAddress::createByName(HOST);
        while(!cSocket->isConnected()){
            PRINTL(util::_DEBUG, "Conectando ao UnityPlayer...\n");
            cSocket->connect(addr, PORT);
            sleep(1);
        }
    }catch(lavidlib::UnknownHostException &ex){
        throw lavidlib::RuntimeException(ex.getMessage().c_str());
    }catch(lavidlib::SocketException &ex){
        throw lavidlib::RuntimeException(ex.getMessage().c_str());
    }
}

//Armazena as glosas em uma fila até q o método initialize() seja chamado p/ fazer os envios
void Renderer::receiveGlosa(string glosa, int64_t pts) {
	ostringstream oss;
	string formatedGlosa; //Formato da glosa que será enviada para o player: "glosa#pts"
	
	if(glosa == BADSENTENCE || glosa == BADTEXT)
		formatedGlosa = "_DEFAULT"; //O player entende "#pts" como pose neutra
	else
		formatedGlosa = glosa;

		oss << pts;
		formatedGlosa += "#";
		formatedGlosa += oss.str();
		glosaQueue.push(formatedGlosa);
}

void Renderer::exportGlosa() {
	if(glosaQueue.empty())
		throw lavidlib::RuntimeException("Fila de glosas vazia!");

	int glosaSize;
	char* glosaBff;

	string glosaCpy = glosaQueue.front(); //Pega quem estiver na frente da fila
	glosaSize = strlen(glosaCpy.c_str())+1;
	glosaBff = new char[glosaSize];
	strcpy(glosaBff, glosaCpy.c_str());

	try {
		cSocket->write(glosaBff, glosaSize); //Envia a glosa formatada p/ o player
	}catch(lavidlib::IOException &ex){
		throw lavidlib::RuntimeException(ex.getMessage().c_str());
	}

	char* received = new char[3]; //Mensagem de confirmação de recebimento da glosa: "OK\0"
	do {
		try {
			cSocket->read(received, 3); //Aguarda a confirmação
		}catch(lavidlib::IOException &ex){
			throw lavidlib::RuntimeException(ex.getMessage().c_str());
		}
	}while(strcmp(received, OK_FLAG) != 0); //Verifica se é a confirmação correta

	glosaQueue.pop(); //Se o envio foi bem sucedido, remove a glosa da fila

	delete [] glosaBff;
    delete [] received;
}

void Renderer::waitScreenShots() {
	int endSize;
	char* finalize;

	endSize = strlen(END_FLAG)+1;
	finalize = new char[endSize];

	PRINTL(util::_DEBUG, "Aguardando a captura das ScreenShots.\n");
	do {
		try {
			cSocket->read(finalize, endSize); //Aguarda o player notificar o fim da captura das ScreenShots
		}catch(lavidlib::IOException &ex){
			throw lavidlib::RuntimeException(ex.getMessage().c_str());
		}
	}while(strcmp(finalize, END_FLAG) != 0); //Verifica se é a mensagem correta ("FINALIZE\0")

    cSocket->close();
}

void Renderer::renderVideo() {
	PRINTL(util::_INFO, "Gerando vídeo...\n");

    string command = "ffmpeg -y -loglevel quiet -framerate 30 -i ";
    command.append(PATH_SCREENS).append(userID).append("/frame_%d.png ")
    .append("-vcodec libx264 -pix_fmt yuv420p ").append(pathOutVideo);
    system(command.c_str());
}

void Renderer::initialize() {
	executeServerScript();
	try{
		connectToUnityPlayer();
	}catch(lavidlib::RuntimeException &ex){
		throw lavidlib::RuntimeException(ex.getMessage().c_str());
	}
	this->Start();
}

void Renderer::Run() {
	PRINTL(util::_DEBUG, "Enviando glosas para o player...\n");
	while(!glosaQueue.empty()){ //Inicia o envio das glosas que estão na fila
		try{
			exportGlosa();
		}catch(lavidlib::RuntimeException &ex){
			throw lavidlib::RuntimeException(ex.getMessage().c_str());
		}
	}
	
	receiveGlosa(END_FLAG, -1); //Quando a fila estiver vazia, a flag "FINALIZE" será enviada
	try{
		exportGlosa();
		waitScreenShots();
	}catch(lavidlib::RuntimeException &ex){
		throw lavidlib::RuntimeException(ex.getMessage().c_str());
	}
	renderVideo();
	notifyListeners();
	cleanFiles();
}

void Renderer::cleanFiles() {
    string clean = "rm -rf ";
    clean.append(PATH_SCREENS).append(userID).append("/");
    system(clean.c_str());
}