/* * File: Mixer.cpp * Author: eduardo * * Created on 17 de Janeiro de 2012, 15:28 */ #include "Mixer.h" /* Construtores e destrutores...*/ Mixer::Mixer() { this->setNumThreads("1"); DPRINTF("Done!\n"); } Mixer::Mixer(string mainVideo, string secondaryVideo) { this->setMainVideo(mainVideo); this->setSecondaryVideo(secondaryVideo); this->setNumThreads("1"); DPRINTF("Done!\n"); } Mixer::~Mixer() { DDDPRINTF("Mixer finalized!\n"); } /* FIM de Construtores e destrutores...*/ /*Faz a chamada ffmpeg no terminal.*/ void Mixer::initialize(string mainVideo, string slVideo, int positionSecondaryVideo, int sizeSecondaryVideo, int transparency, char* _id, char* path_uploads, char* path_contents){ DPRINTF("[AGUARDE] Mixando...\n") uploads = path_uploads; contents = path_contents; stringstream ss; ss << _id; ss >> user_id; this->setMainVideo(mainVideo); this->setSecondaryVideo(slVideo); this->setNumThreads("8"); //tem que aparecer antes do metodo adjustVideosFps() //this->adjustVideosFps(); this->setSize(sizeSecondaryVideo); this->setPositionSecondaryVideo(positionSecondaryVideo); this->setTransparency(transparency); this->setPathFinal(); this->mixVideos(); } void Mixer::mixVideos () { //convertendo os numeros em string para concatenar à frase std::stringstream num1; num1 << this->widthSecondaryVideo; string num1String; num1 >> num1String; std::stringstream num2; num2 << this->heightSecondaryVideo; string num2String; num2 >> num2String; /*std::stringstream num2; num2 << this->heightSecondaryVideo; string num2String, aux; num2 >> aux; num2String = "in_h*"+aux;*/ string strPosition; if(this->getPositionSecondaryVideo() == TOP_LEFT) strPosition = "10:10"; else if((this->getPositionSecondaryVideo() == TOP_RIGHT)) strPosition = "main_w-overlay_w-10:10"; else if((this->getPositionSecondaryVideo() == BOTTOM_RIGHT)) strPosition = "main_w-overlay_w-10:main_h-overlay_h-10"; else if((this->getPositionSecondaryVideo() == BOTTOM_LEFT)) strPosition = "10:main_h-overlay_h-10"; else{ //se não escolheu nenhum inteiro válido, consideramos BOTTOM_RIGHT o local padrão, mostra msg de erro strPosition = "main_w-overlay_w-10:main_h-overlay_h-10"; cout << "####################################################################\n"; cout << "# Posicao do vídeo de libras é inválido! #\n"; cout << "# Assumiremos a posicao padrao (Bottom_Right)! #\n"; cout << "# OPCOES: 1-Top_Left; 2-Top_Right; 3-Bottom_Right; 4-Bottom_Left; #\n"; cout << "####################################################################"; } //retira a string .ts da primeira string //string nameOfMainVideo = mainVideo.substr(0,mainVideo.length()-3); int dotPosition = 0; for(int k = mainVideo.length(); k >= 0; k--) { if (mainVideo[k] == '.') { dotPosition = k; break; } } string nameOfMainVideo = mainVideo.substr(0, dotPosition); string transparency; if(this->getTransparency()==0){ transparency = ""; } else transparency = "transp"; /*string ffmpegSentence = "ffmpeg -i "+this->mainVideo+" -y -vf \"movie="+this->secondaryVideo+", "+ "scale="+ num1String +":"+num2String+", setpts=PTS-STARTPTS [movie]; "+ "[in] setpts=PTS-STARTPTS, [movie] overlay"+transparency+"="+strPosition+ " [out]\" -sameq -threads "+this->numThreads+" "+nameOfMainVideo+"_Libras.ts";*/ /*string ffmpegSentence = "ffmpeg -i "+this->mainVideo+" -y -vf \"movie="+this->secondaryVideo+", "+ "scale="+ num1String +":"+num2String+", setpts=PTS-STARTPTS [movie]; "+ "[in] setpts=PTS-STARTPTS, [movie] overlay"+transparency+"="+strPosition+ " [out]\" -sameq -ar 22050 -ab 32 -f flv -acodec pcm_s16le -vcodec flv -threads "+this->numThreads+" "+nameOfMainVideo+"_Libras.flv";*/ //LEONARDO /*string ffmpegSentence = "ffmpeg -i "+this->mainVideo+" -y -vf \"movie="+this->secondaryVideo+", "+ "scale="+ num1String +":"+num2String+", [movie] overlay"+transparency+"="+strPosition+ " [out]\" -sameq -ar 22050 -ab 32 -f flv -acodec pcm_s16le -vcodec flv -threads "+this->numThreads+" "+nameOfMainVideo+"_Libras.flv";*/ //TRANSCODIFICAR PARA FLV /* string ffmpegSentence = "ffmpeg -i "+this->mainVideo+" -y -vf \"movie="+this->secondaryVideo+", "+ "scale="+ num1String +":"+num2String+", setpts=PTS-STARTPTS, [movie] overlay"+transparency+"="+strPosition+ " [out]\" -sameq -strict experimental -vcodec mpeg2video -r 30 -threads "+this->numThreads+" "+pathFinal; */ string ffmpegSentence = "ffmpeg -i "+this->mainVideo+" -v quiet -y -vf \"movie="+this->secondaryVideo+", "+ "scale="+ num1String +":"+num2String+", setpts=PTS-STARTPTS, [movie] overlay"+transparency+"="+strPosition+ " [out]\" -qscale 0 -strict experimental -vcodec libx264 -preset fast -r 30 -threads "+this->numThreads+" "+pathFinal; /* string ffmpegSentence = "ffmpeg -i "+this->mainVideo+" -y -vf \"movie="+this->secondaryVideo+", "+ "scale="+ num1String +":"+num2String+", setpts=PTS-STARTPTS, [movie] overlay"+transparency+"="+strPosition+ " [out]\" -sameq -threads "+this->numThreads+" "+pathFinal; */ /* convertendo e obtendo ótimos resultados de tamanho do vídeo ffmpeg -i videoDemoLibras.ts -vcodec libx264 -f flv -ar 22050 -ab 32 -sameq -threads 8 -y teste.flv */ //printf("\n\n%s\n\n", ffmpegSentence.c_str()); system(ffmpegSentence.c_str()); //string removeVideoCMD = "rm -rf "+nameOfMainVideo+".ts"; //removo o vídeo exemplo-45fps.ts //system(removeVideoCMD.c_str()); } void Mixer::setPathFinal(){ stringstream ss; ss << contents; ss >> pathFinal; pathFinal.append("/").append(user_id).append(".mp4"); cout << "Path: " << pathFinal << endl; } /*Ajusta o FPS do vídeo principal para 45 se preciso...*/ void Mixer::adjustVideosFps(){ //primeiro executo a linha de comando que me dá todas as informações do vídeo string ffmpegSentence = "ffmpeg -i "+this->mainVideo+" 2> "+temporaryTextFile; system(ffmpegSentence.c_str()); //executo o comando ffmpeg que escreve no arquivo temporário fpsAndLine arrayDeFps[10]; //array onde será guardado os fps encontrados int qtdadeDeFPSEncontrados = 0; this->readFileFPS(arrayDeFps, &qtdadeDeFPSEncontrados); //leio o arquivo procurando os FPS disponíveis this->convertMainVideoFPS(arrayDeFps, &qtdadeDeFPSEncontrados); //converte o fps do vídeo principal } /*Lê do arquivo procurando o fps...*/ void Mixer::readFileFPS(fpsAndLine arrayDeFps [], int * qtdadeDeFPSEncontrados){ ifstream arq(temporaryTextFile.c_str());//abrindo arquivo com info. dos vídeos if (arq.is_open()){ int indiceDoFPSEncontrados = 0; //indice a ser utilizado no array string line; while (!arq.eof()){ getline(arq,line); //linha lida no arquivo int auxProgram = line.find("Program "); //procura pela string "fps," if(auxProgram >= 0){ string id = line.substr(auxProgram+10); if(atoi(id.c_str()) != 0){ //diferente de 0, a conversão deu blz... arrayDeFps[indiceDoFPSEncontrados].possibleProgramID = id; printf("\n\n\n\n\nID: %s\n\n\n\n\n",id.c_str()); } } int aux = line.find("fps,"); //procura pela string "fps," if(aux >= 0){ int i; int espacos = 0; //quantidade de espacos encontrados for(i = aux;espacos != 2;i--){ if(line.at(i) == ' '){ //se for espaço incremente espacos++; } } string fps = line.substr(i+espacos,aux-i-espacos-1);//extrai o fps da linha double fpsDouble = atof(fps.c_str()); //transformo de string pra double arrayDeFps[indiceDoFPSEncontrados].fps = fpsDouble; //armazeno o fps em um array de struct arrayDeFps[indiceDoFPSEncontrados].line = line; //armazeno a linha em um array de struct indiceDoFPSEncontrados++; //achei um fps, preenchi um struct, vou pro prox. } } arq.close(); //*qtdadeDeFPSEncontrados = indiceDoFPSEncontrados + 1; *qtdadeDeFPSEncontrados = indiceDoFPSEncontrados; } } void Mixer::convertMainVideoFPS(fpsAndLine arrayDeFps [], int * qtdadeDeFPSEncontrados){ //retira a string .ts da primeira string string nameOfMainVideo = mainVideo.substr(0,mainVideo.length()-3); int i; if(*qtdadeDeFPSEncontrados > 1){ //cout << "\n############################\nConverter fps do vídeo principal com vários canais!\n############################\n"); for(i = 0; i < *qtdadeDeFPSEncontrados;i++){ //procura pela string "Video: h264 (High), yuv420p, 1920x1080 [PAR 1:1 DAR 16:9]," int indexMainVideo1 = arrayDeFps[i].line.find("Video: h264 (High)"); int indexMainVideo2 = arrayDeFps[i].line.find("yuv420p"); int indexMainVideo3 = arrayDeFps[i].line.find("1920x1080"); //int indexMainVideo = arrayDeFps[i].line.find("DAR 16:9"); //printf("\n\n\n\n\n\n\nPID do canal: %s \n\n\n\n\n\n\n",arrayDeFps[i].possibleProgramID.c_str()); if(indexMainVideo1 > 0 && indexMainVideo2 > 0 && indexMainVideo3 > 0){ //eis aqui o vídeo principal //printf("\n\n\n\n\n\n\nPID do canal a ser alterado: %s \n\n\n\n\n\n\n",arrayDeFps[i].possibleProgramID.c_str()); string ffmpegSentence45 = "ffmpeg -i "+this->mainVideo+" -v quiet -y -r 45 -vcodec libx264 -streamid 0:"+arrayDeFps[i].possibleProgramID+ "-sameq -threads "+this->numThreads+" "+nameOfMainVideo+"-45fps.ts"; system(ffmpegSentence45.c_str()); //string removeVideoCMD = "rm -rf "+nameOfMainVideo+".ts"; //removo o vídeo exemplo.ts //system(removeVideoCMD.c_str()); this->setMainVideo(nameOfMainVideo+"-45fps.ts"); break; } } } else{ //cout << "\n############################\nConverter fps do vídeo principal com apenas um canal!\n############################\n"); string ffmpegSentence45 = "ffmpeg -i "+this->mainVideo+" -v quiet -y -r 45 -vcodec libx264 " "-sameq -threads "+this->numThreads+" "+nameOfMainVideo+"-45fps.ts"; system(ffmpegSentence45.c_str()); //string removeVideoCMD = "rm -rf "+nameOfMainVideo+".ts"; //removo o vídeo exemplo.ts //system(removeVideoCMD.c_str()); this->setMainVideo(nameOfMainVideo+"-45fps.ts"); } } /* O valor da largura e altura está na unidade de Pixels. * Se o valor da variável for -1, deverá manter a proporção da mesma em relação * à outra. * Ex.: 600:-1 ==> largura é 600 e a altura será calculada em relação à mesma para * manter proporção. * Ex.: -1:600 ==> altura é 600 e a largura será calculada em relação à mesma para * manter proporção. */ void Mixer::setSize(int size){ string ffprobeSentence = "ffprobe -show_streams "+this->mainVideo+" 2> /dev/null | grep \"height=\" | cut -d'=' -f2 > "+temporaryTextFile; system(ffprobeSentence.c_str()); //printf("\n\n%s\n\n",ffprobeSentence.c_str()); string heightStr = "324"; //se não conseguir ler do arquivo a altura será essa.. :( ifstream arq(temporaryTextFile.c_str());//abrindo arquivo com info. dos vídeos if (arq.is_open()){ getline(arq,heightStr); //lendo o tamanho(altura) do vídeo arq.close(); } string removeFileSentence = "rm -rf "+temporaryTextFile; //system(removeFileSentence.c_str()); int height = atoi(heightStr.c_str()); if(size == SMALL){ this->widthSecondaryVideo = -1; this->heightSecondaryVideo = (0.3*height); } else if(size == MEDIUM){ this->widthSecondaryVideo = -1; this->heightSecondaryVideo = (0.4*height); } else if(size == LARGE){ this->widthSecondaryVideo = -1; this->heightSecondaryVideo = (0.5*height); } else{ //se não escolheu nenhum inteiro válido, consideramos MEDIUM_WIDTH a largura padrão, mostra msg de erro this->widthSecondaryVideo = -1; this->heightSecondaryVideo = (0.4*height); cout << "################################################\n"; cout << "# Tamanho do vídeo de libras é inválido! #\n"; cout << "# Assumiremos a largura padrao (Medium_Width)! #\n"; cout << "# OPCOES: 1-Small; 2-Medium; 3-Large; #\n"; cout << "################################################"; } } /*Setters e getters...*/ void Mixer::setMainVideo(string mainVideo){ this->mainVideo = mainVideo; //retira a string .ts da primeira string, adiciona o "temp" antes e o ".txt" depois //string nameOfMainVideo = mainVideo.substr(0,mainVideo.length()-3); int dotPosition = 0; for(int k = mainVideo.length(); k >= 0; k--) { if (mainVideo[k] == '.') { dotPosition = k; break; } } //ajeitar isso depois nameOfMainVideo = mainVideo.substr(0, dotPosition); stringstream ss; ss << uploads; ss >> temporaryTextFile; temporaryTextFile.append("/").append(this->user_id).append("/tamanho.txt"); //printf("##########temporaryTextFile: %s\n", temporaryTextFile.c_str()); } string Mixer::getMainVideo(){ return this->mainVideo; } void Mixer::setSecondaryVideo(string secondaryVideo){ this->secondaryVideo = secondaryVideo; } string Mixer::getSecondaryVideo(){ return this->secondaryVideo; } void Mixer::setPositionSecondaryVideo(int positionSecondaryVideo){ this->positionSecondaryVideo = positionSecondaryVideo; } int Mixer::getPositionSecondaryVideo(){ return this->positionSecondaryVideo; } void Mixer::setTransparency(int transparency){ this->transparency = transparency; } int Mixer::getTransparency(){ return this->transparency; } void Mixer::setNumThreads(string numThreads){ this->numThreads = numThreads; } string Mixer::getNumThreads(){ return this->numThreads; }