mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-05 23:40:02 +01:00
309 lines
8.7 KiB
C++
309 lines
8.7 KiB
C++
|
|
#include <stdio.h>
|
|
#include <iostream>
|
|
|
|
// standalone image loader
|
|
#include "stb_image.h"
|
|
|
|
// Opengl
|
|
#include <glad/glad.h>
|
|
#include <glm/glm.hpp>
|
|
#include <glm/gtc/type_ptr.hpp>
|
|
#include <glm/ext/vector_float2.hpp>
|
|
#include <glm/ext/vector_float3.hpp>
|
|
#include <glm/ext/vector_float4.hpp>
|
|
#include <glm/ext/matrix_float4x4.hpp>
|
|
#include <glm/gtc/matrix_access.hpp>
|
|
#include <glm/ext/matrix_transform.hpp>
|
|
|
|
// GStreamer
|
|
#include <gst/gst.h>
|
|
#include <gst/gstbin.h>
|
|
#include <gst/gl/gl.h>
|
|
|
|
// vmix
|
|
#include "defines.h"
|
|
#include "ImageShader.h"
|
|
#include "Settings.h"
|
|
#include "Resource.h"
|
|
#include "FrameBuffer.h"
|
|
#include "RenderingManager.h"
|
|
#include "UserInterfaceManager.h"
|
|
|
|
#include "imgui.h"
|
|
#include "ImGuiToolkit.h"
|
|
#include "GstToolkit.h"
|
|
#include "MediaPlayer.h"
|
|
#include "Scene.h"
|
|
#include "Primitives.h"
|
|
#include "ImGuiVisitor.h"
|
|
#include "SessionVisitor.h"
|
|
|
|
#define PI 3.14159265358979323846
|
|
|
|
// test scene
|
|
|
|
//// ("file:///home/bhbn/Videos/MOV001.MOD");
|
|
//// ("file:///home/bhbn/Videos/TestFormats/Commodore64GameReviewMoondust.flv");
|
|
//// ("file:///home/bhbn/Videos/fish.mp4");
|
|
//// ("file:///home/bhbn/Videos/jean/Solitude1080p.mov");
|
|
//// ("file:///home/bhbn/Videos/TearsOfSteel_720p_h265.mkv");
|
|
//// ("file:///home/bhbn/Videos/TestFormats/_h264GoldenLamps.mkv");
|
|
//// ("file:///home/bhbn/Videos/TestEncoding/vpxvp9high.webm");
|
|
//// ("file:///home/bhbn/Videos/iss.mov");
|
|
//// ("file:///home/bhbn/Videos//iss.mov");
|
|
//// ("file:///Users/Herbelin/Movies/mp2test.mpg");
|
|
///
|
|
Scene scene;
|
|
FrameBuffer *output;
|
|
MediaSurface testnode1("file:///home/bhbn/Videos/iss.mov");
|
|
MediaSurface testnode2("file:///home/bhbn/Videos/fish.mp4");
|
|
ImageSurface testnode3("images/seed_512.jpg");
|
|
|
|
|
|
void drawMediaPlayer()
|
|
{
|
|
static GstClockTime begin = GST_CLOCK_TIME_NONE;
|
|
static GstClockTime end = GST_CLOCK_TIME_NONE;
|
|
|
|
if ( !testnode2.getMediaPlayer() || !testnode2.getMediaPlayer()->isOpen() )
|
|
return;
|
|
|
|
MediaPlayer *mp = testnode2.getMediaPlayer();
|
|
|
|
ImGui::SetNextWindowPos(ImVec2(200, 200), ImGuiCond_FirstUseEver);
|
|
ImGui::SetNextWindowSize(ImVec2(300, 300), ImGuiCond_FirstUseEver);
|
|
ImGui::Begin(IMGUI_TITLE_MEDIAPLAYER);
|
|
float width = ImGui::GetContentRegionAvail().x;
|
|
float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
|
|
|
|
ImVec2 imagesize ( width, width / mp->aspectRatio());
|
|
ImGui::Image((void*)(intptr_t)mp->texture(), imagesize);
|
|
|
|
if (ImGui::Button(ICON_FA_FAST_BACKWARD))
|
|
mp->rewind();
|
|
ImGui::SameLine(0, spacing);
|
|
|
|
// remember playing mode of the GUI
|
|
static bool media_playing_mode = mp->isPlaying();
|
|
|
|
// display buttons Play/Stop depending on current playing mode
|
|
if (media_playing_mode) {
|
|
|
|
if (ImGui::Button(ICON_FA_STOP " Stop"))
|
|
media_playing_mode = false;
|
|
ImGui::SameLine(0, spacing);
|
|
|
|
ImGui::PushButtonRepeat(true);
|
|
if (ImGui::Button(ICON_FA_FORWARD))
|
|
mp->fastForward ();
|
|
ImGui::PopButtonRepeat();
|
|
}
|
|
else {
|
|
|
|
if (ImGui::Button(ICON_FA_PLAY " Play"))
|
|
media_playing_mode = true;
|
|
ImGui::SameLine(0, spacing);
|
|
|
|
ImGui::PushButtonRepeat(true);
|
|
if (ImGui::Button(ICON_FA_STEP_FORWARD))
|
|
mp->seekNextFrame();
|
|
ImGui::PopButtonRepeat();
|
|
}
|
|
|
|
ImGui::SameLine(0, spacing * 2.f);
|
|
ImGui::Dummy(ImVec2(width - 700.0, 0)); // right align
|
|
|
|
static int current_loop = 1;
|
|
static const char* loop_names[3] = { "Stop", "Rewind", "Bounce" };
|
|
const char* current_loop_name = loop_names[current_loop];
|
|
ImGui::SameLine(0, spacing);
|
|
if (current_loop == 0) ImGuiToolkit::Icon(0, 15);
|
|
else if (current_loop == 1) ImGuiToolkit::Icon(1, 15);
|
|
else ImGuiToolkit::Icon(19, 14);
|
|
ImGui::SameLine(0, spacing);
|
|
ImGui::SetNextItemWidth(90);
|
|
if ( ImGui::SliderInt("", ¤t_loop, 0, 2, current_loop_name) )
|
|
mp->setLoop( (MediaPlayer::LoopMode) current_loop );
|
|
|
|
float speed = static_cast<float>(mp->playSpeed());
|
|
ImGui::SameLine(0, spacing);
|
|
ImGui::SetNextItemWidth(270);
|
|
// ImGui::SetNextItemWidth(width - 90.0);
|
|
if (ImGui::SliderFloat( "Speed", &speed, -10.f, 10.f, "x %.1f", 2.f))
|
|
mp->setPlaySpeed( static_cast<double>(speed) );
|
|
ImGui::SameLine(0, spacing);
|
|
if (ImGuiToolkit::ButtonIcon(19, 15)) {
|
|
speed = 1.f;
|
|
mp->setPlaySpeed( static_cast<double>(speed) );
|
|
}
|
|
|
|
guint64 current_t = mp->position();
|
|
guint64 seek_t = current_t;
|
|
|
|
bool slider_pressed = ImGuiToolkit::TimelineSlider( "simpletimeline", &seek_t,
|
|
mp->duration(), mp->frameDuration());
|
|
|
|
// if the seek target time is different from the current position time
|
|
// (i.e. the difference is less than one frame)
|
|
if ( ABS_DIFF (current_t, seek_t) > mp->frameDuration() ) {
|
|
|
|
// request seek (ASYNC)
|
|
mp->seekTo(seek_t);
|
|
}
|
|
|
|
// play/stop command should be following the playing mode (buttons)
|
|
// AND force to stop when the slider is pressed
|
|
bool media_play = media_playing_mode & (!slider_pressed);
|
|
|
|
// apply play action to media only if status should change
|
|
// NB: The seek command performed an ASYNC state change, but
|
|
// gst_element_get_state called in isPlaying() will wait for the state change to complete.
|
|
if ( mp->isPlaying() != media_play ) {
|
|
mp->play( media_play );
|
|
}
|
|
|
|
// display info
|
|
ImGui::Text("%s %d x %d", mp->codec().c_str(), mp->width(), mp->height());
|
|
ImGui::Text("Framerate %.2f / %.2f", mp->updateFrameRate() , mp->frameRate() );
|
|
|
|
ImGui::End();
|
|
}
|
|
|
|
|
|
void drawScene()
|
|
{
|
|
// compute dt
|
|
static gint64 last_time = gst_util_get_timestamp ();
|
|
gint64 current_time = gst_util_get_timestamp ();
|
|
gint64 dt = current_time - last_time;
|
|
last_time = current_time;
|
|
|
|
// recursive update from root of scene
|
|
scene.root_.update( static_cast<float>( GST_TIME_AS_MSECONDS(dt)) * 0.001f );
|
|
|
|
// draw in output frame buffer
|
|
glm::mat4 MV = glm::identity<glm::mat4>();
|
|
glm::mat4 P = glm::scale( glm::ortho(-5.f, 5.f, -5.f, 5.f), glm::vec3(1.f, output->aspectRatio(), 1.f));
|
|
output->begin();
|
|
scene.root_.draw(MV, P);
|
|
output->end();
|
|
|
|
// draw in main view
|
|
scene.root_.draw(MV, Rendering::manager().Projection());
|
|
|
|
// draw GUI tree scene
|
|
ImGui::Begin(IMGUI_TITLE_MAINWINDOW);
|
|
static ImGuiVisitor v;
|
|
scene.accept(v);
|
|
ImGui::End();
|
|
}
|
|
|
|
|
|
void drawPreview()
|
|
{
|
|
if (output)
|
|
{
|
|
ImGui::SetNextWindowPos(ImVec2(100, 300), ImGuiCond_FirstUseEver);
|
|
ImGui::SetNextWindowSize(ImVec2(640, 480), ImGuiCond_FirstUseEver);
|
|
ImGui::Begin(ICON_FA_LAPTOP " Preview");
|
|
float width = ImGui::GetContentRegionAvail().x;
|
|
|
|
ImVec2 imagesize ( width, width / output->aspectRatio());
|
|
ImGui::Image((void*)(intptr_t)output->texture(), imagesize, ImVec2(0.f, 0.f), ImVec2(1.f, -1.f));
|
|
|
|
ImGui::End();
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
int main(int, char**)
|
|
{
|
|
///
|
|
/// Settings
|
|
///
|
|
Settings::Load();
|
|
|
|
///
|
|
/// RENDERING INIT
|
|
///
|
|
if ( !Rendering::manager().Init() )
|
|
return 1;
|
|
|
|
///
|
|
/// UI INIT
|
|
///
|
|
if ( !UserInterface::manager().Init() )
|
|
return 1;
|
|
|
|
///
|
|
/// GStreamer
|
|
///
|
|
#ifndef NDEBUG
|
|
gst_debug_set_default_threshold (GST_LEVEL_WARNING);
|
|
gst_debug_set_active(TRUE);
|
|
#endif
|
|
|
|
// test text editor
|
|
// UserInterface::manager().OpenTextEditor( Resource::getText("shaders/texture-shader.fs") );
|
|
|
|
// init the scene
|
|
Rendering::manager().PushFrontDrawCallback(drawScene);
|
|
|
|
// init elements to the scene
|
|
//testnode3.getShader()->blending = Shader::BLEND_OPACITY;
|
|
|
|
glm::vec3 color( 0.8f, 0.8f, 0.f );
|
|
// LineCircle border(color);
|
|
LineSquare border(color, 2);
|
|
ObjModel shadow("models/square_border.obj");
|
|
|
|
Group g1;
|
|
g1.translation_ = glm::vec3(1.f, 1.f, 0.f);
|
|
g1.scale_ = glm::vec3(1.2f, 1.2f, 1.f);
|
|
|
|
Group g2;
|
|
g2.translation_ = glm::vec3(-1.f, -1.f, 0.f);
|
|
// g2.rotation_ = glm::vec3(0.0f, 0.0f, 1.0f);
|
|
|
|
// build tree
|
|
g1.addChild(&shadow);
|
|
g1.addChild(&testnode3);
|
|
g1.addChild(&border);
|
|
scene.root_.addChild(&g1);
|
|
|
|
g2.addChild(&shadow);
|
|
g2.addChild(&testnode1);
|
|
g2.addChild(&border);
|
|
scene.root_.addChild(&g2);
|
|
|
|
// init output FBO
|
|
output = new FrameBuffer(1280, 720);
|
|
Rendering::manager().PushBackDrawCallback(drawPreview);
|
|
|
|
// add media player
|
|
Rendering::manager().PushBackDrawCallback(drawMediaPlayer);
|
|
|
|
///
|
|
/// Main LOOP
|
|
///
|
|
while ( Rendering::manager().isActive() )
|
|
{
|
|
Rendering::manager().Draw();
|
|
}
|
|
|
|
|
|
SessionVisitor savetoxml;
|
|
scene.accept(savetoxml);
|
|
savetoxml.save("/home/bhbn/test.vmx");
|
|
|
|
UserInterface::manager().Terminate();
|
|
Rendering::manager().Terminate();
|
|
|
|
Settings::Save();
|
|
|
|
return 0;
|
|
}
|