Mixer.cpp
14.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
/*
* 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");
PRINTL(util::_DEBUG, "Mixer Done!\n");
}
Mixer::Mixer(string mainVideo, string secondaryVideo) {
this->setMainVideo(mainVideo);
this->setSecondaryVideo(secondaryVideo);
this->setNumThreads("1");
PRINTL(util::_DEBUG, "Done!\n");
}
Mixer::~Mixer() {
PRINTL(util::_DEBUG, "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){
PRINTL(util::_INFO, "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");
}
/*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;
}