-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathVideoCompiler.cpp
More file actions
509 lines (414 loc) · 13.7 KB
/
VideoCompiler.cpp
File metadata and controls
509 lines (414 loc) · 13.7 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
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
#include <iostream>
#include <fstream>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/objdetect.hpp>
#include <opencv2/video/tracking.hpp>
#include <iostream>
#include <math.h>
#include <cmath>
#include <iostream>
#include <filesystem>
#include <vector>
#include <sys\stat.h>
#include "Clip.h"
//Namespaces
using namespace cv;
using namespace std;
void parseInstructions(string filename)
{
ifstream inputFile(filename);
AI AIData;
/// SEARCH FOR KEYWORDS ///
//Parses through text file, finds the word "Pacing," stores the first word after it (the value) in the variable pacing.
string pacing;
string line;
int lineNumber = 0;
while (getline(inputFile, line)) {
lineNumber++;
// Find the position of the word "pacing"
size_t found = line.find("pacing");
// If "pacing" is found, extract the next word
if (found != string::npos) {
istringstream iss(line.substr(found + 6)); // Assuming "pacing" has 6 characters
iss >> pacing;
//Updates the pacing in the AI object
AIData.setPacing(pacing);
pacing = "";
break;
}
}
//Finds and stores "transitions"
string transitions;
lineNumber = 0;
while (getline(inputFile, line)) {
lineNumber++;
// Find the position of the word "pacing"
size_t found = line.find("transitions");
// If "pacing" is found, extract the next word
if (found != string::npos) {
istringstream iss(line.substr(found + 11)); // Assuming "transitions" has 11 characters
iss >> transitions;
//Updates the pacing in the AI object
AIData.setTransitions(transitions);
transitions = "";
break;
}
}
//Finds and stores "color correction"
string color_correction;
lineNumber = 0;
while (getline(inputFile, line)) {
lineNumber++;
// Find the position of the word "pacing"
size_t found = line.find("color correction");
// If "pacing" is found, extract the next word
if (found != string::npos) {
istringstream iss(line.substr(found + 16)); // Assuming "color correction" has 11 characters
iss >> color_correction;
//Updates the pacing in the AI object
AIData.setColorCorrection(color_correction);
color_correction = "";
break;
}
}
//Finds and stores "effects"
string effects;
lineNumber = 0;
while (getline(inputFile, line)) {
lineNumber++;
// Find the position of the word "pacing"
size_t found = line.find("effects");
// If "pacing" is found, extract the next word
if (found != string::npos) {
istringstream iss(line.substr(found + 7)); // Assuming "color correction" has 11 characters
iss >> effects;
//Updates the pacing in the AI object
AIData.setEffects(effects);
effects = "";
break;
}
}
//This parses the text file and stores the neccessary information into the AI object.
}
//Fixes the input path by ensuring it includes an extra backslash.
//In C++, a single backslash "\" is as an escape character, which can lead to path-related issues. This function adds an extra backslash in the path to ensure proper formatting.
string fixDirectory(const string& path)
{
string modified_path = "";
for (char c : path) {
if (c == '\\') {
modified_path += "\\";
}
else {
modified_path += c;
}
}
modified_path += "\\";
return modified_path;
}
//Checks if the given input string represents a valid integer number.
bool isNumber(const string& input) {
try {
stoi(input);
return true;
}
catch (const exception&) {
return false;
}
}
//Checks if a video file with the given name exists at the specified path.
//"name" represents the name of the video file to check.
//"path" represents the directory path where the video file should be located.
//Returns true if the video file exists at the provided path, otherwise returns false.
bool doesFileExist(const string& name, const string& path) {
string new_path = path;
new_path = fixDirectory(new_path); //New path fixes the directory to avoid escape character issues.
string file_location = new_path + name;
ifstream video(new_path + name);
if (video.is_open() == true) //If the video file is found and opened, returns true.
return true;
else
return false;
}
//Parses the text file containing the path and video file names. Returns a vector to store this information.
//"readingFile" is the .txt filename containing the video information.
//Returns a vector containing the data.
vector<string> parse(const string& readingFile)
{
ifstream inputFile(readingFile);
vector<std::string> names;
string line;
int checks = 0;
//Loops through every line in the text file.
while (getline(inputFile, line)) {
if (checks == 0) { //If it's the first line. The firt line contains the path.
string path = fixDirectory(line);
names.push_back(path);
}
else
{
names.push_back(line);
}
checks++;
}
return names;
}
//Function which uses OpenCV to display the clips in succession in a separate window.
//"head" points to the first element in the linked list of Clip objects.
void userDisplay(Clip* head)
{
Clip* display = head;
while (display != NULL)
{
display->Display();
display = display->next;
}
}
//Allows the user to edit the start and end times of video clips.
//"head" pointer to the first clip in the linked list.
//"max_id" is the last element's ID.
void userEdit(Clip* head, int max_id)
{
bool is_editing = true;
while (is_editing == true)
{
string clip_to_edit;
cout << "Enter clip number to edit: ";
cin >> clip_to_edit;
//Check to ensure user enters valid clip number.
if (stoi(clip_to_edit) <= max_id)
{
string new_start;
string new_end;
cout << endl << "<ENTER> to skip" << endl << "Start: ";
cin >> new_start;
cout << "End: ";
cin >> new_end;
//Checks that user entered a valid number
if (new_start.length() > 0 && isNumber(new_start))
{
Clip* update = head;
int clip_selected = stoi(clip_to_edit);
//Traverses through linked list until the clip number is found. Then, data is updated if valid.
while (update->id != clip_selected)
{
update = update->next;
}
if (update->getLength() > stoi(new_start))
update->setStart(stoi(new_start));
else
cout << endl << "Invalid start";
}
if (new_end.length() > 0 && isNumber(new_end))
{
Clip* update = head;
int clip_selected = stoi(clip_to_edit);
while (update->id != clip_selected)
{
update = update->next;
}
if (update->getLength() > stoi(new_end))
update->setEnd(stoi(new_end));
else
cout << endl << "Invalid end";
}
}
else
cout << "Invalid clip";
string option;
std::cout << endl << "Continue? <Y/N>" << endl;
std::cin >> option;
//User input options to continue or exit the editing loop.
if (option == "y" || option == "Y")
is_editing = true;
if (option == "n" || option == "N")
is_editing = false;
else
is_editing = false;
}
}
//Traverses the linked list to add Clips to the VideoWriter. Then, a video file is output in .avi video codec.
//"head" pointer to first clip.
//"output" is the VideoWriter object which will be writing the image sequences.
void userRender(Clip* head, cv::VideoWriter& output)
{
Clip* itr = head;
while (itr != NULL)
{
std::cout << "Rendering clip " << itr->id << "..." << endl;
itr->WriteTo(output);
itr = itr->next;
std::cout << "Finished." << endl;
}
}
int main()
{
//Handles the file names
string filename;
string name_of_file;
//Check for the loop to ensure the user input is valid
bool valid_selection = false;
while (valid_selection == false)
{
string file_choice; //User's choice to either create or use existing .txt file.
string filename; //Name of the file.
/*
* Gives user the option to create a text file containing data for the video editor.
* If user creates <C> the text file, they can add information for a directory and subsequent clip names.
* If user selects an existing <E> text file, they can use an previously created text file stored with video editing data.
* In the text file: First line is the path; all subsequent lines are video file names.
*/
cout << "Create or use existing .txt file? <C/E>" << endl;
cin >> file_choice;
if (file_choice == "C" || file_choice == "c") {
cout << "Enter new file name: " << endl;
cin >> filename;
filename = filename + ".txt";
name_of_file = filename;
ofstream readingFile(filename);
string video_path;
cout << "Enter path to clips: " << endl;
//Ensures that the entire line is added to the video path to avoid spacing issues.
cin.ignore(numeric_limits<streamsize>::max(), '\n');
getline(cin, video_path);
readingFile << video_path;
cout << "Add clip names to project: (Enter <Q> to stop)" << endl;
string clip_name;
cin >> clip_name;
//User can add clips until "q" is pressed.
while (clip_name != "Q" && clip_name != "q")
{
if (doesFileExist(clip_name, video_path) == true) //Makes sure video file exists before adding it to the text file.
readingFile << "\n" + clip_name;
else
{
cout << "Video file not found at path.";
}
cin >> clip_name;
}
valid_selection = true;
}
//Handles when user already has existing file.
else if (file_choice == "E" || file_choice == "e") {
cout << "Enter file name: " << endl;
cin >> filename;
filename = filename + ".txt";
name_of_file = filename;
valid_selection = true;
}
else {
cout << "Invalid selection." << endl;
}
}
cout << endl;
/// USER INPUTS THE PATH TO THE INSTRUCTIONS ///
std::ifstream inputFile("example.txt");
// Check if the file is open
if (!inputFile.is_open()) {
std::cerr << "Error opening the file." << std::endl;
return 1; // Return an error code
}
// Read and print the contents of the file
std::string line;
while (std::getline(inputFile, line)) {
std::cout << line << std::endl;
}
// Close the file
inputFile.close();
//Finds the intstructions file
cout << "Add name of instruction file" << endl;
string instruction_name;
cin >> instruction_name;
string the_instruction_file = instruction_name + ".txt";
std::ifstream inputFile("the_instruction_file");
//Checks if the input file exists in the clips folder
if (doesFileExist(instruction_name, video_path) == true) //Makes sure video file exists before adding it to the text file.
//Initiate the text file parsing instructions
parseInstructions(the_instruction_file);
else
{
cout << "Video file not found at path.";
}
//Creates a file to redirect the console output. OpenCV displays unneccessary information to the console. This is removed for readability.
ofstream file("output.txt");
streambuf* coutBuffer = cout.rdbuf();
cout.rdbuf(file.rdbuf());
//Pointers creates to traverse through linked list of Clip objects. Each Clip object stores data about each video file/clip.
int clip_num = 0;
Clip* clip = nullptr;
Clip* head = nullptr;
//Vector containing video file names and it's path.
vector<string> names = parse(name_of_file);
string path = names[0];
//Loops through the number of video names added into the text file.
if (names.size() > 0)
{
for (int i = 1; i < names.size(); i++) //Starts at 1 to ignore the path name.
{
string video_file = names[i];
Clip* curr = new Clip(video_file, clip_num, path); //Creates Clip object and adds it to the heap for dynamic memory allocation. Linked list is then built.
/// Passes information from AI object into the Clip ///
string color_correction = AI.findColorCorrection();
curr->setColor(color_correction);
if (clip == nullptr)
{
clip = curr;
head = clip;
}
else
{
clip->next = curr;
clip = clip->next;
}
}
}
cout.rdbuf(coutBuffer); //Ends the console output redirection.
ofstream outputFile("junk.txt");
//Pointer to clip object for iteration through the linked list.
Clip* itr = head;
int max_id = 0;
while (itr != NULL)
{
cout << "Processing clip " << itr->id << "..." << endl;
//Rewrites opencv console messages to output file
streambuf* originalOutput = cout.rdbuf();
cout.rdbuf(outputFile.rdbuf());
//Performs the video processing in Clip object and iterates through each clip in the list.
itr->Create();
max_id = itr->id;
itr = itr->next;
cout.rdbuf(originalOutput);
cout << "Finished." << endl;
}
//USER'S CHOICE TO DISPLAY, EDIT OR RENDER
itr = head; //Set back to first position/head of linked list.
string userInput;
cout << endl << "Display, Edit or Render? <D/E/R>" << endl;
cin >> userInput;
while (true)
{
if (userInput == "d" || userInput == "D")
userDisplay(itr);
else if (userInput == "e" || userInput == "E")
userEdit(itr, max_id);
else if (userInput != "r" || userInput != "R")
break;
else
cout << "Invalid selection" << endl;
cout << endl << "Display, Edit or Render? <D/E/R>" << endl;
cin >> userInput;
}
itr = head;
//Uses the OpenCV VideoWriter to write a video file from image sequences in .avi format..
VideoWriter Output("Test.avi", VideoWriter::fourcc('M', 'J', 'P', 'G'), clip->getFPS(), Size(clip->getWidth(), clip->getHeight()));
userRender(itr, Output);
//Deallocates dynamic memory to prevent memory leaks.
while (itr != nullptr) {
Clip* next_clip = itr->next; //Store the next pointer before deleting.
delete itr; //Delete the current Clip object.
itr = next_clip; //Move to the next Clip object.
}
head = nullptr;
}