File VideoRecorder.cpp¶
File List > src > utils > VideoRecorder.cpp
Go to the documentation of this file
// #####################################################################
// >>>>>>>>>>>>>>>>>>>>> BEGINNING OF LEGAL NOTICE >>>>>>>>>>>>>>>>>>>>>
//######################################################################
//
// This source file, along with its associated content, was authored by
// Andrea Settimi, Hong-Bin Yang, Naravich Chutisilp, and numerous other
// contributors. The code was originally developed at the Laboratory for
// Timber Construction (IBOIS, director: Prof. Yves Weinand) at the School of
// Architecture, Civil and Environmental Engineering (ENAC) at the Swiss
// Federal Institute of Technology in Lausanne (EPFL) for the Doctoral
// Research "Augmented Carpentry" (PhD researcher: Andrea Settimi,
// co-director: Dr. Julien Gamerro, director: Prof. Yves Weinand).
//
// Although the entire repository is distributed under the GPL license,
// these particular source files may also be used under the terms of the
// MIT license. By accessing or using this file, you agree to the following:
//
// 1. You may reproduce, modify, and distribute this file in accordance
// with the terms of the MIT license.
// 2. You must retain this legal notice in all copies or substantial
// portions of this file.
// 3. This file is provided "AS IS," without any express or implied
// warranties, including but not limited to the implied warranties of
// merchantability and fitness for a particular purpose.
//
// If you cannot or will not comply with the above conditions, you are
// not permitted to use this file. By proceeding, you acknowledge and
// accept all terms and conditions herein.
//
//######################################################################
// <<<<<<<<<<<<<<<<<<<<<<< END OF LEGAL NOTICE <<<<<<<<<<<<<<<<<<<<<<<<
// #####################################################################
#include "VideoRecorder.h"
#include "../AIAC/Application.h"
#include <opencv2/opencv.hpp>
#include <filesystem>
#include "AIAC/LayerUtils.h"
namespace AIAC::Utils {
VideoRecorder::VideoRecorder(const std::string& basePath)
: m_BasePath(basePath)
{ this->UpdatePaths();
this->InitializeDirectories();
}
VideoRecorder::~VideoRecorder() {
this->DeleteFrameFolder();
}
void VideoRecorder::UpdatePaths() {
auto now = std::chrono::system_clock::now();
auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
this->m_RecorderPath = this->m_BasePath + "/recorder";
this->m_FramesPath = this->m_RecorderPath + "/frames_"+ std::to_string(timestamp);
this->m_VideoPath = this->m_RecorderPath + "/video_"+ std::to_string(timestamp);
}
void VideoRecorder::CaptureFrames() {
int width = AIAC_APP.GetWindow()->GetDisplayW();
int height = AIAC_APP.GetWindow()->GetDisplayH();
std::vector<unsigned char> pixels(width * height * 4); // 4 for RGBA
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
if(std::filesystem::exists(this->m_FramesPath)) {
this->SaveFrames(height, width, pixels);
} else {
AIAC_ERROR("Error: {0} does not exist!", this->m_FramesPath);
}
}
void VideoRecorder::SaveFrames(int height, int width, std::vector<unsigned char> pixels) {
cv::Mat image(height, width, CV_8UC4, pixels.data());
cv::flip(image, image, 0);
cv::cvtColor(image, image, cv::COLOR_RGBA2BGR);
auto now = std::chrono::system_clock::now();
auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
std::stringstream filename;
filename << std::setfill('0') << std::setw(13) << timestamp << ".jpg";
cv::imwrite(this->m_FramesPath + "/" + filename.str(), image);
}
void VideoRecorder::MakeVideoFromFrames() {
const std::string framesFolder = this->m_FramesPath;
std::vector<std::string> framePaths;
for (const auto& entry : std::filesystem::directory_iterator(framesFolder)) {
framePaths.push_back(entry.path().string());
}
std::sort(framePaths.begin(), framePaths.end());
const std::string imageListFile = "image_list.txt";
std::ofstream imageList(imageListFile);
for (const std::string& framePath : framePaths) {
imageList << "file '" << framePath << "'\n";
}
imageList.close();
auto now = std::chrono::system_clock::now();
auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
std::stringstream videoname;
videoname << std::setfill('0') << std::setw(13) << timestamp << ".mp4";
const std::string videoPath = this->m_VideoPath + "/" + videoname.str();
std::string ffmpegCommand = "ffmpeg -y -f concat -safe 0 -i " + imageListFile + " -vf \"fps=30\" -c:v libx264 -pix_fmt yuv420p " + videoPath + " 2>/dev/null";
int result = std::system(ffmpegCommand.c_str());
if (result == 0) {
AIAC_INFO("Video saved to: {0}", videoPath);
} else {
AIAC_ERROR("Error: ffmpeg could not create video!");
}
std::remove(imageListFile.c_str());
}
void VideoRecorder::InitializeDirectories(){
for(const auto& path: {this->m_RecorderPath,this->m_FramesPath, this->m_VideoPath}) {
LayerUtils::CreateFolder(path);
}
}
void VideoRecorder::DeleteFrameFolder(){
if (std::filesystem::exists(this->m_FramesPath)) {
std::filesystem::remove_all(this->m_FramesPath);
} else {
AIAC_ERROR("Could not delete {0} folder", this->m_FramesPath);}
}
}