Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bunch of fixes #260

Open
wants to merge 43 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
ca712ad
Remove executable permissions from image
Nov 13, 2018
cb5fea1
Use dict.items()
Nov 13, 2018
e7260e1
Parse command arguments as list
Nov 13, 2018
7314f99
Improve type annotations
Nov 13, 2018
310e0f8
Fix regular expression for floating point time
Nov 13, 2018
14ba111
Chapter is optional in .vcp file
Nov 13, 2018
aac5d34
Add documentation and type annotations
Nov 18, 2018
abe6013
videoservice: Fix handling streams w/o codec_type
pmhahn Nov 10, 2019
17366cd
fix ffprobe parsing for keyframes
ratcashdev Dec 29, 2019
8321b11
Use float timecodes throughout smartcut
ratcashdev Dec 29, 2019
306f153
Fix: can't concat list and string
ratcashdev Dec 29, 2019
161931e
Bugfix: project file to include the media location
ratcashdev Dec 29, 2019
9f828cc
Revert "fix ffprobe parsing for keyframes"
ratcashdev Dec 30, 2019
98abe25
Add missing ffprobe argument for CSV output. This was lost in the con…
ratcashdev Dec 30, 2019
1ea25a5
Support for MPEG4 movies keyframes based on the dts_time information.
ratcashdev Dec 31, 2019
70256c4
Added TODO: process sub-streams in the smartcut process independently…
ratcashdev Dec 31, 2019
4668600
Bugfix: if the input stream has a .ts extension, lossless transcoding…
ratcashdev Dec 31, 2019
72f80b3
Bugfix: Don't re-encode segments during smartcut (especially middle o…
ratcashdev Jan 1, 2020
2d8aa6f
function to losslessly inject keyframes to cut-positions using ffmpeg…
ratcashdev Jan 1, 2020
f4382ac
Inject keyframes to CUT positions.
ratcashdev Jan 1, 2020
4b26643
Don't re-parse keyframes for every single segment. Keep it around for…
ratcashdev Jan 1, 2020
597e926
Bugfix: Smartcut START segment invalid duration.
ratcashdev Jan 1, 2020
64a53b1
Round timestamps to 6 decimals.
ratcashdev Jan 2, 2020
9378cfd
Use OUTPUT seeking (-i before -ss for ffmpeg). This radically improve…
ratcashdev Jan 2, 2020
57dec52
Logging improvement
ratcashdev Jan 2, 2020
b30bd59
Fix hardcoded FPS for keyframe injection
ratcashdev Jan 2, 2020
95a7b78
Bugfix: Use output seeking on both branch paths for CUT
ratcashdev Jan 4, 2020
d2b9267
Some minor improvements
pikim Feb 2, 2020
d7a67c6
Allow custom encoding options, copy by default
pikim Feb 2, 2020
9097871
Merge code from https://github.com/ozmartian/vidcutter/pull/251/commi…
pikim Feb 2, 2020
551069f
Merge code from https://github.com/ozmartian/vidcutter/pull/213/commi…
pikim Feb 2, 2020
b93d02f
Merge code from https://github.com/ozmartian/vidcutter/pull/203/commi…
pikim Feb 2, 2020
4336a22
Merge code from https://github.com/ozmartian/vidcutter/pull/183/commi…
pikim Feb 2, 2020
612e486
Merge code from https://github.com/ozmartian/vidcutter/pull/183/commi…
pikim Feb 2, 2020
9a97a31
Merge code from https://github.com/ozmartian/vidcutter/pull/183/commi…
pikim Feb 2, 2020
86065e7
Remove unused code
pikim Feb 2, 2020
ad8f8dd
Try using faster input seeking
pikim Feb 2, 2020
8315d47
Start endproc
pikim Feb 2, 2020
5216fd5
Switched to input seeking again, fixed bisectioning
pikim Feb 6, 2020
bfcf0b8
Use combined seeking as it is much faster
pikim Feb 6, 2020
6625b84
Improve h264 quality
pikim Feb 6, 2020
480d500
Replace verbosity level number with text
pikim Feb 9, 2020
c3aee10
Merge pull request #2 from ozmartian/master
pikim Dec 7, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file modified _build/InnoSetup/assets/SmallWizardImage.bmp
100755 → 100644
Empty file.
Empty file modified _build/InnoSetup/assets/WizModernImage.bmp
100755 → 100644
Empty file.
Empty file modified _build/InnoSetup/assets/WizModernImage.psd
100755 → 100644
Empty file.
Empty file modified _packaging/snap/snapcraft.yaml
100755 → 100644
Empty file.
Empty file modified vidcutter/images/_originals/clip-index-header.psd
100755 → 100644
Empty file.
Empty file modified vidcutter/images/_originals/dialog-backdrop-02.psd
100755 → 100644
Empty file.
Empty file modified vidcutter/images/_originals/dialog-backdrop.psd
100755 → 100644
Empty file.
Empty file modified vidcutter/images/_originals/player-buttons.psd
100755 → 100644
Empty file.
Empty file modified vidcutter/images/_originals/startup-backdrop.psd
100755 → 100644
Empty file.
Empty file modified vidcutter/images/_originals/vidcutter-dmg.png
100755 → 100644
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified vidcutter/images/arrow-left-on.png
100755 → 100644
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified vidcutter/images/arrow-left.png
100755 → 100644
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified vidcutter/images/arrow-right-on.png
100755 → 100644
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified vidcutter/images/arrow-right.png
100755 → 100644
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified vidcutter/images/dark/info-active.png
100755 → 100644
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified vidcutter/images/dark/info-hover.png
100755 → 100644
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified vidcutter/images/dark/info.png
100755 → 100644
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified vidcutter/images/dialog-backdrop.png
100755 → 100644
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified vidcutter/images/filmstrip-thumbs.png
100755 → 100644
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified vidcutter/images/handle-nothumbs.png
100755 → 100644
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified vidcutter/images/handle.png
100755 → 100644
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified vidcutter/images/light/info-active.png
100755 → 100644
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified vidcutter/images/light/info-hover.png
100755 → 100644
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified vidcutter/images/light/info.png
100755 → 100644
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified vidcutter/images/light/toolbar-end.png
100755 → 100644
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified vidcutter/images/light/toolbar-open.png
100755 → 100644
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified vidcutter/images/light/toolbar-pause.png
100755 → 100644
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified vidcutter/images/light/toolbar-play.png
100755 → 100644
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified vidcutter/images/light/toolbar-save.png
100755 → 100644
Empty file modified vidcutter/images/light/toolbar-start.png
100755 → 100644
Empty file modified vidcutter/images/startup-backdrop.jpg
100755 → 100644
23 changes: 12 additions & 11 deletions vidcutter/libs/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#######################################################################

from enum import Enum
from typing import Dict, List

from PyQt5.QtCore import QSize

Expand All @@ -40,41 +41,41 @@ def filter_settings() -> Munch:
)

@property
def thumbnails(self) -> dict:
def thumbnails(self) -> Dict[str, QSize]:
return {'INDEX': QSize(100, 70), 'TIMELINE': QSize(105, 60)}

@property
def video_codecs(self) -> list:
def video_codecs(self) -> List[str]:
return ['flv', 'h263', 'libvpx', 'libx264', 'libx265', 'libxvid', 'mpeg2video', 'mpeg4', 'msmpeg4', 'wmv2']

@property
def audio_codecs(self) -> list:
def audio_codecs(self) -> List[str]:
return ['aac', 'ac3', 'libfaac', 'libmp3lame', 'libvo_aacenc', 'libvorbis', 'mp2', 'wmav2']

@property
def formats(self) -> list:
def formats(self) -> List[str]:
return [
'3g2', '3gp', 'aac', 'ac3', 'avi', 'dv', 'flac', 'flv', 'm4a', 'm4v', 'mka', 'mkv', 'mov', 'mp3',
'mp4', 'mpg', 'ogg', 'vob', 'wav', 'webm', 'wma', 'wmv'
]

@property
def mpeg_formats(self) -> list:
def mpeg_formats(self) -> List[str]:
return [
'h264', 'hevc', 'mpeg4', 'divx', 'xvid', 'webm', 'ivf', 'vp9', 'mpeg2video', 'mpg2', 'mp2', 'mp3',
'aac'
]

@property
def encoding(self) -> dict:
def encoding(self) -> Dict[str, List[str]]:
return {
'hevc': 'libx265 -tune zerolatency -preset ultrafast -x265-params crf=23 -qp 4 -flags +cgop',
'h264': 'libx264 -tune film -preset ultrafast -x264-params crf=23 -qp 0 -flags +cgop',
'vp9': 'libvpx-vp9 -deadline best -quality best'
'hevc': ['libx265', '-tune', 'zerolatency', '-preset', 'ultrafast', '-x265-params', 'crf=23', '-qp', '4', '-flags', '+cgop'],
'h264': ['libx264', '-tune', 'film', '-preset', 'ultrafast', '-x264-params', 'crf=18', '-qp', '0', '-flags', '+cgop'],
'vp9': ['libvpx-vp9', '-deadline', 'best', '-quality', 'best'],
}

@property
def binaries(self) -> dict:
def binaries(self) -> Dict[str, Dict[str, List[str]]]:
return {
'nt': { # Windows
'ffmpeg': ['ffmpeg.exe'],
Expand All @@ -89,7 +90,7 @@ def binaries(self) -> dict:
}

@property
def filters(self) -> dict:
def filters(self) -> Dict[str, List[str]]:
return {
'all': [
'3g2', '3gp', 'amv', 'asf', 'asx', 'avi', 'bin', 'dat', 'div', 'divx', 'f4v', 'flv',
Expand Down
418 changes: 303 additions & 115 deletions vidcutter/libs/videoservice.py

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion vidcutter/mediainfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def __init__(self, media, parent=None, flags=Qt.Dialog | Qt.WindowCloseButtonHin
okButton.accepted.connect(self.close)
button_layout = QHBoxLayout()
mediainfo_version = self.parent.videoService.cmdExec(self.parent.videoService.backends.mediainfo,
'--version', True)
['--version'], True)
if len(mediainfo_version) >= 2:
mediainfo_version = mediainfo_version.split('\n')[1]
mediainfo_label = QLabel('<div style="font-size:11px;"><b>Media information by:</b><br/>%s @ '
Expand Down
37 changes: 27 additions & 10 deletions vidcutter/videocutter.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ def __init__(self, parent: QMainWindow):
self.videoService.addScenes.connect(self.addScenes)

self.project_files = {
'edl': re.compile(r'(\d+(?:\.?\d+)?)\t(\d+(?:\.?\d+)?)\t([01])'),
'vcp': re.compile(r'(\d+(?:\.?\d+)?)\t(\d+(?:\.?\d+)?)\t([01])\t(".*")$')
'edl': re.compile(r'(\d+(?:\.\d+)?)\t(\d+(?:\.\d+)?)\t([01])'),
'vcp': re.compile(r'(\d+(?:\.\d+)?)\t(\d+(?:\.\d+)?)\t([01])(?:\t"(.*)")?$')
}

self._initIcons()
Expand Down Expand Up @@ -437,7 +437,7 @@ def __init__(self, parent: QMainWindow):
if sys.platform != 'darwin':
controlsLayout.addSpacing(5)

layout = QVBoxLayout()
layout = QVBoxLayout()
layout.setSpacing(0)
layout.setContentsMargins(10, 10, 10, 0)
layout.addLayout(self.videoLayout)
Expand Down Expand Up @@ -864,8 +864,7 @@ def openProject(self, checked: bool = False, project_file: str = None) -> Option
clip_start = self.delta2QTime(float(start))
clip_end = self.delta2QTime(float(stop))
clip_image = self.captureImage(self.currentMedia, clip_start)
if project_type == 'vcp' and self.createChapters and len(chapter):
chapter = chapter[1:len(chapter) - 1]
if project_type == 'vcp' and self.createChapters and chapter is not None:
if not len(chapter):
chapter = None
else:
Expand Down Expand Up @@ -941,19 +940,19 @@ def saveProject(self, reboot: bool = False) -> None:
'Cannot save project file at {0}:\n\n{1}'.format(project_save, file.errorString()))
return
qApp.setOverrideCursor(Qt.WaitCursor)
if ptype == 'VidCutter Project (*.vcp)':
if ptype == 'VidCutter Project (*.vcp)' or ptype == 'VidCutter Project':
# noinspection PyUnresolvedReferences
QTextStream(file) << '{}\n'.format(self.currentMedia)
for clip in self.clipTimes:
start_time = timedelta(hours=clip[0].hour(), minutes=clip[0].minute(), seconds=clip[0].second(),
milliseconds=clip[0].msec())
stop_time = timedelta(hours=clip[1].hour(), minutes=clip[1].minute(), seconds=clip[1].second(),
milliseconds=clip[1].msec())
if ptype == 'VidCutter Project (*.vcp)':
if ptype == 'VidCutter Project (*.vcp)' or ptype == 'VidCutter Project':
if self.createChapters:
chapter = '"{}"'.format(clip[4]) if clip[4] is not None else '""'
else:
chapter = ''
chapter = '""'
# noinspection PyUnresolvedReferences
QTextStream(file) << '{0}\t{1}\t{2}\t{3}\n'.format(self.delta2String(start_time),
self.delta2String(stop_time), 0, chapter)
Expand Down Expand Up @@ -1360,6 +1359,13 @@ def saveMedia(self) -> None:
self.videoService.smartinit(clips)
self.smartcutter(file, source_file, source_ext)
return
videoWithForcedKeyframes = f'{source_file}-forced{source_ext}'
self.videoService.forceKeyframes(
source='{0}{1}'.format(source_file, source_ext),
clipTimes=self.clipTimes,
fps=eval(self.videoService.streams.video.avg_frame_rate),
output=videoWithForcedKeyframes)

steps = 3 if clips > 1 else 2
self.seekSlider.showProgress(steps)
self.parent.lock_gui(True)
Expand All @@ -1375,7 +1381,8 @@ def saveMedia(self) -> None:
filename = os.path.join(self.workFolder, os.path.basename(filename))
filename = QDir.toNativeSeparators(filename)
filelist.append(filename)
if not self.videoService.cut(source='{0}{1}'.format(source_file, source_ext),
# if not self.videoService.cut(source='{0}{1}'.format(source_file, source_ext),
if not self.videoService.cut(source=videoWithForcedKeyframes,
output=filename,
frametime=clip[0].toString(self.timeformat),
duration=duration,
Expand All @@ -1391,6 +1398,13 @@ def saveMedia(self) -> None:

def smartcutter(self, file: str, source_file: str, source_ext: str) -> None:
self.smartcut_monitor = Munch(clips=[], results=[], externals=0)
videoWithForcedKeyframes = f'{source_file}-forced{source_ext}'
self.videoService.forceKeyframes(
source='{0}{1}'.format(source_file, source_ext),
clipTimes=self.clipTimes,
fps=eval(self.videoService.streams.video.avg_frame_rate),
output=videoWithForcedKeyframes)
keyframes = self.videoService.getKeyframes(videoWithForcedKeyframes)
for index, clip in enumerate(self.clipTimes):
if len(clip[3]):
self.smartcut_monitor.clips.append(clip[3])
Expand All @@ -1403,11 +1417,14 @@ def smartcutter(self, file: str, source_file: str, source_ext: str) -> None:
filename = os.path.join(self.workFolder, os.path.basename(filename))
filename = QDir.toNativeSeparators(filename)
self.smartcut_monitor.clips.append(filename)

# source='{0}{1}'.format(source_file, source_ext)
self.videoService.smartcut(index=index,
source='{0}{1}'.format(source_file, source_ext),
source=videoWithForcedKeyframes,
output=filename,
start=VideoCutter.qtime2delta(clip[0]),
end=VideoCutter.qtime2delta(clip[1]),
keyframes=keyframes,
allstreams=True)

@pyqtSlot(bool, str)
Expand Down