This commit is contained in:
tkmxqrdxddd
2024-10-18 17:43:33 +02:00
parent adab2de87b
commit b942f0a962
3 changed files with 58 additions and 215 deletions

3
.gitignore vendored
View File

@@ -30,4 +30,5 @@
*.exe *.exe
*.out *.out
*.app *.app
.output /output
/.qtcreator

View File

@@ -1,5 +1,5 @@
# #
# 'make' build executable file 'main' # 'make' build executable file 'VideoConverter'
# 'make clean' removes all .o and executable files # 'make clean' removes all .o and executable files
# #
@@ -7,94 +7,43 @@
CXX = g++ CXX = g++
# define any compile-time flags # define any compile-time flags
CXXFLAGS := -std=c++17 -Wall -Wextra -g $(shell pkg-config --cflags gtk+-3.0) CXXFLAGS = -std=c++17 -Wall -Wextra -g
# define library paths in addition to /usr/lib
# if I wanted to include libraries not in /usr/lib I'd specify
# their path using -Lpath, something like:
LFLAGS =
# define output directory # define output directory
OUTPUT := output OUTPUT = output
# define source directory # define source directory
SRC := src SRC = src
# define include directory # define the main executable name
INCLUDE := include MAIN = VideoConverter
# define lib directory
LIB := lib
ifeq ($(OS),Windows_NT)
MAIN := main.exe
SOURCEDIRS := $(SRC)
INCLUDEDIRS := $(INCLUDE)
LIBDIRS := $(LIB)
FIXPATH = $(subst /,\,$1)
RM := del /q /f
MD := mkdir
else
MAIN := main
SOURCEDIRS := $(shell find $(SRC) -type d)
INCLUDEDIRS := $(shell find $(INCLUDE) -type d)
LIBDIRS := $(shell find $(LIB) -type d)
FIXPATH = $1
RM = rm -f
MD := mkdir -p
endif
# define any directories containing header files other than /usr/include
INCLUDES := $(patsubst %,-I%, $(INCLUDEDIRS:%/=%))
# define the C libs
LIBS := $(patsubst %,-L%, $(LIBDIRS:%/=%))
LIBS += $(shell pkg-config --libs gtk+-3.0)
# define the C source files # define the C source files
SOURCES := $(wildcard $(patsubst %,%/*.cpp, $(SOURCEDIRS))) SOURCES = $(wildcard $(SRC)/*.cpp)
# define the C object files # define the C object files
OBJECTS := $(SOURCES:.cpp=.o) OBJECTS = $(SOURCES:.cpp=.o)
# define the dependency output files OUTPUTMAIN = $(OUTPUT)/$(MAIN)
DEPS := $(OBJECTS:.o=.d)
# all: $(OUTPUT) $(OUTPUTMAIN)
# The following part of the makefile is generic; it can be used to @echo "Building executable: $(MAIN)"
# build any executable just by changing the definitions above and by
# deleting dependencies appended to the file from 'make depend'
#
OUTPUTMAIN := $(call FIXPATH,$(OUTPUT)/$(MAIN))
all: $(OUTPUT) $(MAIN)
@echo Executing 'all' complete! @echo Executing 'all' complete!
$(OUTPUT): $(OUTPUT):
$(MD) $(OUTPUT) mkdir -p $(OUTPUT)
$(MAIN): $(OBJECTS) $(OUTPUTMAIN): $(OBJECTS)
$(CXX) $(CXXFLAGS) $(INCLUDES) -o $(OUTPUTMAIN) $(OBJECTS) $(LFLAGS) $(LIBS) $(CXX) $(CXXFLAGS) -o $(OUTPUTMAIN) $(OBJECTS)
# include all .d files
-include $(DEPS)
# this is a suffix replacement rule for building .o's and .d's from .c's
# it uses automatic variables $<: the name of the prerequisite of
# the rule(a .c file) and $@: the name of the target of the rule (a .o file)
# -MMD generates dependency output files same name as the .o file
# (see the gnu make manual section about automatic variables)
.cpp.o:
$(CXX) $(CXXFLAGS) $(INCLUDES) -c -MMD $< -o $@
.PHONY: clean .PHONY: clean
clean: clean:
$(RM) $(OUTPUTMAIN) @echo "Cleaning up..."
$(RM) $(call FIXPATH,$(OBJECTS)) rm -f $(OUTPUTMAIN)
$(RM) $(call FIXPATH,$(DEPS)) rm -f $(OBJECTS)
@echo Cleanup complete! @echo Cleanup complete!
run: all run: all
@echo "Running executable: $(OUTPUTMAIN)"
./$(OUTPUTMAIN) ./$(OUTPUTMAIN)
@echo Executing 'run: all' complete! @echo Executing 'run: all' complete!

View File

@@ -1,167 +1,60 @@
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <cstdlib>
#include <stdexcept>
#include <gtk/gtk.h>
#include <thread> #include <thread>
#include <atomic> #include <cstdlib>
class VideoConverter { class VideoConverter {
private: private:
std::string input_file; bool conversionInProgress;
std::string output_file;
std::atomic<bool> conversion_in_progress;
GtkWidget *window;
GtkWidget *input_entry;
GtkWidget *output_entry;
GtkWidget *convert_button;
GtkWidget *progress_bar;
static void on_convert_clicked(GtkWidget *widget, gpointer data) {
auto *converter = static_cast<VideoConverter*>(data);
converter->start_conversion();
}
static void on_window_destroy(GtkWidget *widget, gpointer data) {
gtk_main_quit();
}
void start_conversion() {
if (conversion_in_progress) {
show_error("Conversion already in progress");
return;
}
input_file = gtk_entry_get_text(GTK_ENTRY(input_entry));
output_file = gtk_entry_get_text(GTK_ENTRY(output_entry));
if (input_file.empty() || output_file.empty()) {
show_error("Please enter both input and output file names");
return;
}
conversion_in_progress = true;
gtk_widget_set_sensitive(convert_button, FALSE);
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress_bar), 0.0);
std::thread conversion_thread(&VideoConverter::convert, this);
conversion_thread.detach();
}
void convert() {
std::string command = "ffmpeg -i " + input_file +
" -c:v dnxhd -profile:v dnxhr_hq -pix_fmt yuv422p -c:a alac " +
output_file + " -progress pipe:1";
FILE* pipe = popen(command.c_str(), "r");
if (!pipe) {
gdk_threads_add_idle(G_SOURCE_FUNC(show_error_wrapper),
const_cast<char*>("Failed to start FFmpeg process"));
conversion_in_progress = false;
return;
}
char buffer[128];
std::string result = "";
while (!feof(pipe)) {
if (fgets(buffer, 128, pipe) != NULL) {
result += buffer;
if (result.find("progress=end") != std::string::npos) {
gdk_threads_add_idle(G_SOURCE_FUNC(update_progress_wrapper),
const_cast<gpointer>(static_cast<const void*>(this)));
break;
}
}
}
int status = pclose(pipe);
conversion_in_progress = false;
if (status == 0) {
gdk_threads_add_idle(G_SOURCE_FUNC(show_success_wrapper),
const_cast<char*>("Video conversion completed successfully"));
} else {
gdk_threads_add_idle(G_SOURCE_FUNC(show_error_wrapper),
const_cast<char*>("Error occurred during video conversion"));
}
}
static gboolean update_progress_wrapper(gpointer data) {
auto *converter = static_cast<VideoConverter*>(data);
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(converter->progress_bar), 1.0);
gtk_widget_set_sensitive(converter->convert_button, TRUE);
return FALSE;
}
static gboolean show_error_wrapper(gpointer data) {
auto *message = static_cast<char*>(data);
VideoConverter::show_message_dialog(GTK_MESSAGE_ERROR, message);
return FALSE;
}
static gboolean show_success_wrapper(gpointer data) {
auto *message = static_cast<char*>(data);
VideoConverter::show_message_dialog(GTK_MESSAGE_INFO, message);
return FALSE;
}
static void show_message_dialog(GtkMessageType type, const char* message) {
GtkWidget *dialog = gtk_message_dialog_new(NULL,
GTK_DIALOG_MODAL,
type,
GTK_BUTTONS_OK,
"%s", message);
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
}
void show_error(const char* message) {
show_message_dialog(GTK_MESSAGE_ERROR, message);
}
public: public:
VideoConverter() : conversion_in_progress(false) {} VideoConverter() : conversionInProgress(false) {}
void create_window() { void startConversion(const std::string &inputFile, const std::string &outputFile) {
window = gtk_window_new(GTK_WINDOW_TOPLEVEL); if (conversionInProgress) {
gtk_window_set_title(GTK_WINDOW(window), "Video Converter"); std::cerr << "Error: Conversion already in progress." << std::endl;
gtk_container_set_border_width(GTK_CONTAINER(window), 10); return;
}
GtkWidget *grid = gtk_grid_new(); if (inputFile.empty() || outputFile.empty()) {
gtk_container_add(GTK_CONTAINER(window), grid); std::cerr << "Error: Please enter both input and output file names." << std::endl;
return;
}
GtkWidget *input_label = gtk_label_new("Input File:"); conversionInProgress = true;
gtk_grid_attach(GTK_GRID(grid), input_label, 0, 0, 1, 1); std::cout << "Starting conversion..." << std::endl;
input_entry = gtk_entry_new(); std::thread conversionThread([this, inputFile, outputFile]() {
gtk_grid_attach(GTK_GRID(grid), input_entry, 1, 0, 1, 1); std::string command = "ffmpeg -i \"" + inputFile + "\" -c:v dnxhd -profile:v dnxhr_hq -pix_fmt yuv422p -c:a alac \"" + outputFile + "\"";
int result = std::system(command.c_str());
conversionInProgress = false;
GtkWidget *output_label = gtk_label_new("Output File:"); if (result == 0) {
gtk_grid_attach(GTK_GRID(grid), output_label, 0, 1, 1, 1); std::cout << "Video conversion completed successfully." << std::endl;
} else {
std::cerr << "Error: Conversion failed with exit code " << result << std::endl;
}
});
output_entry = gtk_entry_new(); conversionThread.detach(); // Detach the thread to allow it to run independently
gtk_grid_attach(GTK_GRID(grid), output_entry, 1, 1, 1, 1);
convert_button = gtk_button_new_with_label("Convert");
g_signal_connect(convert_button, "clicked", G_CALLBACK(on_convert_clicked), this);
gtk_grid_attach(GTK_GRID(grid), convert_button, 0, 2, 2, 1);
progress_bar = gtk_progress_bar_new();
gtk_grid_attach(GTK_GRID(grid), progress_bar, 0, 3, 2, 1);
g_signal_connect(window, "destroy", G_CALLBACK(on_window_destroy), NULL);
gtk_widget_show_all(window);
} }
}; };
int main(int argc, char *argv[]) { int main() {
gtk_init(&argc, &argv);
VideoConverter converter; VideoConverter converter;
converter.create_window(); std::string inputFile, outputFile;
gtk_main(); std::cout << "Welcome to the Video Converter!" << std::endl;
std::cout << "Enter the input file path: ";
std::getline(std::cin, inputFile);
std::cout << "Enter the output file path: ";
std::getline(std::cin, outputFile);
converter.startConversion(inputFile, outputFile);
// Keep the application running until the conversion is done
std::cout << "Press Enter to exit..." << std::endl;
std::cin.get();
return 0; return 0;
} }