#include "renderer.h" Renderer::Renderer(char* path_Contents, char* id) { this->pathOutVideo = path_Contents; this->userID = id; cSocket = new StreamSocket(); listeners = new list(); 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::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()); } void Renderer::connectToUnityPlayer() { try{ int i = 0; // Contador de tentativas static InetAddress* addr = InetAddress::createByName(HOST); PRINTL(util::_DEBUG, "Conectando ao UnityPlayer...\n"); while(!cSocket->isConnected()){ try{ cSocket->connect(addr, PORT); }catch(lavidlib::SocketException &ex){ if(i < 10) { // Numeros de tentativas de conexão (pode ser alterado) i++; sleep(1); }else{ PRINTL(util::_ERROR, "Número de tentativas de conexão excedido!\n"); throw lavidlib::RuntimeException(ex.getMessage().c_str()); } } } }catch(lavidlib::UnknownHostException &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 = ""; //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::_DEBUG, "Renderizando...\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()); } } PRINTL(util::_INFO, "Gerando vídeo...\n"); 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()); }