Skip to content
sushidelivery edited this page Oct 19, 2023 · 38 revisions

LayerUtils encompasses a collection of helper functions and tools.

Video Recorder

Video Recorder manages the overall process of the video recording.

OnFrameEnd function gets called at the end of each frame render cycle. If the recording is active (m_Recording flag is true), it captures the frame using the CaptureFrames function from the VideoRecorder utility.

    void LayerUtils::OnFrameEnd() {
        // check if the recording flag is set to true
        if(this->m_Recording){
            // capture the frames
            this->m_VideoRecorder->CaptureFrames();
        }
    }

StartRecording function initiates the video recording process. Sets the m_Recording flag to true, enabling the frame capture in OnFrameEnd. It also gets the save path (either default or UI specified path). Initializes the m_VideoRecorder object with the specified save path. The object then creates the necessary folders.

// create the video recorder object
this->m_VideoRecorder = std::make_unique<AIAC::Utils::VideoRecorder>(savePath);

During screen recording, the utility captures the screen content frame-by-frame using OpenGL to capture the screen's content. It then processes frames using OpenCV and saves each frame as a .jpg file in /frames folder.

From src/utils/VideoRecorder.h:

void VideoRecorder::CaptureFrames();
void VideoRecorder::SaveFrames(int height, int width, std::vector<unsigned char> pixels);

StopRecording function stops the video recording process and initiates the processing of the frames and creates the video. Sets the m_Recording flag to false, stopping the frame capture in OnFrameEnd. Marks the processing flag m_Processing as true for UI (so UI displays the status of the video processing).

    void LayerUtils::StopRecording(){
        AIAC_INFO("Stopped Recording");
        // set the recording flag to false
        this->m_Recording = false;
        // create the video from the frames in a separate thread
        std::thread([this]{
            this->m_Processing = true;
            this->m_VideoRecorder->MakeVideoFromFrames();
            // delete the frames folder and video recorder object
            this->m_VideoRecorder.reset();
            this->m_Processing = false;
        }).detach();
    };

For the video processing, the VideoRecorder utility gathers all saved frames, sorts them, and uses FFmpeg (at a frame rate of 30 fps, and encoded using the libx264 codec) to create a video file, which is then stored in the /video folder.

From src/utils/VideoRecorder.h :

void VideoRecorder::MakeVideoFromFrames();

After the video processing is done, the StopRecording function destroys the m_VideoRecorder object and sets m_Processing to false for the UI.

When m_VideoRecorder object is destroyed it, it also ensures proper cleanup, specifically by deleting the /frames folder to free up resources.

IsProcessing is used to check the state of the video processing and then it uses it to control the start & stop buttons.

Hole and Toolhead Axis Exporter

Hole and Toolhead Axis Exporter designed for exporting coordinates of different toolheads and holes. The exported data is written to a file.

ExportCoordinates() function gathers all the functions in one pipeline, it exports both the toolhead and hole axis coordinates (and other information) and writes them from the internal buffer m_Buffer to a file using WriteBufferToFile().

The ExportToolheadAxis() is responsible for exporting the toolhead information. It first retrieves the active toolhead type from AC_FF_TOOL macro. In this case, the types are DRILLBIT, CIRCULARSAW, CHAINSAW.

    void HoleToolheadAxisExporter::ExportToolheadAxis(){
        ACToolHeadType activeToolheadType = AC_FF_TOOL->GetType();
        if (activeToolheadType == ACToolHeadType::DRILLBIT){
            auto drillBitData = AC_FF_TOOL->GetData<DrillBitData>();
            this->WriteCoordToBuffer("Toolhead", AC_FF_TOOL->GetName(), "ToolbaseGO", drillBitData.ToolbaseGO);
            this->WriteCoordToBuffer("Toolhead", AC_FF_TOOL->GetName(), "TooltipGO", drillBitData.TooltipGO);
        }
...

For different type of toolhead, we are getting different types of GO points. For drillbit, we export drillBitData.ToolbaseGO and drillBitData.TooltipGO. Other GO points that could be retrieved can be found in AIAC/ACInfoToolhead.h

The ExportHoleAxis() is responsible for accessing the hole information.

    void HoleToolheadAxisExporter::ExportHoleAxis(){
        std::string activeHoleType = AC_FF_COMP->GetTypeString();
        if (activeHoleType == "HOLE"){
            TimberInfo::Hole* hole = dynamic_cast<TimberInfo::Hole*>(AC_FF_COMP);
            if (hole) {
                std::string currentComponentID = AIAC_APP.GetLayer<LayerModel>()->GetACInfoModel().GetTimberInfo().GetCurrentComponentID();
                this->WriteCoordToBuffer(activeHoleType, currentComponentID, "StartPoint", hole->GetStartPointGO());
                this->WriteCoordToBuffer(activeHoleType, currentComponentID, "EndPoint", hole->GetEndPointGO());
            }
        }
    }

Again, we are making sure that it is the hole by checking if AC_FF_COMP is pointing to an object of type TimberInfo::Hole. If AC_FF_COMP is indeed an instance of TimberInfo::Hole or is derived from it, the dynamic_cast will succeed, and the resulting value of the cast will be a valid pointer to that object.

TimberInfo::Hole* hole = dynamic_cast<TimberInfo::Hole*>(AC_FF_COMP);

WriteCoordToBuffer is the function that is called in ExportHoleAxis() and ExportToolheadAxis() to write the information and coordinates to buffer m_Buffer. It writes:

        void WriteCoordToBuffer(const std::string& itemType, //its a hole/toolhead
                                std::string itemName, // toolhead/hole current name
                                const std::string& pointType, // GO point type
                                std::shared_ptr<GOPoint> goPoint // shared pointer that has X,Y,Z coordinates);

WriteBufferToFile() function exports the information about toolhead/holes to /temp/coordinates.log file by default. It also writes the current timestamp in the YYYY-MM-DD HH:MM:SS format and creates the line spacing between each batch of the exports.

SetSaveFolderPath manages the save path where the utils should be saved. In UI, it used in void LayerUI::ShowSaveVideoRecorderFileDialog()or it just uses the default path from config.ini

void SetSaveFolderPath(std::string path);

There are also functions that are used in LayerUI.cpp.

Screenshot

The Screenshot class is intended to take the snap of the current window and the camera buffer which is colored.

Window Screenshot Buffer Screenshot

For current window snap, LayerUtils.cpp checks if the m_WindowScreenshot is true, if it is, then OnFrameEnd() calls TakeWindowScreenshot() which receives the path for screenshot saving and begins to capture the current state of the window, in CaptureWindow().

The camera buffer screenshot TakeBufferScreenshot() in LayerUtils.cpp receives the saving path, then it calls CaptureBuffer() that gets the colored camera buffer frame from the GetColorCurrentFrame().

 void Screenshot::CaptureBuffer() {
        cv::Mat currentFrame;
        AIAC_APP.GetLayer<AIAC::LayerCamera>()->MainCamera.GetColorCurrentFrame().GetCvMat().copyTo(currentFrame);

All the screenshots are saved in /temp/screenshots folder by default.

GetSaveFolderPath is used to get the path of the current utils folder, so the VideoRecorder, HoleToolheadAxisExporter and Screenshot could write in this path. It is also used in LayerUI.cpp to display the path for the user.

std::string GetSaveFolderPath(){return m_UtilsPath;};

IsProcessing is used to check the state of the video processing and then it uses it to control the start & stop buttons.

Home

GO system

Layers

Utilities

Clone this wiki locally