...
 
Commits (62)
......@@ -4,7 +4,7 @@
[Kdenlive](https://kdenlive.org) is a Free and Open Source video editing application, based on MLT Framework and KDE Frameworks 5. It is distributed under the GNU General Public Licence Version 2.
# Builing from source
# Building from source
[Instructions to build Kdenlive](https://community.kde.org/Kdenlive/Development) are available on the KDE wiki.
......
......@@ -262,7 +262,7 @@
</ul>
</description>
<releases>
<release date="2019-03-26" version="19.04.0"/>
<release date="2019-03-26" version="19.07.70"/>
</releases>
<url type="homepage">https://kdenlive.org/</url>
<url type="bugtracker">https://bugs.kde.org</url>
......
......@@ -108,6 +108,7 @@ add_subdirectory( ext_gdkpixbuf )
add_subdirectory( ext_gtk+ )
add_subdirectory( ext_gavl )
add_subdirectory( ext_frei0r )
add_subdirectory( ext_opencv )
add_subdirectory( ext_vidstab )
add_subdirectory( ext_mlt )
add_subdirectory( ext_ruby )
......
# Script to build OpenCV for digiKam bundle.
#
# Copyright (c) 2015-2017, Gilles Caulier, <caulier dot gilles at gmail dot com>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
#
set(EXTPREFIX_opencv "${EXTPREFIX}" )
set(Opencv_Conf -DBUILD_EXAMPLES=OFF
-DBUILD_TESTS=OFF
-DBUILD_DOCS=OFF
-DBUILD_PERF_TESTS=OFF
-DBUILD_NEW_PYTHON_SUPPORT=OFF
-BUILD_ZLIB=OFF
-DOPENCV_BUILD_3RDPARTY_LIBS=OFF
-DINSTALL_C_EXAMPLES=OFF
-DINSTALL_PYTHON_EXAMPLES=OFF
-DWITH_1394=OFF
-DWITH_VTK=OFF
-DWITH_CUDA=OFF
-DWITH_DIRECTX=OFF
-DWITH_DSHOW=OFF
-DWITH_EIGEN=OFF
-DWITH_FFMPEG=OFF
-DWITH_GSTREAMER=OFF
-DWITH_GTK=OFF
-DWITH_IPP=OFF
-DWITH_JASPER=OFF
-DWITH_JPEG=OFF
-DWITH_MATLAB=OFF
-DWITH_OPENEXR=OFF
-DWITH_OPENNI=OFF
-DWITH_PNG=OFF
-DWITH_PVAPI=OFF
-DWITH_WIN32UI=OFF
-DWITH_QT=OFF
-DWITH_QUICKTIME=OFF
-DWITH_QT_OPENGL=OFF
-DWITH_TBB=OFF
-DWITH_TIFF=OFF
-DWITH_UNICAP=OFF
-DWITH_V4L=OFF
-DWITH_VFW=OFF
-DWITH_VIDEOINPUT=OFF
-DWITH_XINE=OFF
-DWITH_OPENCL=OFF
-DWITH_GPHOTO2=OFF
-DBUILD_opencv_videoio=OFF
# The OpenCV contrib repo external project
ExternalProject_Add(
ext_opencv_contrib
DOWNLOAD_DIR ${EXT_DOWNLOAD_DIR}
URL https://github.com/opencv/opencv_contrib/archive/4.1.0.tar.gz
URL_MD5 5357a038f54ba15c771abb0d91a5519d
# This is a support repository for OpenCV 4.x and does not contain any
# build or install rules. This will be hooked into OpenCV which will control
# those steps.
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
)
JoinListAsString("${Opencv_Conf}" " " BASH_OPTIONS)
if(MINGW)
ExternalProject_Add(ext_opencv
URL https://github.com/Itseez/opencv/archive/3.2.0.zip
URL_MD5 bfc6a261eb069b709bcfe7e363ef5899
CMAKE_ARGS -DCMAKE_BUILD_TYPE=${GLOBAL_BUILD_TYPE}
-DCMAKE_TOOLCHAIN_FILE=${MXE_TOOLCHAIN}
-DCMAKE_INSTALL_PREFIX=${MXE_INSTALL_PREFIX}
-DCMAKE_BUILD_WITH_INSTALL_RPATH=ON
${GLOBAL_PROFILE}
${Opencv_Conf}
UPDATE_COMMAND ""
ALWAYS 0
)
ExternalProject_Add_step(ext_opencv before_download
# Note : under MXE, in case of curl is not compiled with https support,
# we cannot download the tarball as under Linux/MacOS.
# COMMAND wget -N https://github.com/Itseez/opencv/archive/3.2.0.zip -O ${EXTERNALS_DOWNLOAD_DIR}/3.2.0.zip
# DEPENDERS download
)
elseif(APPLE)
ExternalProject_Add(ext_opencv
DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR}
URL https://github.com/Itseez/opencv/archive/3.2.0.zip
URL_MD5 bfc6a261eb069b709bcfe7e363ef5899
CONFIGURE_COMMAND cp ${CMAKE_CURRENT_SOURCE_DIR}/../../../../bootstrap.macports <SOURCE_DIR>/. &&
<SOURCE_DIR>/bootstrap.macports ${EXTPREFIX_opencv} RelWithDebInfo x86_64 "${BASH_OPTIONS}"
BUILD_COMMAND cd <SOURCE_DIR>/build && $(MAKE)
INSTALL_COMMAND cd <SOURCE_DIR>/build && make install/fast
BUILD_IN_SOURCE 1
UPDATE_COMMAND ""
ALWAYS 0
)
else() #Linux
ExternalProject_Add(ext_opencv
DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR}
URL https://github.com/Itseez/opencv/archive/3.2.0.zip
URL_MD5 bfc6a261eb069b709bcfe7e363ef5899
INSTALL_DIR ${EXTPREFIX_opencv}
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${EXTPREFIX_opencv}
-DCMAKE_BUILD_TYPE=${GLOBAL_BUILD_TYPE}
${GLOBAL_PROFILE}
${Opencv_Conf}
UPDATE_COMMAND ""
ALWAYS 0
)
endif()
# The OpenCV external project
ExternalProject_Add(
ext_opencv
DOWNLOAD_DIR ${EXT_DOWNLOAD_DIR}
URL https://github.com/opencv/opencv/archive/4.1.0.tar.gz
URL_MD5 b80c59c7e4feee6a00608315e02b0b73
CMAKE_ARGS ${CMAKE_GLOBAL_PROFILE} -DOPENCV_EXTRA_MODULES_PATH=${EXT_BUILD_DIR}/deps-build/ext_opencv/ext_opencv_contrib-prefix/src/ext_opencv_contrib/modules -DOPENCV_GENERATE_PKGCONFIG=ON
DEPENDS ext_opencv_contrib
)
......@@ -63,7 +63,7 @@ fi
cd $BUILD_PREFIX/deps-build/
# Configure the dependencies for building
cmake $KDENLIVE_SOURCES/packaging/appimage/3rdparty -DCMAKE_INSTALL_PREFIX=$DEPS_INSTALL_PREFIX -DEXT_INSTALL_DIR=$DEPS_INSTALL_PREFIX -DEXT_DOWNLOAD_DIR=$DOWNLOADS_DIR
cmake $KDENLIVE_SOURCES/packaging/appimage/3rdparty -DCMAKE_INSTALL_PREFIX=$DEPS_INSTALL_PREFIX -DEXT_INSTALL_DIR=$DEPS_INSTALL_PREFIX -DEXT_DOWNLOAD_DIR=$DOWNLOADS_DIR -DEXT_BUILD_DIR=$BUILD_PREFIX
# Now start building everything we need, in the appropriate order
......@@ -118,13 +118,12 @@ cmake --build . --target ext_gtk+
cmake --build . --target ext_gavl
cmake --build . --target ext_frei0r
cmake --build . --target ext_vidstab
#cmake --build . --target ext_opencv
cmake --build . --target ext_opencv
#export CC=/usr/bin/gcc-6
#export CXX=/usr/bin/g++-6
#cmake --build . --target ext_movit
cmake --build . --target ext_mlt
cmake --build . --target ext_kbookmarks
cmake --build . --target ext_kxmlgui
cmake --build . --target ext_kconfigwidgets
......
......@@ -272,13 +272,43 @@ bool TimelineFunctions::requestSpacerEndOperation(const std::shared_ptr<Timeline
return false;
}
bool TimelineFunctions::breakAffectedGroups(const std::shared_ptr<TimelineItemModel> &timeline, QVector<int> tracks, QPoint zone, Fun &undo, Fun &redo)
{
// Check if we have grouped clips that are on unaffected tracks, and ungroup them
bool result = true;
std::unordered_set<int> affectedItems;
// First find all affected items
for (int &trackId : tracks) {
std::unordered_set<int> items = timeline->getItemsInRange(trackId, zone.x(), zone.y());
affectedItems.insert(items.begin(), items.end());
}
for (int item : affectedItems) {
if (timeline->m_groups->isInGroup(item)) {
int groupId = timeline->m_groups->getRootId(item);
std::unordered_set<int> all_children = timeline->m_groups->getLeaves(groupId);
for (int child: all_children) {
int childTrackId = timeline->getItemTrackId(child);
if (!tracks.contains(childTrackId)) {
// This item should not be affected by the operation, ungroup it
result = result && timeline->requestClipUngroup(child, undo, redo);
}
}
}
}
return result;
}
bool TimelineFunctions::extractZone(const std::shared_ptr<TimelineItemModel> &timeline, QVector<int> tracks, QPoint zone, bool liftOnly)
{
// Start undoable command
std::function<bool(void)> undo = []() { return true; };
std::function<bool(void)> redo = []() { return true; };
bool result = true;
for (int trackId : tracks) {
result = breakAffectedGroups(timeline, tracks, zone, undo, redo);
for (int &trackId : tracks) {
if (timeline->getTrackById_const(trackId)->isLocked()) {
continue;
}
......@@ -298,37 +328,36 @@ bool TimelineFunctions::insertZone(const std::shared_ptr<TimelineItemModel> &tim
std::function<bool(void)> undo = []() { return true; };
std::function<bool(void)> redo = []() { return true; };
bool result = true;
QVector<int> affectedTracks;
auto it = timeline->m_allTracks.cbegin();
while (it != timeline->m_allTracks.cend()) {
int target_track = (*it)->getId();
if (!trackIds.contains(target_track) && !timeline->getTrackById_const(target_track)->shouldReceiveTimelineOp()) {
++it;
continue;
}
affectedTracks << target_track;
++it;
}
result = breakAffectedGroups(timeline, affectedTracks, QPoint(insertFrame, insertFrame + (zone.y() - zone.x())), undo, redo);
if (overwrite) {
// Cut all tracks
auto it = timeline->m_allTracks.cbegin();
while (it != timeline->m_allTracks.cend()) {
int target_track = (*it)->getId();
if (!trackIds.contains(target_track) && !timeline->getTrackById_const(target_track)->shouldReceiveTimelineOp()) {
++it;
continue;
}
for (int target_track : affectedTracks) {
result = result && TimelineFunctions::liftZone(timeline, target_track, QPoint(insertFrame, insertFrame + (zone.y() - zone.x())), undo, redo);
if (!result) {
qDebug() << "// LIFTING ZONE FAILED\n";
break;
}
++it;
}
} else {
// Cut all tracks
auto it = timeline->m_allTracks.cbegin();
while (it != timeline->m_allTracks.cend()) {
int target_track = (*it)->getId();
if (!trackIds.contains(target_track) && !timeline->getTrackById_const(target_track)->shouldReceiveTimelineOp()) {
++it;
continue;
}
for (int target_track : affectedTracks) {
int startClipId = timeline->getClipByPosition(target_track, insertFrame);
if (startClipId > -1) {
// There is a clip, cut it
result = result && TimelineFunctions::requestClipCut(timeline, startClipId, insertFrame, undo, redo);
}
++it;
}
result = result && TimelineFunctions::requestInsertSpace(timeline, QPoint(insertFrame, insertFrame + (zone.y() - zone.x())), undo, redo);
}
......
......@@ -119,6 +119,10 @@ struct TimelineFunctions
*/
static int getOffsetTrackId(const std::shared_ptr<TimelineItemModel> &timeline, int startTrack, int offset, bool audioOffset);
static QPair<QList<int>, QList<int>> getAVTracksIds(const std::shared_ptr<TimelineItemModel> &timeline);
/** @brief This function breaks group is an item in the zone is grouped with an item outside of selected tracks
*/
static bool breakAffectedGroups(const std::shared_ptr<TimelineItemModel> &timeline, QVector<int> tracks, QPoint zone, Fun &undo, Fun &redo);
};
#endif
......@@ -136,19 +136,19 @@ public:
IsAudioRole,
SortRole,
ShowKeyframesRole,
AudioLevelsRole, /// clip only
AudioChannelsRole, /// clip only
IsCompositeRole, /// track only
IsLockedRole, /// track only
HeightRole, /// track only
TrackTagRole, /// track only
FadeInRole, /// clip only
FadeOutRole, /// clip only
FileHashRole, /// clip only
SpeedRole, /// clip only
ReloadThumbRole, /// clip only
PositionOffsetRole,/// clip only
ItemATrack, /// composition only
AudioLevelsRole, /// clip only
AudioChannelsRole, /// clip only
IsCompositeRole, /// track only
IsLockedRole, /// track only
HeightRole, /// track only
TrackTagRole, /// track only
FadeInRole, /// clip only
FadeOutRole, /// clip only
FileHashRole, /// clip only
SpeedRole, /// clip only
ReloadThumbRole, /// clip only
PositionOffsetRole, /// clip only
ItemATrack, /// composition only
ItemIdRole,
ThumbsFormatRole, /// track only
EffectNamesRole, // track and clip only
......@@ -439,6 +439,8 @@ public:
@param right is true if we change the right side of the item, false otherwise
@param logUndo if set to true, an undo object is created
@param snap if set to true, the resize order will be coerced to use the snapping grid
if @param allowSingleResize is false, then the resize will also be applied to any clip in the same AV group (allow resizing audio and video at the same
time)
*/
Q_INVOKABLE int requestItemResize(int itemId, int size, bool right, bool logUndo = true, int snapDistance = -1, bool allowSingleResize = false);
......
......@@ -1470,7 +1470,7 @@ void TimelineController::extract(int clipId)
int in = m_model->getClipPosition(clipId);
QPoint zone(in, in + m_model->getClipPlaytime(clipId));
int track = m_model->getClipTrackId(clipId);
TimelineFunctions::extractZone(m_model, QVector<int>() << track, zone, false);
TimelineFunctions::extractZone(m_model, {track}, zone, false);
}
bool TimelineController::insertClipZone(const QString &binId, int tid, int position)
......
......@@ -228,6 +228,70 @@ TEST_CASE("Clip manipulation", "[ClipModel]")
timeline->m_allClips[cid3]->m_endlessResize = false;
timeline->m_allClips[cid4]->m_endlessResize = false;
SECTION("Endless clips can be resized both sides")
{
timeline->m_allClips[cid1]->m_endlessResize = true;
REQUIRE(timeline->checkConsistency());
REQUIRE(timeline->getTrackClipsCount(tid1) == 0);
REQUIRE(timeline->getTrackClipsCount(tid2) == 0);
int l = timeline->getClipPlaytime(cid1);
// try resizing uninserted clip
REQUIRE(timeline->requestItemResize(cid1, l + 2, false) == l + 2);
REQUIRE(timeline->getClipPlaytime(cid1) == l + 2);
undoStack->undo();
REQUIRE(timeline->getClipPlaytime(cid1) == l);
undoStack->redo();
REQUIRE(timeline->getClipPlaytime(cid1) == l + 2);
undoStack->undo();
REQUIRE(timeline->getClipPlaytime(cid1) == l);
REQUIRE(timeline->requestItemResize(cid1, 3 * l, true) == 3 * l);
REQUIRE(timeline->getClipPlaytime(cid1) == 3 * l);
undoStack->undo();
REQUIRE(timeline->getClipPlaytime(cid1) == l);
undoStack->redo();
REQUIRE(timeline->getClipPlaytime(cid1) == 3 * l);
undoStack->undo();
REQUIRE(timeline->getClipPlaytime(cid1) == l);
// try resizing inserted clip
int pos = 10;
REQUIRE(timeline->requestClipMove(cid1, tid1, pos));
auto state = [&](int s, int p) {
REQUIRE(timeline->checkConsistency());
REQUIRE(timeline->getClipTrackId(cid1) == tid1);
REQUIRE(timeline->getClipPosition(cid1) == p);
REQUIRE(timeline->getTrackClipsCount(tid1) == 1);
REQUIRE(timeline->getTrackClipsCount(tid2) == 0);
REQUIRE(timeline->getClipPlaytime(cid1) == s);
};
state(l, pos);
// too big
REQUIRE(timeline->requestItemResize(cid1, l + pos + 2, false) == -1);
REQUIRE(timeline->requestItemResize(cid1, l + 2, false) == l + 2);
state(l + 2, pos - 2);
undoStack->undo();
state(l, pos);
undoStack->redo();
state(l + 2, pos - 2);
undoStack->undo();
state(l, pos);
REQUIRE(timeline->requestItemResize(cid1, 3 * l, true) == 3 * l);
state(3 * l, pos);
undoStack->undo();
state(l, pos);
undoStack->redo();
state(3 * l, pos);
undoStack->undo();
state(l, pos);
}
SECTION("Insert a clip in a track and change track")
{
REQUIRE(timeline->checkConsistency());
......
......@@ -80,12 +80,15 @@ TEST_CASE("Advanced trimming operations", "[Trimming]")
};
state();
// require cut position outside the clip
REQUIRE_FALSE(TimelineFunctions::requestClipCut(timeline, cid2, 0));
REQUIRE_FALSE(TimelineFunctions::requestClipCut(timeline, cid2, 5 * l));
// can't cut on edges either
REQUIRE_FALSE(TimelineFunctions::requestClipCut(timeline, cid2, l));
REQUIRE_FALSE(TimelineFunctions::requestClipCut(timeline, cid2, l + l - 5));
// require cut position outside the clip. Should return true and nothing is done
REQUIRE(TimelineFunctions::requestClipCut(timeline, cid2, 0));
state();
REQUIRE(TimelineFunctions::requestClipCut(timeline, cid2, 5 * l));
state();
// cut on edges doesn't do anything either
REQUIRE(TimelineFunctions::requestClipCut(timeline, cid2, l));
state();
REQUIRE(TimelineFunctions::requestClipCut(timeline, cid2, l + l - 5));
state();
REQUIRE(TimelineFunctions::requestClipCut(timeline, cid2, l + 4));
......@@ -213,10 +216,11 @@ TEST_CASE("Advanced trimming operations", "[Trimming]")
};
state();
REQUIRE_FALSE(TimelineFunctions::requestClipCut(timeline, cid2, 0));
REQUIRE_FALSE(TimelineFunctions::requestClipCut(timeline, cid2, 5 * l));
REQUIRE_FALSE(TimelineFunctions::requestClipCut(timeline, cid2, l));
REQUIRE_FALSE(TimelineFunctions::requestClipCut(timeline, cid2, 2 * l));
// These functions will return true but do nothing
REQUIRE(TimelineFunctions::requestClipCut(timeline, cid2, 0));
REQUIRE(TimelineFunctions::requestClipCut(timeline, cid2, 5 * l));
REQUIRE(TimelineFunctions::requestClipCut(timeline, cid2, l));
REQUIRE(TimelineFunctions::requestClipCut(timeline, cid2, 2 * l));
state();
REQUIRE(TimelineFunctions::requestClipCut(timeline, cid2, l + 4));
......