mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-14 11:49:59 +01:00
BugFix Video recorder and image sequence encoder
Improved and simplified UI control of encoding of image sequences into video files. Bugs fixed to prevent problems with video recorder.
This commit is contained in:
@@ -79,13 +79,9 @@ bool MultiFileRecorder::add_image (const std::string &image_filename, GstCaps *c
|
|||||||
// set flag to only read VIDEO
|
// set flag to only read VIDEO
|
||||||
g_object_set(G_OBJECT(img_pipeline), "flags", 0x00000001, NULL);
|
g_object_set(G_OBJECT(img_pipeline), "flags", 0x00000001, NULL);
|
||||||
|
|
||||||
// instruct sink to use the required caps (without framerate)
|
// instruct sink to use the required caps
|
||||||
GstCaps *sinkcaps = gst_caps_copy(caps);
|
|
||||||
GValue v = {GST_TYPE_FRACTION, {{0}, {1}}};
|
|
||||||
gst_caps_set_value(sinkcaps, "framerate", &v);
|
|
||||||
|
|
||||||
GstElement *sink = gst_element_factory_make("appsink", "imgsink");
|
GstElement *sink = gst_element_factory_make("appsink", "imgsink");
|
||||||
gst_app_sink_set_caps(GST_APP_SINK(sink), sinkcaps);
|
gst_app_sink_set_caps(GST_APP_SINK(sink), caps);
|
||||||
|
|
||||||
// set playbin sink
|
// set playbin sink
|
||||||
g_object_set(G_OBJECT(img_pipeline), "video-sink", sink, NULL);
|
g_object_set(G_OBJECT(img_pipeline), "video-sink", sink, NULL);
|
||||||
@@ -137,7 +133,6 @@ bool MultiFileRecorder::add_image (const std::string &image_filename, GstCaps *c
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Clean up */
|
/* Clean up */
|
||||||
gst_caps_unref(caps);
|
|
||||||
gst_sample_unref(sample);
|
gst_sample_unref(sample);
|
||||||
gst_element_set_state(img_pipeline, GST_STATE_NULL);
|
gst_element_set_state(img_pipeline, GST_STATE_NULL);
|
||||||
gst_object_unref(GST_OBJECT(img_pipeline));
|
gst_object_unref(GST_OBJECT(img_pipeline));
|
||||||
@@ -165,7 +160,7 @@ bool MultiFileRecorder::start_record (const std::string &video_filename)
|
|||||||
if (Settings::application.render.gpu_decoding && (int) VideoRecorder::hardware_encoder.size() > 0 &&
|
if (Settings::application.render.gpu_decoding && (int) VideoRecorder::hardware_encoder.size() > 0 &&
|
||||||
GstToolkit::has_feature(VideoRecorder::hardware_encoder[profile_]) ) {
|
GstToolkit::has_feature(VideoRecorder::hardware_encoder[profile_]) ) {
|
||||||
|
|
||||||
description += VideoRecorder::hardware_profile_description[Settings::application.record.profile];
|
description += VideoRecorder::hardware_profile_description[Settings::application.image_sequence.profile];
|
||||||
Log::Info("MultiFileRecorder use hardware accelerated encoder (%s)", VideoRecorder::hardware_encoder[profile_].c_str());
|
Log::Info("MultiFileRecorder use hardware accelerated encoder (%s)", VideoRecorder::hardware_encoder[profile_].c_str());
|
||||||
}
|
}
|
||||||
// revert to software encoder
|
// revert to software encoder
|
||||||
@@ -317,8 +312,13 @@ bool MultiFileRecorder::finished ()
|
|||||||
// get the filename from encoder
|
// get the filename from encoder
|
||||||
filename_ = promises_.back().get();
|
filename_ = promises_.back().get();
|
||||||
if (!filename_.empty()) {
|
if (!filename_.empty()) {
|
||||||
// save path location
|
// save path location if valid
|
||||||
|
std::string uri = GstToolkit::filename_to_uri(filename_);
|
||||||
|
MediaInfo media = MediaPlayer::UriDiscoverer(uri);
|
||||||
|
if (media.valid && !media.isimage)
|
||||||
Settings::application.recentRecordings.push(filename_);
|
Settings::application.recentRecordings.push(filename_);
|
||||||
|
else
|
||||||
|
Settings::application.recentRecordings.remove(filename_);
|
||||||
}
|
}
|
||||||
// done with this recoding
|
// done with this recoding
|
||||||
promises_.pop_back();
|
promises_.pop_back();
|
||||||
@@ -336,6 +336,7 @@ std::string MultiFileRecorder::assemble (MultiFileRecorder *rec)
|
|||||||
rec->progress_ = 0.f;
|
rec->progress_ = 0.f;
|
||||||
rec->width_ = 0;
|
rec->width_ = 0;
|
||||||
rec->height_ = 0;
|
rec->height_ = 0;
|
||||||
|
rec->cancel_ = false;
|
||||||
|
|
||||||
// input files
|
// input files
|
||||||
if ( rec->files_.size() < 1 ) {
|
if ( rec->files_.size() < 1 ) {
|
||||||
@@ -372,6 +373,14 @@ std::string MultiFileRecorder::assemble (MultiFileRecorder *rec)
|
|||||||
|
|
||||||
if ( rec->start_record( filename ) )
|
if ( rec->start_record( filename ) )
|
||||||
{
|
{
|
||||||
|
// specify caps for images (same as video, without framerate)
|
||||||
|
GstCaps *tmp_caps = gst_caps_copy( gst_app_src_get_caps(rec->src_) );
|
||||||
|
GValue v = G_VALUE_INIT;
|
||||||
|
g_value_init (&v, GST_TYPE_FRACTION);
|
||||||
|
gst_value_set_fraction (&v, 0, 1);
|
||||||
|
gst_caps_set_value(tmp_caps, "framerate", &v);
|
||||||
|
g_value_unset (&v);
|
||||||
|
|
||||||
// progressing
|
// progressing
|
||||||
rec->progress_ += inc_;
|
rec->progress_ += inc_;
|
||||||
|
|
||||||
@@ -381,7 +390,7 @@ std::string MultiFileRecorder::assemble (MultiFileRecorder *rec)
|
|||||||
if ( rec->cancel_ )
|
if ( rec->cancel_ )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if ( rec->add_image( *file, gst_app_src_get_caps(rec->src_) ) ) {
|
if ( rec->add_image( *file, tmp_caps) ) {
|
||||||
// validate file
|
// validate file
|
||||||
rec->frame_count_++;
|
rec->frame_count_++;
|
||||||
|
|
||||||
@@ -414,6 +423,8 @@ std::string MultiFileRecorder::assemble (MultiFileRecorder *rec)
|
|||||||
Log::Info("MultiFileRecorder %d images encoded (%s).", rec->frame_count_, GstToolkit::time_to_string(rec->timestamp_, GstToolkit::TIME_STRING_READABLE).c_str());
|
Log::Info("MultiFileRecorder %d images encoded (%s).", rec->frame_count_, GstToolkit::time_to_string(rec->timestamp_, GstToolkit::TIME_STRING_READABLE).c_str());
|
||||||
else
|
else
|
||||||
filename = std::string();
|
filename = std::string();
|
||||||
|
|
||||||
|
gst_caps_unref(tmp_caps);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
filename = std::string();
|
filename = std::string();
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#include "GstToolkit.h"
|
#include "GstToolkit.h"
|
||||||
#include "SystemToolkit.h"
|
#include "SystemToolkit.h"
|
||||||
|
#include "MediaPlayer.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "Audio.h"
|
#include "Audio.h"
|
||||||
|
|
||||||
@@ -333,7 +334,7 @@ std::string VideoRecorder::init(GstCaps *caps)
|
|||||||
|
|
||||||
// apply settings
|
// apply settings
|
||||||
buffering_size_ = MAX( MIN_BUFFER_SIZE, buffering_preset_value[Settings::application.record.buffering_mode]);
|
buffering_size_ = MAX( MIN_BUFFER_SIZE, buffering_preset_value[Settings::application.record.buffering_mode]);
|
||||||
frame_duration_ = gst_util_uint64_scale_int (1, GST_SECOND, framerate_preset_value[Settings::application.record.framerate_mode]);
|
frame_duration_ = gst_util_uint64_scale_int (1, GST_SECOND, MAXI(framerate_preset_value[Settings::application.record.framerate_mode], 15));
|
||||||
timestamp_on_clock_ = Settings::application.record.priority_mode < 1;
|
timestamp_on_clock_ = Settings::application.record.priority_mode < 1;
|
||||||
keyframe_count_ = framerate_preset_value[Settings::application.record.framerate_mode];
|
keyframe_count_ = framerate_preset_value[Settings::application.record.framerate_mode];
|
||||||
|
|
||||||
@@ -366,7 +367,8 @@ std::string VideoRecorder::init(GstCaps *caps)
|
|||||||
else {
|
else {
|
||||||
|
|
||||||
// Add Audio to pipeline
|
// Add Audio to pipeline
|
||||||
if (!Settings::application.record.audio_device.empty()) {
|
if ( Settings::application.accept_audio &&
|
||||||
|
!Settings::application.record.audio_device.empty()) {
|
||||||
// ensure the Audio manager has the device specified in settings
|
// ensure the Audio manager has the device specified in settings
|
||||||
int current_audio = Audio::manager().index(Settings::application.record.audio_device);
|
int current_audio = Audio::manager().index(Settings::application.record.audio_device);
|
||||||
if (current_audio > -1) {
|
if (current_audio > -1) {
|
||||||
@@ -498,9 +500,15 @@ void VideoRecorder::terminate()
|
|||||||
Log::Info("Video Recording : try a lower resolution / a lower framerate / a larger buffer size / a faster codec.");
|
Log::Info("Video Recording : try a lower resolution / a lower framerate / a larger buffer size / a faster codec.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// remember and inform
|
// remember and inform if valid
|
||||||
|
std::string uri = GstToolkit::filename_to_uri(filename_);
|
||||||
|
MediaInfo media = MediaPlayer::UriDiscoverer(uri);
|
||||||
|
if (media.valid && !media.isimage) {
|
||||||
Settings::application.recentRecordings.push(filename_);
|
Settings::application.recentRecordings.push(filename_);
|
||||||
Log::Notify("Video Recording %s is ready.", filename_.c_str());
|
Log::Notify("Video Recording %s is ready.", filename_.c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Settings::application.recentRecordings.remove(filename_);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string VideoRecorder::info() const
|
std::string VideoRecorder::info() const
|
||||||
|
|||||||
@@ -186,7 +186,6 @@ void Settings::Save(uint64_t runtime, const std::string &filename)
|
|||||||
RecordNode->SetAttribute("profile", application.record.profile);
|
RecordNode->SetAttribute("profile", application.record.profile);
|
||||||
RecordNode->SetAttribute("timeout", application.record.timeout);
|
RecordNode->SetAttribute("timeout", application.record.timeout);
|
||||||
RecordNode->SetAttribute("delay", application.record.delay);
|
RecordNode->SetAttribute("delay", application.record.delay);
|
||||||
RecordNode->SetAttribute("resolution_mode", application.record.resolution_mode);
|
|
||||||
RecordNode->SetAttribute("framerate_mode", application.record.framerate_mode);
|
RecordNode->SetAttribute("framerate_mode", application.record.framerate_mode);
|
||||||
RecordNode->SetAttribute("buffering_mode", application.record.buffering_mode);
|
RecordNode->SetAttribute("buffering_mode", application.record.buffering_mode);
|
||||||
RecordNode->SetAttribute("priority_mode", application.record.priority_mode);
|
RecordNode->SetAttribute("priority_mode", application.record.priority_mode);
|
||||||
@@ -194,6 +193,12 @@ void Settings::Save(uint64_t runtime, const std::string &filename)
|
|||||||
RecordNode->SetAttribute("audio_device", application.record.audio_device.c_str());
|
RecordNode->SetAttribute("audio_device", application.record.audio_device.c_str());
|
||||||
pRoot->InsertEndChild(RecordNode);
|
pRoot->InsertEndChild(RecordNode);
|
||||||
|
|
||||||
|
// Image sequence
|
||||||
|
XMLElement *SequenceNode = xmlDoc.NewElement( "Sequence" );
|
||||||
|
SequenceNode->SetAttribute("profile", application.image_sequence.profile);
|
||||||
|
SequenceNode->SetAttribute("framerate", application.image_sequence.framerate_mode);
|
||||||
|
pRoot->InsertEndChild(SequenceNode);
|
||||||
|
|
||||||
// Transition
|
// Transition
|
||||||
XMLElement *TransitionNode = xmlDoc.NewElement( "Transition" );
|
XMLElement *TransitionNode = xmlDoc.NewElement( "Transition" );
|
||||||
TransitionNode->SetAttribute("cross_fade", application.transition.cross_fade);
|
TransitionNode->SetAttribute("cross_fade", application.transition.cross_fade);
|
||||||
@@ -507,7 +512,6 @@ void Settings::Load(const string &filename)
|
|||||||
recordnode->QueryIntAttribute("profile", &application.record.profile);
|
recordnode->QueryIntAttribute("profile", &application.record.profile);
|
||||||
recordnode->QueryUnsignedAttribute("timeout", &application.record.timeout);
|
recordnode->QueryUnsignedAttribute("timeout", &application.record.timeout);
|
||||||
recordnode->QueryIntAttribute("delay", &application.record.delay);
|
recordnode->QueryIntAttribute("delay", &application.record.delay);
|
||||||
recordnode->QueryIntAttribute("resolution_mode", &application.record.resolution_mode);
|
|
||||||
recordnode->QueryIntAttribute("framerate_mode", &application.record.framerate_mode);
|
recordnode->QueryIntAttribute("framerate_mode", &application.record.framerate_mode);
|
||||||
recordnode->QueryIntAttribute("buffering_mode", &application.record.buffering_mode);
|
recordnode->QueryIntAttribute("buffering_mode", &application.record.buffering_mode);
|
||||||
recordnode->QueryIntAttribute("priority_mode", &application.record.priority_mode);
|
recordnode->QueryIntAttribute("priority_mode", &application.record.priority_mode);
|
||||||
@@ -526,6 +530,13 @@ void Settings::Load(const string &filename)
|
|||||||
application.record.audio_device = "";
|
application.record.audio_device = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Record
|
||||||
|
XMLElement * sequencenode = pRoot->FirstChildElement("Sequence");
|
||||||
|
if (sequencenode != nullptr) {
|
||||||
|
sequencenode->QueryIntAttribute("profile", &application.image_sequence.profile);
|
||||||
|
sequencenode->QueryIntAttribute("framerate", &application.image_sequence.framerate_mode);
|
||||||
|
}
|
||||||
|
|
||||||
// Source
|
// Source
|
||||||
XMLElement * sourceconfnode = pRoot->FirstChildElement("Source");
|
XMLElement * sourceconfnode = pRoot->FirstChildElement("Source");
|
||||||
if (sourceconfnode != nullptr) {
|
if (sourceconfnode != nullptr) {
|
||||||
|
|||||||
@@ -104,7 +104,6 @@ struct RecordConfig
|
|||||||
int profile;
|
int profile;
|
||||||
uint timeout;
|
uint timeout;
|
||||||
int delay;
|
int delay;
|
||||||
int resolution_mode;
|
|
||||||
int framerate_mode;
|
int framerate_mode;
|
||||||
int buffering_mode;
|
int buffering_mode;
|
||||||
int priority_mode;
|
int priority_mode;
|
||||||
@@ -115,7 +114,6 @@ struct RecordConfig
|
|||||||
profile = 0;
|
profile = 0;
|
||||||
timeout = RECORD_MAX_TIMEOUT;
|
timeout = RECORD_MAX_TIMEOUT;
|
||||||
delay = 0;
|
delay = 0;
|
||||||
resolution_mode = 1;
|
|
||||||
framerate_mode = 1;
|
framerate_mode = 1;
|
||||||
buffering_mode = 2;
|
buffering_mode = 2;
|
||||||
priority_mode = 1;
|
priority_mode = 1;
|
||||||
@@ -318,6 +316,7 @@ struct Application
|
|||||||
|
|
||||||
// settings exporters
|
// settings exporters
|
||||||
RecordConfig record;
|
RecordConfig record;
|
||||||
|
RecordConfig image_sequence;
|
||||||
|
|
||||||
// settings new source
|
// settings new source
|
||||||
SourceConfig source;
|
SourceConfig source;
|
||||||
@@ -380,6 +379,7 @@ struct Application
|
|||||||
windows[0].h = 930;
|
windows[0].h = 930;
|
||||||
accept_audio = false;
|
accept_audio = false;
|
||||||
dialogPosition = glm::ivec2(-1, -1);
|
dialogPosition = glm::ivec2(-1, -1);
|
||||||
|
image_sequence.framerate_mode = 15;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3859,7 +3859,7 @@ void Navigator::RenderNewPannel(const ImVec2 &iconsize)
|
|||||||
IMAGES_FILES_PATTERN);
|
IMAGES_FILES_PATTERN);
|
||||||
static MultiFileSequence _numbered_sequence;
|
static MultiFileSequence _numbered_sequence;
|
||||||
static MultiFileRecorder _video_recorder;
|
static MultiFileRecorder _video_recorder;
|
||||||
static int _fps = 25;
|
static int codec_id = -1;
|
||||||
|
|
||||||
ImGui::Text("Image sequence");
|
ImGui::Text("Image sequence");
|
||||||
|
|
||||||
@@ -3874,8 +3874,7 @@ void Navigator::RenderNewPannel(const ImVec2 &iconsize)
|
|||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGuiToolkit::HelpToolTip("Create a source displaying a sequence of images;\n"
|
ImGuiToolkit::HelpToolTip("Create a source displaying a sequence of images;\n"
|
||||||
ICON_FA_CARET_RIGHT " files numbered consecutively\n"
|
ICON_FA_CARET_RIGHT " files numbered consecutively\n"
|
||||||
ICON_FA_CARET_RIGHT " create a video from many images\n"
|
ICON_FA_CARET_RIGHT " create a video from many images");
|
||||||
"Supports PNG, JPG or TIF.");
|
|
||||||
|
|
||||||
// return from thread for folder openning
|
// return from thread for folder openning
|
||||||
if (_selectImagesDialog.closed()) {
|
if (_selectImagesDialog.closed()) {
|
||||||
@@ -3891,9 +3890,16 @@ void Navigator::RenderNewPannel(const ImVec2 &iconsize)
|
|||||||
|
|
||||||
// automatically create a MultiFile Source if possible
|
// automatically create a MultiFile Source if possible
|
||||||
if (_numbered_sequence.valid()) {
|
if (_numbered_sequence.valid()) {
|
||||||
|
// always come back to propose image sequence when possible
|
||||||
|
codec_id = -1;
|
||||||
|
// show source preview available if possible
|
||||||
std::string label = BaseToolkit::transliterate( BaseToolkit::common_pattern(sourceSequenceFiles) );
|
std::string label = BaseToolkit::transliterate( BaseToolkit::common_pattern(sourceSequenceFiles) );
|
||||||
new_source_preview_.setSource( Mixer::manager().createSourceMultifile(sourceSequenceFiles, _fps), label);
|
new_source_preview_
|
||||||
}
|
.setSource(Mixer::manager().createSourceMultifile(sourceSequenceFiles,
|
||||||
|
Settings::application.image_sequence.framerate_mode),
|
||||||
|
label);
|
||||||
|
} else
|
||||||
|
codec_id = Settings::application.image_sequence.profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
// multiple files selected
|
// multiple files selected
|
||||||
@@ -3907,45 +3913,85 @@ void Navigator::RenderNewPannel(const ImVec2 &iconsize)
|
|||||||
info.appendf("%d %s", (int) sourceSequenceFiles.size(), _numbered_sequence.codec.c_str());
|
info.appendf("%d %s", (int) sourceSequenceFiles.size(), _numbered_sequence.codec.c_str());
|
||||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||||
ImGui::InputText("Images", (char *)info.c_str(), info.size(), ImGuiInputTextFlags_ReadOnly);
|
ImGui::InputText("Images", (char *)info.c_str(), info.size(), ImGuiInputTextFlags_ReadOnly);
|
||||||
info.clear();
|
|
||||||
if (_numbered_sequence.location.empty())
|
|
||||||
info.append("Not consecutively numbered");
|
|
||||||
else
|
|
||||||
info.appendf("%s", SystemToolkit::base_filename(_numbered_sequence.location).c_str());
|
|
||||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
|
||||||
ImGui::InputText("Filenames", (char *)info.c_str(), info.size(), ImGuiInputTextFlags_ReadOnly);
|
|
||||||
ImGui::PopStyleColor(1);
|
ImGui::PopStyleColor(1);
|
||||||
|
|
||||||
// offer to open file browser at location
|
|
||||||
std::string path = SystemToolkit::path_filename(sourceSequenceFiles.front());
|
|
||||||
std::string label = BaseToolkit::truncated(path, 25);
|
|
||||||
label = BaseToolkit::transliterate(label);
|
|
||||||
ImGuiToolkit::ButtonOpenUrl( label.c_str(), path.c_str(), ImVec2(IMGUI_RIGHT_ALIGN, 0) );
|
|
||||||
ImGui::SameLine(0, IMGUI_SAME_LINE);
|
|
||||||
ImGui::Text("Folder");
|
|
||||||
|
|
||||||
// set framerate
|
// set framerate
|
||||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||||
ImGui::SliderInt("Framerate", &_fps, 1, 30, "%d fps");
|
ImGui::SliderInt("Framerate", &Settings::application.image_sequence.framerate_mode, 1, 30, "%d fps");
|
||||||
if (ImGui::IsItemDeactivatedAfterEdit()){
|
if (ImGui::IsItemDeactivatedAfterEdit()){
|
||||||
if (new_source_preview_.filled()) {
|
if (new_source_preview_.filled()) {
|
||||||
std::string label = BaseToolkit::transliterate( BaseToolkit::common_pattern(sourceSequenceFiles) );
|
std::string label = BaseToolkit::transliterate( BaseToolkit::common_pattern(sourceSequenceFiles) );
|
||||||
new_source_preview_.setSource( Mixer::manager().createSourceMultifile(sourceSequenceFiles, _fps), label);
|
new_source_preview_
|
||||||
|
.setSource(Mixer::manager().createSourceMultifile(
|
||||||
|
sourceSequenceFiles,
|
||||||
|
Settings::application.image_sequence.framerate_mode),
|
||||||
|
label);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Spacing();
|
// select CODEC: decide for gst sequence (codec_id = -1) or encoding a video
|
||||||
|
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||||
|
std::string codec_current = codec_id < 0 ? ICON_FA_SORT_NUMERIC_DOWN " Numbered images"
|
||||||
|
: std::string(ICON_FA_FILM " ") + VideoRecorder::profile_name[codec_id];
|
||||||
|
if (ImGui::BeginCombo("##CodecSequence", codec_current.c_str())) {
|
||||||
|
// special case; if possible, offer to create an image sequence gst source
|
||||||
|
if (ImGui::Selectable( ICON_FA_SORT_NUMERIC_DOWN " Numbered images",
|
||||||
|
codec_id < 0,
|
||||||
|
_numbered_sequence.valid()
|
||||||
|
? ImGuiSelectableFlags_None
|
||||||
|
: ImGuiSelectableFlags_Disabled)) {
|
||||||
|
// select id of image sequence
|
||||||
|
codec_id = -1;
|
||||||
|
// Open source preview for image sequence
|
||||||
|
if (_numbered_sequence.valid()) {
|
||||||
|
std::string label = BaseToolkit::transliterate(
|
||||||
|
BaseToolkit::common_pattern(sourceSequenceFiles));
|
||||||
|
new_source_preview_
|
||||||
|
.setSource(Mixer::manager().createSourceMultifile(
|
||||||
|
sourceSequenceFiles,
|
||||||
|
Settings::application.image_sequence.framerate_mode),
|
||||||
|
label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// always offer to encode a video
|
||||||
|
for (int i = VideoRecorder::H264_STANDARD; i < VideoRecorder::VP8; ++i) {
|
||||||
|
std::string label = std::string(ICON_FA_FILM " ") + VideoRecorder::profile_name[i];
|
||||||
|
if (ImGui::Selectable(label.c_str(), codec_id == i)) {
|
||||||
|
// select id of video encoding codec
|
||||||
|
codec_id = i;
|
||||||
|
Settings::application.image_sequence.profile = i;
|
||||||
|
// close source preview (no image sequence)
|
||||||
|
new_source_preview_.setSource();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndCombo();
|
||||||
|
}
|
||||||
|
// Indication
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (_numbered_sequence.valid())
|
||||||
|
ImGuiToolkit::HelpToolTip(ICON_FA_SORT_NUMERIC_DOWN " Selected images are numbered consecutively; "
|
||||||
|
"an image sequence source can be created.\n\n"
|
||||||
|
ICON_FA_FILM " Alternatively, choose a codec to encode a video with the selected images and create a video source.");
|
||||||
|
else
|
||||||
|
ImGuiToolkit::HelpToolTip(ICON_FA_SORT_NUMERIC_DOWN " Selected images are NOT numbered consecutively; "
|
||||||
|
"it is not possible to create a sequence source.\n\n"
|
||||||
|
ICON_FA_FILM " Instead, choose a codec to encode a video with the selected images and create a video source.");
|
||||||
|
|
||||||
|
// if video encoding codec selected
|
||||||
|
if ( codec_id >= 0 )
|
||||||
|
{
|
||||||
// Offer to create video from sequence
|
// Offer to create video from sequence
|
||||||
if ( ImGui::Button( ICON_FA_FILM " Make a video", ImVec2(ImGui::GetContentRegionAvail().x, 0)) ) {
|
ImGui::NewLine();
|
||||||
|
if ( ImGui::Button( ICON_FA_FILM " Encode video", ImVec2(ImGui::GetContentRegionAvail().x, 0)) ) {
|
||||||
// start video recorder
|
// start video recorder
|
||||||
_video_recorder.setFiles( sourceSequenceFiles );
|
_video_recorder.setFiles( sourceSequenceFiles );
|
||||||
_video_recorder.setFramerate( _fps );
|
_video_recorder.setFramerate( Settings::application.image_sequence.framerate_mode );
|
||||||
_video_recorder.setProfile( (VideoRecorder::Profile) Settings::application.record.profile );
|
_video_recorder.setProfile( (VideoRecorder::Profile) Settings::application.image_sequence.profile );
|
||||||
_video_recorder.start();
|
_video_recorder.start();
|
||||||
// dialog
|
// open dialog
|
||||||
ImGui::OpenPopup(LABEL_VIDEO_SEQUENCE);
|
ImGui::OpenPopup(LABEL_VIDEO_SEQUENCE);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// video recorder finished: inform and open pannel to import video source from recent recordings
|
// video recorder finished: inform and open pannel to import video source from recent recordings
|
||||||
if ( _video_recorder.finished() ) {
|
if ( _video_recorder.finished() ) {
|
||||||
@@ -3955,7 +4001,7 @@ void Navigator::RenderNewPannel(const ImVec2 &iconsize)
|
|||||||
else {
|
else {
|
||||||
Log::Notify("Image sequence saved to %s.", _video_recorder.filename().c_str());
|
Log::Notify("Image sequence saved to %s.", _video_recorder.filename().c_str());
|
||||||
// open the file as new recording
|
// open the file as new recording
|
||||||
// if (Settings::application.recentRecordings.load_at_start)
|
// if (Settings::application.recentRecordings.load_at_start)
|
||||||
UserInterface::manager().navigator.setNewMedia(Navigator::MEDIA_RECORDING, _video_recorder.filename());
|
UserInterface::manager().navigator.setNewMedia(Navigator::MEDIA_RECORDING, _video_recorder.filename());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3978,7 +4024,8 @@ void Navigator::RenderNewPannel(const ImVec2 &iconsize)
|
|||||||
ImGui::ProgressBar(_video_recorder.progress());
|
ImGui::ProgressBar(_video_recorder.progress());
|
||||||
|
|
||||||
ImGui::Spacing();
|
ImGui::Spacing();
|
||||||
if (ImGui::Button(ICON_FA_TIMES " Cancel"))
|
ImGui::Spacing();
|
||||||
|
if (ImGui::Button(ICON_FA_TIMES " Cancel",ImVec2(ImGui::GetContentRegionAvail().x, 0)))
|
||||||
_video_recorder.cancel();
|
_video_recorder.cancel();
|
||||||
|
|
||||||
ImGui::EndPopup();
|
ImGui::EndPopup();
|
||||||
|
|||||||
Reference in New Issue
Block a user