|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// TnzCore includes
|
|
Toshihiro Shimizu |
890ddd |
#include "tsystem.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tstopwatch.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tthreadmessage.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "timagecache.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tlevel_io.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "trasterimage.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "timageinfo.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "trop.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tsop.h"
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// TnzLib includes
|
|
Toshihiro Shimizu |
890ddd |
#include "toonz/toonzscene.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "toonz/sceneproperties.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "toonz/txsheet.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "toonz/tcamera.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "toonz/preferences.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "toonz/trasterimageutils.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "toonz/levelupdater.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "toutputproperties.h"
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// tcg includes
|
|
Toshihiro Shimizu |
890ddd |
#include "tcg/tcg_macros.h"
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// Qt includes
|
|
Toshihiro Shimizu |
890ddd |
#include <qcoreapplication></qcoreapplication>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#include "toonz/movierenderer.h"
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//**************************************************************************
|
|
Toshihiro Shimizu |
890ddd |
// Local Namespace stuff
|
|
Toshihiro Shimizu |
890ddd |
//**************************************************************************
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
namespace
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int RenderSessionId = 0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//---------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void addMark(const TRasterP &mark, TRasterImageP img)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
TRasterP raster = img->getRaster();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (raster->getLx() >= mark->getLx() && raster->getLy() >= mark->getLy()) {
|
|
Toshihiro Shimizu |
890ddd |
TRasterP ras = raster->clone();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int borderx = troundp(0.035 * (ras->getLx() - mark->getLx()));
|
|
Toshihiro Shimizu |
890ddd |
int bordery = troundp(0.035 * (ras->getLy() - mark->getLy()));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TRect rect = TRect(borderx, bordery, borderx + mark->getLx() - 1, bordery + mark->getLy() - 1);
|
|
Toshihiro Shimizu |
890ddd |
TRop::over(ras->extract(rect), mark);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
img->setRaster(ras);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//---------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void getRange(ToonzScene *scene, bool isPreview, int &from, int &to)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
TSceneProperties *sprop = scene->getProperties();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int step;
|
|
Toshihiro Shimizu |
890ddd |
if (isPreview)
|
|
Toshihiro Shimizu |
890ddd |
sprop->getPreviewProperties()->getRange(from, to, step);
|
|
Toshihiro Shimizu |
890ddd |
else
|
|
Toshihiro Shimizu |
890ddd |
sprop->getOutputProperties()->getRange(from, to, step);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (to < 0) {
|
|
Toshihiro Shimizu |
890ddd |
TXsheet *xs = scene->getXsheet();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// NOTE: Use of numeric_limits::min is justified since the type is *INTERGRAL*.
|
|
Toshihiro Shimizu |
890ddd |
from = (std::numeric_limits<int>::max)(), to = (std::numeric_limits<int>::min)();</int></int>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (int k = 0; k < xs->getColumnCount(); ++k) {
|
|
Toshihiro Shimizu |
890ddd |
int r0, r1;
|
|
Toshihiro Shimizu |
890ddd |
xs->getCellRange(k, r0, r1);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
from = tmin(from, r0), to = tmax(to, r1);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//---------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
QString getPreviewName(unsigned long renderSessionId)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
return "previewed" + QString::number(renderSessionId) + ".noext";
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
} // namespace
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//**************************************************************************
|
|
Toshihiro Shimizu |
890ddd |
// MovieRenderer::Imp definition
|
|
Toshihiro Shimizu |
890ddd |
//**************************************************************************
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
class MovieRenderer::Imp : public TRenderPort, public TSmartObject
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Toshihiro Shimizu |
890ddd |
ToonzScene *m_scene;
|
|
Toshihiro Shimizu |
890ddd |
TRenderer m_renderer;
|
|
Toshihiro Shimizu |
890ddd |
TFilePath m_fp;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TRenderSettings m_renderSettings;
|
|
Toshihiro Shimizu |
890ddd |
TDimension m_frameSize;
|
|
Toshihiro Shimizu |
890ddd |
double m_xDpi, m_yDpi;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
std::set<movierenderer::listener *=""> m_listeners;</movierenderer::listener>
|
|
Toshihiro Shimizu |
890ddd |
std::auto_ptr<levelupdater> m_levelUpdaterA, m_levelUpdaterB;</levelupdater>
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackP m_st;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
std::map<double, std::pair<trasterp,="" trasterp="">> m_toBeSaved;</double,>
|
|
Toshihiro Shimizu |
890ddd |
std::vector<pair<double, tfxpair="">> m_framesToBeRendered;</pair<double,>
|
|
Toshihiro Shimizu |
890ddd |
std::string m_renderCacheId;
|
|
Toshihiro Shimizu |
890ddd |
/*--- 同じラスタのキャッシュを使いまわすとき、
|
|
Toshihiro Shimizu |
890ddd |
最初のものだけガンマをかけ、以降はそれを使いまわすようにする。
|
|
Toshihiro Shimizu |
890ddd |
---*/
|
|
Toshihiro Shimizu |
890ddd |
std::map<double, bool=""> m_toBeAppliedGamma;</double,>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TThread::Mutex m_mutex;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int m_renderSessionId;
|
|
Toshihiro Shimizu |
890ddd |
long m_whiteSample;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int m_nextFrameIdxToSave;
|
|
Toshihiro Shimizu |
890ddd |
int m_savingThreadsCount;
|
|
Toshihiro Shimizu |
890ddd |
bool m_firstCompletedRaster;
|
|
Toshihiro Shimizu |
890ddd |
bool m_failure;
|
|
Toshihiro Shimizu |
890ddd |
bool m_cacheResults;
|
|
Toshihiro Shimizu |
890ddd |
bool m_preview;
|
|
Toshihiro Shimizu |
890ddd |
bool m_movieType;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Toshihiro Shimizu |
890ddd |
Imp(ToonzScene *scene, const TFilePath &moviePath, int threadCount, bool cacheResults);
|
|
Toshihiro Shimizu |
890ddd |
~Imp();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// TRenderPort methods
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void onRenderRasterCompleted(const RenderData &renderData);
|
|
Toshihiro Shimizu |
890ddd |
void onRenderFailure(const RenderData &renderData, TException &e);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
/*-- キャンセル時にはm_overallRenderedRegionを更新しない --*/
|
|
Toshihiro Shimizu |
890ddd |
virtual void onRenderFinished(bool isCanceled = false);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void doRenderRasterCompleted(const RenderData &renderData);
|
|
Toshihiro Shimizu |
890ddd |
void doPreviewRasterCompleted(const RenderData &renderData);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// Helper methods
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void prepareForStart();
|
|
Toshihiro Shimizu |
890ddd |
void addSoundtrack(int r0, int r1, double fps);
|
|
Toshihiro Shimizu |
890ddd |
void postProcessImage(const TRasterImageP &img, bool has64bitOutputSupport, const TRasterP &mark, int frame);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//! Saves the specified rasters at the specified time; returns whether the frames were successfully saved, and
|
|
Toshihiro Shimizu |
890ddd |
//! the associated time-adjusted level frame.
|
|
Toshihiro Shimizu |
890ddd |
std::pair<bool, int=""> saveFrame(double frame, const std::pair<trasterp, trasterp=""> &rasters);</trasterp,></bool,>
|
|
Toshihiro Shimizu |
890ddd |
std::string getRenderCacheId();
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//---------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
MovieRenderer::Imp::Imp(ToonzScene *scene,
|
|
Toshihiro Shimizu |
890ddd |
const TFilePath &moviePath,
|
|
Toshihiro Shimizu |
890ddd |
int threadCount,
|
|
Toshihiro Shimizu |
890ddd |
bool cacheResults)
|
|
Toshihiro Shimizu |
890ddd |
: m_scene(scene), m_renderer(threadCount), m_fp(moviePath), m_frameSize(scene->getCurrentCamera()->getRes()), m_xDpi(72), m_yDpi(72), m_renderSessionId(RenderSessionId++), m_nextFrameIdxToSave(0), m_savingThreadsCount(0), m_whiteSample(0), m_firstCompletedRaster(true) //< I know, sounds weird - it's just set to false
|
|
Toshihiro Shimizu |
890ddd |
,
|
|
Toshihiro Shimizu |
890ddd |
m_failure(false) // AFTER the first completed raster gets processed
|
|
Toshihiro Shimizu |
890ddd |
,
|
|
Toshihiro Shimizu |
890ddd |
m_cacheResults(cacheResults), m_preview(moviePath.isEmpty()), m_movieType(isMovieType(moviePath))
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_renderCacheId = m_fp.withName(m_fp.getName() + "#RENDERID" + QString::number(m_renderSessionId).toStdString())
|
|
Toshihiro Shimizu |
890ddd |
.getLevelName();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
m_renderer.addPort(this);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//---------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
MovieRenderer::Imp::~Imp()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_renderer.removePort(this); // Please, note: a TRenderer instance is currently a shared-pointer-like
|
|
Toshihiro Shimizu |
890ddd |
} // object to a private worker. *That* object may outlive the TRenderer instance.
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//---------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void MovieRenderer::Imp::prepareForStart()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
struct locals {
|
|
Toshihiro Shimizu |
890ddd |
static void eraseUncompatibleExistingLevel(const TFilePath &fp, const TDimension &imageSize) // nothrow
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
assert(!fp.isEmpty());
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (TSystem::doesExistFileOrLevel(fp)) {
|
|
Toshihiro Shimizu |
890ddd |
bool remove = false;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// In case the raster specifics are different from those of a currently
|
|
Toshihiro Shimizu |
890ddd |
// existing movie, erase it
|
|
Toshihiro Shimizu |
890ddd |
try {
|
|
Toshihiro Shimizu |
890ddd |
TLevelReaderP lr(fp);
|
|
Toshihiro Shimizu |
890ddd |
lr->loadInfo();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
const TImageInfo *info = lr->getImageInfo();
|
|
Toshihiro Shimizu |
890ddd |
if (!info || info->m_lx != imageSize.lx || info->m_ly != imageSize.ly)
|
|
Toshihiro Shimizu |
890ddd |
TSystem::removeFileOrLevel(fp); // nothrow
|
|
Toshihiro Shimizu |
890ddd |
} catch (...) {
|
|
Toshihiro Shimizu |
890ddd |
// Same if the level could not be read/opened
|
|
Toshihiro Shimizu |
890ddd |
TSystem::removeFileOrLevel(fp); // nothrow
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// NOTE: The level removal procedure could still fail.
|
|
Toshihiro Shimizu |
890ddd |
// In this case, no signaling takes place. The level readers will throw
|
|
Toshihiro Shimizu |
890ddd |
// when the time to write on the file comes, leading to a render failure.
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TOutputProperties *oprop = m_scene->getProperties()->getOutputProperties();
|
|
Toshihiro Shimizu |
890ddd |
double frameRate = (double)oprop->getFrameRate();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
/*-- Frame rate の stretch --*/
|
|
Toshihiro Shimizu |
890ddd |
double stretchFactor = oprop->getRenderSettings().m_timeStretchTo / oprop->getRenderSettings().m_timeStretchFrom;
|
|
Toshihiro Shimizu |
890ddd |
frameRate *= stretchFactor;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// Get the shrink
|
|
Toshihiro Shimizu |
890ddd |
int shrinkX = m_renderSettings.m_shrinkX, shrinkY = m_renderSettings.m_shrinkY;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//Build the render area
|
|
Toshihiro Shimizu |
890ddd |
TPointD cameraPos(-0.5 * m_frameSize.lx, -0.5 * m_frameSize.ly);
|
|
Toshihiro Shimizu |
890ddd |
TDimensionD cameraRes(double(m_frameSize.lx) / shrinkX, double(m_frameSize.ly) / shrinkY);
|
|
Toshihiro Shimizu |
890ddd |
TDimension cameraResI(cameraRes.lx, cameraRes.ly);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TRectD renderArea(cameraPos.x, cameraPos.y, cameraPos.x + cameraRes.lx, cameraPos.y + cameraRes.ly);
|
|
Toshihiro Shimizu |
890ddd |
setRenderArea(renderArea);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (!m_fp.isEmpty()) {
|
|
Toshihiro Shimizu |
890ddd |
try // Construction of a LevelUpdater may throw (well, almost ANY operation on a LevelUpdater
|
|
Toshihiro Shimizu |
890ddd |
{ // could throw). But due to backward compatibility this function is assumed to be non-throwing.
|
|
Toshihiro Shimizu |
890ddd |
if (!m_renderSettings.m_stereoscopic) {
|
|
Toshihiro Shimizu |
890ddd |
locals::eraseUncompatibleExistingLevel(m_fp, cameraResI);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
m_levelUpdaterA.reset(new LevelUpdater(m_fp, oprop->getFileFormatProperties(m_fp.getType())));
|
|
Toshihiro Shimizu |
890ddd |
m_levelUpdaterA->getLevelWriter()->setFrameRate(frameRate);
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
TFilePath leftFp = m_fp.withName(m_fp.getName() + "_l");
|
|
Toshihiro Shimizu |
890ddd |
TFilePath rightFp = m_fp.withName(m_fp.getName() + "_r");
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
locals::eraseUncompatibleExistingLevel(leftFp, cameraResI);
|
|
Toshihiro Shimizu |
890ddd |
locals::eraseUncompatibleExistingLevel(rightFp, cameraResI);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
m_levelUpdaterA.reset(new LevelUpdater(leftFp, oprop->getFileFormatProperties(leftFp.getType())));
|
|
Toshihiro Shimizu |
890ddd |
m_levelUpdaterA->getLevelWriter()->setFrameRate(frameRate);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
m_levelUpdaterB.reset(new LevelUpdater(rightFp, oprop->getFileFormatProperties(rightFp.getType())));
|
|
Toshihiro Shimizu |
890ddd |
m_levelUpdaterB->getLevelWriter()->setFrameRate(frameRate);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
} catch (...) {
|
|
Toshihiro Shimizu |
890ddd |
// If we get here, it's because one of the LevelUpdaters could not be created. So, let's say
|
|
Toshihiro Shimizu |
890ddd |
// that if one could not be created, then ALL OF THEM couldn't (ie saving is not possible at all).
|
|
Toshihiro Shimizu |
890ddd |
m_levelUpdaterA.reset();
|
|
Toshihiro Shimizu |
890ddd |
m_levelUpdaterB.reset();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//---------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void MovieRenderer::Imp::addSoundtrack(int r0, int r1, double fps)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
TCG_ASSERT(r0 <= r1, return );
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TXsheet::SoundProperties *prop = new TXsheet::SoundProperties(); // Ownership will be surrendered ...
|
|
Toshihiro Shimizu |
890ddd |
prop->m_frameRate = fps;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrack *snd = m_scene->getXsheet()->makeSound(prop); // ... here
|
|
Toshihiro Shimizu |
890ddd |
if (!snd) {
|
|
Toshihiro Shimizu |
890ddd |
// No soundtrack
|
|
Toshihiro Shimizu |
890ddd |
m_whiteSample = (r1 - r0 + 1) * 918; // 918?? wtf... I don't think it has
|
|
Toshihiro Shimizu |
890ddd |
return; // any arcane meaning - but i'm not touching it.
|
|
Toshihiro Shimizu |
890ddd |
} // My impression would be that... no sound implies
|
|
Toshihiro Shimizu |
890ddd |
// no access to m_whiteSample, no?
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
double samplePerFrame = snd->getSampleRate() / fps;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// Extract the useful part of scene soundtrack
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackP snd1 = snd->extract((TINT32)(r0 * samplePerFrame),
|
|
Toshihiro Shimizu |
890ddd |
(TINT32)(r1 * samplePerFrame));
|
|
Toshihiro Shimizu |
890ddd |
assert(!m_st);
|
|
Toshihiro Shimizu |
890ddd |
if (!m_st) {
|
|
Toshihiro Shimizu |
890ddd |
// First, add white sound before the 'from' instant
|
|
Toshihiro Shimizu |
890ddd |
m_st = TSoundTrack::create(snd1->getFormat(), m_whiteSample);
|
|
Toshihiro Shimizu |
890ddd |
m_whiteSample = 0; // Why? Probably being pedantic here... I guess
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// Then, add the rest
|
|
Toshihiro Shimizu |
890ddd |
TINT32 fromSample = m_st->getSampleCount();
|
|
Toshihiro Shimizu |
890ddd |
TINT32 numSample = tmax(TINT32((r1 - r0 + 1) * samplePerFrame),
|
|
Toshihiro Shimizu |
890ddd |
snd1->getSampleCount());
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
m_st = TSop::insertBlank(m_st, fromSample, numSample + m_whiteSample);
|
|
Toshihiro Shimizu |
890ddd |
m_st->copy(snd1, TINT32(fromSample + m_whiteSample));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
m_whiteSample = 0;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//---------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void MovieRenderer::Imp::onRenderRasterCompleted(const RenderData &renderData)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
if (m_preview)
|
|
Toshihiro Shimizu |
890ddd |
doPreviewRasterCompleted(renderData);
|
|
Toshihiro Shimizu |
890ddd |
else
|
|
Toshihiro Shimizu |
890ddd |
doRenderRasterCompleted(renderData);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//---------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void MovieRenderer::Imp::postProcessImage(const TRasterImageP &img, bool has64bitOutputSupport, const TRasterP &mark, int frame)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
img->setDpi(m_xDpi, m_yDpi);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (img->getRaster()->getPixelSize() == 8 && !has64bitOutputSupport) {
|
|
Toshihiro Shimizu |
890ddd |
TRaster32P aux(img->getRaster()->getLx(), img->getRaster()->getLy());
|
|
Toshihiro Shimizu |
890ddd |
TRop::convert(aux, img->getRaster());
|
|
Toshihiro Shimizu |
890ddd |
img->setRaster(aux);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (mark)
|
|
Toshihiro Shimizu |
890ddd |
addMark(mark, img);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (Preferences::instance()->isSceneNumberingEnabled())
|
|
Toshihiro Shimizu |
890ddd |
TRasterImageUtils::addGlobalNumbering(img, m_scene->getSceneName(), frame);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//---------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
std::pair<bool, int=""> MovieRenderer::Imp::saveFrame(double frame, const std::pair<trasterp, trasterp=""> &rasters)</trasterp,></bool,>
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
bool success = false;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// Build the frame number to write to
|
|
Toshihiro Shimizu |
890ddd |
double stretchFac = double(m_renderSettings.m_timeStretchTo) / m_renderSettings.m_timeStretchFrom;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int fr = (stretchFac != 1) ? tround(frame * stretchFac) : int(frame);
|
|
Toshihiro Shimizu |
890ddd |
TFrameId fid(fr + 1);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (m_levelUpdaterA.get()) {
|
|
Toshihiro Shimizu |
890ddd |
assert(m_levelUpdaterB.get() || !rasters.second);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// Analyze writer
|
|
Toshihiro Shimizu |
890ddd |
bool has64bitOutputSupport = false;
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
if (TImageWriterP writerA = m_levelUpdaterA->getLevelWriter()->getFrameWriter(fid))
|
|
Toshihiro Shimizu |
890ddd |
has64bitOutputSupport = writerA->is64bitOutputSupported();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// NOTE: If the writer could not be retrieved, the updater will throw.
|
|
Toshihiro Shimizu |
890ddd |
// Failure will be catched then.
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// Prepare the images to be flushed
|
|
Toshihiro Shimizu |
890ddd |
TRasterP rasterA = rasters.first, rasterB = rasters.second;
|
|
Toshihiro Shimizu |
890ddd |
assert(rasterA);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
/*--- 同じラスタのキャッシュを使いまわすとき、
|
|
Toshihiro Shimizu |
890ddd |
最初のものだけガンマをかけ、以降はそれを使いまわすようにする。
|
|
Toshihiro Shimizu |
890ddd |
---*/
|
|
Toshihiro Shimizu |
890ddd |
if (m_renderSettings.m_gamma != 1.0 && m_toBeAppliedGamma[frame]) {
|
|
Toshihiro Shimizu |
890ddd |
TRop::gammaCorrect(rasterA, m_renderSettings.m_gamma);
|
|
Toshihiro Shimizu |
890ddd |
if (rasterB)
|
|
Toshihiro Shimizu |
890ddd |
TRop::gammaCorrect(rasterB, m_renderSettings.m_gamma);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// Flush images
|
|
Toshihiro Shimizu |
890ddd |
try {
|
|
Toshihiro Shimizu |
890ddd |
TRasterImageP imgA(rasterA);
|
|
Toshihiro Shimizu |
890ddd |
postProcessImage(imgA, has64bitOutputSupport, m_renderSettings.m_mark, fid.getNumber());
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
m_levelUpdaterA->update(fid, imgA);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (rasterB) {
|
|
Toshihiro Shimizu |
890ddd |
TRasterImageP imgB(rasterB);
|
|
Toshihiro Shimizu |
890ddd |
postProcessImage(imgB, has64bitOutputSupport, m_renderSettings.m_mark, fid.getNumber());
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
m_levelUpdaterB->update(fid, imgB);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// Should no more throw from here on
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (m_cacheResults) {
|
|
Toshihiro Shimizu |
890ddd |
if (imgA->getRaster()->getPixelSize() == 8) {
|
|
Toshihiro Shimizu |
890ddd |
// Convert 64-bit images to 32 - cached images are supposed to be 32-bit
|
|
Toshihiro Shimizu |
890ddd |
TRaster32P aux(imgA->getRaster()->getLx(), imgA->getRaster()->getLy());
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TRop::convert(aux, imgA->getRaster());
|
|
Toshihiro Shimizu |
890ddd |
imgA->setRaster(aux);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TImageCache::instance()->add(m_renderCacheId + toString(fid.getNumber()), imgA);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
success = true;
|
|
Toshihiro Shimizu |
890ddd |
} catch (...) {
|
|
Toshihiro Shimizu |
890ddd |
// Nothing. The images could not be saved for whatever reason.
|
|
Toshihiro Shimizu |
890ddd |
// Failure is reported.
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
return std::make_pair(success, fr);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//---------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void MovieRenderer::Imp::doRenderRasterCompleted(const RenderData &renderData)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
assert(!(m_cacheResults && m_levelUpdaterB.get())); // Cannot cache results on stereoscopy
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
QMutexLocker locker(&m_mutex);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// Build soundtrack at the first time a frame is completed - and the filetype is that of a movie.
|
|
Toshihiro Shimizu |
890ddd |
if (m_firstCompletedRaster && m_movieType && !m_st) {
|
|
Toshihiro Shimizu |
890ddd |
int from, to;
|
|
Toshihiro Shimizu |
890ddd |
getRange(m_scene, false, from, to);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TLevelP oldLevel(m_levelUpdaterA->getInputLevel());
|
|
Toshihiro Shimizu |
890ddd |
if (oldLevel) {
|
|
Toshihiro Shimizu |
890ddd |
from = tmin(from, oldLevel->begin()->first.getNumber() - 1);
|
|
Toshihiro Shimizu |
890ddd |
to = tmax(to, (--oldLevel->end())->first.getNumber() - 1);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
addSoundtrack(from, to, m_scene->getProperties()->getOutputProperties()->getFrameRate());
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (m_st) {
|
|
Toshihiro Shimizu |
890ddd |
m_levelUpdaterA->getLevelWriter()->saveSoundTrack(m_st.getPointer());
|
|
Toshihiro Shimizu |
890ddd |
if (m_levelUpdaterB.get())
|
|
Toshihiro Shimizu |
890ddd |
m_levelUpdaterB->getLevelWriter()->saveSoundTrack(m_st.getPointer());
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// Output frames must be *cloned*, since the supplied rasters will be overwritten by m_renderer
|
|
Toshihiro Shimizu |
890ddd |
TRasterP toBeSavedRasA = renderData.m_rasA->clone();
|
|
Toshihiro Shimizu |
890ddd |
TRasterP toBeSavedRasB = renderData.m_rasB ? renderData.m_rasB->clone() : TRasterP();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
m_toBeSaved[renderData.m_frames[0]] = std::make_pair(toBeSavedRasA, toBeSavedRasB);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
m_toBeAppliedGamma[renderData.m_frames[0]] = true;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// Prepare the cluster's frames to be saved (possibly in the future)
|
|
Toshihiro Shimizu |
890ddd |
std::vector<double>::const_iterator jt;</double>
|
|
Toshihiro Shimizu |
890ddd |
for (jt = renderData.m_frames.begin(), ++jt; jt != renderData.m_frames.end(); ++jt) {
|
|
Toshihiro Shimizu |
890ddd |
m_toBeSaved[*jt] = std::make_pair(toBeSavedRasA, toBeSavedRasB);
|
|
Toshihiro Shimizu |
890ddd |
m_toBeAppliedGamma[*jt] = false;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// Attempt flushing as many frames as possible to the level updater(s)
|
|
Toshihiro Shimizu |
890ddd |
while (!m_toBeSaved.empty()) {
|
|
Toshihiro Shimizu |
890ddd |
std::map<double, std::pair<trasterp,="" trasterp="">>::iterator ft = m_toBeSaved.begin();</double,>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// In the *movie type* case, frames must be saved sequentially.
|
|
Toshihiro Shimizu |
890ddd |
// If the frame is not the next one in the sequence, wait until *that* frame is available.
|
|
Toshihiro Shimizu |
890ddd |
if (m_movieType && (ft->first != m_framesToBeRendered[m_nextFrameIdxToSave].first))
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// This thread will be the one processing ft - remove it from the map to prevent another
|
|
Toshihiro Shimizu |
890ddd |
// thread from interfering
|
|
Toshihiro Shimizu |
890ddd |
double frame = ft->first;
|
|
Toshihiro Shimizu |
890ddd |
std::pair<trasterp, trasterp=""> rasters = ft->second;</trasterp,>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
++m_nextFrameIdxToSave;
|
|
Toshihiro Shimizu |
890ddd |
m_toBeSaved.erase(ft);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// Save current frame
|
|
Toshihiro Shimizu |
890ddd |
std::pair<bool, int=""> savedFrame;</bool,>
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
// Time the saving procedure
|
|
Toshihiro Shimizu |
890ddd |
struct SaveTimer {
|
|
Toshihiro Shimizu |
890ddd |
int &m_count;
|
|
Toshihiro Shimizu |
890ddd |
SaveTimer(int &count) : m_count(count)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
if (m_count++ == 0)
|
|
Toshihiro Shimizu |
890ddd |
TStopWatch::global(0).start();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
~SaveTimer()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
if (--m_count == 0)
|
|
Toshihiro Shimizu |
890ddd |
TStopWatch::global(0).stop();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
} saveTimer(m_savingThreadsCount);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// Unlock the mutex only in case this is NOT a movie type. Single images can be saved concurrently.
|
|
Toshihiro Shimizu |
890ddd |
struct MutexUnlocker {
|
|
Toshihiro Shimizu |
890ddd |
QMutexLocker *m_locker;
|
|
Toshihiro Shimizu |
890ddd |
~MutexUnlocker()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
if (m_locker)
|
|
Toshihiro Shimizu |
890ddd |
m_locker->relock();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
} unlocker = {m_movieType ? (QMutexLocker *)0 : (locker.unlock(), &locker)};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
savedFrame = saveFrame(frame, rasters);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// Report status and deal with responses
|
|
Toshihiro Shimizu |
890ddd |
bool okToContinue = true;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
std::set<movierenderer::listener *="">::iterator lt = m_listeners.begin();</movierenderer::listener>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (savedFrame.first) {
|
|
Toshihiro Shimizu |
890ddd |
for (; lt != m_listeners.end(); ++lt)
|
|
Toshihiro Shimizu |
890ddd |
okToContinue &= (*lt)->onFrameCompleted(savedFrame.second);
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
for (; lt != m_listeners.end(); ++lt) {
|
|
Toshihiro Shimizu |
890ddd |
TException e;
|
|
Toshihiro Shimizu |
890ddd |
okToContinue &= (*lt)->onFrameFailed(savedFrame.second, e);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (!okToContinue) {
|
|
Toshihiro Shimizu |
890ddd |
// Some listener invoked termination of the render procedure. It seems it's their right
|
|
Toshihiro Shimizu |
890ddd |
// to do so. I wonder what happens if two listeners would disagree on the matter...
|
|
Toshihiro Shimizu |
890ddd |
// BTW stop the rendering, alright.
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
int from, to;
|
|
Toshihiro Shimizu |
890ddd |
getRange(m_scene, false, from, to); // It's ok since cancels can only happen from Toonz...
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (int i = from; i < to; i++)
|
|
Toshihiro Shimizu |
890ddd |
TImageCache::instance()->remove(m_renderCacheId + toString(i + 1));
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
m_renderer.stopRendering();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
m_levelUpdaterA.reset(); // No more saving. Further attempts to save images
|
|
Toshihiro Shimizu |
890ddd |
m_levelUpdaterB.reset(); // will be rejected and treated as failures.
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
m_firstCompletedRaster = false;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//---------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void MovieRenderer::Imp::doPreviewRasterCompleted(const RenderData &renderData)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
// Most probably unused now. I'm not reviewing this.
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
assert(!m_levelUpdaterA.get());
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
QMutexLocker sl(&m_mutex);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
QString name = getPreviewName(m_renderSessionId);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TRasterP ras = renderData.m_rasA->clone();
|
|
Toshihiro Shimizu |
890ddd |
if (renderData.m_rasB) {
|
|
Toshihiro Shimizu |
890ddd |
assert(m_renderSettings.m_stereoscopic);
|
|
Toshihiro Shimizu |
890ddd |
TRop::makeStereoRaster(ras, renderData.m_rasB);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TRasterImageP img(ras);
|
|
Toshihiro Shimizu |
890ddd |
img->setDpi(m_xDpi, m_yDpi);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
try {
|
|
Toshihiro Shimizu |
890ddd |
if (renderData.m_info.m_mark != TRasterP())
|
|
Toshihiro Shimizu |
890ddd |
addMark(renderData.m_info.m_mark, img);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (img->getRaster()->getPixelSize() == 8) {
|
|
Toshihiro Shimizu |
890ddd |
TRaster32P aux(img->getRaster()->getLx(), img->getRaster()->getLy());
|
|
Toshihiro Shimizu |
890ddd |
TRop::convert(aux, img->getRaster());
|
|
Toshihiro Shimizu |
890ddd |
img->setRaster(aux);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
QString frameName = name + QString::number(renderData.m_frames[0] + 1);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TImageCache::instance()->add(frameName.toStdString(), img);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//controlla se ci sono frame(uguali ad altri) da mettere in cache
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
std::vector<double>::const_iterator jt;</double>
|
|
Toshihiro Shimizu |
890ddd |
for (jt = renderData.m_frames.begin(), ++jt; jt != renderData.m_frames.end(); ++jt) {
|
|
Toshihiro Shimizu |
890ddd |
frameName = name + QString::number(*jt + 1);
|
|
Toshihiro Shimizu |
890ddd |
TImageCache::instance()->add(frameName.toStdString(), img);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
} catch (...) {
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
std::set<movierenderer::listener *="">::iterator listenerIt = m_listeners.begin();</movierenderer::listener>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool okToContinue = true;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (; listenerIt != m_listeners.end(); ++listenerIt)
|
|
Toshihiro Shimizu |
890ddd |
okToContinue &= (*listenerIt)->onFrameCompleted(renderData.m_frames[0]);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (!okToContinue) {
|
|
Toshihiro Shimizu |
890ddd |
// Svuoto la cache nel caso in cui si esce dal render prima della fine
|
|
Toshihiro Shimizu |
890ddd |
int from, to;
|
|
Toshihiro Shimizu |
890ddd |
getRange(m_scene, true, from, to);
|
|
Toshihiro Shimizu |
890ddd |
for (int i = from; i < to; i++) {
|
|
Toshihiro Shimizu |
890ddd |
QString frameName = name + QString::number(i + 1);
|
|
Toshihiro Shimizu |
890ddd |
TImageCache::instance()->remove(frameName.toStdString());
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
m_renderer.stopRendering();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
m_firstCompletedRaster = false;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//---------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void MovieRenderer::Imp::onRenderFailure(const RenderData &renderData, TException &e)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
QMutexLocker sl(&m_mutex); // Lock as soon as possible.
|
|
Toshihiro Shimizu |
890ddd |
// No sense making it later in this case!
|
|
Toshihiro Shimizu |
890ddd |
m_failure = true;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// If the saver object has already been destroyed - or it was never
|
|
Toshihiro Shimizu |
890ddd |
// created to begin with, nothing to be done
|
|
Toshihiro Shimizu |
890ddd |
if (!m_levelUpdaterA.get())
|
|
Toshihiro Shimizu |
890ddd |
return; // The preview case would fall here
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// Flush out as much as we can of the frames that were already rendered
|
|
Toshihiro Shimizu |
890ddd |
m_toBeSaved[0.0] = std::make_pair(TRasterP(), TRasterP()); // ?? Why is this ??
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
std::map<double, std::pair<trasterp,="" trasterp="">>::iterator it = m_toBeSaved.begin();</double,>
|
|
Toshihiro Shimizu |
890ddd |
while (it != m_toBeSaved.end()) {
|
|
Toshihiro Shimizu |
890ddd |
if (m_movieType && (it->first != m_framesToBeRendered[m_nextFrameIdxToSave].first))
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// o_o!
|
|
Toshihiro Shimizu |
890ddd |
// I would have expected that at least those frames that were computed could
|
|
Toshihiro Shimizu |
890ddd |
// attempt saving! Why is this not addressed? They're even marked as 'failed'!
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
double stretchFac = (double)renderData.m_info.m_timeStretchTo / renderData.m_info.m_timeStretchFrom;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int fr;
|
|
Toshihiro Shimizu |
890ddd |
if (stretchFac != 1)
|
|
Toshihiro Shimizu |
890ddd |
fr = tround(it->first * stretchFac);
|
|
Toshihiro Shimizu |
890ddd |
else
|
|
Toshihiro Shimizu |
890ddd |
fr = (int)it->first;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// No saving? Really?
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
std::set<movierenderer::listener *="">::iterator lt = m_listeners.begin();</movierenderer::listener>
|
|
Toshihiro Shimizu |
890ddd |
bool okToContinue = true;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (; lt != m_listeners.end(); ++lt)
|
|
Toshihiro Shimizu |
890ddd |
okToContinue &= (*lt)->onFrameFailed((int)it->first, e);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (!okToContinue)
|
|
Toshihiro Shimizu |
890ddd |
m_renderer.stopRendering();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
++m_nextFrameIdxToSave;
|
|
Toshihiro Shimizu |
890ddd |
m_toBeSaved.erase(it++);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//---------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void MovieRenderer::Imp::onRenderFinished(bool isCanceled)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
TFilePath levelName(m_levelUpdaterA.get() ? m_fp : TFilePath(getPreviewName(m_renderSessionId).toStdWString()));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// Close updaters. After this, the output levels should be finalized on disk.
|
|
Toshihiro Shimizu |
890ddd |
m_levelUpdaterA.reset();
|
|
Toshihiro Shimizu |
890ddd |
m_levelUpdaterB.reset();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (!m_failure) {
|
|
Toshihiro Shimizu |
890ddd |
// Inform listeners of the render completion
|
|
Toshihiro Shimizu |
890ddd |
std::set<movierenderer::listener *="">::iterator it;</movierenderer::listener>
|
|
Toshihiro Shimizu |
890ddd |
for (it = m_listeners.begin(); it != m_listeners.end(); ++it)
|
|
Toshihiro Shimizu |
890ddd |
(*it)->onSequenceCompleted(levelName);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// I wonder why listeners are not informed of a failed sequence, btw...
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
release(); // The movieRenderer is released by the render process. It could eventually be deleted.
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//======================================================================================
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//======================
|
|
Toshihiro Shimizu |
890ddd |
// MovieRenderer
|
|
Toshihiro Shimizu |
890ddd |
//----------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
MovieRenderer::MovieRenderer(ToonzScene *scene, const TFilePath &moviePath, int threadCount, bool cacheResults)
|
|
Toshihiro Shimizu |
890ddd |
: m_imp(new Imp(scene, moviePath, threadCount, cacheResults))
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_imp->addRef(); // See MovieRenderer::start(). Can't just delete it in the dtor.
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//---------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
MovieRenderer::~MovieRenderer()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_imp->release();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//---------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void MovieRenderer::setRenderSettings(const TRenderSettings &renderSettings)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_renderSettings = renderSettings;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//---------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void MovieRenderer::setDpi(double xDpi, double yDpi)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_xDpi = xDpi;
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_yDpi = yDpi;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//---------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void MovieRenderer::addListener(Listener *listener)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_listeners.insert(listener);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//---------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void MovieRenderer::addFrame(double frame, const TFxPair &fxPair)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_framesToBeRendered.push_back(std::make_pair(frame, fxPair));
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//---------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void MovieRenderer::enablePrecomputing(bool on)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_renderer.enablePrecomputing(on);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//---------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool MovieRenderer::isPrecomputingEnabled() const
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
return m_imp->m_renderer.isPrecomputingEnabled();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//---------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void MovieRenderer::start()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_imp->prepareForStart();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//Add a reference to MovieRenderer's Imp. The reference is 'owned' by TRenderer's render process - when it
|
|
Toshihiro Shimizu |
890ddd |
//ends (that is, when notifies onRenderFinished), the reference is released. As to TRenderer's specifics,
|
|
Toshihiro Shimizu |
890ddd |
//this is ensured to happen only after all the other port notifications for each frame have been invoked.
|
|
Toshihiro Shimizu |
890ddd |
m_imp->addRef();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//Prepare the TRenderer::RenderDatas to render
|
|
Toshihiro Shimizu |
890ddd |
RenderDataVector *datasToBeRendered = new RenderDataVector;
|
|
Toshihiro Shimizu |
890ddd |
size_t i, size = m_imp->m_framesToBeRendered.size();
|
|
Toshihiro Shimizu |
890ddd |
for (i = 0; i < size; ++i)
|
|
Toshihiro Shimizu |
890ddd |
datasToBeRendered->push_back(TRenderer::RenderData(
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_framesToBeRendered[i].first,
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_renderSettings,
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_framesToBeRendered[i].second));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_renderer.startRendering(datasToBeRendered);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//---------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void MovieRenderer::onCanceled()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_renderer.stopRendering(true);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//---------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TRenderer *MovieRenderer::getTRenderer()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
// Again, this is somewhat BAD. The pointed-to object dies together with the MovieRenderer instance.
|
|
Toshihiro Shimizu |
890ddd |
// Since a TRenderer is already smart-pointer-like, we could just return a copy - however, it really
|
|
Toshihiro Shimizu |
890ddd |
// shouln't be that way. Maybe one day we'll revert that and actually use a smart pointer class.
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// For now, no use of this function seems to access the returned pointer beyond the lifespan of the
|
|
Toshihiro Shimizu |
890ddd |
// associated MovieRenderer instance - so I'm not gonna touch the class interface.
|
|
Toshihiro Shimizu |
890ddd |
return &m_imp->m_renderer;
|
|
Toshihiro Shimizu |
890ddd |
}
|