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