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:
parent
62d519fb72
commit
f2da01b0ab
15 changed files with 97 additions and 62 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -64,6 +64,7 @@ public:
|
|||
// void *m_decompressedBuffer;
|
||||
private:
|
||||
Ffmpeg *ffmpegReader;
|
||||
bool ffmpegFramesCreated = false;
|
||||
TDimension m_size;
|
||||
int m_frameCount, m_lx, m_ly;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -61,6 +61,7 @@ public:
|
|||
// void *m_decompressedBuffer;
|
||||
private:
|
||||
Ffmpeg *ffmpegReader;
|
||||
bool ffmpegFramesCreated = false;
|
||||
TDimension m_size;
|
||||
int m_frameCount, m_lx, m_ly;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -60,6 +60,7 @@ public:
|
|||
// void *m_decompressedBuffer;
|
||||
private:
|
||||
Ffmpeg *ffmpegReader;
|
||||
bool ffmpegFramesCreated = false;
|
||||
TDimension m_size;
|
||||
int m_frameCount, m_lx, m_ly;
|
||||
};
|
||||
|
|
|
@ -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() ==
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue