mirror of
https://github.com/tkmxqrdxddd/davinci-video-converter
synced 2025-11-08 18:45:05 +01:00
edit
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -30,4 +30,5 @@
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
.output
|
||||
/output
|
||||
/.qtcreator
|
||||
|
||||
87
Makefile
87
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!
|
||||
|
||||
183
src/main.cpp
183
src/main.cpp
@@ -1,167 +1,60 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <cstdlib>
|
||||
#include <stdexcept>
|
||||
#include <gtk/gtk.h>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <cstdlib>
|
||||
|
||||
class VideoConverter {
|
||||
private:
|
||||
std::string input_file;
|
||||
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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user