mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-13 11:19:58 +01:00
New MediaPlayer image with timeline
Enable playing and seeking into a timeline on a media player that loaded an image. Timeline sets a duration (end) and is saved/loaded. Add a gstreamer imagefreeze element in the pipeline to simulate a playable stream. Distinction must be made between 'isImage' (what was loaded) and 'singleFrame' (what is in the pipeline). GUI is added and customized with menu and dialog.
This commit is contained in:
@@ -204,24 +204,44 @@ void ImGuiToolkit::Icon(int i, int j, bool enabled)
|
|||||||
ImGui::Image((void*)(intptr_t)textureicons, ImVec2(ImGui::GetTextLineHeightWithSpacing(), ImGui::GetTextLineHeightWithSpacing()), uv0, uv1, tint_color);
|
ImGui::Image((void*)(intptr_t)textureicons, ImVec2(ImGui::GetTextLineHeightWithSpacing(), ImGui::GetTextLineHeightWithSpacing()), uv0, uv1, tint_color);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImGuiToolkit::ButtonIcon(int i, int j, const char *tooltip)
|
bool ImGuiToolkit::ButtonIcon(int i, int j, const char *tooltip, bool expanded)
|
||||||
{
|
{
|
||||||
// icons.dds is a 20 x 20 grid of icons
|
|
||||||
if (textureicons == 0)
|
|
||||||
textureicons = Resource::getTextureDDS("images/icons.dds");
|
|
||||||
|
|
||||||
ImVec2 uv0( static_cast<float>(i) * 0.05, static_cast<float>(j) * 0.05 );
|
|
||||||
ImVec2 uv1( uv0.x + 0.05, uv0.y + 0.05 );
|
|
||||||
|
|
||||||
ImGui::PushID( i*20 + j);
|
|
||||||
ImGuiContext& g = *GImGui;
|
ImGuiContext& g = *GImGui;
|
||||||
bool ret = ImGui::ImageButton((void*)(intptr_t)textureicons,
|
bool ret = false;
|
||||||
ImVec2(g.FontSize, g.FontSize),
|
|
||||||
uv0, uv1, g.Style.FramePadding.y);
|
|
||||||
ImGui::PopID();
|
|
||||||
|
|
||||||
if (tooltip != nullptr && ImGui::IsItemHovered())
|
if (expanded) {
|
||||||
ImGuiToolkit::ToolTip(tooltip);
|
// make some space
|
||||||
|
char space_buf[] = " ";
|
||||||
|
const ImVec2 space_size = ImGui::CalcTextSize(" ", NULL);
|
||||||
|
const int space_num = static_cast<int>( ceil(g.FontSize / space_size.x) );
|
||||||
|
space_buf[space_num]='\0';
|
||||||
|
|
||||||
|
char text_buf[256];
|
||||||
|
ImFormatString(text_buf, IM_ARRAYSIZE(text_buf), "%s %s", space_buf, tooltip);
|
||||||
|
|
||||||
|
ImVec2 draw_pos = ImGui::GetCursorScreenPos() + g.Style.FramePadding * 0.5;
|
||||||
|
ret = ImGui::Button(text_buf);
|
||||||
|
|
||||||
|
// overlay of icon on top of first item
|
||||||
|
_drawIcon(draw_pos, i, j);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// icons.dds is a 20 x 20 grid of icons
|
||||||
|
if (textureicons == 0)
|
||||||
|
textureicons = Resource::getTextureDDS("images/icons.dds");
|
||||||
|
|
||||||
|
ImVec2 uv0( static_cast<float>(i) * 0.05, static_cast<float>(j) * 0.05 );
|
||||||
|
ImVec2 uv1( uv0.x + 0.05, uv0.y + 0.05 );
|
||||||
|
|
||||||
|
ImGui::PushID( i*20 + j);
|
||||||
|
ret = ImGui::ImageButton((void*)(intptr_t)textureicons,
|
||||||
|
ImVec2(g.FontSize, g.FontSize),
|
||||||
|
uv0, uv1, g.Style.FramePadding.y);
|
||||||
|
ImGui::PopID();
|
||||||
|
|
||||||
|
if (tooltip != nullptr && ImGui::IsItemHovered())
|
||||||
|
ImGuiToolkit::ToolTip(tooltip);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ namespace ImGuiToolkit
|
|||||||
void ShowIconsWindow(bool* p_open);
|
void ShowIconsWindow(bool* p_open);
|
||||||
|
|
||||||
// buttons and gui items with icon
|
// buttons and gui items with icon
|
||||||
bool ButtonIcon (int i, int j, const char* tooltip = nullptr);
|
bool ButtonIcon (int i, int j, const char* tooltip = nullptr, bool expanded = false);
|
||||||
bool ButtonIconToggle (int i, int j, int i_toggle, int j_toggle, bool* toggle, const char *tooltip = nullptr);
|
bool ButtonIconToggle (int i, int j, int i_toggle, int j_toggle, bool* toggle, const char *tooltip = nullptr);
|
||||||
bool ButtonIconMultistate (std::vector<std::pair<int, int> > icons, int* state, std::vector<std::string> tooltips);
|
bool ButtonIconMultistate (std::vector<std::pair<int, int> > icons, int* state, std::vector<std::string> tooltips);
|
||||||
bool MenuItemIcon (int i, int j, const char* label, const char* shortcut = nullptr, bool selected = false, bool enabled = true);
|
bool MenuItemIcon (int i, int j, const char* label, const char* shortcut = nullptr, bool selected = false, bool enabled = true);
|
||||||
|
|||||||
@@ -98,14 +98,14 @@ void InfoVisitor::visit(MediaPlayer &mp)
|
|||||||
oss << SystemToolkit::filename(mp.filename()) << std::endl;
|
oss << SystemToolkit::filename(mp.filename()) << std::endl;
|
||||||
oss << mp.media().codec_name.substr(0, mp.media().codec_name.find_first_of(" (,")) << ", ";
|
oss << mp.media().codec_name.substr(0, mp.media().codec_name.find_first_of(" (,")) << ", ";
|
||||||
oss << mp.width() << " x " << mp.height();
|
oss << mp.width() << " x " << mp.height();
|
||||||
if (!mp.isImage() && mp.frameRate() > 0.)
|
if (!mp.singleFrame() && mp.frameRate() > 0.)
|
||||||
oss << ", " << std::fixed << std::setprecision(0) << mp.frameRate() << " fps";
|
oss << ", " << std::fixed << std::setprecision(0) << mp.frameRate() << " fps";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
oss << mp.filename() << std::endl;
|
oss << mp.filename() << std::endl;
|
||||||
oss << mp.media().codec_name << std::endl;
|
oss << mp.media().codec_name << std::endl;
|
||||||
oss << mp.width() << " x " << mp.height() ;
|
oss << mp.width() << " x " << mp.height() ;
|
||||||
if (!mp.isImage() && mp.frameRate() > 0.)
|
if (!mp.singleFrame() && mp.frameRate() > 0.)
|
||||||
oss << ", " << std::fixed << std::setprecision(1) << mp.frameRate() << " fps";
|
oss << ", " << std::fixed << std::setprecision(1) << mp.frameRate() << " fps";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -352,6 +352,13 @@ void MediaPlayer::execute_open()
|
|||||||
video_filter_available_ = false;
|
video_filter_available_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// hack to simulate a playable and seekable stream with an image
|
||||||
|
if (media_.isimage && !singleFrame()) {
|
||||||
|
media_.seekable = true;
|
||||||
|
video_filter_ = "imagefreeze";
|
||||||
|
video_filter_available_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Add a filter to playbin if provided
|
// Add a filter to playbin if provided
|
||||||
if ( !video_filter_.empty()) {
|
if ( !video_filter_.empty()) {
|
||||||
// try to create the pipeline element given
|
// try to create the pipeline element given
|
||||||
@@ -403,7 +410,7 @@ void MediaPlayer::execute_open()
|
|||||||
callbacks.new_event = NULL;
|
callbacks.new_event = NULL;
|
||||||
#endif
|
#endif
|
||||||
callbacks.new_preroll = callback_new_preroll;
|
callbacks.new_preroll = callback_new_preroll;
|
||||||
if (media_.isimage) {
|
if (singleFrame()) {
|
||||||
callbacks.eos = NULL;
|
callbacks.eos = NULL;
|
||||||
callbacks.new_sample = NULL;
|
callbacks.new_sample = NULL;
|
||||||
}
|
}
|
||||||
@@ -434,8 +441,8 @@ void MediaPlayer::execute_open()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// in case discoverer failed to get duration
|
// in case discoverer failed to get duration of a video
|
||||||
if (timeline_.end() == GST_CLOCK_TIME_NONE) {
|
if (!media_.isimage && timeline_.end() == GST_CLOCK_TIME_NONE) {
|
||||||
gint64 d = GST_CLOCK_TIME_NONE;
|
gint64 d = GST_CLOCK_TIME_NONE;
|
||||||
if ( gst_element_query_duration(pipeline_, GST_FORMAT_TIME, &d) )
|
if ( gst_element_query_duration(pipeline_, GST_FORMAT_TIME, &d) )
|
||||||
timeline_.setEnd(d);
|
timeline_.setEnd(d);
|
||||||
@@ -445,7 +452,7 @@ void MediaPlayer::execute_open()
|
|||||||
Log::Info("MediaPlayer %s Opened '%s' (%s %d x %d)", std::to_string(id_).c_str(),
|
Log::Info("MediaPlayer %s Opened '%s' (%s %d x %d)", std::to_string(id_).c_str(),
|
||||||
SystemToolkit::filename(uri_).c_str(), media_.codec_name.c_str(), media_.width, media_.height);
|
SystemToolkit::filename(uri_).c_str(), media_.codec_name.c_str(), media_.width, media_.height);
|
||||||
|
|
||||||
if (!isImage())
|
if (!singleFrame())
|
||||||
Log::Info("MediaPlayer %s Timeline [%ld %ld] %ld frames, %d gaps", std::to_string(id_).c_str(),
|
Log::Info("MediaPlayer %s Timeline [%ld %ld] %ld frames, %d gaps", std::to_string(id_).c_str(),
|
||||||
timeline_.begin(), timeline_.end(), timeline_.numFrames(), timeline_.numGaps());
|
timeline_.begin(), timeline_.end(), timeline_.numFrames(), timeline_.numGaps());
|
||||||
|
|
||||||
@@ -506,6 +513,12 @@ void MediaPlayer::execute_open()
|
|||||||
description += std::to_string(media_.framerate_d) + " ! ";
|
description += std::to_string(media_.framerate_d) + " ! ";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// hack to simulate a playable and seekable stream with an image
|
||||||
|
if (media_.isimage && !singleFrame()) {
|
||||||
|
media_.seekable = true;
|
||||||
|
description += "imagefreeze ! ";
|
||||||
|
}
|
||||||
|
|
||||||
// set app sink
|
// set app sink
|
||||||
description += "queue ! appsink name=sink";
|
description += "queue ! appsink name=sink";
|
||||||
|
|
||||||
@@ -563,7 +576,7 @@ void MediaPlayer::execute_open()
|
|||||||
callbacks.new_event = NULL;
|
callbacks.new_event = NULL;
|
||||||
#endif
|
#endif
|
||||||
callbacks.new_preroll = callback_new_preroll;
|
callbacks.new_preroll = callback_new_preroll;
|
||||||
if (media_.isimage) {
|
if (singleFrame()) {
|
||||||
callbacks.eos = NULL;
|
callbacks.eos = NULL;
|
||||||
callbacks.new_sample = NULL;
|
callbacks.new_sample = NULL;
|
||||||
}
|
}
|
||||||
@@ -591,8 +604,8 @@ void MediaPlayer::execute_open()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// in case discoverer failed to get duration
|
// in case discoverer failed to get duration of a video
|
||||||
if (timeline_.end() == GST_CLOCK_TIME_NONE) {
|
if (!media_.isimage && timeline_.end() == GST_CLOCK_TIME_NONE) {
|
||||||
gint64 d = GST_CLOCK_TIME_NONE;
|
gint64 d = GST_CLOCK_TIME_NONE;
|
||||||
if ( gst_element_query_duration(pipeline_, GST_FORMAT_TIME, &d) )
|
if ( gst_element_query_duration(pipeline_, GST_FORMAT_TIME, &d) )
|
||||||
timeline_.setEnd(d);
|
timeline_.setEnd(d);
|
||||||
@@ -602,7 +615,7 @@ void MediaPlayer::execute_open()
|
|||||||
Log::Info("MediaPlayer %s Opened '%s' (%s %d x %d)", std::to_string(id_).c_str(),
|
Log::Info("MediaPlayer %s Opened '%s' (%s %d x %d)", std::to_string(id_).c_str(),
|
||||||
SystemToolkit::filename(uri_).c_str(), media_.codec_name.c_str(), media_.width, media_.height);
|
SystemToolkit::filename(uri_).c_str(), media_.codec_name.c_str(), media_.width, media_.height);
|
||||||
|
|
||||||
if (!isImage())
|
if (!singleFrame())
|
||||||
Log::Info("MediaPlayer %s Timeline [%ld %ld] %ld frames, %d gaps", std::to_string(id_).c_str(),
|
Log::Info("MediaPlayer %s Timeline [%ld %ld] %ld frames, %d gaps", std::to_string(id_).c_str(),
|
||||||
timeline_.begin(), timeline_.end(), timeline_.numFrames(), timeline_.numGaps());
|
timeline_.begin(), timeline_.end(), timeline_.numFrames(), timeline_.numGaps());
|
||||||
|
|
||||||
@@ -783,6 +796,11 @@ bool MediaPlayer::isImage() const
|
|||||||
return media_.isimage;
|
return media_.isimage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MediaPlayer::singleFrame() const
|
||||||
|
{
|
||||||
|
return timeline_.end() == GST_CLOCK_TIME_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
std::string MediaPlayer::decoderName()
|
std::string MediaPlayer::decoderName()
|
||||||
{
|
{
|
||||||
if (decoder_name_.empty()) {
|
if (decoder_name_.empty()) {
|
||||||
@@ -856,8 +874,8 @@ void MediaPlayer::execute_play_command(bool on)
|
|||||||
|
|
||||||
void MediaPlayer::play(bool on)
|
void MediaPlayer::play(bool on)
|
||||||
{
|
{
|
||||||
// ignore if disabled, and cannot play an image
|
// ignore if disabled, and cannot play a single frame
|
||||||
if (!enabled_ || media_.isimage || pending_)
|
if (!enabled_ || pending_ || singleFrame())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Metronome
|
// Metronome
|
||||||
@@ -881,7 +899,7 @@ void MediaPlayer::play(bool on)
|
|||||||
bool MediaPlayer::isPlaying(bool testpipeline) const
|
bool MediaPlayer::isPlaying(bool testpipeline) const
|
||||||
{
|
{
|
||||||
// image cannot play
|
// image cannot play
|
||||||
if (media_.isimage)
|
if (singleFrame())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// if not ready yet, answer with requested state
|
// if not ready yet, answer with requested state
|
||||||
@@ -1032,7 +1050,7 @@ void MediaPlayer::init_texture(guint index)
|
|||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
|
||||||
if (!media_.isimage) {
|
if ( !singleFrame() ) {
|
||||||
|
|
||||||
// set pbo image size
|
// set pbo image size
|
||||||
pbo_size_ = media_.height * media_.width * 4;
|
pbo_size_ = media_.height * media_.width * 4;
|
||||||
@@ -1146,9 +1164,10 @@ void MediaPlayer::update()
|
|||||||
if (media_.valid) {
|
if (media_.valid) {
|
||||||
if (!media_.log.empty())
|
if (!media_.log.empty())
|
||||||
Log::Info("'%s' : %s", uri().c_str(), media_.log.c_str());
|
Log::Info("'%s' : %s", uri().c_str(), media_.log.c_str());
|
||||||
|
if (!media_.isimage) {
|
||||||
timeline_.setEnd( media_.end );
|
timeline_.setEnd( media_.end );
|
||||||
timeline_.setStep( media_.dt );
|
timeline_.setStep( media_.dt );
|
||||||
|
}
|
||||||
execute_open();
|
execute_open();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -1163,7 +1182,7 @@ void MediaPlayer::update()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// prevent unnecessary updates: disabled or already filled image
|
// prevent unnecessary updates: disabled or already filled image
|
||||||
if ( (!enabled_ && !force_update_) || (media_.isimage && textureindex_>0 ) )
|
if ( (!enabled_ && !force_update_) || (singleFrame() && textureindex_>0 ) )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// local variables before trying to update
|
// local variables before trying to update
|
||||||
@@ -1222,10 +1241,15 @@ void MediaPlayer::update()
|
|||||||
// do NOT do another seek yet
|
// do NOT do another seek yet
|
||||||
}
|
}
|
||||||
// otherwise check for need to seek (pipeline management)
|
// otherwise check for need to seek (pipeline management)
|
||||||
else {
|
else if (position_ != GST_CLOCK_TIME_NONE) {
|
||||||
// manage timeline: test if position falls into a gap
|
// manage timeline:
|
||||||
TimeInterval gap;
|
TimeInterval gap;
|
||||||
if (position_ != GST_CLOCK_TIME_NONE && timeline_.getGapAt(position_, gap)) {
|
// ensure we remain within the begin to end range
|
||||||
|
if (position_ > timeline_.last() || position_ < timeline_.first()) {
|
||||||
|
need_loop = true;
|
||||||
|
}
|
||||||
|
// test if position falls into a gap
|
||||||
|
else if (timeline_.getGapAt(position_, gap)) {
|
||||||
// if in a gap, seek to next section
|
// if in a gap, seek to next section
|
||||||
if (gap.is_valid()) {
|
if (gap.is_valid()) {
|
||||||
// jump in one or the other direction
|
// jump in one or the other direction
|
||||||
@@ -1339,7 +1363,7 @@ void MediaPlayer::setPlaySpeed(double s)
|
|||||||
rate_ = SIGN(rate_) * MIN_PLAY_SPEED;
|
rate_ = SIGN(rate_) * MIN_PLAY_SPEED;
|
||||||
|
|
||||||
// discard if too early or not possible
|
// discard if too early or not possible
|
||||||
if (media_.isimage || !media_.seekable || pipeline_ == nullptr)
|
if (pipeline_ == nullptr || !media_.seekable)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -1352,7 +1376,7 @@ void MediaPlayer::setPlaySpeed(double s)
|
|||||||
// are GST_CLOCK_TIME_NONE, the playback direction does not change
|
// are GST_CLOCK_TIME_NONE, the playback direction does not change
|
||||||
// and the seek is not flushing. (Since: 1.18)
|
// and the seek is not flushing. (Since: 1.18)
|
||||||
// if all conditions to use GST_SEEK_FLAG_INSTANT_RATE_CHANGE are met
|
// if all conditions to use GST_SEEK_FLAG_INSTANT_RATE_CHANGE are met
|
||||||
if ( rate_change_ == RATE_CHANGE_INSTANT && !change_direction ) {
|
if ( rate_change_ == RATE_CHANGE_INSTANT && !change_direction && !media_.isimage) {
|
||||||
|
|
||||||
int seek_flags = GST_SEEK_FLAG_INSTANT_RATE_CHANGE;
|
int seek_flags = GST_SEEK_FLAG_INSTANT_RATE_CHANGE;
|
||||||
seek_flags |= GST_SEEK_FLAG_TRICKMODE;
|
seek_flags |= GST_SEEK_FLAG_TRICKMODE;
|
||||||
|
|||||||
@@ -118,7 +118,11 @@ public:
|
|||||||
/**
|
/**
|
||||||
* True if its an image
|
* True if its an image
|
||||||
* */
|
* */
|
||||||
bool isImage() const;
|
bool isImage() const;
|
||||||
|
/**
|
||||||
|
* True if it has only one frame
|
||||||
|
* */
|
||||||
|
bool singleFrame() const;
|
||||||
/**
|
/**
|
||||||
* Pause / Play
|
* Pause / Play
|
||||||
* Can play backward if play speed is negative
|
* Can play backward if play speed is negative
|
||||||
@@ -269,8 +273,10 @@ public:
|
|||||||
*/
|
*/
|
||||||
static std::list<MediaPlayer*> registered() { return registered_; }
|
static std::list<MediaPlayer*> registered() { return registered_; }
|
||||||
static std::list<MediaPlayer*>::const_iterator begin() { return registered_.cbegin(); }
|
static std::list<MediaPlayer*>::const_iterator begin() { return registered_.cbegin(); }
|
||||||
static std::list<MediaPlayer*>::const_iterator end() { return registered_.cend(); }
|
static std::list<MediaPlayer*>::const_iterator end() { return registered_.cend(); }
|
||||||
|
/**
|
||||||
|
* Discoverer to check uri and get media info
|
||||||
|
* */
|
||||||
static MediaInfo UriDiscoverer(const std::string &uri);
|
static MediaInfo UriDiscoverer(const std::string &uri);
|
||||||
std::string log() const { return media_.log; }
|
std::string log() const { return media_.log; }
|
||||||
|
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ void MediaSource::play (bool on)
|
|||||||
|
|
||||||
bool MediaSource::playable () const
|
bool MediaSource::playable () const
|
||||||
{
|
{
|
||||||
return !mediaplayer_->isImage();
|
return !mediaplayer_->singleFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaSource::replay ()
|
void MediaSource::replay ()
|
||||||
|
|||||||
@@ -851,7 +851,21 @@ void SessionLoader::visit(MediaPlayer &n)
|
|||||||
XMLElement *timelineelement = mediaplayerNode->FirstChildElement("Timeline");
|
XMLElement *timelineelement = mediaplayerNode->FirstChildElement("Timeline");
|
||||||
if (timelineelement) {
|
if (timelineelement) {
|
||||||
Timeline tl;
|
Timeline tl;
|
||||||
tl.setTiming( n.timeline()->interval(), n.timeline()->step());
|
|
||||||
|
TimeInterval interval_(n.timeline()->interval());
|
||||||
|
if (interval_.is_valid())
|
||||||
|
tl.setTiming( interval_, n.timeline()->step());
|
||||||
|
else {
|
||||||
|
GstClockTime b = GST_CLOCK_TIME_NONE;
|
||||||
|
GstClockTime e = GST_CLOCK_TIME_NONE;
|
||||||
|
GstClockTime s = GST_CLOCK_TIME_NONE;
|
||||||
|
timelineelement->QueryUnsigned64Attribute("begin", &b);
|
||||||
|
timelineelement->QueryUnsigned64Attribute("end", &e);
|
||||||
|
timelineelement->QueryUnsigned64Attribute("step", &s);
|
||||||
|
interval_ = TimeInterval(b,e);
|
||||||
|
tl.setTiming( interval_, s);
|
||||||
|
}
|
||||||
|
|
||||||
XMLElement *gapselement = timelineelement->FirstChildElement("Gaps");
|
XMLElement *gapselement = timelineelement->FirstChildElement("Gaps");
|
||||||
if (gapselement) {
|
if (gapselement) {
|
||||||
XMLElement* gap = gapselement->FirstChildElement("Interval");
|
XMLElement* gap = gapselement->FirstChildElement("Interval");
|
||||||
|
|||||||
@@ -410,7 +410,7 @@ void SessionVisitor::visit(MediaPlayer &n)
|
|||||||
XMLElement *newelement = xmlDoc_->NewElement("MediaPlayer");
|
XMLElement *newelement = xmlDoc_->NewElement("MediaPlayer");
|
||||||
newelement->SetAttribute("id", n.id());
|
newelement->SetAttribute("id", n.id());
|
||||||
|
|
||||||
if (!n.isImage()) {
|
if (!n.singleFrame()) {
|
||||||
newelement->SetAttribute("play", n.isPlaying());
|
newelement->SetAttribute("play", n.isPlaying());
|
||||||
newelement->SetAttribute("loop", (int) n.loop());
|
newelement->SetAttribute("loop", (int) n.loop());
|
||||||
newelement->SetAttribute("speed", n.playSpeed());
|
newelement->SetAttribute("speed", n.playSpeed());
|
||||||
@@ -421,6 +421,9 @@ void SessionVisitor::visit(MediaPlayer &n)
|
|||||||
|
|
||||||
// timeline
|
// timeline
|
||||||
XMLElement *timelineelement = xmlDoc_->NewElement("Timeline");
|
XMLElement *timelineelement = xmlDoc_->NewElement("Timeline");
|
||||||
|
timelineelement->SetAttribute("begin", n.timeline()->begin());
|
||||||
|
timelineelement->SetAttribute("end", n.timeline()->end());
|
||||||
|
timelineelement->SetAttribute("step", n.timeline()->step());
|
||||||
|
|
||||||
// gaps in timeline
|
// gaps in timeline
|
||||||
XMLElement *gapselement = xmlDoc_->NewElement("Gaps");
|
XMLElement *gapselement = xmlDoc_->NewElement("Gaps");
|
||||||
|
|||||||
@@ -573,7 +573,7 @@ void PlayFastForward::update(Source *s, float dt)
|
|||||||
if (ms != nullptr) {
|
if (ms != nullptr) {
|
||||||
MediaPlayer *mp = ms->mediaplayer();
|
MediaPlayer *mp = ms->mediaplayer();
|
||||||
// works only if media player is enabled and valid
|
// works only if media player is enabled and valid
|
||||||
if (mp && mp->isEnabled() && !mp->isImage()) {
|
if (mp && mp->isEnabled() && !mp->singleFrame()) {
|
||||||
media_ = mp;
|
media_ = mp;
|
||||||
playspeed_ = media_->playSpeed();
|
playspeed_ = media_->playSpeed();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -372,61 +372,85 @@ void SourceControlWindow::Render()
|
|||||||
//
|
//
|
||||||
// Menu for video Mediaplayer control
|
// Menu for video Mediaplayer control
|
||||||
//
|
//
|
||||||
if (ImGui::BeginMenu(ICON_FA_FILM " Video", mediaplayer_active_) )
|
if (ImGui::BeginMenu(ICON_FA_PHOTO_VIDEO " Media", mediaplayer_active_) )
|
||||||
{
|
{
|
||||||
if (ImGui::MenuItem( ICON_FA_REDO_ALT " Reload" ))
|
if ( !mediaplayer_active_->singleFrame() ) {
|
||||||
mediaplayer_active_->reopen();
|
if (ImGui::MenuItem( ICON_FA_REDO_ALT " Reload" ))
|
||||||
if (ImGuiToolkit::MenuItemIcon(16, 16, "Gstreamer effect", nullptr,
|
mediaplayer_active_->reopen();
|
||||||
false, mediaplayer_active_->videoEffectAvailable()) )
|
if (ImGuiToolkit::MenuItemIcon(16, 16, "Gstreamer effect", nullptr,
|
||||||
mediaplayer_edit_pipeline_ = true;
|
false, mediaplayer_active_->videoEffectAvailable()) )
|
||||||
if (ImGui::BeginMenu(ICON_FA_SNOWFLAKE " On deactivation"))
|
mediaplayer_edit_pipeline_ = true;
|
||||||
{
|
if (ImGui::BeginMenu(ICON_FA_MICROCHIP " Hardware decoding"))
|
||||||
bool option = !mediaplayer_active_->rewindOnDisabled();
|
{
|
||||||
if (ImGui::MenuItem(ICON_FA_STOP " Stop", NULL, &option ))
|
bool hwdec = !mediaplayer_active_->softwareDecodingForced();
|
||||||
mediaplayer_active_->setRewindOnDisabled(false);
|
if (ImGui::MenuItem("Auto", "", &hwdec ))
|
||||||
option = mediaplayer_active_->rewindOnDisabled();
|
mediaplayer_active_->setSoftwareDecodingForced(false);
|
||||||
if (ImGui::MenuItem(ICON_FA_FAST_BACKWARD " Rewind & Stop", NULL, &option ))
|
hwdec = mediaplayer_active_->softwareDecodingForced();
|
||||||
mediaplayer_active_->setRewindOnDisabled(true);
|
if (ImGui::MenuItem("Disabled", "", &hwdec ))
|
||||||
ImGui::EndMenu();
|
mediaplayer_active_->setSoftwareDecodingForced(true);
|
||||||
}
|
ImGui::EndMenu();
|
||||||
if (ImGui::BeginMenu(ICON_FA_MICROCHIP " Hardware decoding"))
|
}
|
||||||
{
|
if (ImGui::BeginMenu(ICON_FA_SNOWFLAKE " On deactivation"))
|
||||||
bool hwdec = !mediaplayer_active_->softwareDecodingForced();
|
{
|
||||||
if (ImGui::MenuItem("Auto", "", &hwdec ))
|
bool option = !mediaplayer_active_->rewindOnDisabled();
|
||||||
mediaplayer_active_->setSoftwareDecodingForced(false);
|
if (ImGui::MenuItem(ICON_FA_STOP " Stop", NULL, &option ))
|
||||||
hwdec = mediaplayer_active_->softwareDecodingForced();
|
mediaplayer_active_->setRewindOnDisabled(false);
|
||||||
if (ImGui::MenuItem("Disabled", "", &hwdec ))
|
option = mediaplayer_active_->rewindOnDisabled();
|
||||||
mediaplayer_active_->setSoftwareDecodingForced(true);
|
if (ImGui::MenuItem(ICON_FA_FAST_BACKWARD " Rewind & Stop", NULL, &option ))
|
||||||
ImGui::EndMenu();
|
mediaplayer_active_->setRewindOnDisabled(true);
|
||||||
}
|
ImGui::EndMenu();
|
||||||
ImGui::Separator();
|
}
|
||||||
ImGui::TextDisabled("Timeline");
|
ImGui::Separator();
|
||||||
if (ImGui::MenuItem(ICON_FA_WINDOW_CLOSE " Reset")){
|
ImGui::TextDisabled("Timeline");
|
||||||
mediaplayer_timeline_zoom_ = 1.f;
|
|
||||||
mediaplayer_active_->timeline()->clearFading();
|
|
||||||
mediaplayer_active_->timeline()->clearGaps();
|
|
||||||
std::ostringstream oss;
|
|
||||||
oss << SystemToolkit::base_filename( mediaplayer_active_->filename() );
|
|
||||||
oss << ": Reset timeline";
|
|
||||||
Action::manager().store(oss.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::MenuItem(LABEL_EDIT_FADING))
|
if ( mediaplayer_active_->isImage()) {
|
||||||
mediaplayer_edit_fading_ = true;
|
if ( ImGuiToolkit::MenuItemIcon(1, 14, "Remove")){
|
||||||
|
// set empty timeline
|
||||||
|
Timeline tl;
|
||||||
|
mediaplayer_active_->setTimeline(tl);
|
||||||
|
mediaplayer_active_->play(false);
|
||||||
|
// re-open the image with NO timeline
|
||||||
|
mediaplayer_active_->reopen();
|
||||||
|
mediaplayer_active_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ImGui::MenuItem(ICON_FA_HOURGLASS_HALF " Duration")){
|
||||||
|
mediaplayer_set_duration_ = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::MenuItem(ICON_FA_WINDOW_CLOSE " Reset")){
|
||||||
|
mediaplayer_timeline_zoom_ = 1.f;
|
||||||
|
mediaplayer_active_->timeline()->clearFading();
|
||||||
|
mediaplayer_active_->timeline()->clearGaps();
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << SystemToolkit::base_filename( mediaplayer_active_->filename() );
|
||||||
|
oss << ": Reset timeline";
|
||||||
|
Action::manager().store(oss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::MenuItem(LABEL_EDIT_FADING))
|
||||||
|
mediaplayer_edit_fading_ = true;
|
||||||
|
|
||||||
|
if (ImGui::BeginMenu(ICON_FA_CLOCK " Metronome"))
|
||||||
|
{
|
||||||
|
Metronome::Synchronicity sync = mediaplayer_active_->syncToMetronome();
|
||||||
|
bool active = sync == Metronome::SYNC_NONE;
|
||||||
|
if (ImGuiToolkit::MenuItemIcon(5, 13, " Not synchronized", NULL, active ))
|
||||||
|
mediaplayer_active_->setSyncToMetronome(Metronome::SYNC_NONE);
|
||||||
|
active = sync == Metronome::SYNC_BEAT;
|
||||||
|
if (ImGuiToolkit::MenuItemIcon(6, 13, " Sync to beat", NULL, active ))
|
||||||
|
mediaplayer_active_->setSyncToMetronome(Metronome::SYNC_BEAT);
|
||||||
|
active = sync == Metronome::SYNC_PHASE;
|
||||||
|
if (ImGuiToolkit::MenuItemIcon(7, 13, " Sync to phase", NULL, active ))
|
||||||
|
mediaplayer_active_->setSyncToMetronome(Metronome::SYNC_PHASE);
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (ImGui::MenuItem( ICON_FA_REDO_ALT " Reload" ))
|
||||||
|
mediaplayer_active_->reopen();
|
||||||
|
|
||||||
if (ImGui::BeginMenu(ICON_FA_CLOCK " Metronome"))
|
|
||||||
{
|
|
||||||
Metronome::Synchronicity sync = mediaplayer_active_->syncToMetronome();
|
|
||||||
bool active = sync == Metronome::SYNC_NONE;
|
|
||||||
if (ImGuiToolkit::MenuItemIcon(5, 13, " Not synchronized", NULL, active ))
|
|
||||||
mediaplayer_active_->setSyncToMetronome(Metronome::SYNC_NONE);
|
|
||||||
active = sync == Metronome::SYNC_BEAT;
|
|
||||||
if (ImGuiToolkit::MenuItemIcon(6, 13, " Sync to beat", NULL, active ))
|
|
||||||
mediaplayer_active_->setSyncToMetronome(Metronome::SYNC_BEAT);
|
|
||||||
active = sync == Metronome::SYNC_PHASE;
|
|
||||||
if (ImGuiToolkit::MenuItemIcon(7, 13, " Sync to phase", NULL, active ))
|
|
||||||
mediaplayer_active_->setSyncToMetronome(Metronome::SYNC_PHASE);
|
|
||||||
ImGui::EndMenu();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
@@ -640,7 +664,7 @@ void SourceControlWindow::RenderSelection(size_t i)
|
|||||||
for (auto source = selection_.begin(); source != selection_.end(); ++source) {
|
for (auto source = selection_.begin(); source != selection_.end(); ++source) {
|
||||||
// collect durations of all media sources
|
// collect durations of all media sources
|
||||||
MediaSource *ms = dynamic_cast<MediaSource *>(*source);
|
MediaSource *ms = dynamic_cast<MediaSource *>(*source);
|
||||||
if (ms != nullptr && !ms->mediaplayer()->isImage())
|
if (ms != nullptr && !ms->mediaplayer()->singleFrame())
|
||||||
durations.push_back(static_cast<guint64>(static_cast<double>(ms->mediaplayer()->timeline()->sectionsDuration()) / fabs(ms->mediaplayer()->playSpeed())));
|
durations.push_back(static_cast<guint64>(static_cast<double>(ms->mediaplayer()->timeline()->sectionsDuration()) / fabs(ms->mediaplayer()->playSpeed())));
|
||||||
// compute the displayed width of frames of this source, and keep the max to align afterwards
|
// compute the displayed width of frames of this source, and keep the max to align afterwards
|
||||||
float w = 1.5f * timeline_height_ * (*source)->frame()->aspectRatio();
|
float w = 1.5f * timeline_height_ * (*source)->frame()->aspectRatio();
|
||||||
@@ -677,7 +701,7 @@ void SourceControlWindow::RenderSelection(size_t i)
|
|||||||
|
|
||||||
// get media source
|
// get media source
|
||||||
MediaSource *ms = dynamic_cast<MediaSource *>(*source);
|
MediaSource *ms = dynamic_cast<MediaSource *>(*source);
|
||||||
if (ms == nullptr || ms->mediaplayer()->isImage()) {
|
if (ms == nullptr || ms->mediaplayer()->singleFrame()) {
|
||||||
// leave the source in the list and continue
|
// leave the source in the list and continue
|
||||||
++source;
|
++source;
|
||||||
continue;
|
continue;
|
||||||
@@ -1284,7 +1308,7 @@ void SourceControlWindow::RenderSelectedSources()
|
|||||||
std::string label(ICON_FA_PLUS_CIRCLE);
|
std::string label(ICON_FA_PLUS_CIRCLE);
|
||||||
if (space > buttons_width_) { // enough space to show full button with label text
|
if (space > buttons_width_) { // enough space to show full button with label text
|
||||||
label += LABEL_STORE_SELECTION;
|
label += LABEL_STORE_SELECTION;
|
||||||
width = buttons_width_;
|
width = buttons_width_ - ImGui::GetTextLineHeightWithSpacing();
|
||||||
}
|
}
|
||||||
ImGui::SameLine(0, space -width);
|
ImGui::SameLine(0, space -width);
|
||||||
ImGui::SetNextItemWidth(width);
|
ImGui::SetNextItemWidth(width);
|
||||||
@@ -1385,6 +1409,47 @@ void SourceControlWindow::RenderSingleSource(Source *s)
|
|||||||
/// Play button bar
|
/// Play button bar
|
||||||
///
|
///
|
||||||
DrawButtonBar(bottom, rendersize.x);
|
DrawButtonBar(bottom, rendersize.x);
|
||||||
|
|
||||||
|
// If possibly a media source, but is not playable
|
||||||
|
// then offer to make it playable by adding a timeline
|
||||||
|
if ( ms != nullptr )
|
||||||
|
{
|
||||||
|
if (ms->mediaplayer()->isImage()) {
|
||||||
|
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.00f, 0.00f, 0.00f, 0.00f));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.14f, 0.14f, 0.14f, 0.5f));
|
||||||
|
|
||||||
|
float space = ImGui::GetContentRegionAvail().x;
|
||||||
|
float width = buttons_height_ ;
|
||||||
|
if (space > buttons_width_)
|
||||||
|
width = buttons_width_ - ImGui::GetTextLineHeightWithSpacing();
|
||||||
|
ImGui::SameLine(0, space -width);
|
||||||
|
ImGui::SetNextItemWidth(width);
|
||||||
|
if (ImGuiToolkit::ButtonIcon( 0, 14, LABEL_ADD_TIMELINE, space > buttons_width_ )) {
|
||||||
|
|
||||||
|
// activate mediaplayer
|
||||||
|
mediaplayer_active_ = ms->mediaplayer();
|
||||||
|
|
||||||
|
// set timeline to default 1 second
|
||||||
|
Timeline tl;
|
||||||
|
TimeInterval interval(0, GST_SECOND);
|
||||||
|
// set fixed framerate to 25 FPS
|
||||||
|
tl.setTiming( interval, 40 * GST_MSECOND);
|
||||||
|
mediaplayer_active_->setTimeline(tl);
|
||||||
|
|
||||||
|
// set to play
|
||||||
|
mediaplayer_active_->play(true);
|
||||||
|
|
||||||
|
// re-open the image with a timeline
|
||||||
|
mediaplayer_active_->reopen();
|
||||||
|
|
||||||
|
// open dialog to set duration
|
||||||
|
mediaplayer_set_duration_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PopStyleColor(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1746,6 +1811,9 @@ void SourceControlWindow::RenderMediaPlayer(MediaSource *ms)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Dialog to edit timeline fade in and out
|
||||||
|
///
|
||||||
if (mediaplayer_edit_fading_) {
|
if (mediaplayer_edit_fading_) {
|
||||||
ImGui::OpenPopup(LABEL_EDIT_FADING);
|
ImGui::OpenPopup(LABEL_EDIT_FADING);
|
||||||
mediaplayer_edit_fading_ = false;
|
mediaplayer_edit_fading_ = false;
|
||||||
@@ -1824,11 +1892,14 @@ void SourceControlWindow::RenderMediaPlayer(MediaSource *ms)
|
|||||||
ImGui::EndPopup();
|
ImGui::EndPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Dialog to set gstreamer video effect
|
||||||
|
///
|
||||||
static std::string _effect_description = "";
|
static std::string _effect_description = "";
|
||||||
static bool _effect_description_changed = false;
|
static bool _effect_description_changed = false;
|
||||||
if (mediaplayer_edit_pipeline_) {
|
if (mediaplayer_edit_pipeline_) {
|
||||||
// open dialog
|
// open dialog
|
||||||
ImGui::OpenPopup("Gstreamer Video effect");
|
ImGui::OpenPopup(DIALOG_GST_EFFECT);
|
||||||
mediaplayer_edit_pipeline_ = false;
|
mediaplayer_edit_pipeline_ = false;
|
||||||
// initialize dialog
|
// initialize dialog
|
||||||
_effect_description = mediaplayer_active_->videoEffect();
|
_effect_description = mediaplayer_active_->videoEffect();
|
||||||
@@ -1838,7 +1909,7 @@ void SourceControlWindow::RenderMediaPlayer(MediaSource *ms)
|
|||||||
ImGui::SetNextWindowSize(mpp_dialog_size, ImGuiCond_Always);
|
ImGui::SetNextWindowSize(mpp_dialog_size, ImGuiCond_Always);
|
||||||
const ImVec2 mpp_dialog_pos = top + rendersize * 0.5f - mpp_dialog_size * 0.5f;
|
const ImVec2 mpp_dialog_pos = top + rendersize * 0.5f - mpp_dialog_size * 0.5f;
|
||||||
ImGui::SetNextWindowPos(mpp_dialog_pos, ImGuiCond_Always);
|
ImGui::SetNextWindowPos(mpp_dialog_pos, ImGuiCond_Always);
|
||||||
if (ImGui::BeginPopupModal("Gstreamer Video effect", NULL, ImGuiWindowFlags_NoResize))
|
if (ImGui::BeginPopupModal(DIALOG_GST_EFFECT, NULL, ImGuiWindowFlags_NoResize))
|
||||||
{
|
{
|
||||||
const ImVec2 pos = ImGui::GetCursorPos();
|
const ImVec2 pos = ImGui::GetCursorPos();
|
||||||
const ImVec2 area = ImGui::GetContentRegionAvail();
|
const ImVec2 area = ImGui::GetContentRegionAvail();
|
||||||
@@ -1970,6 +2041,58 @@ void SourceControlWindow::RenderMediaPlayer(MediaSource *ms)
|
|||||||
ImGui::CloseCurrentPopup();
|
ImGui::CloseCurrentPopup();
|
||||||
ImGui::EndPopup();
|
ImGui::EndPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////
|
||||||
|
/// Dialog to set timeline duration
|
||||||
|
///
|
||||||
|
static double timeline_duration_ = 0.0;
|
||||||
|
if (mediaplayer_set_duration_) {
|
||||||
|
mediaplayer_set_duration_ = false;
|
||||||
|
// open dialog
|
||||||
|
if (mediaplayer_active_) {
|
||||||
|
// get current duration of mediaplayer
|
||||||
|
GstClockTime end = mediaplayer_active_->timeline()->end();
|
||||||
|
timeline_duration_ = (double) ( GST_TIME_AS_MSECONDS(end) ) / 1000.f;
|
||||||
|
// open dialog to change duration
|
||||||
|
ImGui::OpenPopup(DIALOG_TIMELINE_DURATION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const ImVec2 tld_dialog_size(buttons_width_ * 2.f, buttons_height_ * 4);
|
||||||
|
ImGui::SetNextWindowSize(tld_dialog_size, ImGuiCond_Always);
|
||||||
|
const ImVec2 tld_dialog_pos = top + rendersize * 0.5f - tld_dialog_size * 0.5f;
|
||||||
|
ImGui::SetNextWindowPos(tld_dialog_pos, ImGuiCond_Always);
|
||||||
|
if (ImGui::BeginPopupModal(DIALOG_TIMELINE_DURATION, NULL, ImGuiWindowFlags_NoResize))
|
||||||
|
{
|
||||||
|
const ImVec2 pos = ImGui::GetCursorPos();
|
||||||
|
const ImVec2 area = ImGui::GetContentRegionAvail();
|
||||||
|
|
||||||
|
ImGui::Spacing();
|
||||||
|
ImGui::Text("Set the duration of the timeline");
|
||||||
|
ImGui::Spacing();
|
||||||
|
|
||||||
|
// get current timeline
|
||||||
|
Timeline tl = *mediaplayer_active_->timeline();
|
||||||
|
ImGui::InputDouble("second", &timeline_duration_, 1.0f, 10.0f, "%.2f");
|
||||||
|
timeline_duration_ = ABS(timeline_duration_);
|
||||||
|
|
||||||
|
bool close = false;
|
||||||
|
ImGui::SetCursorPos(pos + ImVec2(0.f, area.y - buttons_height_));
|
||||||
|
if (ImGui::Button(ICON_FA_TIMES " Cancel", ImVec2(area.x * 0.3f, 0)))
|
||||||
|
close = true;
|
||||||
|
ImGui::SetCursorPos(pos + ImVec2(area.x * 0.7f, area.y - buttons_height_));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetStyleColorVec4(ImGuiCol_Tab));
|
||||||
|
if (ImGui::Button(ICON_FA_CHECK " Apply", ImVec2(area.x * 0.3f, 0))
|
||||||
|
|| ImGui::IsKeyPressedMap(ImGuiKey_Enter) || ImGui::IsKeyPressedMap(ImGuiKey_KeyPadEnter) ) {
|
||||||
|
// change timeline end
|
||||||
|
mediaplayer_active_->timeline()->setEnd( GST_MSECOND * (GstClockTime) ( timeline_duration_ * 1000.f ) );
|
||||||
|
// close dialog
|
||||||
|
close = true;
|
||||||
|
}
|
||||||
|
ImGui::PopStyleColor(1);
|
||||||
|
if (close)
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SourceControlWindow::DrawButtonBar(ImVec2 bottom, float width)
|
void SourceControlWindow::DrawButtonBar(ImVec2 bottom, float width)
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ class SourceControlWindow : public WorkspaceWindow
|
|||||||
// Render a single media player
|
// Render a single media player
|
||||||
MediaPlayer *mediaplayer_active_;
|
MediaPlayer *mediaplayer_active_;
|
||||||
bool mediaplayer_edit_fading_;
|
bool mediaplayer_edit_fading_;
|
||||||
|
bool mediaplayer_set_duration_;
|
||||||
bool mediaplayer_edit_pipeline_;
|
bool mediaplayer_edit_pipeline_;
|
||||||
bool mediaplayer_mode_;
|
bool mediaplayer_mode_;
|
||||||
bool mediaplayer_slider_pressed_;
|
bool mediaplayer_slider_pressed_;
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ public:
|
|||||||
* */
|
* */
|
||||||
bool enabled() const;
|
bool enabled() const;
|
||||||
/**
|
/**
|
||||||
* True if its an image
|
* True if it has only one frame
|
||||||
* */
|
* */
|
||||||
bool singleFrame() const;
|
bool singleFrame() const;
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -216,6 +216,9 @@
|
|||||||
#define LABEL_AUTO_MEDIA_PLAYER ICON_FA_USER_CIRCLE " User selection"
|
#define LABEL_AUTO_MEDIA_PLAYER ICON_FA_USER_CIRCLE " User selection"
|
||||||
#define LABEL_STORE_SELECTION " Create batch"
|
#define LABEL_STORE_SELECTION " Create batch"
|
||||||
#define LABEL_EDIT_FADING ICON_FA_RANDOM " Fade in & out"
|
#define LABEL_EDIT_FADING ICON_FA_RANDOM " Fade in & out"
|
||||||
#define LABEL_VIDEO_SEQUENCE " Encode an image sequence"
|
#define LABEL_VIDEO_SEQUENCE " Encode an image sequence"
|
||||||
|
#define LABEL_ADD_TIMELINE "Add timeline"
|
||||||
|
#define DIALOG_TIMELINE_DURATION ICON_FA_HOURGLASS_HALF " Set timeline duration"
|
||||||
|
#define DIALOG_GST_EFFECT "Gstreamer Video effect"
|
||||||
|
|
||||||
#endif // VMIX_DEFINES_H
|
#endif // VMIX_DEFINES_H
|
||||||
|
|||||||
Reference in New Issue
Block a user