diff --git a/.gitignore b/.gitignore index b4c1104..afbb367 100644 --- a/.gitignore +++ b/.gitignore @@ -30,4 +30,5 @@ *.exe *.out *.app -.output +/output +/.qtcreator diff --git a/Makefile b/Makefile index 94da212..91a9202 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ # -# 'make' build executable file 'main' +# 'make' build executable file 'VideoConverter' # 'make clean' removes all .o and executable files # @@ -7,94 +7,43 @@ CXX = g++ # define any compile-time flags -CXXFLAGS := -std=c++17 -Wall -Wextra -g $(shell pkg-config --cflags gtk+-3.0) - -# 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 = +CXXFLAGS = -std=c++17 -Wall -Wextra -g # define output directory -OUTPUT := output +OUTPUT = output # define source directory -SRC := src +SRC = src -# define include directory -INCLUDE := include - -# 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 main executable name +MAIN = VideoConverter # define the C source files -SOURCES := $(wildcard $(patsubst %,%/*.cpp, $(SOURCEDIRS))) +SOURCES = $(wildcard $(SRC)/*.cpp) # define the C object files -OBJECTS := $(SOURCES:.cpp=.o) +OBJECTS = $(SOURCES:.cpp=.o) -# define the dependency output files -DEPS := $(OBJECTS:.o=.d) +OUTPUTMAIN = $(OUTPUT)/$(MAIN) -# -# The following part of the makefile is generic; it can be used to -# 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) +all: $(OUTPUT) $(OUTPUTMAIN) + @echo "Building executable: $(MAIN)" @echo Executing 'all' complete! $(OUTPUT): - $(MD) $(OUTPUT) + mkdir -p $(OUTPUT) -$(MAIN): $(OBJECTS) - $(CXX) $(CXXFLAGS) $(INCLUDES) -o $(OUTPUTMAIN) $(OBJECTS) $(LFLAGS) $(LIBS) - -# 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 $@ +$(OUTPUTMAIN): $(OBJECTS) + $(CXX) $(CXXFLAGS) -o $(OUTPUTMAIN) $(OBJECTS) .PHONY: clean clean: - $(RM) $(OUTPUTMAIN) - $(RM) $(call FIXPATH,$(OBJECTS)) - $(RM) $(call FIXPATH,$(DEPS)) + @echo "Cleaning up..." + rm -f $(OUTPUTMAIN) + rm -f $(OBJECTS) @echo Cleanup complete! run: all + @echo "Running executable: $(OUTPUTMAIN)" ./$(OUTPUTMAIN) @echo Executing 'run: all' complete! diff --git a/src/main.cpp b/src/main.cpp index 75de2bb..4896bfe 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,167 +1,60 @@ #include #include -#include -#include -#include #include -#include +#include class VideoConverter { private: - std::string input_file; - std::string output_file; - std::atomic 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(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("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(static_cast(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("Video conversion completed successfully")); - } else { - gdk_threads_add_idle(G_SOURCE_FUNC(show_error_wrapper), - const_cast("Error occurred during video conversion")); - } - } - - static gboolean update_progress_wrapper(gpointer data) { - auto *converter = static_cast(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(data); - VideoConverter::show_message_dialog(GTK_MESSAGE_ERROR, message); - return FALSE; - } - - static gboolean show_success_wrapper(gpointer data) { - auto *message = static_cast(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); - } + bool conversionInProgress; public: - VideoConverter() : conversion_in_progress(false) {} + VideoConverter() : conversionInProgress(false) {} - void create_window() { - window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_title(GTK_WINDOW(window), "Video Converter"); - gtk_container_set_border_width(GTK_CONTAINER(window), 10); + void startConversion(const std::string &inputFile, const std::string &outputFile) { + if (conversionInProgress) { + std::cerr << "Error: Conversion already in progress." << std::endl; + return; + } - GtkWidget *grid = gtk_grid_new(); - gtk_container_add(GTK_CONTAINER(window), grid); + if (inputFile.empty() || outputFile.empty()) { + std::cerr << "Error: Please enter both input and output file names." << std::endl; + return; + } - GtkWidget *input_label = gtk_label_new("Input File:"); - gtk_grid_attach(GTK_GRID(grid), input_label, 0, 0, 1, 1); + conversionInProgress = true; + std::cout << "Starting conversion..." << std::endl; - input_entry = gtk_entry_new(); - gtk_grid_attach(GTK_GRID(grid), input_entry, 1, 0, 1, 1); + std::thread conversionThread([this, inputFile, outputFile]() { + 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:"); - gtk_grid_attach(GTK_GRID(grid), output_label, 0, 1, 1, 1); + if (result == 0) { + 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(); - 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); + conversionThread.detach(); // Detach the thread to allow it to run independently } }; -int main(int argc, char *argv[]) { - gtk_init(&argc, &argv); - +int main() { 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; }