File indexing completed on 2024-12-22 04:14:55

0001 /*
0002  *  SPDX-FileCopyrightText: 2020 Dmitrii Utkin <loentar@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: LGPL-2.1-only
0005  */
0006 
0007 #include "recorder_export_config.h"
0008 
0009 #include <kis_config.h>
0010 
0011 #include <QString>
0012 #include <QDir>
0013 
0014 namespace
0015 {
0016 const QString keyAnimationExport = "ANIMATION_EXPORT";
0017 const QString keyFfmpegPath = "ffmpeg_path";
0018 const QString keyVideoDirectory = "recorder_export/videodirectory";
0019 const QString keyInputFps = "recorder_export/inputfps";
0020 const QString keyFps = "recorder_export/fps";
0021 const QString keyResultPreview="recorder_export/resultpreview";
0022 const QString keyFirstFrameSec = "recorder_export/firstframesec";
0023 const QString keyExtendResult = "recorder_export/extendresult";
0024 const QString keyLastFrameSec = "recorder_export/lastframesec";
0025 const QString keyResize = "recorder_export/resize";
0026 const QString keySize = "recorder_export/size";
0027 const QString keyLockRatio = "recorder_export/lockratio";
0028 const QString keyLockFps = "recorder_export/lockfps";
0029 const QString keyProfileIndex = "recorder_export/profileIndex";
0030 const QString keyProfiles = "recorder_export/profiles";
0031 const QString keyEditedProfiles = "recorder_export/editedprofiles";
0032 
0033 const QString profilePrefix = "-framerate $IN_FPS\n-i \"$INPUT_DIR%07d.$EXT\"\n-framerate $IN_FPS\n-start_number $FRAMES-1\n-i \"$INPUT_DIR%07d.$EXT\"\n";
0034 
0035 const QList<RecorderProfile> defaultProfiles = {
0036     { "MP4 x264",   "mp4",  profilePrefix % "-filter_complex \"\n"
0037       /* Filter documentation https://trac.ffmpeg.org/wiki/FilteringGuide
0038        * Inside the complex filter command each line is a different filter that is applied to an input stream.
0039        * The input stream to transform is specified at the start of each line in the format '[$STREAM_NAME]' (ex. [p1], [v1], [v2]).
0040        * Immediatly following the input stream name will be the filter to apply (ex: trim, scale, loop)
0041        * Depending on the filter it may or may have various options set
0042        * After all options for the filter a name can be specified that will correspond to the output stream of the filter. If no name is specified it will be used as the final result for the output file.
0043        */
0044                                             " [0]loop=$LAST_FRAME_SEC*$IN_FPS:size=1:start=$FRAMES[main1];\n"
0045                                             " [main1]scale=$WIDTH:$HEIGHT[main2];\n"
0046                                             " [main2]loop=1:size=1:start=0[main3];\n"
0047                                             " [main3]setpts=PTS-STARTPTS[main4];\n"
0048 
0049                                             " [1]split [first1][transition1];\n"
0050                                             " [transition1]scale=$WIDTH:$HEIGHT [transition2];\n"
0051                                             " [transition2]loop='if(gte($FIRST_FRAME_SEC, 1), 1*$IN_FPS, 0)':size=1:start=1[transition3];\n"
0052                                             " [transition3]setpts=PTS-STARTPTS[transition4];\n"
0053 
0054                                             " [transition4][main4]xfade=transition=smoothright:duration=0.5:offset=0[v1];\n"
0055                                             " [v1]setpts=PTS-STARTPTS[v2];\n"
0056                                             " [v2]trim=start_frame=1[v3];\n"
0057 
0058                                             " [first1]loop='if(gte($FIRST_FRAME_SEC, 1), ($FIRST_FRAME_SEC*$IN_FPS) - 0.5*$IN_FPS, $FIRST_FRAME_SEC*$IN_FPS)':size=1:start=1[preview1];\n"
0059                                             " [preview1]scale=$WIDTH:$HEIGHT[preview2];\n"
0060                                             " [preview2]setpts=PTS-STARTPTS[preview3];\n"
0061                                             " [preview3][v3] concat [final1];\n"
0062                                             " [final1] setpts=PTS-STARTPTS[final2];\n"
0063                                             " [final2] trim=start_frame=1\n"
0064 
0065                                             "\"\n-c:v libx264\n-r $OUT_FPS\n-pix_fmt yuv420p" },
0066     { "MP4 openh264",   "mp4",  profilePrefix % "-filter_complex \"\n"
0067                                         /* Filter documentation https://trac.ffmpeg.org/wiki/FilteringGuide
0068                                          * Inside the complex filter command each line is a different filter that is applied to an input stream.
0069                                          * The input stream to transform is specified at the start of each line in the format '[$STREAM_NAME]' (ex. [p1], [v1], [v2]).
0070                                          * Immediatly following the input stream name will be the filter to apply (ex: trim, scale, loop)
0071                                          * Depending on the filter it may or may have various options set
0072                                          * After all options for the filter a name can be specified that will correspond to the output stream of the filter. If no name is specified it will be used as the final result for the output file.
0073                                          */
0074                                         " [0]loop=$LAST_FRAME_SEC*$IN_FPS:size=1:start=$FRAMES[main1];\n"
0075                                         " [main1]scale=$WIDTH:$HEIGHT[main2];\n"
0076                                         " [main2]loop=1:size=1:start=0[main3];\n"
0077                                         " [main3]setpts=PTS-STARTPTS[main4];\n"
0078 
0079                                         " [1]split [first1][transition1];\n"
0080                                         " [transition1]scale=$WIDTH:$HEIGHT [transition2];\n"
0081                                         " [transition2]loop='if(gte($FIRST_FRAME_SEC, 1), 1*$IN_FPS, 0)':size=1:start=1[transition3];\n"
0082                                         " [transition3]setpts=PTS-STARTPTS[transition4];\n"
0083 
0084                                         " [transition4][main4]xfade=transition=smoothright:duration=0.5:offset=0[v1];\n"
0085                                         " [v1]setpts=PTS-STARTPTS[v2];\n"
0086                                         " [v2]trim=start_frame=1[v3];\n"
0087 
0088                                         " [first1]loop='if(gte($FIRST_FRAME_SEC, 1), ($FIRST_FRAME_SEC*$IN_FPS) - 0.5*$IN_FPS, $FIRST_FRAME_SEC*$IN_FPS)':size=1:start=1[preview1];\n"
0089                                         " [preview1]scale=$WIDTH:$HEIGHT[preview2];\n"
0090                                         " [preview2]setpts=PTS-STARTPTS[preview3];\n"
0091                                         " [preview3][v3] concat [final1];\n"
0092                                         " [final1] setpts=PTS-STARTPTS[final2];\n"
0093                                         " [final2] trim=start_frame=1\n"
0094 
0095                                         "\"\n-c:v libopenh264\n-r $OUT_FPS\n-pix_fmt yuv420p" },
0096     { "GIF",        "gif",  profilePrefix % "-filter_complex \"\n"
0097                                             " [0]loop=$LAST_FRAME_SEC*$IN_FPS:size=1:start=$FRAMES[main1];\n"
0098                                             " [main1]scale=$WIDTH:$HEIGHT[main2];\n"
0099                                             " [main2]loop=1:size=1:start=0[main3];\n"
0100                                             " [main3]setpts=PTS-STARTPTS[main4];\n"
0101                                             " [1]split [first1][transition1];\n"
0102                                             " [transition1]scale=$WIDTH:$HEIGHT [transition2];\n"
0103                                             " [transition2]loop='if(gte($FIRST_FRAME_SEC, 1), 1*$IN_FPS, 0)':size=1:start=1[transition3];\n"
0104                                             " [transition3]setpts=PTS-STARTPTS[transition4];\n"
0105                                             " [transition4][main4]xfade=transition=smoothright:duration=0.5:offset=0[v1];\n"
0106                                             " [v1]setpts=PTS-STARTPTS[v2];\n"
0107                                             " [v2]trim=start_frame=1[v3];\n"
0108                                             " [first1]loop='if(gte($FIRST_FRAME_SEC, 1), ($FIRST_FRAME_SEC*$IN_FPS) - 0.5*$IN_FPS, $FIRST_FRAME_SEC*$IN_FPS)':size=1:start=1[preview1];\n"
0109                                             " [preview1]scale=$WIDTH:$HEIGHT[preview2];\n"
0110                                             " [preview2]setpts=PTS-STARTPTS[preview3];\n"
0111                                             " [preview3][v3] concat [final1];\n"
0112                                             " [final1] setpts=PTS-STARTPTS[final2];\n"
0113                                             " [final2] trim=start_frame=1[final3];\n"
0114                                             " [final3]split[final4][final5];\n"
0115                                             " [final4]palettegen[palettegen];\n"
0116                                             " [final5][palettegen]paletteuse\"\n-loop -1" },
0117     { "Matroska",   "mkv",  profilePrefix % "-filter_complex \"\n"
0118                                             " [0]loop=$LAST_FRAME_SEC*$IN_FPS:size=1:start=$FRAMES[main1];\n"
0119                                             " [main1]scale=$WIDTH:$HEIGHT[main2];\n"
0120                                             " [main2]loop=1:size=1:start=0[main3];\n"
0121                                             " [main3]setpts=PTS-STARTPTS[main4];\n"
0122 
0123                                             " [1]split [first1][transition1];\n"
0124                                             " [transition1]scale=$WIDTH:$HEIGHT [transition2];\n"
0125                                             " [transition2]loop='if(gte($FIRST_FRAME_SEC, 1), 1*$IN_FPS, 0)':size=1:start=1[transition3];\n"
0126                                             " [transition3]setpts=PTS-STARTPTS[transition4];\n"
0127 
0128                                             " [transition4][main4]xfade=transition=smoothright:duration=0.5:offset=0[v1];\n"
0129                                             " [v1]setpts=PTS-STARTPTS[v2];\n"
0130                                             " [v2]trim=start_frame=1[v3];\n"
0131 
0132                                             " [first1]loop='if(gte($FIRST_FRAME_SEC, 1), ($FIRST_FRAME_SEC*$IN_FPS) - 0.5*$IN_FPS, $FIRST_FRAME_SEC*$IN_FPS)':size=1:start=1[preview1];\n"
0133                                             " [preview1]scale=$WIDTH:$HEIGHT[preview2];\n"
0134                                             " [preview2]setpts=PTS-STARTPTS[preview3];\n"
0135                                             " [preview3][v3] concat [final1];\n"
0136                                             " [final1] setpts=PTS-STARTPTS[final2];\n"
0137                                             " [final2] trim=start_frame=1\n"
0138                                             "\"\n-r $OUT_FPS" },
0139     { "WebM",       "webm", profilePrefix % "-filter_complex \"\n"
0140                                             " [0]loop=$LAST_FRAME_SEC*$IN_FPS:size=1:start=$FRAMES[main1];\n"
0141                                             " [main1]scale=$WIDTH:$HEIGHT[main2];\n"
0142                                             " [main2]loop=1:size=1:start=0[main3];\n"
0143                                             " [main3]setpts=PTS-STARTPTS[main4];\n"
0144 
0145                                             " [1]split [first1][transition1];\n"
0146                                             " [transition1]scale=$WIDTH:$HEIGHT [transition2];\n"
0147                                             " [transition2]loop='if(gte($FIRST_FRAME_SEC, 1), 1*$IN_FPS, 0)':size=1:start=1[transition3];\n"
0148                                             " [transition3]setpts=PTS-STARTPTS[transition4];\n"
0149 
0150                                             " [transition4][main4]xfade=transition=smoothright:duration=0.5:offset=0[v1];\n"
0151                                             " [v1]setpts=PTS-STARTPTS[v2];\n"
0152                                             " [v2]trim=start_frame=1[v3];\n"
0153 
0154                                             " [first1]loop='if(gte($FIRST_FRAME_SEC, 1), ($FIRST_FRAME_SEC*$IN_FPS) - 0.5*$IN_FPS, $FIRST_FRAME_SEC*$IN_FPS)':size=1:start=1[preview1];\n"
0155                                             " [preview1]scale=$WIDTH:$HEIGHT[preview2];\n"
0156                                             " [preview2]setpts=PTS-STARTPTS[preview3];\n"
0157                                             " [preview3][v3] concat [final1];\n"
0158                                             " [final1] setpts=PTS-STARTPTS[final2];\n"
0159                                             " [final2] trim=start_frame=1\n"
0160                                             "\"\n-r $OUT_FPS" },
0161     { "MP4 x264 (Flash Effect)",  "mp4", profilePrefix % "-filter_complex \"\n"
0162                                             " [1]loop=$LAST_FRAME_SEC*$IN_FPS:size=1:start=0[fade1];\n"
0163                                             " [fade1]fps=$OUT_FPS[fade2];\n"
0164                                             " [fade2]fade=type=in:color=white:start_time=0.7:duration=0.7[fade3];\n"
0165                                             " [fade3]setsar=1[fade4];\n"
0166                                             " [0]setsar=1[main0];\n"
0167                                             " [main0][fade4] concat=n=2:v=1[main1];\n"
0168                                             " [main1]scale=$WIDTH:$HEIGHT[main2];\n"
0169                                             " [main2]loop=1:size=1:start=0[main3];\n"
0170                                             " [main3]setpts=PTS-STARTPTS[main4];\n"
0171                                             " [main4]fps=fps=$IN_FPS[main5];\n"
0172                                             " [1]split [first1][transition1];\n"
0173                                             " [transition1]scale=$WIDTH:$HEIGHT [transition2];\n"
0174                                             " [transition2]loop='if(gte($FIRST_FRAME_SEC, 1), 1*$IN_FPS, 0)':size=1:start=1[transition3];\n"
0175                                             " [transition3]setpts=PTS-STARTPTS[transition4];\n"
0176                                             " [transition4][main5]xfade=transition=smoothright:duration=0.5:offset=0[v1];\n"
0177                                             " [v1]setpts=PTS-STARTPTS[v2];\n"
0178                                             " [v2]trim=start_frame=1[v3];\n"
0179                                             " [first1]loop='if(gte($FIRST_FRAME_SEC, 1), ($FIRST_FRAME_SEC*$IN_FPS) - 0.5*$IN_FPS, $FIRST_FRAME_SEC*$IN_FPS)':size=1:start=1[preview1];\n"
0180                                             " [preview1]scale=$WIDTH:$HEIGHT[preview2];\n"
0181                                             " [preview2]setpts=PTS-STARTPTS[preview3];\n"
0182                                             " [preview3][v3] concat [final1];\n"
0183                                             " [final1] setpts=PTS-STARTPTS[final2];\n"
0184                                             " [final2] trim=start_frame=1\n"
0185                                             "\"\n-c:v libx264\n-r $OUT_FPS\n-pix_fmt yuv420p" },
0186     { "MP4 openh264 (Flash Effect)",  "mp4", profilePrefix % "-filter_complex \"\n"
0187                                                        " [1]loop=$LAST_FRAME_SEC*$IN_FPS:size=1:start=0[fade1];\n"
0188                                                        " [fade1]fps=$OUT_FPS[fade2];\n"
0189                                                        " [fade2]fade=type=in:color=white:start_time=0.7:duration=0.7[fade3];\n"
0190                                                        " [fade3]setsar=1[fade4];\n"
0191                                                        " [0]setsar=1[main0];\n"
0192                                                        " [main0][fade4] concat=n=2:v=1[main1];\n"
0193                                                        " [main1]scale=$WIDTH:$HEIGHT[main2];\n"
0194                                                        " [main2]loop=1:size=1:start=0[main3];\n"
0195                                                        " [main3]setpts=PTS-STARTPTS[main4];\n"
0196                                                        " [main4]fps=fps=$IN_FPS[main5];\n"
0197                                                        " [1]split [first1][transition1];\n"
0198                                                        " [transition1]scale=$WIDTH:$HEIGHT [transition2];\n"
0199                                                        " [transition2]loop='if(gte($FIRST_FRAME_SEC, 1), 1*$IN_FPS, 0)':size=1:start=1[transition3];\n"
0200                                                        " [transition3]setpts=PTS-STARTPTS[transition4];\n"
0201                                                        " [transition4][main5]xfade=transition=smoothright:duration=0.5:offset=0[v1];\n"
0202                                                        " [v1]setpts=PTS-STARTPTS[v2];\n"
0203                                                        " [v2]trim=start_frame=1[v3];\n"
0204                                                        " [first1]loop='if(gte($FIRST_FRAME_SEC, 1), ($FIRST_FRAME_SEC*$IN_FPS) - 0.5*$IN_FPS, $FIRST_FRAME_SEC*$IN_FPS)':size=1:start=1[preview1];\n"
0205                                                        " [preview1]scale=$WIDTH:$HEIGHT[preview2];\n"
0206                                                        " [preview2]setpts=PTS-STARTPTS[preview3];\n"
0207                                                        " [preview3][v3] concat [final1];\n"
0208                                                        " [final1] setpts=PTS-STARTPTS[final2];\n"
0209                                                        " [final2] trim=start_frame=1\n"
0210                                                        "\"\n-c:v libopenh264\n-r $OUT_FPS\n-pix_fmt yuv420p" },
0211     { "Custom1",  "editme", profilePrefix % "-filter_complex \"loop=$LAST_FRAME_SEC:size=1:start=$FRAMES,scale=$WIDTH:$HEIGHT\"\n-r $OUT_FPS" },
0212     { "Custom2",  "editme", profilePrefix % "-filter_complex \"loop=$LAST_FRAME_SEC:size=1:start=$FRAMES,scale=$WIDTH:$HEIGHT\"\n-r $OUT_FPS" },
0213     { "Custom3",  "editme", profilePrefix % "-filter_complex \"loop=$LAST_FRAME_SEC:size=1:start=$FRAMES,scale=$WIDTH:$HEIGHT\"\n-r $OUT_FPS" },
0214     { "Custom4",  "editme", profilePrefix % "-filter_complex \"loop=$LAST_FRAME_SEC:size=1:start=$FRAMES,scale=$WIDTH:$HEIGHT\"\n-r $OUT_FPS" }
0215 };
0216 }
0217 
0218 RecorderExportConfig::RecorderExportConfig(bool readOnly)
0219     : config(new KisConfig(readOnly))
0220 {
0221 }
0222 
0223 RecorderExportConfig::~RecorderExportConfig()
0224 {
0225     delete config;
0226 }
0227 
0228 void RecorderExportConfig::loadConfiguration(RecorderExportSettings *settings, bool loadLockFps) const
0229 {
0230     settings->inputFps = inputFps();
0231     settings->fps = fps();
0232     settings->resultPreview = resultPreview();
0233     settings->firstFrameSec = firstFrameSec();
0234     settings->extendResult = extendResult();
0235     settings->lastFrameSec = lastFrameSec();
0236     settings->resize = resize();
0237     settings->size = size();
0238     settings->lockRatio = lockRatio();
0239     settings->ffmpegPath = ffmpegPath();
0240     settings->profiles = profiles();
0241     settings->defaultProfiles = defaultProfiles();
0242     settings->profileIndex = profileIndex();
0243     settings->videoDirectory = videoDirectory();
0244     if (loadLockFps)
0245         settings->lockFps = lockFps();
0246 }
0247 
0248 int RecorderExportConfig::inputFps() const
0249 {
0250     return config->readEntry(keyInputFps, 30);
0251 }
0252 
0253 void RecorderExportConfig::setInputFps(int value)
0254 {
0255     config->writeEntry(keyInputFps, value);
0256 }
0257 
0258 
0259 int RecorderExportConfig::fps() const
0260 {
0261     return config->readEntry(keyFps, 30);
0262 }
0263 
0264 void RecorderExportConfig::setFps(int value)
0265 {
0266     config->writeEntry(keyFps, value);
0267 }
0268 
0269 bool RecorderExportConfig::resultPreview() const
0270 {
0271     return config->readEntry(keyResultPreview, true);
0272 }
0273 
0274 void RecorderExportConfig::setResultPreview(bool value)
0275 {
0276     config->writeEntry(keyResultPreview, value);
0277 }
0278 
0279 int RecorderExportConfig::firstFrameSec() const
0280 {
0281     return config->readEntry(keyFirstFrameSec, 2);
0282 }
0283 
0284 void RecorderExportConfig::setFirstFrameSec(int value)
0285 {
0286     config->writeEntry(keyFirstFrameSec, value);
0287 }
0288 
0289 
0290 bool RecorderExportConfig::extendResult() const
0291 {
0292     return config->readEntry(keyExtendResult, true);
0293 }
0294 
0295 void RecorderExportConfig::setExtendResult(bool value)
0296 {
0297     config->writeEntry(keyExtendResult, value);
0298 }
0299 
0300 int RecorderExportConfig::lastFrameSec() const
0301 {
0302     return config->readEntry(keyLastFrameSec, 5);
0303 }
0304 
0305 void RecorderExportConfig::setLastFrameSec(int value)
0306 {
0307     config->writeEntry(keyLastFrameSec, value);
0308 }
0309 
0310 bool RecorderExportConfig::resize() const
0311 {
0312     return config->readEntry(keyResize, false);
0313 }
0314 
0315 void RecorderExportConfig::setResize(bool value)
0316 {
0317     config->writeEntry(keyResize, value);
0318 }
0319 
0320 
0321 QSize RecorderExportConfig::size() const
0322 {
0323     return config->readEntry(keySize, QSize(1024, 1024));
0324 }
0325 
0326 void RecorderExportConfig::setSize(const QSize &value)
0327 {
0328     config->writeEntry(keySize, value);
0329 }
0330 
0331 
0332 bool RecorderExportConfig::lockRatio() const
0333 {
0334     return config->readEntry(keyLockRatio, false);
0335 }
0336 
0337 void RecorderExportConfig::setLockRatio(bool value)
0338 {
0339     config->writeEntry(keyLockRatio, value);
0340 }
0341 
0342 bool RecorderExportConfig::lockFps() const
0343 {
0344     return config->readEntry(keyLockFps, false);
0345 }
0346 
0347 void RecorderExportConfig::setLockFps(bool value)
0348 {
0349     config->writeEntry(keyLockFps, value);
0350 }
0351 
0352 int RecorderExportConfig::profileIndex() const
0353 {
0354     return config->readEntry(keyProfileIndex, 0);
0355 }
0356 
0357 void RecorderExportConfig::setProfileIndex(int value)
0358 {
0359     config->writeEntry(keyProfileIndex, value);
0360 }
0361 
0362 QList<RecorderProfile> RecorderExportConfig::profiles() const
0363 {
0364     const QString &profilesStr = config->readEntry(keyProfiles, QString());
0365     if (profilesStr.isEmpty())
0366         return ::defaultProfiles;
0367 
0368     const QSet<int> &editedIndexes = editedProfilesIndexes();
0369     QList<RecorderProfile> profiles;
0370     const QStringList &profilesList = profilesStr.split("\n");
0371     int index = 0;
0372     for (const QString &profileStr : profilesList) {
0373         // take saved profile in case it's edited.. or something bad happen
0374         if (editedIndexes.contains(index) || index >= ::defaultProfiles.size()) {
0375             const QStringList& profileList = profileStr.split("|");
0376             if (profileList.size() == 3) {
0377                 profiles.append({profileList[0], profileList[1], QString(profileList[2]).replace("\\n", "\n")});
0378             }
0379         } else {
0380             // use default profile to make it possible to upgrade
0381             profiles.append(::defaultProfiles[index]);
0382         }
0383 
0384         ++index;
0385     }
0386     return profiles;
0387 }
0388 
0389 void RecorderExportConfig::setProfiles(const QList<RecorderProfile> &value)
0390 {
0391     Q_ASSERT(value.size() == ::defaultProfiles.size());
0392 
0393     const QSet<int> &savedEditedProfilesIndexes = editedProfilesIndexes();
0394     QSet<int> editedProfilesIndexes = savedEditedProfilesIndexes;
0395     QString outValue;
0396     const QRegExp cleanUp("[\n|]");
0397     int index = 0;
0398     for (const RecorderProfile &profile : value) {
0399         const RecorderProfile &defaultProfile = ::defaultProfiles[index];
0400         if (profile != defaultProfile) {
0401             editedProfilesIndexes.insert(index);
0402         } else {
0403             editedProfilesIndexes.remove(index);
0404         }
0405 
0406         outValue += QString(profile.name).replace(cleanUp, " ") % "|"
0407                 % QString(profile.extension).replace(cleanUp, " ") % "|"
0408                 % QString(profile.arguments).replace("\n", "\\n").replace("|", " ") % "\n";
0409 
0410         ++index;
0411     }
0412 
0413     config->writeEntry(keyProfiles, outValue);
0414     if (savedEditedProfilesIndexes != editedProfilesIndexes) {
0415         setEditedProfilesIndexes(editedProfilesIndexes);
0416     }
0417 }
0418 
0419 
0420 QList<RecorderProfile> RecorderExportConfig::defaultProfiles() const
0421 {
0422     return ::defaultProfiles;
0423 }
0424 
0425 QSet<int> RecorderExportConfig::editedProfilesIndexes() const
0426 {
0427     const QVariantList &readValue = config->readEntry(keyEditedProfiles, QVariantList());
0428     QSet<int> result;
0429     for (const QVariant &item : readValue) {
0430         result.insert(item.toInt());
0431     }
0432     return result;
0433 }
0434 
0435 void RecorderExportConfig::setEditedProfilesIndexes(const QSet<int> &value)
0436 {
0437     QVariantList writeValue;
0438     for (int index : value) {
0439         writeValue.append(index);
0440     }
0441     config->writeEntry(keyEditedProfiles, writeValue);
0442 }
0443 
0444 
0445 QString RecorderExportConfig::ffmpegPath() const
0446 {
0447     return KisConfig(true).ffmpegLocation();
0448 }
0449 
0450 void RecorderExportConfig::setFfmpegPath(const QString &value)
0451 {
0452     KisConfig cfg(false);
0453     cfg.setFFMpegLocation(value);
0454 }
0455 
0456 
0457 QString RecorderExportConfig::videoDirectory() const
0458 {
0459     return config->readEntry(keyVideoDirectory, QDir::homePath());
0460 }
0461 
0462 void RecorderExportConfig::setVideoDirectory(const QString &value)
0463 {
0464     config->writeEntry(keyVideoDirectory, value);
0465 }
0466 
0467 bool operator==(const RecorderProfile &left, const RecorderProfile &right)
0468 {
0469     return left.arguments == right.arguments
0470         && left.name == right.name
0471         && left.extension == right.extension;
0472 }
0473 
0474 bool operator!=(const RecorderProfile &left, const RecorderProfile &right)
0475 {
0476     return !(left == right);
0477 }