Skip to content

Commit

Permalink
add feature: merge video & audio to a new video
Browse files Browse the repository at this point in the history
  • Loading branch information
taseikyo committed Dec 20, 2019
1 parent 860bbc9 commit 033dd73
Show file tree
Hide file tree
Showing 8 changed files with 197 additions and 32 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ A simple [Cat Calendar](cat-calendar) image generator that uses the "www.dutanga

### FFmpeg Helper

[FFmpeg Helper](ffmpeg-helper) is a FFmpeg-based tool to cut/merge video and extract audio from the video.
[FFmpeg Helper](ffmpeg-helper) is a FFmpeg-based tool to cut/merge video, extract audio from the video and merge video & audio to new video.

<div align="center">
<img src="images/ffmpeg-helper.gif" alt="FFmpeg Helper" title="FFmpeg Helper" />
Expand Down
9 changes: 8 additions & 1 deletion ffmpeg-helper/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## FFmpeg Helper

a FFmpeg-based tool to cut/merge video and extract audio from the video.
a FFmpeg-based tool to cut/merge video, extract audio from the video and merge video & audio to new video.

### cut video

Expand All @@ -14,3 +14,10 @@ mode:
<img src="../images/ffmpeg-helper.gif" alt="FFmpeg Helper" title="FFmpeg Helper" />
</div>

### extract audio

extract audio from a video

### merge video & audio

merge video & audio to a new video
5 changes: 0 additions & 5 deletions ffmpeg-helper/ffmpeg-helper/mwin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,3 @@ MWin::~MWin()
{
delete ui;
}

void MWin::on_duration_check_stateChanged(int arg1)
{

}
3 changes: 0 additions & 3 deletions ffmpeg-helper/ffmpeg-helper/mwin.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@ class MWin : public QMainWindow
explicit MWin(QWidget *parent = nullptr);
~MWin();

private slots:
void on_duration_check_stateChanged(int arg1);

private:
Ui::MWin *ui;
};
Expand Down
88 changes: 83 additions & 5 deletions ffmpeg-helper/ffmpeg-helper/mwin.ui
Original file line number Diff line number Diff line change
Expand Up @@ -226,11 +226,14 @@
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>Merge</string>
<string>Merge Videos</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QTableWidget" name="tableWidget">
<widget class="QTableWidget" name="merge_video_table">
<property name="acceptDrops">
<bool>false</bool>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
Expand Down Expand Up @@ -261,7 +264,82 @@
</spacer>
</item>
<item>
<widget class="QToolButton" name="select_files_btn">
<widget class="QToolButton" name="select_video_files_btn">
<property name="minimumSize">
<size>
<width>85</width>
<height>0</height>
</size>
</property>
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="text">
<string>Select Files</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="start_merge_video_btn">
<property name="minimumSize">
<size>
<width>85</width>
<height>0</height>
</size>
</property>
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="text">
<string>Merge</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_3">
<attribute name="title">
<string>Merge V/A</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QTableWidget" name="merge_va_table">
<property name="acceptDrops">
<bool>false</bool>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="columnCount">
<number>0</number>
</property>
<attribute name="horizontalHeaderStretchLastSection">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_7">
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="select_va_files_btn">
<property name="minimumSize">
<size>
<width>85</width>
Expand All @@ -277,7 +355,7 @@
</widget>
</item>
<item>
<widget class="QToolButton" name="start_merge_btn">
<widget class="QToolButton" name="start_merge_va_btn">
<property name="minimumSize">
<size>
<width>85</width>
Expand Down Expand Up @@ -307,4 +385,4 @@
<include location="res.qrc"/>
</resources>
<connections/>
</ui>
</ui>
122 changes: 105 additions & 17 deletions ffmpeg-helper/src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,20 @@
DURATION_MODE = 0
ENDTIME_MODE = 1

ALLOW_VIDEO_TYPE = ["mp4", "avi", "mkv", "ts", "rmvb", "rm", "mov"]
ALLOW_AUDIO_TYPE = ["m4a", "mp3", "acc", "wav", "flac"]


class MWin(QMainWindow, Ui_MWin):
def __init__(self, parent=None):
super(MWin, self).__init__(parent)
self.setupUi(self)

self.cut_file_path = ""
self.merge_files_path = ""
self.merge_files_path = []

self.merge_video_path = ""
self.merge_audio_path = ""

self.mode = DURATION_MODE

Expand All @@ -38,7 +44,12 @@ def __init__(self, parent=None):
self.setAcceptDrops(True)

def dragEnterEvent(self, e):
allow_type = ["mp4", "avi", "mkv", "ts", "rmvb", "rm", "mov"]
# tab1 and tab2 only accept video while tab3 accepts video and audio
allow_type = (
ALLOW_VIDEO_TYPE
if self.tabWidget.currentIndex() in (0, 1)
else ALLOW_VIDEO_TYPE + ALLOW_AUDIO_TYPE
)
_, ext = os.path.splitext(e.mimeData().text())
if ext[1:] in allow_type:
e.accept()
Expand All @@ -48,9 +59,35 @@ def dragEnterEvent(self, e):
def dropEvent(self, e):
# e.mimeData().text() = file:///F:videio/xxx.mp4
filename = e.mimeData().text()[8:]
self.cut_file_path = filename
self.filename_label.setText(os.path.basename(filename))
self.log_edit.setPlainText("")
tab_index = self.tabWidget.currentIndex()
if tab_index == 0:
self.cut_file_path = filename
self.filename_label.setText(os.path.basename(filename))
self.log_edit.setPlainText("")
elif tab_index == 1:
row = self.merge_video_table.rowCount()
if row == 0:
self.merge_video_table.setRowCount(0)
self.merge_video_table.setColumnCount(1)
self.merge_video_table.setHorizontalHeaderLabels(["Merge Filenames"])
self.merge_video_table.horizontalHeader().setStretchLastSection(True)
self.merge_files_path.append(filename)
self.merge_video_table.insertRow(row)
self.merge_video_table.setItem(row, 0, QTableWidgetItem(filename))
else:
row = self.merge_va_table.rowCount()
if row == 0:
self.merge_va_table.setRowCount(0)
self.merge_va_table.setColumnCount(1)
self.merge_va_table.setHorizontalHeaderLabels(["Merge Filenames"])
self.merge_va_table.horizontalHeader().setStretchLastSection(True)
self.merge_va_table.insertRow(row)
self.merge_va_table.setItem(row, 0, QTableWidgetItem(filename))
_, ext = os.path.splitext(filename)
if ext[1:] in ALLOW_AUDIO_TYPE:
self.merge_audio_path = filename
else:
self.merge_video_path = filename

@pyqtSlot()
def on_select_file_btn_clicked(self):
Expand Down Expand Up @@ -150,27 +187,27 @@ def time_interval_check(self, time_start, time_end):
return start < end

@pyqtSlot()
def on_select_files_btn_clicked(self):
def on_select_video_files_btn_clicked(self):
files, ok = QFileDialog.getOpenFileNames(
self, "choose file", ".", "MP4 Files (*.mp4)"
self, "choose file", "", "MP4 Files (*.mp4)"
)
if not ok:
return
self.merge_files_path = files

self.tableWidget.clearContents()
self.tableWidget.setRowCount(0)
self.tableWidget.setColumnCount(1)
self.tableWidget.setHorizontalHeaderLabels(["Merge Filenames"])
self.tableWidget.horizontalHeader().setStretchLastSection(True)
self.merge_video_table.clearContents()
self.merge_video_table.setRowCount(0)
self.merge_video_table.setColumnCount(1)
self.merge_video_table.setHorizontalHeaderLabels(["Merge Filenames"])
self.merge_video_table.horizontalHeader().setStretchLastSection(True)

for x in range(len(files)):
self.tableWidget.insertRow(x)
self.merge_video_table.insertRow(x)
print(files[x])
self.tableWidget.setItem(x, 0, QTableWidgetItem(files[x]))
self.merge_video_table.setItem(x, 0, QTableWidgetItem(files[x]))

@pyqtSlot()
def on_start_merge_btn_clicked(self):
def on_start_merge_video_btn_clicked(self):
if not self.merge_files_path or len(self.merge_files_path) < 2:
return

Expand Down Expand Up @@ -202,8 +239,8 @@ def on_start_merge_btn_clicked(self):
os.remove(f"{ts_files[0]}_merge.mp4")
return

# for x in ts_files:
# os.remove(x)
for x in ts_files:
os.remove(x)

os.chdir(cwd)

Expand All @@ -218,6 +255,57 @@ def log_display(self, text):
def error_handler(self, emsg):
QMessageBox.warning(self, "FFmpeg Helper", emsg, QMessageBox.Ok)

@pyqtSlot()
def on_select_va_files_btn_clicked(self):
files, ok = QFileDialog.getOpenFileNames(self, "choose file", "", "*")
if not ok:
return

self.merge_video_path = ""
self.merge_audio_path = ""

self.merge_va_table.clearContents()
self.merge_va_table.setRowCount(0)
self.merge_va_table.setColumnCount(1)
self.merge_va_table.setHorizontalHeaderLabels(["Merge Filenames"])
self.merge_va_table.horizontalHeader().setStretchLastSection(True)

for x in range(len(files)):
self.merge_va_table.insertRow(x)
print(files[x])
self.merge_va_table.setItem(x, 0, QTableWidgetItem(files[x]))

@pyqtSlot()
def on_start_merge_va_btn_clicked(self):
if self.merge_va_table.rowCount() < 2:
return

if self.merge_video_path and self.merge_audio_path:
self.merge_video_audio()

for x in range(self.merge_va_table.rowCount()):
file = self.merge_va_table.item(x, 0).text()
_, ext = os.path.splitext(file)
if ext[1:] in ALLOW_AUDIO_TYPE:
self.merge_audio_path = file
elif ext[1:] in ALLOW_VIDEO_TYPE:
self.merge_video_path = file

if self.merge_video_path and self.merge_audio_path:
self.merge_video_audio()
break

def merge_video_audio(self):
cmd = f'''mp4box.exe -add "{self.merge_video_path}#trackID=1:name=" -add "{self.merge_audio_path}#trackID=1:name=" -new "{self.merge_video_path}_merge.mp4"'''
print(cmd)
try:
with os.popen(cmd) as f:
print(f.read())
except Exception as e:
print(e)
os.remove(f"{self.merge_video_path}_merge.mp4")
return


class Cmder(QThread):
log = pyqtSignal(str)
Expand Down
Binary file added ffmpeg-helper/src/mp4box.exe
Binary file not shown.
Binary file modified images/ffmpeg-helper.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 033dd73

Please sign in to comment.