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
|
*.exe
|
||||||
*.out
|
*.out
|
||||||
*.app
|
*.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
|
# '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!
|
||||||
|
|||||||
183
src/main.cpp
183
src/main.cpp
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user