Fix ffmpeg loaded levels (#2876)

* Fix reading ffmpeg frame count and rate

* Make ffmpeg loaded levels uneditable

* Ffmpeg extract frames only when loading

* Fix ffmpeg gif input frame rate
This commit is contained in:
manongjohn 2019-11-14 00:07:58 -05:00 committed by Jeremy Bullock
parent 62d519fb72
commit f2da01b0ab
15 changed files with 97 additions and 62 deletions

View file

@ -258,8 +258,8 @@ ffmpegFileInfo Ffmpeg::getInfo() {
} else {
QFile infoText(tempPath);
getSize();
getFrameRate();
getFrameCount();
getFrameRate();
infoText.open(QIODevice::WriteOnly);
std::string infoToWrite =
std::to_string(m_lx) + " " + std::to_string(m_ly) + " " +
@ -306,14 +306,13 @@ TRasterImageP Ffmpeg::getImage(int frameIndex) {
}
double Ffmpeg::getFrameRate() {
if (m_frameCount > 0) {
QStringList fpsArgs;
fpsArgs << "-v";
fpsArgs << "error";
fpsArgs << "-select_streams";
fpsArgs << "v:0";
fpsArgs << "-show_entries";
fpsArgs << "stream=avg_frame_rate";
fpsArgs << "stream=r_frame_rate";
fpsArgs << "-of";
fpsArgs << "default=noprint_wrappers=1:nokey=1";
fpsArgs << m_path.getQString();
@ -322,8 +321,7 @@ double Ffmpeg::getFrameRate() {
int fpsNum = fpsResults.split("/")[0].toInt();
int fpsDen = fpsResults.split("/")[1].toInt();
if (fpsDen > 0) {
m_frameRate = fpsNum / fpsDen;
}
m_frameRate = (double)fpsNum / (double)fpsDen;
}
return m_frameRate;
}
@ -355,13 +353,13 @@ int Ffmpeg::getFrameCount() {
frameCountArgs << "-select_streams";
frameCountArgs << "v:0";
frameCountArgs << "-show_entries";
frameCountArgs << "stream=nb_read_frames";
frameCountArgs << "stream=duration";
frameCountArgs << "-of";
frameCountArgs << "default=nokey=1:noprint_wrappers=1";
frameCountArgs << m_path.getQString();
QString frameResults = runFfprobe(frameCountArgs);
m_frameCount = frameResults.toInt();
m_frameCount = frameResults.toDouble() * getFrameRate();
return m_frameCount;
}

View file

@ -92,7 +92,7 @@ TLevelWriterGif::~TLevelWriterGif() {
preIArgs << "-v";
preIArgs << "warning";
preIArgs << "-r";
preIArgs << QString::number(m_frameRate);
preIArgs << QString::number((m_frameRate < 1 ? 12.0 : m_frameRate));
if (m_palette) {
postIArgs << "-i";
postIArgs << palette;
@ -194,8 +194,6 @@ TLevelReaderGif::TLevelReaderGif(const TFilePath &path)
m_lx = m_size.lx;
m_ly = m_size.ly;
ffmpegReader->getFramesFromMovie();
m_frameCount = ffmpegReader->getGifFrameCount();
// set values
m_info = new TImageInfo();
m_info->m_frameRate = fps;
@ -239,6 +237,10 @@ TDimension TLevelReaderGif::getSize() { return m_size; }
//------------------------------------------------
TImageP TLevelReaderGif::load(int frameIndex) {
if (!ffmpegFramesCreated) {
ffmpegReader->getFramesFromMovie();
ffmpegFramesCreated = true;
}
return ffmpegReader->getImage(frameIndex);
}

View file

@ -64,6 +64,7 @@ public:
// void *m_decompressedBuffer;
private:
Ffmpeg *ffmpegReader;
bool ffmpegFramesCreated = false;
TDimension m_size;
int m_frameCount, m_lx, m_ly;
};

View file

@ -173,8 +173,6 @@ TLevelReaderMp4::TLevelReaderMp4(const TFilePath &path) : TLevelReader(path) {
m_lx = m_size.lx;
m_ly = m_size.ly;
ffmpegReader->getFramesFromMovie();
// set values
m_info = new TImageInfo();
m_info->m_frameRate = fps;
@ -219,6 +217,10 @@ TDimension TLevelReaderMp4::getSize() { return m_size; }
//------------------------------------------------
TImageP TLevelReaderMp4::load(int frameIndex) {
if (!ffmpegFramesCreated) {
ffmpegReader->getFramesFromMovie();
ffmpegFramesCreated = true;
}
return ffmpegReader->getImage(frameIndex);
}

View file

@ -61,6 +61,7 @@ public:
// void *m_decompressedBuffer;
private:
Ffmpeg *ffmpegReader;
bool ffmpegFramesCreated = false;
TDimension m_size;
int m_frameCount, m_lx, m_ly;
};

View file

@ -174,8 +174,6 @@ TLevelReaderWebm::TLevelReaderWebm(const TFilePath &path) : TLevelReader(path) {
m_lx = m_size.lx;
m_ly = m_size.ly;
ffmpegReader->getFramesFromMovie();
// set values
m_info = new TImageInfo();
m_info->m_frameRate = fps;
@ -220,6 +218,10 @@ TDimension TLevelReaderWebm::getSize() { return m_size; }
//------------------------------------------------
TImageP TLevelReaderWebm::load(int frameIndex) {
if (!ffmpegFramesCreated) {
ffmpegReader->getFramesFromMovie();
ffmpegFramesCreated = true;
}
return ffmpegReader->getImage(frameIndex);
}

View file

@ -60,6 +60,7 @@ public:
// void *m_decompressedBuffer;
private:
Ffmpeg *ffmpegReader;
bool ffmpegFramesCreated = false;
TDimension m_size;
int m_frameCount, m_lx, m_ly;
};

View file

@ -990,6 +990,9 @@ QString TTool::updateEnabled(int rowIndex, int columnIndex) {
// Check level type write support
if (sl->getPath().getType() ==
"psd" || // We don't have the API to write psd files
sl->getPath().getType() == "gif" ||
sl->getPath().getType() == "mp4" ||
sl->getPath().getType() == "webm" ||
sl->is16BitChannelLevel() || // Inherited by previous implementation.
// Could be fixed?
sl->getProperties()->getBpp() ==

View file

@ -495,7 +495,9 @@ bool pasteStrokesInCellWithoutUndo(
} else {
vi = cell.getImage(true);
sl = cell.getSimpleLevel();
if (sl->getType() == OVL_XSHLEVEL && sl->getPath().getType() == "psd")
if (sl->getType() == OVL_XSHLEVEL &&
(sl->getPath().getType() == "psd" || sl->getPath().getType() == "gif" ||
sl->getPath().getType() == "mp4" || sl->getPath().getType() == "webm"))
return false;
fid = cell.getFrameId();
if (!vi) {
@ -1561,7 +1563,9 @@ static void pasteRasterImageInCell(int row, int col,
if (sl) oldPalette = sl->getPalette();
} else {
TXshSimpleLevel *sl = cell.getSimpleLevel();
if (sl->getType() == OVL_XSHLEVEL && sl->getPath().getType() == "psd")
if (sl->getType() == OVL_XSHLEVEL &&
(sl->getPath().getType() == "psd" || sl->getPath().getType() == "gif" ||
sl->getPath().getType() == "mp4" || sl->getPath().getType() == "webm"))
return;
oldPalette = sl->getPalette();
}

View file

@ -1296,7 +1296,8 @@ public:
void undo() const override;
int getSize() const override {
return sizeof *this + (sizeof(TXshLevelP) + sizeof(TXshSimpleLevel *)) *
return sizeof *this +
(sizeof(TXshLevelP) + sizeof(TXshSimpleLevel *)) *
m_insertedLevels.size();
}
@ -1526,7 +1527,11 @@ void CloneLevelUndo::cloneLevels() const {
assert(lt->first && !lt->second.empty());
TXshSimpleLevel *srcSl = lt->first;
if (srcSl->getPath().getType() == "psd") continue;
if (srcSl->getPath().getType() == "psd" ||
srcSl->getPath().getType() == "gif" ||
srcSl->getPath().getType() == "mp4" ||
srcSl->getPath().getType() == "webm")
continue;
const TFilePath &srcPath = srcSl->getPath();

View file

@ -180,6 +180,9 @@ static bool canMergeColumns(int column, int mColumn, bool forMatchlines) {
// Check level type write support. Based on TTool::updateEnabled()
if (level->getType() == OVL_XSHLEVEL &&
(level->getPath().getType() == "psd" || // PSD files.
level->getPath().getType() == "gif" ||
level->getPath().getType() == "mp4" ||
level->getPath().getType() == "webm" ||
level->is16BitChannelLevel() || // 16bpc images.
level->getProperties()->getBpp() == 1)) { // Black & White images.
return false;

View file

@ -1065,7 +1065,10 @@ void FilmstripFrames::contextMenuEvent(QContextMenuEvent *event) {
menu->addAction(cm->getAction(MI_RevertToCleanedUp));
if (sl &&
(sl->getType() == TZP_XSHLEVEL || sl->getType() == PLI_XSHLEVEL ||
(sl->getType() == OVL_XSHLEVEL && sl->getPath().getType() != "psd")))
(sl->getType() == OVL_XSHLEVEL && sl->getPath().getType() != "psd" &&
sl->getPath().getType() != "gif" &&
sl->getPath().getType() != "mp4" &&
sl->getPath().getType() != "webm")))
menu->addAction(cm->getAction(MI_RevertToLastSaved));
}

View file

@ -57,7 +57,9 @@ void TFilmstripSelection::enableCommands() {
bool doEnable =
(type == PLI_XSHLEVEL || type == TZP_XSHLEVEL || type == MESH_XSHLEVEL ||
(type == OVL_XSHLEVEL && path.getType() != "psd"));
(type == OVL_XSHLEVEL && path.getType() != "psd" &&
path.getType() != "gif" && path.getType() != "mp4" &&
path.getType() != "webm"));
TRasterImageP ri = (TRasterImageP)sl->getSimpleLevel()->getFrame(
sl->getSimpleLevel()->getFirstFid(), false);

View file

@ -309,7 +309,10 @@ void doCloneLevelNoSave(const TCellSelection::Range &range,
fid = cell.getFrameId();
if (cell.getSimpleLevel() == 0 ||
cell.getSimpleLevel()->getPath().getType() == "psd")
cell.getSimpleLevel()->getPath().getType() == "psd" ||
cell.getSimpleLevel()->getPath().getType() == "gif" ||
cell.getSimpleLevel()->getPath().getType() == "mp4" ||
cell.getSimpleLevel()->getPath().getType() == "webm")
continue;
std::map<TXshSimpleLevel *, TXshLevelP>::iterator it =

View file

@ -119,7 +119,9 @@ bool isAreadOnlyLevel(const TFilePath &path) {
if (path.getDots() == "." ||
(path.getDots() == ".." &&
(path.getType() == "tlv" || path.getType() == "tpl"))) {
if (path.getType() == "psd") return true;
if (path.getType() == "psd" || path.getType() == "gif" ||
path.getType() == "mp4" || path.getType() == "webm")
return true;
if (!TSystem::doesExistFileOrLevel(path)) return false;
TFileStatus fs(path);
return !fs.isWritable();
@ -1046,7 +1048,8 @@ static TFilePath getLevelPathAndSetNameWithPsdLevelName(
if (removeFileName) wLevelName = list[1].toStdWString();
TLevelSet *levelSet = xshLevel->getScene()->getLevelSet();
if (levelSet && levelSet->hasLevel(
if (levelSet &&
levelSet->hasLevel(
wLevelName)) // levelSet should be asserted instead
levelSet->renameLevel(xshLevel, wLevelName);
@ -1712,6 +1715,9 @@ void TXshSimpleLevel::saveSimpleLevel(const TFilePath &decodedFp,
// strategia
LevelUpdater updater(this);
updater.getLevelWriter()->setCreator(getCreatorString());
if (updater.getImageInfo())
updater.getLevelWriter()->setFrameRate(
updater.getImageInfo()->m_frameRate);
if (isLevelModified) {
// Apply the level's renumber table, before saving other files.
@ -2259,8 +2265,7 @@ TFilePath TXshSimpleLevel::getExistingHookFile(
}
assert(h >= 0);
return (h < 0) ? TFilePath()
: decodedLevelPath.getParentDir() +
return (h < 0) ? TFilePath() : decodedLevelPath.getParentDir() +
TFilePath(hookFiles[h].toStdWString());
}
@ -2294,8 +2299,8 @@ TRectD TXshSimpleLevel::getBBox(const TFrameId &fid) const {
if (!info) return TRectD();
bbox = TRectD(TPointD(info->m_x0, info->m_y0),
TPointD(info->m_x1, info->m_y1))
- 0.5 * TPointD(info->m_lx, info->m_ly);
TPointD(info->m_x1, info->m_y1)) -
0.5 * TPointD(info->m_lx, info->m_ly);
if (info->m_dpix > 0.0 && info->m_dpiy > 0.0)
dpiX = info->m_dpix, dpiY = info->m_dpiy;