3rd party interface adjustments + more
This commit is contained in:
parent
cea78e587a
commit
7b474d9950
|
@ -16,9 +16,10 @@ set(HEADERS
|
|||
../include/tnzimage.h
|
||||
ffmpeg/tiio_gif.h
|
||||
ffmpeg/tiio_webm.h
|
||||
ffmpeg/tiio_apng.h
|
||||
ffmpeg/tiio_mp4.h
|
||||
ffmpeg/tiio_mov.h
|
||||
ffmpeg/tiio_ffmpeg.h
|
||||
ffmpeg/tiio_ff_mov.h
|
||||
sprite/tiio_sprite.h
|
||||
mesh/tiio_mesh.h
|
||||
exr/tinyexr_otmod.h
|
||||
|
@ -44,9 +45,10 @@ set(SOURCES
|
|||
tzl/tiio_tzl.cpp
|
||||
ffmpeg/tiio_gif.cpp
|
||||
ffmpeg/tiio_webm.cpp
|
||||
ffmpeg/tiio_apng.cpp
|
||||
ffmpeg/tiio_mp4.cpp
|
||||
ffmpeg/tiio_mov.cpp
|
||||
ffmpeg/tiio_ffmpeg.cpp
|
||||
ffmpeg/tiio_ff_mov.cpp
|
||||
sprite/tiio_sprite.cpp
|
||||
mesh/tiio_mesh.cpp
|
||||
exr/tiio_exr.cpp
|
||||
|
|
228
toonz/sources/image/ffmpeg/tiio_apng.cpp
Normal file
228
toonz/sources/image/ffmpeg/tiio_apng.cpp
Normal file
|
@ -0,0 +1,228 @@
|
|||
|
||||
#include "tiio_apng.h"
|
||||
#include "tsystem.h"
|
||||
#include "trasterimage.h"
|
||||
#include "tsound.h"
|
||||
#include "timageinfo.h"
|
||||
#include "toonz/stage.h"
|
||||
#include <QStringList>
|
||||
|
||||
//===========================================================
|
||||
//
|
||||
// TImageWriterAPng
|
||||
//
|
||||
//===========================================================
|
||||
|
||||
class TImageWriterAPng : public TImageWriter {
|
||||
public:
|
||||
int m_frameIndex;
|
||||
|
||||
TImageWriterAPng(const TFilePath &path, int frameIndex, TLevelWriterAPng *lwg)
|
||||
: TImageWriter(path), m_frameIndex(frameIndex), m_lwg(lwg) {
|
||||
m_lwg->addRef();
|
||||
}
|
||||
~TImageWriterAPng() { m_lwg->release(); }
|
||||
|
||||
bool is64bitOutputSupported() override { return false; }
|
||||
void save(const TImageP &img) override { m_lwg->save(img, m_frameIndex); }
|
||||
|
||||
private:
|
||||
TLevelWriterAPng *m_lwg;
|
||||
};
|
||||
|
||||
//===========================================================
|
||||
//
|
||||
// TLevelWriterAPng;
|
||||
//
|
||||
//===========================================================
|
||||
|
||||
TLevelWriterAPng::TLevelWriterAPng(const TFilePath &path, TPropertyGroup *winfo)
|
||||
: TLevelWriter(path, winfo) {
|
||||
if (!m_properties) m_properties = new Tiio::APngWriterProperties();
|
||||
|
||||
std::string scale = m_properties->getProperty("Scale")->getValueAsString();
|
||||
m_scale = QString::fromStdString(scale).toInt();
|
||||
|
||||
TBoolProperty *extPng = (TBoolProperty *)m_properties->getProperty("ExtPng");
|
||||
m_extPng = extPng->getValue();
|
||||
|
||||
TBoolProperty *loop = (TBoolProperty *)m_properties->getProperty("Looping");
|
||||
m_looping = loop->getValue();
|
||||
|
||||
if (m_extPng) {
|
||||
m_path = m_path.getParentDir() + TFilePath(m_path.getWideName() + L".png");
|
||||
}
|
||||
|
||||
ffmpegWriter = new Ffmpeg();
|
||||
ffmpegWriter->setPath(m_path);
|
||||
if (TSystem::doesExistFileOrLevel(m_path)) TSystem::deleteFile(m_path);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
|
||||
TLevelWriterAPng::~TLevelWriterAPng() {
|
||||
QStringList preIArgs;
|
||||
QStringList postIArgs;
|
||||
|
||||
int outLx = m_lx;
|
||||
int outLy = m_ly;
|
||||
|
||||
// set scaling
|
||||
if (m_scale != 0) {
|
||||
outLx = m_lx * m_scale / 100;
|
||||
outLy = m_ly * m_scale / 100;
|
||||
}
|
||||
// ffmpeg doesn't like resolutions that aren't divisible by 2.
|
||||
if (outLx % 2 != 0) outLx++;
|
||||
if (outLy % 2 != 0) outLy++;
|
||||
|
||||
preIArgs << "-framerate";
|
||||
preIArgs << QString::number(m_frameRate);
|
||||
postIArgs << "-plays";
|
||||
postIArgs << (m_looping ? "0" : "1");
|
||||
postIArgs << "-f";
|
||||
postIArgs << "apng";
|
||||
postIArgs << "-s";
|
||||
postIArgs << QString::number(outLx) + "x" + QString::number(outLy);
|
||||
|
||||
ffmpegWriter->runFfmpeg(preIArgs, postIArgs, false, false, true);
|
||||
ffmpegWriter->cleanUpFiles();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
|
||||
TImageWriterP TLevelWriterAPng::getFrameWriter(TFrameId fid) {
|
||||
if (!fid.getLetter().isEmpty()) return TImageWriterP(0);
|
||||
int index = fid.getNumber();
|
||||
TImageWriterAPng *iwg = new TImageWriterAPng(m_path, index, this);
|
||||
return TImageWriterP(iwg);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
void TLevelWriterAPng::setFrameRate(double fps) {
|
||||
m_frameRate = fps;
|
||||
ffmpegWriter->setFrameRate(fps);
|
||||
}
|
||||
|
||||
void TLevelWriterAPng::saveSoundTrack(TSoundTrack *st) {
|
||||
ffmpegWriter->saveSoundTrack(st);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
|
||||
void TLevelWriterAPng::save(const TImageP &img, int frameIndex) {
|
||||
TRasterImageP image(img);
|
||||
m_lx = image->getRaster()->getLx();
|
||||
m_ly = image->getRaster()->getLy();
|
||||
ffmpegWriter->createIntermediateImage(img, frameIndex);
|
||||
}
|
||||
|
||||
//===========================================================
|
||||
//
|
||||
// TImageReaderAPng
|
||||
//
|
||||
//===========================================================
|
||||
|
||||
class TImageReaderAPng final : public TImageReader {
|
||||
public:
|
||||
int m_frameIndex;
|
||||
|
||||
TImageReaderAPng(const TFilePath &path, int index, TLevelReaderAPng *lra,
|
||||
TImageInfo *info)
|
||||
: TImageReader(path), m_lra(lra), m_frameIndex(index), m_info(info) {
|
||||
m_lra->addRef();
|
||||
}
|
||||
~TImageReaderAPng() { m_lra->release(); }
|
||||
|
||||
TImageP load() override { return m_lra->load(m_frameIndex); }
|
||||
TDimension getSize() const { return m_lra->getSize(); }
|
||||
TRect getBBox() const { return TRect(); }
|
||||
const TImageInfo *getImageInfo() const override { return m_info; }
|
||||
|
||||
private:
|
||||
TLevelReaderAPng *m_lra;
|
||||
TImageInfo *m_info;
|
||||
|
||||
// not implemented
|
||||
TImageReaderAPng(const TImageReaderAPng &);
|
||||
TImageReaderAPng &operator=(const TImageReaderAPng &src);
|
||||
};
|
||||
|
||||
//===========================================================
|
||||
//
|
||||
// TLevelReaderAPng
|
||||
//
|
||||
//===========================================================
|
||||
|
||||
TLevelReaderAPng::TLevelReaderAPng(const TFilePath &path) : TLevelReader(path) {
|
||||
ffmpegReader = new Ffmpeg();
|
||||
ffmpegReader->setPath(m_path);
|
||||
ffmpegReader->disablePrecompute();
|
||||
ffmpegFileInfo tempInfo = ffmpegReader->getInfo();
|
||||
double fps = tempInfo.m_frameRate;
|
||||
m_frameCount = tempInfo.m_frameCount;
|
||||
m_size = TDimension(tempInfo.m_lx, tempInfo.m_ly);
|
||||
m_lx = m_size.lx;
|
||||
m_ly = m_size.ly;
|
||||
|
||||
// set values
|
||||
m_info = new TImageInfo();
|
||||
m_info->m_frameRate = fps;
|
||||
m_info->m_lx = m_lx;
|
||||
m_info->m_ly = m_ly;
|
||||
m_info->m_bitsPerSample = 8;
|
||||
m_info->m_samplePerPixel = 4;
|
||||
m_info->m_dpix = Stage::standardDpi;
|
||||
m_info->m_dpiy = Stage::standardDpi;
|
||||
}
|
||||
//-----------------------------------------------------------
|
||||
|
||||
TLevelReaderAPng::~TLevelReaderAPng() {}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
|
||||
TLevelP TLevelReaderAPng::loadInfo() {
|
||||
if (m_frameCount == -1) return TLevelP();
|
||||
TLevelP level;
|
||||
for (int i = 1; i <= m_frameCount; i++) level->setFrame(i, TImageP());
|
||||
return level;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
|
||||
TImageReaderP TLevelReaderAPng::getFrameReader(TFrameId fid) {
|
||||
if (!fid.getLetter().isEmpty()) return TImageReaderP(0);
|
||||
int index = fid.getNumber();
|
||||
|
||||
TImageReaderAPng *irm = new TImageReaderAPng(m_path, index, this, m_info);
|
||||
return TImageReaderP(irm);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
TDimension TLevelReaderAPng::getSize() { return m_size; }
|
||||
|
||||
//------------------------------------------------
|
||||
|
||||
TImageP TLevelReaderAPng::load(int frameIndex) {
|
||||
if (!ffmpegFramesCreated) {
|
||||
ffmpegReader->getFramesFromMovie();
|
||||
ffmpegFramesCreated = true;
|
||||
}
|
||||
return ffmpegReader->getImage(frameIndex);
|
||||
}
|
||||
|
||||
Tiio::APngWriterProperties::APngWriterProperties()
|
||||
: m_scale("Scale", 1, 100, 100)
|
||||
, m_looping("Looping", true)
|
||||
, m_extPng("ExtPng", false) {
|
||||
bind(m_scale);
|
||||
bind(m_looping);
|
||||
bind(m_extPng);
|
||||
}
|
||||
|
||||
void Tiio::APngWriterProperties::updateTranslation() {
|
||||
m_scale.setQStringName(tr("Scale"));
|
||||
m_looping.setQStringName(tr("Looping"));
|
||||
m_extPng.setQStringName(tr("Write as .png"));
|
||||
}
|
86
toonz/sources/image/ffmpeg/tiio_apng.h
Normal file
86
toonz/sources/image/ffmpeg/tiio_apng.h
Normal file
|
@ -0,0 +1,86 @@
|
|||
#pragma once
|
||||
|
||||
#ifndef TTIO_APNG_INCLUDED
|
||||
#define TTIO_APNG_INCLUDED
|
||||
|
||||
#include "tproperty.h"
|
||||
#include "tlevel_io.h"
|
||||
#include "tiio_ffmpeg.h"
|
||||
#include <QCoreApplication>
|
||||
|
||||
//===========================================================
|
||||
//
|
||||
// TLevelWriterAPng
|
||||
//
|
||||
//===========================================================
|
||||
|
||||
class TLevelWriterAPng : public TLevelWriter {
|
||||
public:
|
||||
TLevelWriterAPng(const TFilePath &path, TPropertyGroup *winfo);
|
||||
~TLevelWriterAPng();
|
||||
void setFrameRate(double fps) override;
|
||||
|
||||
TImageWriterP getFrameWriter(TFrameId fid) override;
|
||||
void save(const TImageP &image, int frameIndex);
|
||||
|
||||
void saveSoundTrack(TSoundTrack *st) override;
|
||||
|
||||
static TLevelWriter *create(const TFilePath &path, TPropertyGroup *winfo) {
|
||||
return new TLevelWriterAPng(path, winfo);
|
||||
}
|
||||
|
||||
private:
|
||||
Ffmpeg *ffmpegWriter;
|
||||
int m_lx, m_ly;
|
||||
int m_scale;
|
||||
bool m_looping;
|
||||
bool m_extPng;
|
||||
};
|
||||
|
||||
//===========================================================
|
||||
//
|
||||
// TLevelReaderAPng
|
||||
//
|
||||
//===========================================================
|
||||
|
||||
class TLevelReaderAPng final : public TLevelReader {
|
||||
public:
|
||||
TLevelReaderAPng(const TFilePath &path);
|
||||
~TLevelReaderAPng();
|
||||
TImageReaderP getFrameReader(TFrameId fid) override;
|
||||
|
||||
static TLevelReader *create(const TFilePath &f) {
|
||||
return new TLevelReaderAPng(f);
|
||||
}
|
||||
|
||||
TLevelP loadInfo() override;
|
||||
TImageP load(int frameIndex);
|
||||
TDimension getSize();
|
||||
private:
|
||||
Ffmpeg *ffmpegReader;
|
||||
bool ffmpegFramesCreated = false;
|
||||
TDimension m_size;
|
||||
int m_frameCount, m_lx, m_ly;
|
||||
};
|
||||
|
||||
//===========================================================================
|
||||
|
||||
namespace Tiio {
|
||||
|
||||
//===========================================================================
|
||||
|
||||
class APngWriterProperties : public TPropertyGroup {
|
||||
Q_DECLARE_TR_FUNCTIONS(APngWriterProperties)
|
||||
public:
|
||||
TIntProperty m_scale;
|
||||
TBoolProperty m_looping;
|
||||
TBoolProperty m_extPng;
|
||||
APngWriterProperties();
|
||||
void updateTranslation() override;
|
||||
};
|
||||
|
||||
//===========================================================================
|
||||
|
||||
} // namespace Tiio
|
||||
|
||||
#endif
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
#include "tsystem.h"
|
||||
#include "tiio_mov.h"
|
||||
#include "tiio_ff_mov.h"
|
||||
#include "trasterimage.h"
|
||||
#include "timageinfo.h"
|
||||
#include "tsound.h"
|
||||
|
@ -9,36 +9,38 @@
|
|||
|
||||
//===========================================================
|
||||
//
|
||||
// TImageWriterMov
|
||||
// TImageWriterFFMov
|
||||
//
|
||||
//===========================================================
|
||||
|
||||
class TImageWriterMov : public TImageWriter {
|
||||
class TImageWriterFFMov : public TImageWriter {
|
||||
public:
|
||||
int m_frameIndex;
|
||||
|
||||
TImageWriterMov(const TFilePath &path, int frameIndex, TLevelWriterMov *lwg)
|
||||
TImageWriterFFMov(const TFilePath &path, int frameIndex,
|
||||
TLevelWriterFFMov *lwg)
|
||||
: TImageWriter(path), m_frameIndex(frameIndex), m_lwg(lwg) {
|
||||
m_lwg->addRef();
|
||||
}
|
||||
~TImageWriterMov() { m_lwg->release(); }
|
||||
~TImageWriterFFMov() { m_lwg->release(); }
|
||||
|
||||
bool is64bitOutputSupported() override { return false; }
|
||||
void save(const TImageP &img) override { m_lwg->save(img, m_frameIndex); }
|
||||
|
||||
private:
|
||||
TLevelWriterMov *m_lwg;
|
||||
TLevelWriterFFMov *m_lwg;
|
||||
};
|
||||
|
||||
//===========================================================
|
||||
//
|
||||
// TLevelWriterMov;
|
||||
// TLevelWriterFFMov;
|
||||
//
|
||||
//===========================================================
|
||||
|
||||
TLevelWriterMov::TLevelWriterMov(const TFilePath &path, TPropertyGroup *winfo)
|
||||
TLevelWriterFFMov::TLevelWriterFFMov(const TFilePath &path,
|
||||
TPropertyGroup *winfo)
|
||||
: TLevelWriter(path, winfo) {
|
||||
if (!m_properties) m_properties = new Tiio::MovWriterProperties();
|
||||
if (!m_properties) m_properties = new Tiio::FFMovWriterProperties();
|
||||
if (m_properties->getPropertyCount() == 0) {
|
||||
m_scale = 100;
|
||||
m_vidQuality = 100;
|
||||
|
@ -56,8 +58,7 @@ TLevelWriterMov::TLevelWriterMov(const TFilePath &path, TPropertyGroup *winfo)
|
|||
|
||||
//-----------------------------------------------------------
|
||||
|
||||
TLevelWriterMov::~TLevelWriterMov() {
|
||||
// QProcess createMov;
|
||||
TLevelWriterFFMov::~TLevelWriterFFMov() {
|
||||
QStringList preIArgs;
|
||||
QStringList postIArgs;
|
||||
|
||||
|
@ -84,12 +85,12 @@ TLevelWriterMov::~TLevelWriterMov() {
|
|||
preIArgs << "-framerate";
|
||||
preIArgs << QString::number(m_frameRate);
|
||||
|
||||
postIArgs << "-pix_fmt";
|
||||
postIArgs << "yuva444p10le";
|
||||
postIArgs << "-c:v";
|
||||
postIArgs << "prores_ks";
|
||||
postIArgs << "-profile";
|
||||
postIArgs << "4444";
|
||||
postIArgs << "-pix_fmt";
|
||||
postIArgs << "yuva444p10le";
|
||||
postIArgs << "-profile:v";
|
||||
postIArgs << "4";
|
||||
postIArgs << "-s";
|
||||
postIArgs << QString::number(outLx) + "x" + QString::number(outLy);
|
||||
postIArgs << "-b";
|
||||
|
@ -101,28 +102,26 @@ TLevelWriterMov::~TLevelWriterMov() {
|
|||
|
||||
//-----------------------------------------------------------
|
||||
|
||||
TImageWriterP TLevelWriterMov::getFrameWriter(TFrameId fid) {
|
||||
// if (IOError != 0)
|
||||
// throw TImageException(m_path, buildMovExceptionString(IOError));
|
||||
TImageWriterP TLevelWriterFFMov::getFrameWriter(TFrameId fid) {
|
||||
if (!fid.getLetter().isEmpty()) return TImageWriterP(0);
|
||||
int index = fid.getNumber();
|
||||
TImageWriterMov *iwg = new TImageWriterMov(m_path, index, this);
|
||||
int index = fid.getNumber();
|
||||
TImageWriterFFMov *iwg = new TImageWriterFFMov(m_path, index, this);
|
||||
return TImageWriterP(iwg);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
void TLevelWriterMov::setFrameRate(double fps) {
|
||||
void TLevelWriterFFMov::setFrameRate(double fps) {
|
||||
m_frameRate = fps;
|
||||
ffmpegWriter->setFrameRate(fps);
|
||||
}
|
||||
|
||||
void TLevelWriterMov::saveSoundTrack(TSoundTrack *st) {
|
||||
void TLevelWriterFFMov::saveSoundTrack(TSoundTrack *st) {
|
||||
ffmpegWriter->saveSoundTrack(st);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
|
||||
void TLevelWriterMov::save(const TImageP &img, int frameIndex) {
|
||||
void TLevelWriterFFMov::save(const TImageP &img, int frameIndex) {
|
||||
TRasterImageP image(img);
|
||||
m_lx = image->getRaster()->getLx();
|
||||
m_ly = image->getRaster()->getLy();
|
||||
|
@ -131,20 +130,20 @@ void TLevelWriterMov::save(const TImageP &img, int frameIndex) {
|
|||
|
||||
//===========================================================
|
||||
//
|
||||
// TImageReaderMov
|
||||
// TImageReaderFFMov
|
||||
//
|
||||
//===========================================================
|
||||
|
||||
class TImageReaderMov final : public TImageReader {
|
||||
class TImageReaderFFMov final : public TImageReader {
|
||||
public:
|
||||
int m_frameIndex;
|
||||
|
||||
TImageReaderMov(const TFilePath &path, int index, TLevelReaderMov *lra,
|
||||
TImageInfo *info)
|
||||
TImageReaderFFMov(const TFilePath &path, int index, TLevelReaderFFMov *lra,
|
||||
TImageInfo *info)
|
||||
: TImageReader(path), m_lra(lra), m_frameIndex(index), m_info(info) {
|
||||
m_lra->addRef();
|
||||
}
|
||||
~TImageReaderMov() { m_lra->release(); }
|
||||
~TImageReaderFFMov() { m_lra->release(); }
|
||||
|
||||
TImageP load() override { return m_lra->load(m_frameIndex); }
|
||||
TDimension getSize() const { return m_lra->getSize(); }
|
||||
|
@ -152,21 +151,22 @@ public:
|
|||
const TImageInfo *getImageInfo() const override { return m_info; }
|
||||
|
||||
private:
|
||||
TLevelReaderMov *m_lra;
|
||||
TLevelReaderFFMov *m_lra;
|
||||
TImageInfo *m_info;
|
||||
|
||||
// not implemented
|
||||
TImageReaderMov(const TImageReaderMov &);
|
||||
TImageReaderMov &operator=(const TImageReaderMov &src);
|
||||
TImageReaderFFMov(const TImageReaderFFMov &);
|
||||
TImageReaderFFMov &operator=(const TImageReaderFFMov &src);
|
||||
};
|
||||
|
||||
//===========================================================
|
||||
//
|
||||
// TLevelReaderMov
|
||||
// TLevelReaderFFMov
|
||||
//
|
||||
//===========================================================
|
||||
|
||||
TLevelReaderMov::TLevelReaderMov(const TFilePath &path) : TLevelReader(path) {
|
||||
TLevelReaderFFMov::TLevelReaderFFMov(const TFilePath &path)
|
||||
: TLevelReader(path) {
|
||||
ffmpegReader = new Ffmpeg();
|
||||
ffmpegReader->setPath(m_path);
|
||||
ffmpegReader->disablePrecompute();
|
||||
|
@ -189,13 +189,11 @@ TLevelReaderMov::TLevelReaderMov(const TFilePath &path) : TLevelReader(path) {
|
|||
}
|
||||
//-----------------------------------------------------------
|
||||
|
||||
TLevelReaderMov::~TLevelReaderMov() {
|
||||
// ffmpegReader->cleanUpFiles();
|
||||
}
|
||||
TLevelReaderFFMov::~TLevelReaderFFMov() {}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
|
||||
TLevelP TLevelReaderMov::loadInfo() {
|
||||
TLevelP TLevelReaderFFMov::loadInfo() {
|
||||
if (m_frameCount == -1) return TLevelP();
|
||||
TLevelP level;
|
||||
for (int i = 1; i <= m_frameCount; i++) level->setFrame(i, TImageP());
|
||||
|
@ -204,23 +202,21 @@ TLevelP TLevelReaderMov::loadInfo() {
|
|||
|
||||
//-----------------------------------------------------------
|
||||
|
||||
TImageReaderP TLevelReaderMov::getFrameReader(TFrameId fid) {
|
||||
// if (IOError != 0)
|
||||
// throw TImageException(m_path, buildAVIExceptionString(IOError));
|
||||
TImageReaderP TLevelReaderFFMov::getFrameReader(TFrameId fid) {
|
||||
if (!fid.getLetter().isEmpty()) return TImageReaderP(0);
|
||||
int index = fid.getNumber();
|
||||
|
||||
TImageReaderMov *irm = new TImageReaderMov(m_path, index, this, m_info);
|
||||
TImageReaderFFMov *irm = new TImageReaderFFMov(m_path, index, this, m_info);
|
||||
return TImageReaderP(irm);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
TDimension TLevelReaderMov::getSize() { return m_size; }
|
||||
TDimension TLevelReaderFFMov::getSize() { return m_size; }
|
||||
|
||||
//------------------------------------------------
|
||||
|
||||
TImageP TLevelReaderMov::load(int frameIndex) {
|
||||
TImageP TLevelReaderFFMov::load(int frameIndex) {
|
||||
if (!ffmpegFramesCreated) {
|
||||
ffmpegReader->getFramesFromMovie();
|
||||
ffmpegFramesCreated = true;
|
||||
|
@ -228,16 +224,13 @@ TImageP TLevelReaderMov::load(int frameIndex) {
|
|||
return ffmpegReader->getImage(frameIndex);
|
||||
}
|
||||
|
||||
Tiio::MovWriterProperties::MovWriterProperties()
|
||||
Tiio::FFMovWriterProperties::FFMovWriterProperties()
|
||||
: m_vidQuality("Quality", 1, 100, 90), m_scale("Scale", 1, 100, 100) {
|
||||
bind(m_vidQuality);
|
||||
bind(m_scale);
|
||||
}
|
||||
|
||||
void Tiio::MovWriterProperties::updateTranslation() {
|
||||
void Tiio::FFMovWriterProperties::updateTranslation() {
|
||||
m_vidQuality.setQStringName(tr("Quality"));
|
||||
m_scale.setQStringName(tr("Scale"));
|
||||
}
|
||||
|
||||
// Tiio::Reader* Tiio::makeMovReader(){ return nullptr; }
|
||||
// Tiio::Writer* Tiio::makeMovWriter(){ return nullptr; }
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#ifndef TTIO_MOV_INCLUDED
|
||||
#define TTIO_MOV_INCLUDED
|
||||
#ifndef TTIO_FFMPEG_MOV_INCLUDED
|
||||
#define TTIO_FFMPEG_MOV_INCLUDED
|
||||
|
||||
#include "tproperty.h"
|
||||
#include "tlevel_io.h"
|
||||
|
@ -11,14 +11,14 @@
|
|||
|
||||
//===========================================================
|
||||
//
|
||||
// TLevelWriterMov
|
||||
// TLevelWriterFFMov
|
||||
//
|
||||
//===========================================================
|
||||
|
||||
class TLevelWriterMov : public TLevelWriter {
|
||||
class TLevelWriterFFMov : public TLevelWriter {
|
||||
public:
|
||||
TLevelWriterMov(const TFilePath &path, TPropertyGroup *winfo);
|
||||
~TLevelWriterMov();
|
||||
TLevelWriterFFMov(const TFilePath &path, TPropertyGroup *winfo);
|
||||
~TLevelWriterFFMov();
|
||||
void setFrameRate(double fps) override;
|
||||
|
||||
TImageWriterP getFrameWriter(TFrameId fid) override;
|
||||
|
@ -27,7 +27,7 @@ public:
|
|||
void saveSoundTrack(TSoundTrack *st) override;
|
||||
|
||||
static TLevelWriter *create(const TFilePath &path, TPropertyGroup *winfo) {
|
||||
return new TLevelWriterMov(path, winfo);
|
||||
return new TLevelWriterFFMov(path, winfo);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -35,30 +35,27 @@ private:
|
|||
int m_lx, m_ly;
|
||||
int m_scale;
|
||||
int m_vidQuality;
|
||||
// void *m_buffer;
|
||||
};
|
||||
|
||||
//===========================================================
|
||||
//
|
||||
// TLevelReaderMov
|
||||
// TLevelReaderFFMov
|
||||
//
|
||||
//===========================================================
|
||||
|
||||
class TLevelReaderMov final : public TLevelReader {
|
||||
class TLevelReaderFFMov final : public TLevelReader {
|
||||
public:
|
||||
TLevelReaderMov(const TFilePath &path);
|
||||
~TLevelReaderMov();
|
||||
TLevelReaderFFMov(const TFilePath &path);
|
||||
~TLevelReaderFFMov();
|
||||
TImageReaderP getFrameReader(TFrameId fid) override;
|
||||
|
||||
static TLevelReader *create(const TFilePath &f) {
|
||||
return new TLevelReaderMov(f);
|
||||
return new TLevelReaderFFMov(f);
|
||||
}
|
||||
|
||||
TLevelP loadInfo() override;
|
||||
TImageP load(int frameIndex);
|
||||
TDimension getSize();
|
||||
// TThread::Mutex m_mutex;
|
||||
// void *m_decompressedBuffer;
|
||||
private:
|
||||
Ffmpeg *ffmpegReader;
|
||||
bool ffmpegFramesCreated = false;
|
||||
|
@ -72,22 +69,17 @@ namespace Tiio {
|
|||
|
||||
//===========================================================================
|
||||
|
||||
class MovWriterProperties : public TPropertyGroup {
|
||||
Q_DECLARE_TR_FUNCTIONS(MovWriterProperties)
|
||||
class FFMovWriterProperties : public TPropertyGroup {
|
||||
Q_DECLARE_TR_FUNCTIONS(FFMovWriterProperties)
|
||||
public:
|
||||
// TEnumProperty m_pixelSize;
|
||||
// TBoolProperty m_matte;
|
||||
TIntProperty m_vidQuality;
|
||||
TIntProperty m_scale;
|
||||
MovWriterProperties();
|
||||
FFMovWriterProperties();
|
||||
void updateTranslation() override;
|
||||
};
|
||||
|
||||
//===========================================================================
|
||||
|
||||
// Tiio::Reader *makeMovReader();
|
||||
// Tiio::Writer *makeMovWriter();
|
||||
} // namespace Tiio
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -3,6 +3,8 @@
|
|||
#include "tsystem.h"
|
||||
#include "tsound.h"
|
||||
#include "tenv.h"
|
||||
#include "timageinfo.h"
|
||||
#include "toonz/stage.h"
|
||||
|
||||
#include <QProcess>
|
||||
#include <QEventLoop>
|
||||
|
@ -13,137 +15,50 @@
|
|||
#include "toonz/preferences.h"
|
||||
#include "toonz/toonzfolders.h"
|
||||
#include "tmsgcore.h"
|
||||
#include "thirdparty.h"
|
||||
|
||||
Ffmpeg::Ffmpeg() {
|
||||
m_ffmpegPath = Preferences::instance()->getFfmpegPath();
|
||||
m_ffmpegTimeout = Preferences::instance()->getFfmpegTimeout();
|
||||
if (m_ffmpegTimeout > 0)
|
||||
m_ffmpegTimeout *= 1000;
|
||||
else
|
||||
m_ffmpegTimeout = ThirdParty::getFFmpegTimeout() * 1000;
|
||||
if (m_ffmpegTimeout <= 0)
|
||||
m_ffmpegTimeout = -1;
|
||||
std::string strPath = m_ffmpegPath.toStdString();
|
||||
m_intermediateFormat = "png";
|
||||
m_startNumber = 2147483647; // Lowest frame determines starting frame
|
||||
}
|
||||
Ffmpeg::~Ffmpeg() {}
|
||||
|
||||
bool Ffmpeg::checkFfmpeg() {
|
||||
QString exe = "ffmpeg";
|
||||
#if defined(_WIN32)
|
||||
exe = exe + ".exe";
|
||||
#endif
|
||||
|
||||
// check the user defined path in preferences first
|
||||
QString path = Preferences::instance()->getFfmpegPath() + "/" + exe;
|
||||
if (TSystem::doesExistFileOrLevel(TFilePath(path))) return true;
|
||||
|
||||
// Let's try and autodetect the exe included with release
|
||||
QStringList folderList;
|
||||
|
||||
folderList.append(".");
|
||||
folderList.append("./ffmpeg"); // ffmpeg folder
|
||||
|
||||
#ifdef MACOSX
|
||||
// Look inside app
|
||||
folderList.append("./" +
|
||||
QString::fromStdString(TEnv::getApplicationFileName()) +
|
||||
".app/ffmpeg"); // ffmpeg folder
|
||||
#elif defined(LINUX) || defined(FREEBSD)
|
||||
// Need to account for symbolic links
|
||||
folderList.append(TEnv::getWorkingDirectory().getQString() +
|
||||
"/ffmpeg"); // ffmpeg folder
|
||||
#endif
|
||||
|
||||
QString exePath = TSystem::findFileLocation(folderList, exe);
|
||||
|
||||
if (!exePath.isEmpty()) {
|
||||
Preferences::instance()->setValue(ffmpegPath, exePath);
|
||||
return true;
|
||||
}
|
||||
|
||||
// give up
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Ffmpeg::checkFfprobe() {
|
||||
QString exe = "ffprobe";
|
||||
#if defined(_WIN32)
|
||||
exe = exe + ".exe";
|
||||
#endif
|
||||
|
||||
// check the user defined path in preferences first
|
||||
QString path = Preferences::instance()->getFfmpegPath() + "/" + exe;
|
||||
if (TSystem::doesExistFileOrLevel(TFilePath(path))) return true;
|
||||
|
||||
// Let's try and autodetect the exe included with release
|
||||
QStringList folderList;
|
||||
|
||||
folderList.append(".");
|
||||
folderList.append("./ffmpeg"); // ffmpeg folder
|
||||
|
||||
#ifdef MACOSX
|
||||
// Look inside app
|
||||
folderList.append("./" +
|
||||
QString::fromStdString(TEnv::getApplicationFileName()) +
|
||||
".app/ffmpeg"); // ffmpeg folder
|
||||
#elif defined(LINUX) || defined(FREEBSD)
|
||||
// Need to account for symbolic links
|
||||
folderList.append(TEnv::getWorkingDirectory().getQString() +
|
||||
"/ffmpeg"); // ffmpeg folder
|
||||
#endif
|
||||
|
||||
QString exePath = TSystem::findFileLocation(folderList, exe);
|
||||
|
||||
if (!exePath.isEmpty()) {
|
||||
Preferences::instance()->setValue(ffmpegPath, exePath);
|
||||
return true;
|
||||
}
|
||||
|
||||
// give up
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Ffmpeg::checkFormat(std::string format) {
|
||||
QString path = Preferences::instance()->getFfmpegPath() + "/ffmpeg";
|
||||
#if defined(_WIN32)
|
||||
path = path + ".exe";
|
||||
#endif
|
||||
QStringList args;
|
||||
args << "-formats";
|
||||
QProcess ffmpeg;
|
||||
ffmpeg.start(path, args);
|
||||
if (waitFfmpeg(ffmpeg, 60000)) { // 1 minute timeout
|
||||
QString results = ffmpeg.readAllStandardError();
|
||||
results += ffmpeg.readAllStandardOutput();
|
||||
ffmpeg.close();
|
||||
std::string strResults = results.toStdString();
|
||||
std::string::size_type n;
|
||||
n = strResults.find(format);
|
||||
if (n != std::string::npos)
|
||||
return true;
|
||||
}
|
||||
ThirdParty::runFFmpeg(ffmpeg, args);
|
||||
ffmpeg.waitForFinished();
|
||||
QString results = ffmpeg.readAllStandardError();
|
||||
results += ffmpeg.readAllStandardOutput();
|
||||
ffmpeg.close();
|
||||
std::string strResults = results.toStdString();
|
||||
std::string::size_type n;
|
||||
n = strResults.find(format);
|
||||
if (n != std::string::npos)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Ffmpeg::checkCodecs(std::string codec) {
|
||||
QString path = Preferences::instance()->getFfmpegPath() + "/ffmpeg";
|
||||
#if defined(_WIN32)
|
||||
path = path + ".exe";
|
||||
#endif
|
||||
QStringList args;
|
||||
args << "-codecs";
|
||||
QProcess ffmpeg;
|
||||
ffmpeg.start(path, args);
|
||||
if (waitFfmpeg(ffmpeg, 60000)) { // 1 minute timeout
|
||||
QString results = ffmpeg.readAllStandardError();
|
||||
results += ffmpeg.readAllStandardOutput();
|
||||
ffmpeg.close();
|
||||
std::string strResults = results.toStdString();
|
||||
std::string::size_type n;
|
||||
n = strResults.find(codec);
|
||||
if (n != std::string::npos)
|
||||
return true;
|
||||
}
|
||||
ThirdParty::runFFmpeg(ffmpeg, args);
|
||||
ffmpeg.waitForFinished();
|
||||
QString results = ffmpeg.readAllStandardError();
|
||||
results += ffmpeg.readAllStandardOutput();
|
||||
ffmpeg.close();
|
||||
std::string strResults = results.toStdString();
|
||||
std::string::size_type n;
|
||||
n = strResults.find(codec);
|
||||
if (n != std::string::npos)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -167,8 +82,7 @@ void Ffmpeg::createIntermediateImage(const TImageP &img, int frameIndex) {
|
|||
if (frameIndex < m_startNumber) m_startNumber = frameIndex;
|
||||
QString tempPath = getFfmpegCache().getQString() + "//" +
|
||||
QString::fromStdString(m_path.getName()) + "tempOut" +
|
||||
QString::number(frameIndex) + "." +
|
||||
m_intermediateFormat;
|
||||
QString::number(frameIndex) + "." + m_intermediateFormat;
|
||||
std::string saveStatus = "";
|
||||
TRasterImageP tempImage(img);
|
||||
TRasterImage *image = (TRasterImage *)tempImage->cloneImage();
|
||||
|
@ -203,7 +117,7 @@ void Ffmpeg::createIntermediateImage(const TImageP &img, int frameIndex) {
|
|||
|
||||
void Ffmpeg::runFfmpeg(QStringList preIArgs, QStringList postIArgs,
|
||||
bool includesInPath, bool includesOutPath,
|
||||
bool overWriteFiles) {
|
||||
bool overWriteFiles, bool asyncProcess) {
|
||||
QString tempName = "//" + QString::fromStdString(m_path.getName()) +
|
||||
"tempOut%d." + m_intermediateFormat;
|
||||
tempName = getFfmpegCache().getQString() + tempName;
|
||||
|
@ -232,8 +146,8 @@ void Ffmpeg::runFfmpeg(QStringList preIArgs, QStringList postIArgs,
|
|||
|
||||
// write the file
|
||||
QProcess ffmpeg;
|
||||
ffmpeg.start(m_ffmpegPath + "/ffmpeg", args);
|
||||
if (waitFfmpeg(ffmpeg, m_ffmpegTimeout)) {
|
||||
ThirdParty::runFFmpeg(ffmpeg, args);
|
||||
if (waitFfmpeg(ffmpeg, asyncProcess)) {
|
||||
QString results = ffmpeg.readAllStandardError();
|
||||
results += ffmpeg.readAllStandardOutput();
|
||||
int exitCode = ffmpeg.exitCode();
|
||||
|
@ -244,8 +158,8 @@ void Ffmpeg::runFfmpeg(QStringList preIArgs, QStringList postIArgs,
|
|||
|
||||
QString Ffmpeg::runFfprobe(QStringList args) {
|
||||
QProcess ffmpeg;
|
||||
ffmpeg.start(m_ffmpegPath + "/ffprobe", args);
|
||||
if (!waitFfmpeg(ffmpeg, m_ffmpegTimeout)) {
|
||||
ThirdParty::runFFprobe(ffmpeg, args);
|
||||
if (!waitFfmpeg(ffmpeg, false)) {
|
||||
throw TImageException(m_path, "error accessing ffprobe.");
|
||||
}
|
||||
QString results = ffmpeg.readAllStandardError();
|
||||
|
@ -259,19 +173,20 @@ QString Ffmpeg::runFfprobe(QStringList args) {
|
|||
return results;
|
||||
}
|
||||
|
||||
bool Ffmpeg::waitFfmpeg(const QProcess &ffmpeg, int timeout) {
|
||||
QEventLoop eloop;
|
||||
QTimer timer;
|
||||
timer.connect(&timer, &QTimer::timeout, &eloop, [&eloop] { eloop.exit(-2); });
|
||||
ffmpeg.connect(&ffmpeg, &QProcess::errorOccurred, &eloop,
|
||||
[&eloop] { eloop.exit(-1); });
|
||||
ffmpeg.connect(&ffmpeg,
|
||||
static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(
|
||||
&QProcess::finished),
|
||||
&eloop, &QEventLoop::quit);
|
||||
timer.start(timeout);
|
||||
bool Ffmpeg::waitFfmpeg(QProcess &ffmpeg, bool asyncProcess) {
|
||||
if (!asyncProcess) {
|
||||
bool status = ffmpeg.waitForFinished(m_ffmpegTimeout);
|
||||
if (!status) {
|
||||
DVGui::warning(
|
||||
QObject::tr("FFmpeg timed out.\n"
|
||||
"Please check the file for errors.\n"
|
||||
"If the file doesn't play or is incomplete, \n"
|
||||
"Please try raising the FFmpeg timeout in Preferences."));
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
int exitCode = eloop.exec();
|
||||
int exitCode = ThirdParty::waitAsyncProcess(ffmpeg, m_ffmpegTimeout);
|
||||
if (exitCode == 0) return true;
|
||||
if (exitCode == -1) {
|
||||
DVGui::warning(
|
||||
|
@ -544,7 +459,7 @@ void Ffmpeg::getFramesFromMovie(int frame) {
|
|||
|
||||
postIFrameArgs << tempName;
|
||||
|
||||
runFfmpeg(preIFrameArgs, postIFrameArgs, true, true, true);
|
||||
runFfmpeg(preIFrameArgs, postIFrameArgs, true, true, true, false);
|
||||
|
||||
for (int i = 1; i <= m_frameCount; i++) {
|
||||
QString number = QString("%1").arg(i, 4, 10, QChar('0'));
|
||||
|
@ -595,3 +510,99 @@ void Ffmpeg::cleanUpFiles() {
|
|||
void Ffmpeg::disablePrecompute() {
|
||||
Preferences::instance()->setPrecompute(false);
|
||||
}
|
||||
|
||||
//===========================================================
|
||||
//
|
||||
// TImageReaderFFmpeg
|
||||
//
|
||||
//===========================================================
|
||||
|
||||
class TImageReaderFFmpeg final : public TImageReader {
|
||||
public:
|
||||
int m_frameIndex;
|
||||
|
||||
TImageReaderFFmpeg(const TFilePath &path, int index, TLevelReaderFFmpeg *lra,
|
||||
TImageInfo *info)
|
||||
: TImageReader(path), m_lra(lra), m_frameIndex(index), m_info(info) {
|
||||
m_lra->addRef();
|
||||
}
|
||||
~TImageReaderFFmpeg() { m_lra->release(); }
|
||||
|
||||
TImageP load() override { return m_lra->load(m_frameIndex); }
|
||||
TDimension getSize() const { return m_lra->getSize(); }
|
||||
TRect getBBox() const { return TRect(); }
|
||||
const TImageInfo *getImageInfo() const override { return m_info; }
|
||||
|
||||
private:
|
||||
TLevelReaderFFmpeg *m_lra;
|
||||
TImageInfo *m_info;
|
||||
|
||||
// not implemented
|
||||
TImageReaderFFmpeg(const TImageReaderFFmpeg &);
|
||||
TImageReaderFFmpeg &operator=(const TImageReaderFFmpeg &src);
|
||||
};
|
||||
|
||||
//===========================================================
|
||||
//
|
||||
// TLevelReaderFFmpeg
|
||||
//
|
||||
//===========================================================
|
||||
|
||||
TLevelReaderFFmpeg::TLevelReaderFFmpeg(const TFilePath &path)
|
||||
: TLevelReader(path) {
|
||||
ffmpegReader = new Ffmpeg();
|
||||
ffmpegReader->setPath(m_path);
|
||||
ffmpegReader->disablePrecompute();
|
||||
ffmpegFileInfo tempInfo = ffmpegReader->getInfo();
|
||||
double fps = tempInfo.m_frameRate;
|
||||
m_frameCount = tempInfo.m_frameCount;
|
||||
m_size = TDimension(tempInfo.m_lx, tempInfo.m_ly);
|
||||
m_lx = m_size.lx;
|
||||
m_ly = m_size.ly;
|
||||
|
||||
// set values
|
||||
m_info = new TImageInfo();
|
||||
m_info->m_frameRate = fps;
|
||||
m_info->m_lx = m_lx;
|
||||
m_info->m_ly = m_ly;
|
||||
m_info->m_bitsPerSample = 8;
|
||||
m_info->m_samplePerPixel = 4;
|
||||
m_info->m_dpix = Stage::standardDpi;
|
||||
m_info->m_dpiy = Stage::standardDpi;
|
||||
}
|
||||
//-----------------------------------------------------------
|
||||
|
||||
TLevelReaderFFmpeg::~TLevelReaderFFmpeg() {}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
|
||||
TLevelP TLevelReaderFFmpeg::loadInfo() {
|
||||
if (m_frameCount == -1) return TLevelP();
|
||||
TLevelP level;
|
||||
for (int i = 1; i <= m_frameCount; i++) level->setFrame(i, TImageP());
|
||||
return level;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
|
||||
TImageReaderP TLevelReaderFFmpeg::getFrameReader(TFrameId fid) {
|
||||
if (!fid.getLetter().isEmpty()) return TImageReaderP(0);
|
||||
int index = fid.getNumber();
|
||||
|
||||
TImageReaderFFmpeg *irm = new TImageReaderFFmpeg(m_path, index, this, m_info);
|
||||
return TImageReaderP(irm);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
TDimension TLevelReaderFFmpeg::getSize() { return m_size; }
|
||||
|
||||
//------------------------------------------------
|
||||
|
||||
TImageP TLevelReaderFFmpeg::load(int frameIndex) {
|
||||
if (!ffmpegFramesCreated) {
|
||||
ffmpegReader->getFramesFromMovie();
|
||||
ffmpegFramesCreated = true;
|
||||
}
|
||||
return ffmpegReader->getImage(frameIndex);
|
||||
}
|
|
@ -21,8 +21,8 @@ public:
|
|||
~Ffmpeg();
|
||||
void createIntermediateImage(const TImageP &image, int frameIndex);
|
||||
void runFfmpeg(QStringList preIArgs, QStringList postIArgs,
|
||||
bool includesInPath, bool includesOutPath,
|
||||
bool overWriteFiles);
|
||||
bool includesInPath, bool includesOutPath, bool overWriteFiles,
|
||||
bool asyncProcess = true);
|
||||
void runFfmpeg(QStringList preIArgs, QStringList postIArgs, TFilePath path);
|
||||
QString runFfprobe(QStringList args);
|
||||
void cleanUpFiles();
|
||||
|
@ -31,8 +31,6 @@ public:
|
|||
void setPath(TFilePath path);
|
||||
void saveSoundTrack(TSoundTrack *st);
|
||||
bool checkFilesExist();
|
||||
static bool checkFfmpeg();
|
||||
static bool checkFfprobe();
|
||||
static bool checkFormat(std::string format);
|
||||
static bool checkCodecs(std::string format);
|
||||
double getFrameRate();
|
||||
|
@ -46,17 +44,46 @@ public:
|
|||
int getGifFrameCount();
|
||||
|
||||
private:
|
||||
QString m_intermediateFormat, m_ffmpegPath, m_audioPath, m_audioFormat;
|
||||
QString m_intermediateFormat, m_audioPath, m_audioFormat;
|
||||
int m_frameCount = 0, m_lx, m_ly, m_bpp, m_bitsPerSample, m_channelCount,
|
||||
m_ffmpegTimeout = -1, m_startNumber = 2147483647;
|
||||
double m_frameRate = 24.0;
|
||||
bool m_ffmpegExists = false, m_ffprobeExists = false, m_hasSoundTrack = false;
|
||||
double m_frameRate = 24.0;
|
||||
bool m_hasSoundTrack = false;
|
||||
TFilePath m_path;
|
||||
QVector<QString> m_cleanUpList;
|
||||
QStringList m_audioArgs;
|
||||
TUINT32 m_sampleRate;
|
||||
QString cleanPathSymbols();
|
||||
static bool waitFfmpeg(const QProcess &ffmpeg, int timeout);
|
||||
bool waitFfmpeg(QProcess &ffmpeg, bool asyncProcess);
|
||||
};
|
||||
|
||||
//===========================================================
|
||||
//
|
||||
// TLevelReaderFFmpeg
|
||||
//
|
||||
//===========================================================
|
||||
|
||||
class TLevelReaderFFmpeg final : public TLevelReader {
|
||||
public:
|
||||
TLevelReaderFFmpeg(const TFilePath &path);
|
||||
~TLevelReaderFFmpeg();
|
||||
TImageReaderP getFrameReader(TFrameId fid) override;
|
||||
|
||||
static TLevelReader *create(const TFilePath &f) {
|
||||
return new TLevelReaderFFmpeg(f);
|
||||
}
|
||||
|
||||
TLevelP loadInfo() override;
|
||||
TImageP load(int frameIndex);
|
||||
TDimension getSize();
|
||||
|
||||
private:
|
||||
Ffmpeg *ffmpegReader;
|
||||
bool ffmpegFramesCreated = false;
|
||||
TDimension m_size;
|
||||
int m_frameCount, m_lx, m_ly;
|
||||
};
|
||||
|
||||
//===========================================================================
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "tnzimage.h"
|
||||
#include "tiio.h"
|
||||
#include "tfiletype.h"
|
||||
#include "thirdparty.h"
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
|
@ -57,7 +58,8 @@
|
|||
#include "./ffmpeg/tiio_gif.h"
|
||||
#include "./ffmpeg/tiio_webm.h"
|
||||
#include "./ffmpeg/tiio_mp4.h"
|
||||
#include "./ffmpeg/tiio_mov.h"
|
||||
#include "./ffmpeg/tiio_apng.h"
|
||||
#include "./ffmpeg/tiio_ff_mov.h"
|
||||
#include "./mesh/tiio_mesh.h"
|
||||
#include "./sprite/tiio_sprite.h"
|
||||
#include "./exr/tiio_exr.h"
|
||||
|
@ -160,32 +162,45 @@ void initImageIo(bool lightVersion) {
|
|||
|
||||
// ffmpeg
|
||||
#if !defined(_WIN32) || defined(x64) || (defined(_WIN32) && defined(__GNUC__))
|
||||
if (Ffmpeg::checkFfmpeg()) {
|
||||
bool ffprobe = Ffmpeg::checkFfprobe();
|
||||
if (ThirdParty::checkFFmpeg()) {
|
||||
if (Ffmpeg::checkFormat("webm")) {
|
||||
TLevelWriter::define("webm", TLevelWriterWebm::create, true);
|
||||
if (ffprobe) TLevelReader::define("webm", TLevelReaderWebm::create);
|
||||
TLevelReader::define("webm", TLevelReaderWebm::create);
|
||||
TFileType::declare("webm", TFileType::RASTER_LEVEL);
|
||||
Tiio::defineWriterProperties("webm", new Tiio::WebmWriterProperties());
|
||||
}
|
||||
if (Ffmpeg::checkFormat("gif")) {
|
||||
TLevelWriter::define("gif", TLevelWriterGif::create, true);
|
||||
if (ffprobe) TLevelReader::define("gif", TLevelReaderGif::create);
|
||||
TLevelReader::define("gif", TLevelReaderGif::create);
|
||||
TFileType::declare("gif", TFileType::RASTER_LEVEL);
|
||||
Tiio::defineWriterProperties("gif", new Tiio::GifWriterProperties());
|
||||
}
|
||||
if (Ffmpeg::checkFormat("mp4")) {
|
||||
TLevelWriter::define("mp4", TLevelWriterMp4::create, true);
|
||||
if (ffprobe) TLevelReader::define("mp4", TLevelReaderMp4::create);
|
||||
TLevelReader::define("mp4", TLevelReaderMp4::create);
|
||||
TFileType::declare("mp4", TFileType::RASTER_LEVEL);
|
||||
Tiio::defineWriterProperties("mp4", new Tiio::Mp4WriterProperties());
|
||||
}
|
||||
if (Ffmpeg::checkFormat("mov")) {
|
||||
TLevelWriter::define("mov", TLevelWriterMov::create, true);
|
||||
if (ffprobe) TLevelReader::define("mov", TLevelReaderMov::create);
|
||||
TFileType::declare("mov", TFileType::RASTER_LEVEL);
|
||||
Tiio::defineWriterProperties("mov", new Tiio::MovWriterProperties());
|
||||
if (Ffmpeg::checkFormat("apng")) {
|
||||
TLevelWriter::define("apng", TLevelWriterAPng::create, true);
|
||||
TLevelReader::define("apng", TLevelReaderAPng::create);
|
||||
TFileType::declare("apng", TFileType::RASTER_LEVEL);
|
||||
Tiio::defineWriterProperties("apng", new Tiio::APngWriterProperties());
|
||||
}
|
||||
if (Ffmpeg::checkFormat("mov")) {
|
||||
TLevelWriter::define("mov", TLevelWriterFFMov::create, true);
|
||||
TLevelReader::define("mov", TLevelReaderFFMov::create);
|
||||
TFileType::declare("mov", TFileType::RASTER_LEVEL);
|
||||
Tiio::defineWriterProperties("mov", new Tiio::FFMovWriterProperties());
|
||||
}
|
||||
if (Ffmpeg::checkFormat("3gp")) {
|
||||
TLevelReader::define("3gp", TLevelReaderFFmpeg::create);
|
||||
TFileType::declare("3gp", TFileType::RASTER_LEVEL);
|
||||
}
|
||||
TLevelReader::define("webp", TLevelReaderFFmpeg::create);
|
||||
TFileType::declare("webp", TFileType::RASTER_LEVEL);
|
||||
TLevelReader::define("ffvideo", TLevelReaderFFmpeg::create);
|
||||
TFileType::declare("ffvideo", TFileType::RASTER_LEVEL);
|
||||
}
|
||||
#endif
|
||||
// end ffmpeg
|
||||
|
|
71
toonz/sources/include/thirdparty.h
Normal file
71
toonz/sources/include/thirdparty.h
Normal file
|
@ -0,0 +1,71 @@
|
|||
#pragma once
|
||||
|
||||
#ifndef THIRDPARTY_INCLUDED
|
||||
#define THIRDPARTY_INCLUDED
|
||||
|
||||
#include "tcommon.h"
|
||||
|
||||
#include <QProcess>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
#undef DVAPI
|
||||
#ifdef TOONZLIB_EXPORTS
|
||||
#define DVAPI DV_EXPORT_API
|
||||
#else
|
||||
#define DVAPI DV_IMPORT_API
|
||||
#endif
|
||||
|
||||
namespace ThirdParty {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
DVAPI void initialize();
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
DVAPI void getFFmpegVideoSupported(QStringList &exts);
|
||||
DVAPI void getFFmpegAudioSupported(QStringList &exts);
|
||||
|
||||
DVAPI bool findFFmpeg(QString dir);
|
||||
DVAPI bool checkFFmpeg();
|
||||
DVAPI QString autodetectFFmpeg();
|
||||
|
||||
DVAPI QString getFFmpegDir();
|
||||
DVAPI void setFFmpegDir(const QString &dir);
|
||||
DVAPI int getFFmpegTimeout();
|
||||
DVAPI void setFFmpegTimeout(int secs);
|
||||
|
||||
DVAPI void runFFmpeg(QProcess &process, const QStringList &arguments);
|
||||
DVAPI void runFFprobe(QProcess &process, const QStringList &arguments);
|
||||
|
||||
DVAPI void runFFmpegAudio(QProcess &process, QString srcPath, QString dstPath,
|
||||
int samplerate = 44100, int bpp = 16,
|
||||
int channels = 2);
|
||||
DVAPI bool readFFmpegAudio(QProcess &process, QByteArray &rawData);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
DVAPI bool findRhubarb(QString dir);
|
||||
DVAPI bool checkRhubarb();
|
||||
DVAPI QString autodetectRhubarb();
|
||||
|
||||
DVAPI QString getRhubarbDir();
|
||||
DVAPI void setRhubarbDir(const QString &dir);
|
||||
DVAPI int getRhubarbTimeout();
|
||||
DVAPI void setRhubarbTimeout(int secs);
|
||||
|
||||
DVAPI void runRhubarb(QProcess &process, const QStringList &arguments);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// return 0 = No error
|
||||
// return -1 = error code
|
||||
// return -2 = timed out
|
||||
DVAPI int waitAsyncProcess(const QProcess &process, int timeout);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
} // namespace ThirdParty
|
||||
|
||||
#endif
|
|
@ -237,8 +237,8 @@ public:
|
|||
// Some useful utility inlines
|
||||
|
||||
inline bool isMovieType(std::string type) {
|
||||
return (type == "avi" || type == "webm" ||
|
||||
type == "mp4" || type == "mov");
|
||||
return (type == "mov" || type == "avi" || type == "3gp" || type == "webm" ||
|
||||
type == "mp4" || type == "apng");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
|
@ -264,7 +264,7 @@ inline bool isMovieTypeOpaque(const TFilePath &fp) {
|
|||
//-----------------------------------------------------------
|
||||
|
||||
inline bool isSequencialRequired(std::string type) {
|
||||
return (type == "avi" || type == "3gp");
|
||||
return (type == "mov" || type == "avi" || type == "3gp");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
|
@ -279,7 +279,7 @@ inline bool isSequencialRequired(const TFilePath &fp) {
|
|||
inline bool isMultipleFrameType(std::string type) {
|
||||
return (type == "tlv" || type == "tzl" || type == "pli" || type == "mov" ||
|
||||
type == "avi" || type == "3gp" || type == "gif" || type == "mp4" ||
|
||||
type == "webm");
|
||||
type == "webm" || type == "apng");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
|
|
|
@ -145,6 +145,7 @@ public:
|
|||
|
||||
void saveTemplate(ToonzScene *scene);
|
||||
|
||||
// void clearProjectsRoot();
|
||||
// void addProjectsRoot(const TFilePath &fp);
|
||||
void addSVNProjectsRoot(const TFilePath &fp);
|
||||
|
||||
|
|
|
@ -130,6 +130,9 @@ Constructs a TXshColumn with default value.
|
|||
//! Returns the column type used to store levels of the specified type.
|
||||
static ColumnType toColumnType(int levelType);
|
||||
|
||||
//! Returns true if the column can be parent of another.
|
||||
bool canBeParent() const;
|
||||
|
||||
//! Creates an empty TXshColumn of the specified column type.
|
||||
static TXshColumn *createEmpty(int colType);
|
||||
|
||||
|
|
|
@ -2,9 +2,8 @@ set(HEADERS
|
|||
wav/tsio_wav.h
|
||||
aiff/tsio_aiff.h
|
||||
raw/tsio_raw.h
|
||||
mp3/tsio_mp3.h
|
||||
ffmpeg/tsio_ffmpeg.h
|
||||
../include/tnzsound.h
|
||||
tsio.h
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
|
@ -13,7 +12,7 @@ set(SOURCES
|
|||
wav/tsio_wav.cpp
|
||||
aiff/tsio_aiff.cpp
|
||||
raw/tsio_raw.cpp
|
||||
mp3/tsio_mp3.cpp
|
||||
ffmpeg/tsio_ffmpeg.cpp
|
||||
)
|
||||
|
||||
add_library(sound SHARED ${HEADERS} ${SOURCES})
|
||||
|
|
35
toonz/sources/sound/ffmpeg/tsio_ffmpeg.cpp
Normal file
35
toonz/sources/sound/ffmpeg/tsio_ffmpeg.cpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
#include <memory>
|
||||
|
||||
#include "tmachine.h"
|
||||
#include "tsio_ffmpeg.h"
|
||||
#include "tsystem.h"
|
||||
#include "tfilepath_io.h"
|
||||
#include "tsound_t.h"
|
||||
#include "toonz/preferences.h"
|
||||
#include "toonz/toonzfolders.h"
|
||||
#include "thirdparty.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QProcess>
|
||||
|
||||
//==============================================================================
|
||||
|
||||
TSoundTrackReaderFFmpeg::TSoundTrackReaderFFmpeg(const TFilePath &fp)
|
||||
: TSoundTrackReader(fp) {}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
TSoundTrackP TSoundTrackReaderFFmpeg::load() {
|
||||
QProcess ffmpeg;
|
||||
QByteArray rawAudio;
|
||||
|
||||
// Pipe the audio through ffmpeg
|
||||
ThirdParty::runFFmpegAudio(ffmpeg, m_path.getQString(), "-");
|
||||
if (!ThirdParty::readFFmpegAudio(ffmpeg, rawAudio)) return nullptr;
|
||||
|
||||
long sampleCount = rawAudio.size() / 4;
|
||||
|
||||
TSoundTrack *track = new TSoundTrackStereo16(44100, 2, sampleCount);
|
||||
memcpy((char *)track->getRawData(), rawAudio.constData(), sampleCount * 4);
|
||||
return track;
|
||||
}
|
31
toonz/sources/sound/ffmpeg/tsio_ffmpeg.h
Normal file
31
toonz/sources/sound/ffmpeg/tsio_ffmpeg.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
|
||||
#ifndef TSIO_FFMPEG_INCLUDED
|
||||
#define TSIO_FFMPEG_INCLUDED
|
||||
|
||||
#include "tsound_io.h"
|
||||
|
||||
//==========================================================
|
||||
/*!
|
||||
The class TSoundTrackReaderFFmpeg reads audio files
|
||||
*/
|
||||
class TSoundTrackReaderFFmpeg final : public TSoundTrackReader {
|
||||
public:
|
||||
TSoundTrackReaderFFmpeg(const TFilePath &fp);
|
||||
~TSoundTrackReaderFFmpeg() {}
|
||||
|
||||
/*!
|
||||
Loads audio file whose path has been specified in the constructor.
|
||||
It returns a TSoundTrackP created from the audio file
|
||||
*/
|
||||
TSoundTrackP load() override;
|
||||
|
||||
/*!
|
||||
Returns a soundtrack reader able to read audio files
|
||||
*/
|
||||
static TSoundTrackReader *create(const TFilePath &fp) {
|
||||
return new TSoundTrackReaderFFmpeg(fp);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
|
@ -8,6 +8,8 @@
|
|||
#include "tenv.h"
|
||||
#include "toonz/preferences.h"
|
||||
#include "toonz/toonzfolders.h"
|
||||
#include "thirdparty.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QProcess>
|
||||
|
||||
|
@ -37,50 +39,6 @@ TSoundTrackP TSoundTrackReaderMp3::load() {
|
|||
return track;
|
||||
}
|
||||
|
||||
bool FfmpegAudio::checkFfmpeg() {
|
||||
// check the user defined path in preferences first
|
||||
QString path = Preferences::instance()->getFfmpegPath() + "/ffmpeg";
|
||||
#if defined(_WIN32)
|
||||
path = path + ".exe";
|
||||
#endif
|
||||
if (TSystem::doesExistFileOrLevel(TFilePath(path))) return true;
|
||||
|
||||
// check the Tahoma2D root directory next
|
||||
path = QDir::currentPath() + "/ffmpeg";
|
||||
#if defined(_WIN32)
|
||||
path = path + ".exe";
|
||||
#endif
|
||||
if (TSystem::doesExistFileOrLevel(TFilePath(path))) {
|
||||
Preferences::instance()->setValue(ffmpegPath, QDir::currentPath());
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef MACOSX
|
||||
path = QDir::currentPath() + "/" +
|
||||
QString::fromStdString(TEnv::getApplicationFileName()) +
|
||||
".app/ffmpeg/ffmpeg";
|
||||
if (TSystem::doesExistFileOrLevel(TFilePath(path))) {
|
||||
Preferences::instance()->setValue(
|
||||
ffmpegPath, QDir::currentPath() + "/" +
|
||||
QString::fromStdString(TEnv::getApplicationFileName()) +
|
||||
".app/ffmpeg/");
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(LINUX) || defined(FREEBSD)
|
||||
QString currentPath = TEnv::getWorkingDirectory().getQString();
|
||||
path = currentPath + "/ffmpeg/ffmpeg";
|
||||
if (TSystem::doesExistFileOrLevel(TFilePath(path))) {
|
||||
Preferences::instance()->setValue(ffmpegPath, currentPath + "/ffmpeg/");
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// give up
|
||||
return false;
|
||||
}
|
||||
|
||||
TFilePath FfmpegAudio::getFfmpegCache() {
|
||||
QString cacheRoot = ToonzFolder::getCacheRootFolder().getQString();
|
||||
if (!TSystem::doesExistFileOrLevel(TFilePath(cacheRoot + "/ffmpeg"))) {
|
||||
|
@ -93,10 +51,8 @@ TFilePath FfmpegAudio::getFfmpegCache() {
|
|||
|
||||
void FfmpegAudio::runFfmpeg(QStringList args) {
|
||||
// write the file
|
||||
QString m_ffmpegPath = Preferences::instance()->getFfmpegPath();
|
||||
std::string strFfmpegPath = m_ffmpegPath.toStdString();
|
||||
QProcess ffmpeg;
|
||||
ffmpeg.start(m_ffmpegPath + "/ffmpeg", args);
|
||||
ThirdParty::runFFmpeg(ffmpeg, args);
|
||||
ffmpeg.waitForFinished(30000);
|
||||
QString results = ffmpeg.readAllStandardError();
|
||||
results += ffmpeg.readAllStandardOutput();
|
||||
|
|
|
@ -32,7 +32,6 @@ Returns a soundtrack reader able to read .mp3 audio files
|
|||
class FfmpegAudio {
|
||||
public:
|
||||
TFilePath getRawAudio(TFilePath path);
|
||||
static bool checkFfmpeg();
|
||||
|
||||
private:
|
||||
TFilePath getFfmpegCache();
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
|
||||
|
||||
#include "tnzsound.h"
|
||||
#include "tsio.h"
|
||||
// #include "tpluginmanager.h"
|
||||
#include "tsound_io.h"
|
||||
#include "tfiletype.h"
|
||||
#include "thirdparty.h"
|
||||
|
||||
#include "wav/tsio_wav.h"
|
||||
#include "aiff/tsio_aiff.h"
|
||||
#include "raw/tsio_raw.h"
|
||||
#include "ffmpeg/tsio_ffmpeg.h"
|
||||
|
||||
// static TPluginInfo info("soundIOPlugin");
|
||||
|
||||
|
@ -25,10 +30,19 @@ void initSoundIo() {
|
|||
TSoundTrackWriter::define("raw", TSoundTrackWriterRaw::create);
|
||||
TFileType::declare("raw", TFileType::AUDIO_LEVEL);
|
||||
|
||||
if (FfmpegAudio::checkFfmpeg()) {
|
||||
TSoundTrackReader::define("mp3", TSoundTrackReaderMp3::create);
|
||||
// TSoundTrackWriter::define("mp3", TSoundTrackWriterMp3::create);
|
||||
if (ThirdParty::checkFFmpeg()) {
|
||||
TSoundTrackReader::define("mp3", TSoundTrackReaderFFmpeg::create);
|
||||
TFileType::declare("mp3", TFileType::AUDIO_LEVEL);
|
||||
TSoundTrackReader::define("ogg", TSoundTrackReaderFFmpeg::create);
|
||||
TFileType::declare("ogg", TFileType::AUDIO_LEVEL);
|
||||
TSoundTrackReader::define("flac", TSoundTrackReaderFFmpeg::create);
|
||||
TFileType::declare("flac", TFileType::AUDIO_LEVEL);
|
||||
TSoundTrackReader::define("m4a", TSoundTrackReaderFFmpeg::create);
|
||||
TFileType::declare("m4a", TFileType::AUDIO_LEVEL);
|
||||
TSoundTrackReader::define("aac", TSoundTrackReaderFFmpeg::create);
|
||||
TFileType::declare("aac", TFileType::AUDIO_LEVEL);
|
||||
TSoundTrackReader::define("ffaudio", TSoundTrackReaderFFmpeg::create);
|
||||
TFileType::declare("ffaudio", TFileType::AUDIO_LEVEL);
|
||||
}
|
||||
// return &info;
|
||||
}
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#ifndef TSIO_INCLUDED
|
||||
#define TSIO_INCLUDED
|
||||
|
||||
#include "wav/tsio_wav.h"
|
||||
#include "aiff/tsio_aiff.h"
|
||||
#include "raw/tsio_raw.h"
|
||||
#include "mp3/tsio_mp3.h"
|
||||
|
||||
#endif
|
|
@ -449,7 +449,7 @@ int main(int argc, char *argv[]) {
|
|||
exit(1);
|
||||
}
|
||||
}
|
||||
if (ext != "pli") {
|
||||
if (ext != "3gp" && ext != "pli") {
|
||||
convert(srcFilePath, dstFilePath, range, width, prop, resQuality);
|
||||
} else {
|
||||
msg = "Cannot convert to ." + ext + " format.";
|
||||
|
|
|
@ -288,7 +288,10 @@ void BatchesController::setTasksTree(TaskTreeModel *tree) {
|
|||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
inline bool isMovieType(std::string type) { return (type == "avi" || type == "mp4" || type == "webm" || type == "mov"); }
|
||||
inline bool isMovieType(std::string type) {
|
||||
return (type == "mov" || type == "avi" || type == "3gp" || type == "mp4" ||
|
||||
type == "webm");
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -884,7 +884,8 @@ void CastBrowser::viewFile() {
|
|||
if (!TFileType::isViewable(TFileType::getInfo(filePath))) return;
|
||||
|
||||
if (Preferences::instance()->isDefaultViewerEnabled() &&
|
||||
(filePath.getType() == "avi"))
|
||||
(filePath.getType() == "mov" || filePath.getType() == "avi" ||
|
||||
filePath.getType() == "3gp"))
|
||||
QDesktopServices::openUrl(QUrl("file:///" + toQString(filePath)));
|
||||
else
|
||||
::viewFile(filePath);
|
||||
|
|
|
@ -371,7 +371,8 @@ you want to do?";*/
|
|||
if (m_frame >= totalFrameCount &&
|
||||
Preferences::instance()->isGeneratedMovieViewEnabled()) {
|
||||
if (Preferences::instance()->isDefaultViewerEnabled() &&
|
||||
(outPath.getType() == "avi")) {
|
||||
(outPath.getType() == "mov" || outPath.getType() == "avi" ||
|
||||
outPath.getType() == "3gp")) {
|
||||
QString name = QString::fromStdString(outPath.getName());
|
||||
|
||||
if (!TSystem::showDocument(outPath)) {
|
||||
|
|
|
@ -393,7 +393,8 @@ void FileSelection::viewFile() {
|
|||
continue;
|
||||
|
||||
if (Preferences::instance()->isDefaultViewerEnabled() &&
|
||||
(files[i].getType() == "avi"))
|
||||
(files[i].getType() == "mov" || files[i].getType() == "avi" ||
|
||||
files[i].getType() == "3gp"))
|
||||
QDesktopServices::openUrl(QUrl("file:///" + toQString(files[i])));
|
||||
else if (files[i].getType() == "tpl") {
|
||||
viewedPalette = StudioPalette::instance()->getPalette(files[i], false);
|
||||
|
|
|
@ -370,7 +370,9 @@ LoadImagesPopup::LoadImagesPopup(FlipBook *flip)
|
|||
m_shrinkField = new DVGui::LineEdit("1", this);
|
||||
|
||||
// Define the append/load filter types
|
||||
m_appendFilterTypes << "jpg"
|
||||
m_appendFilterTypes << "3gp"
|
||||
<< "mov"
|
||||
<< "jpg"
|
||||
<< "png"
|
||||
<< "tga"
|
||||
<< "tif"
|
||||
|
@ -2269,7 +2271,8 @@ FlipBook *viewFile(const TFilePath &path, int from, int to, int step,
|
|||
}
|
||||
|
||||
// Movie files must not have the ".." extension
|
||||
if ((path.getType() == "avi") &&
|
||||
if ((path.getType() == "mov" || path.getType() == "avi" ||
|
||||
path.getType() == "3gp") &&
|
||||
path.isLevelName()) {
|
||||
DVGui::warning(QObject::tr("%1 has an invalid extension format.")
|
||||
.arg(QString::fromStdString(path.getLevelName())));
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "tsound_io.h"
|
||||
#include "toutputproperties.h"
|
||||
#include "toonz/tproject.h"
|
||||
#include "thirdparty.h"
|
||||
|
||||
// TnzCore includes
|
||||
#include "filebrowsermodel.h"
|
||||
|
@ -530,7 +531,7 @@ void LipSyncPopup::showEvent(QShowEvent *) {
|
|||
m_startAt->setValue(row + 1);
|
||||
m_startAt->clearFocus();
|
||||
|
||||
if (checkRhubarb()) m_rhubarbPath = Preferences::instance()->getRhubarbPath();
|
||||
if (ThirdParty::checkRhubarb()) m_rhubarbPath = ThirdParty::getRhubarbDir();
|
||||
|
||||
TXshLevelHandle *level = app->getCurrentLevel();
|
||||
m_sl = level->getSimpleLevel();
|
||||
|
@ -702,46 +703,6 @@ void LipSyncPopup::saveAudio() {
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool LipSyncPopup::checkRhubarb() {
|
||||
QString exe = "rhubarb";
|
||||
#if defined(_WIN32)
|
||||
exe = exe + ".exe";
|
||||
#endif
|
||||
|
||||
// check the user defined path in preferences first
|
||||
QString path = Preferences::instance()->getRhubarbPath() + "/" + exe;
|
||||
if (TSystem::doesExistFileOrLevel(TFilePath(path))) return true;
|
||||
|
||||
// Let's try and autodetect the exe included with release
|
||||
QStringList folderList;
|
||||
|
||||
folderList.append(".");
|
||||
folderList.append("./rhubarb"); // rhubarb folder
|
||||
|
||||
#ifdef MACOSX
|
||||
// Look inside app
|
||||
folderList.append("./" +
|
||||
QString::fromStdString(TEnv::getApplicationFileName()) +
|
||||
".app/rhubarb"); // rhubarb folder
|
||||
#elif defined(LINUX) || defined(FREEBSD)
|
||||
// Need to account for symbolic links
|
||||
folderList.append(TEnv::getWorkingDirectory().getQString() +
|
||||
"/rhubarb"); // rhubarb folder
|
||||
#endif
|
||||
|
||||
QString exePath = TSystem::findFileLocation(folderList, exe);
|
||||
|
||||
if (!exePath.isEmpty()) {
|
||||
Preferences::instance()->setValue(rhubarbPath, exePath);
|
||||
return true;
|
||||
}
|
||||
|
||||
// give up
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void LipSyncPopup::runRhubarb() {
|
||||
QString cacheRoot = ToonzFolder::getCacheRootFolder().getQString();
|
||||
if (!TSystem::doesExistFileOrLevel(TFilePath(cacheRoot + "/rhubarb"))) {
|
||||
|
|
|
@ -94,7 +94,6 @@ protected:
|
|||
void refreshSoundLevels();
|
||||
void saveAudio();
|
||||
void runRhubarb();
|
||||
bool checkRhubarb();
|
||||
|
||||
public slots:
|
||||
void onApplyButton();
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "cleanupsettingspopup.h"
|
||||
#include "filebrowsermodel.h"
|
||||
#include "expressionreferencemanager.h"
|
||||
#include "thirdparty.h"
|
||||
#include "startuppopup.h"
|
||||
|
||||
// TnzTools includes
|
||||
|
@ -507,6 +508,9 @@ int main(int argc, char *argv[]) {
|
|||
TBigMemoryManager::instance()->setRunOutOfContiguousMemoryHandler(
|
||||
&toonzRunOutOfContMemHandler);
|
||||
|
||||
// Setup third party
|
||||
ThirdParty::initialize();
|
||||
|
||||
// Toonz environment
|
||||
initToonzEnv(argumentPathValues);
|
||||
|
||||
|
|
|
@ -159,7 +159,7 @@ public:
|
|||
TPointD center(0.5 * cameraSize.lx, 0.5 * cameraSize.ly);
|
||||
m_viewAff = TTranslation(center);
|
||||
std::string ext = fp.getType();
|
||||
m_isFrames = ext != "avi";
|
||||
m_isFrames = ext != "avi" && ext != "mov" && ext != "3gp";
|
||||
m_fileOptions = properties.getFileFormatProperties(ext);
|
||||
}
|
||||
|
||||
|
|
|
@ -87,10 +87,9 @@ public:
|
|||
|
||||
if (Preferences::instance()->isGeneratedMovieViewEnabled()) {
|
||||
if (!isPreview && (Preferences::instance()->isDefaultViewerEnabled()) &&
|
||||
(m_fp.getType() == "avi" ||
|
||||
m_fp.getType() == "mp4" ||
|
||||
m_fp.getType() == "gif" || m_fp.getType() == "webm" ||
|
||||
m_fp.getType() == "mov")) {
|
||||
(m_fp.getType() == "mov" || m_fp.getType() == "avi" ||
|
||||
m_fp.getType() == "3gp" || m_fp.getType() == "mp4" ||
|
||||
m_fp.getType() == "gif" || m_fp.getType() == "webm")) {
|
||||
QString name = QString::fromStdString(m_fp.getName());
|
||||
int index;
|
||||
if ((index = name.indexOf("#RENDERID")) != -1) //! quite ugly I
|
||||
|
|
|
@ -482,9 +482,7 @@ void ChangeObjectParent::refresh() {
|
|||
: viewer->getOtherCameraColor();
|
||||
} else if (id.isColumn() && (!xsh->isColumnEmpty(index))) {
|
||||
TXshColumn *colx = xsh->getColumn(index);
|
||||
if (colx->getColumnType() == TXshColumn::eSoundTextType ||
|
||||
colx->getColumnType() == TXshColumn::eSoundType)
|
||||
continue;
|
||||
if (!colx->canBeParent()) continue;
|
||||
|
||||
QColor unused;
|
||||
viewer->getColumnColor(newTextBG, unused, id.getIndex(), xsh);
|
||||
|
|
|
@ -65,6 +65,7 @@ set(HEADERS
|
|||
sandor_fxs/patternmap.h
|
||||
sandor_fxs/toonz4_6staff.h
|
||||
../include/convert2tlv.h
|
||||
../include/thirdparty.h
|
||||
../include/orientation.h
|
||||
../include/toonz/Naa2TlvConverter.h
|
||||
../include/toonz/autoclose.h
|
||||
|
@ -247,6 +248,7 @@ set(SOURCES
|
|||
tcolumnfxset.cpp
|
||||
tdistort.cpp
|
||||
texturemanager.cpp
|
||||
thirdparty.cpp
|
||||
tlog.cpp
|
||||
tnewoutlinevectorize.cpp
|
||||
toonzfolders.cpp
|
||||
|
|
|
@ -241,7 +241,7 @@ void LevelUpdater::open(const TFilePath &fp, TPropertyGroup *pg,
|
|||
TLevelReaderP(); // Release the reader. This is necessary since the
|
||||
m_lw = TLevelWriterP(
|
||||
fp, m_pg->clone()); // original file itself will be MODIFIED.
|
||||
m_lwPath = fp;
|
||||
m_lwPath = m_lw->getFilePath();
|
||||
}
|
||||
} catch (...) {
|
||||
// In this case, TLevelWriterP(..) failed, that object was never
|
||||
|
|
|
@ -295,6 +295,7 @@ void MovieRenderer::Imp::prepareForStart() {
|
|||
m_fp, oprop->getFileFormatProperties(m_fp.getType()),
|
||||
oprop->formatTemplateFId()));
|
||||
m_levelUpdaterA->getLevelWriter()->setFrameRate(frameRate);
|
||||
m_fp = m_levelUpdaterA->getLevelWriter()->getFilePath();
|
||||
} else {
|
||||
TFilePath leftFp = m_fp.withName(m_fp.getName() + "_l");
|
||||
TFilePath rightFp = m_fp.withName(m_fp.getName() + "_r");
|
||||
|
@ -306,11 +307,13 @@ void MovieRenderer::Imp::prepareForStart() {
|
|||
leftFp, oprop->getFileFormatProperties(leftFp.getType()),
|
||||
oprop->formatTemplateFId()));
|
||||
m_levelUpdaterA->getLevelWriter()->setFrameRate(frameRate);
|
||||
leftFp = m_levelUpdaterA->getLevelWriter()->getFilePath();
|
||||
|
||||
m_levelUpdaterB.reset(new LevelUpdater(
|
||||
rightFp, oprop->getFileFormatProperties(rightFp.getType()),
|
||||
oprop->formatTemplateFId()));
|
||||
m_levelUpdaterB->getLevelWriter()->setFrameRate(frameRate);
|
||||
rightFp = m_levelUpdaterB->getLevelWriter()->getFilePath();
|
||||
}
|
||||
} catch (...) {
|
||||
// If we get here, it's because one of the LevelUpdaters could not be
|
||||
|
|
349
toonz/sources/toonzlib/thirdparty.cpp
Normal file
349
toonz/sources/toonzlib/thirdparty.cpp
Normal file
|
@ -0,0 +1,349 @@
|
|||
#include "thirdparty.h"
|
||||
|
||||
// TnzLib includes
|
||||
#include "toonz/preferences.h"
|
||||
|
||||
// TnzCore includes
|
||||
#include "tsystem.h"
|
||||
#include "tmsgcore.h"
|
||||
|
||||
// QT includes
|
||||
#include <QCoreApplication>
|
||||
#include <QEventLoop>
|
||||
#include <QTimer>
|
||||
|
||||
namespace ThirdParty {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void initialize() {
|
||||
// Auto detect FFmpeg
|
||||
if (!ThirdParty::checkFFmpeg()) {
|
||||
QString path = ThirdParty::autodetectFFmpeg();
|
||||
if (!path.isEmpty()) ThirdParty::setFFmpegDir(path);
|
||||
}
|
||||
// Auto detect Rhubarb
|
||||
if (!ThirdParty::checkRhubarb()) {
|
||||
QString path = ThirdParty::autodetectRhubarb();
|
||||
if (!path.isEmpty()) ThirdParty::setRhubarbDir(path);
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// FFmpeg interface
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifdef _WIN32
|
||||
#define FFMPEG_EXE "/ffmpeg.exe"
|
||||
#define FFPROBE_EXE "/ffprobe.exe"
|
||||
#else
|
||||
#define FFMPEG_EXE "/ffmpeg"
|
||||
#define FFPROBE_EXE "/ffprobe"
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void getFFmpegVideoSupported(QStringList &exts) {
|
||||
exts.append("gif");
|
||||
exts.append("mp4");
|
||||
exts.append("webm");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void getFFmpegAudioSupported(QStringList &exts) {
|
||||
exts.append("mp3");
|
||||
exts.append("ogg");
|
||||
exts.append("flac");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool findFFmpeg(QString dir) {
|
||||
// Relative path
|
||||
if (dir.isEmpty() || dir.at(0) == ".") {
|
||||
dir = QCoreApplication::applicationDirPath() + "/" + dir;
|
||||
}
|
||||
|
||||
// Check if both executables exist
|
||||
return TSystem::doesExistFileOrLevel(TFilePath(dir + FFMPEG_EXE)) &&
|
||||
TSystem::doesExistFileOrLevel(TFilePath(dir + FFPROBE_EXE));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool checkFFmpeg() {
|
||||
// Path in preferences
|
||||
return findFFmpeg(Preferences::instance()->getFfmpegPath());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
QString autodetectFFmpeg() {
|
||||
QString dir = Preferences::instance()->getFfmpegPath();
|
||||
if (findFFmpeg(dir)) return dir;
|
||||
|
||||
// Let's try and autodetect the exe included with release
|
||||
QStringList folderList;
|
||||
|
||||
folderList.append(".");
|
||||
folderList.append("./ffmpeg"); // ffmpeg folder
|
||||
|
||||
#ifdef MACOSX
|
||||
// Look inside app
|
||||
folderList.append("./" +
|
||||
QString::fromStdString(TEnv::getApplicationFileName()) +
|
||||
".app/ffmpeg"); // ffmpeg folder
|
||||
#elif defined(LINUX) || defined(FREEBSD)
|
||||
// Need to account for symbolic links
|
||||
folderList.append(TEnv::getWorkingDirectory().getQString() +
|
||||
"/ffmpeg"); // ffmpeg folder
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
folderList.append("/usr/local/bin");
|
||||
folderList.append("/usr/bin");
|
||||
folderList.append("/bin");
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
QString exePath = TSystem::findFileLocation(folderList, "ffmpeg.exe");
|
||||
#else
|
||||
QString exePath = TSystem::findFileLocation(folderList, "ffmpeg");
|
||||
#endif
|
||||
|
||||
if (!exePath.isEmpty()) return exePath;
|
||||
|
||||
// give up
|
||||
return "";
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
QString getFFmpegDir() {
|
||||
return Preferences::instance()->getStringValue(ffmpegPath);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void setFFmpegDir(const QString &dir) {
|
||||
QString path = Preferences::instance()->getFfmpegPath();
|
||||
if (path != dir) Preferences::instance()->setValue(ffmpegPath, dir);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
int getFFmpegTimeout() {
|
||||
return Preferences::instance()->getIntValue(ffmpegTimeout);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void setFFmpegTimeout(int secs) {
|
||||
int timeout = Preferences::instance()->getIntValue(ffmpegTimeout);
|
||||
if (secs != timeout) Preferences::instance()->setValue(ffmpegTimeout, secs);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void runFFmpeg(QProcess &process, const QStringList &arguments) {
|
||||
QString dir = Preferences::instance()->getFfmpegPath();
|
||||
if (dir.at(0) == '.') // Relative path
|
||||
dir = QCoreApplication::applicationDirPath() + "/" + dir;
|
||||
|
||||
process.start(dir + FFMPEG_EXE, arguments);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void runFFprobe(QProcess &process, const QStringList &arguments) {
|
||||
QString dir = Preferences::instance()->getFfmpegPath();
|
||||
if (dir.at(0) == '.') // Relative path
|
||||
dir = QCoreApplication::applicationDirPath() + "/" + dir;
|
||||
|
||||
process.start(dir + FFPROBE_EXE, arguments);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void runFFmpegAudio(QProcess &process, QString srcPath, QString dstPath,
|
||||
int samplerate, int bpp, int channels) {
|
||||
QStringList args;
|
||||
args << "-y";
|
||||
args << "-i";
|
||||
args << srcPath;
|
||||
args << "-f";
|
||||
switch (bpp) {
|
||||
case 8: // unsigned
|
||||
args << "u8";
|
||||
break;
|
||||
case 16:
|
||||
args << "s16le";
|
||||
break;
|
||||
case 24:
|
||||
args << "s24le";
|
||||
break;
|
||||
case 32: // floating-point
|
||||
args << "f32le";
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
args << "-ac";
|
||||
args << QString::number(channels);
|
||||
args << "-ar";
|
||||
args << QString::number(samplerate);
|
||||
args << dstPath;
|
||||
|
||||
ThirdParty::runFFmpeg(process, args);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool readFFmpegAudio(QProcess &process, QByteArray &rawData) {
|
||||
if (!process.waitForStarted()) return false;
|
||||
if (!process.waitForFinished(30000)) return false;
|
||||
bool success = (process.exitCode() == 0);
|
||||
|
||||
if (success) rawData = process.readAllStandardOutput();
|
||||
process.close();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Rhubarb interface
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifdef _WIN32
|
||||
#define RHUBARB_EXE "/rhubarb.exe"
|
||||
#else
|
||||
#define RHUBARB_EXE "/rhubarb"
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool findRhubarb(QString dir) {
|
||||
// Rhubarb executable
|
||||
|
||||
// Relative path
|
||||
if (dir.isEmpty() || dir.at(0) == ".") {
|
||||
dir = QCoreApplication::applicationDirPath() + "/" + dir;
|
||||
}
|
||||
|
||||
// Check if executable exist
|
||||
return TSystem::doesExistFileOrLevel(TFilePath(dir + RHUBARB_EXE));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool checkRhubarb() {
|
||||
// Path in preferences
|
||||
return findRhubarb(Preferences::instance()->getRhubarbPath());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
QString autodetectRhubarb() {
|
||||
QString dir = Preferences::instance()->getRhubarbPath();
|
||||
if (findRhubarb(dir)) return dir;
|
||||
|
||||
// Let's try and autodetect the exe included with release
|
||||
QStringList folderList;
|
||||
|
||||
folderList.append(".");
|
||||
folderList.append("./rhubarb"); // rhubarb folder
|
||||
|
||||
#ifdef MACOSX
|
||||
// Look inside app
|
||||
folderList.append("./" +
|
||||
QString::fromStdString(TEnv::getApplicationFileName()) +
|
||||
".app/rhubarb"); // rhubarb folder
|
||||
#elif defined(LINUX) || defined(FREEBSD)
|
||||
// Need to account for symbolic links
|
||||
folderList.append(TEnv::getWorkingDirectory().getQString() +
|
||||
"/rhubarb"); // rhubarb folder
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
folderList.append("/usr/local/bin");
|
||||
folderList.append(return "/usr/bin");
|
||||
folderList.append(return "/bin");
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
QString exePath = TSystem::findFileLocation(folderList, "rhubarb.exe");
|
||||
#else
|
||||
QString exePath = TSystem::findFileLocation(folderList, "rhubarb");
|
||||
#endif
|
||||
|
||||
if (!exePath.isEmpty()) {
|
||||
Preferences::instance()->setValue(rhubarbPath, exePath);
|
||||
return exePath;
|
||||
}
|
||||
|
||||
// give up
|
||||
return "";
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void runRhubarb(QProcess &process, const QStringList &arguments) {
|
||||
QString dir = Preferences::instance()->getRhubarbPath();
|
||||
if (dir.at(0) == '.') // Relative path
|
||||
dir = QCoreApplication::applicationDirPath() + "/" + dir;
|
||||
|
||||
process.start(dir + RHUBARB_EXE, arguments);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
QString getRhubarbDir() {
|
||||
return Preferences::instance()->getStringValue(rhubarbPath);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void setRhubarbDir(const QString &dir) {
|
||||
QString path = Preferences::instance()->getRhubarbPath();
|
||||
if (path != dir) Preferences::instance()->setValue(rhubarbPath, dir);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
int getRhubarbTimeout() {
|
||||
return Preferences::instance()->getIntValue(rhubarbTimeout);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void setRhubarbTimeout(int secs) {
|
||||
int timeout = Preferences ::instance()->getIntValue(rhubarbTimeout);
|
||||
if (secs != timeout) Preferences::instance()->setValue(rhubarbTimeout, secs);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
int waitAsyncProcess(const QProcess &process, int timeout) {
|
||||
QEventLoop eloop;
|
||||
QTimer timer;
|
||||
timer.connect(&timer, &QTimer::timeout, &eloop, [&eloop] { eloop.exit(-2); });
|
||||
QMetaObject::Connection con1 = process.connect(
|
||||
&process, &QProcess::errorOccurred, &eloop, [&eloop] { eloop.exit(-1); });
|
||||
QMetaObject::Connection con2 = process.connect(
|
||||
&process,
|
||||
static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(
|
||||
&QProcess::finished),
|
||||
&eloop, &QEventLoop::quit);
|
||||
if (timeout >= 0) timer.start(timeout);
|
||||
|
||||
int result = eloop.exec();
|
||||
process.disconnect(con1);
|
||||
process.disconnect(con2);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
} // namespace ThirdParty
|
|
@ -801,7 +801,7 @@ else
|
|||
p->setValue(L"64(RGBM)");
|
||||
}
|
||||
|
||||
bool isMovie = (format=="avi");
|
||||
bool isMovie = (format=="mov" || format=="avi" || format=="3gp");
|
||||
|
||||
|
||||
TLevelWriterP lw;
|
||||
|
|
|
@ -836,6 +836,10 @@ TProjectManager *TProjectManager::instance() {
|
|||
return &_instance;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Clear all projecs roots container.
|
||||
//void TProjectManager::clearProjectsRoot() { m_projectsRoots.clear(); }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/*! Adds the specified folder \b fp in the projecs roots container.\n
|
||||
If \b fp is already contained in the container, the method does nothing.
|
||||
|
|
|
@ -593,6 +593,23 @@ TXshColumn::ColumnType TXshColumn::toColumnType(int levelType) {
|
|||
return colType;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool TXshColumn::canBeParent() const {
|
||||
switch (getColumnType()) {
|
||||
case eLevelType:
|
||||
case eZeraryFxType:
|
||||
case ePaletteType:
|
||||
case eMeshType:
|
||||
return true;
|
||||
case eSoundType:
|
||||
case eSoundTextType:
|
||||
return false;
|
||||
default:
|
||||
assert(!"Unknown level type!");
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool TXshColumn::isRendered() const {
|
||||
// if (!getXsheet() || !getFx()) return false;
|
||||
|
|
|
@ -321,7 +321,7 @@ Dialog::Dialog(QWidget *parent, bool hasButton, bool hasFixedSize,
|
|||
if (x > screen.right() - 50) x = screen.right() - 50;
|
||||
if (x < screen.left()) x = screen.left();
|
||||
if (y > screen.bottom() - 90) y = screen.bottom() - 90;
|
||||
if (y < screen.top()) y = screen.top();
|
||||
if (y <= screen.top()) y = screen.top() + 50; // pad for window title
|
||||
setGeometry(x, y, values.at(2).toInt(), values.at(3).toInt());
|
||||
settings.setValue(m_name, QString::number(x) + " " + QString::number(y) +
|
||||
" " + QString::number(values.at(2).toInt()) +
|
||||
|
|
|
@ -267,7 +267,7 @@ QString InfoViewerImp::getTypeString() {
|
|||
return "Smart Raster Level";
|
||||
else if (ext == "pli" || ext == "svg")
|
||||
return "Vector Level";
|
||||
else if (ext == "avi")
|
||||
else if (ext == "mov" || ext == "avi" || ext == "3gp")
|
||||
return "Movie File";
|
||||
else if (ext == "tnz")
|
||||
return "Tahoma2D Scene";
|
||||
|
|
Loading…
Reference in a new issue