@@ -156,7 +156,7 @@ bool ExportTask::Run()
|
||||
return success;
|
||||
}
|
||||
|
||||
void ExportTask::FrameDownloaded(FramePtr f, const QByteArray &hash, const QVector<rational> ×)
|
||||
bool ExportTask::FrameDownloaded(FramePtr f, const QByteArray &hash, const QVector<rational> ×)
|
||||
{
|
||||
Q_UNUSED(hash)
|
||||
|
||||
@@ -180,14 +180,19 @@ void ExportTask::FrameDownloaded(FramePtr f, const QByteArray &hash, const QVect
|
||||
|
||||
// Unfortunately this can't be done in another thread since the frames need to be sent
|
||||
// one after the other chronologically.
|
||||
encoder_->WriteFrame(time_map_.take(real_time), real_time);
|
||||
if (!encoder_->WriteFrame(time_map_.take(real_time), real_time)) {
|
||||
SetError(encoder_->GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
frame_time_++;
|
||||
emit ProgressChanged(double(frame_time_) / double(GetTotalNumberOfFrames()));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ExportTask::AudioDownloaded(const TimeRange &range, SampleBufferPtr samples)
|
||||
bool ExportTask::AudioDownloaded(const TimeRange &range, SampleBufferPtr samples)
|
||||
{
|
||||
TimeRange adjusted_range = range;
|
||||
|
||||
@@ -196,20 +201,33 @@ void ExportTask::AudioDownloaded(const TimeRange &range, SampleBufferPtr samples
|
||||
}
|
||||
|
||||
if (adjusted_range.in() == audio_time_) {
|
||||
WriteAudioLoop(adjusted_range, samples);
|
||||
if (!WriteAudioLoop(adjusted_range, samples)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
audio_map_.insert(adjusted_range, samples);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ExportTask::EncodeSubtitle(const SubtitleBlock *sub)
|
||||
bool ExportTask::EncodeSubtitle(const SubtitleBlock *sub)
|
||||
{
|
||||
encoder_->WriteSubtitle(sub);
|
||||
if (!encoder_->WriteSubtitle(sub)) {
|
||||
SetError(encoder_->GetError());
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void ExportTask::WriteAudioLoop(const TimeRange& time, SampleBufferPtr samples)
|
||||
bool ExportTask::WriteAudioLoop(const TimeRange& time, SampleBufferPtr samples)
|
||||
{
|
||||
encoder_->WriteAudio(samples);
|
||||
if (!encoder_->WriteAudio(samples)) {
|
||||
SetError(encoder_->GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
audio_time_ = time.out();
|
||||
|
||||
for (auto it=audio_map_.begin(); it!=audio_map_.end(); it++) {
|
||||
@@ -221,12 +239,16 @@ void ExportTask::WriteAudioLoop(const TimeRange& time, SampleBufferPtr samples)
|
||||
audio_map_.erase(it);
|
||||
|
||||
// Call recursively to write the next sample buffer
|
||||
WriteAudioLoop(t, s);
|
||||
if (!WriteAudioLoop(t, s)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Break out of loop
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -38,11 +38,11 @@ public:
|
||||
protected:
|
||||
virtual bool Run() override;
|
||||
|
||||
virtual void FrameDownloaded(FramePtr frame, const QByteArray& hash, const QVector<rational>& times) override;
|
||||
virtual bool FrameDownloaded(FramePtr frame, const QByteArray& hash, const QVector<rational>& times) override;
|
||||
|
||||
virtual void AudioDownloaded(const TimeRange& range, SampleBufferPtr samples) override;
|
||||
virtual bool AudioDownloaded(const TimeRange& range, SampleBufferPtr samples) override;
|
||||
|
||||
virtual void EncodeSubtitle(const SubtitleBlock *sub) override;
|
||||
virtual bool EncodeSubtitle(const SubtitleBlock *sub) override;
|
||||
|
||||
virtual bool TwoStepFrameRendering() const override
|
||||
{
|
||||
@@ -50,7 +50,7 @@ protected:
|
||||
}
|
||||
|
||||
private:
|
||||
void WriteAudioLoop(const TimeRange &time, SampleBufferPtr samples);
|
||||
bool WriteAudioLoop(const TimeRange &time, SampleBufferPtr samples);
|
||||
|
||||
QHash<rational, FramePtr> time_map_;
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ bool PreCacheTask::Run()
|
||||
return true;
|
||||
}
|
||||
|
||||
void PreCacheTask::FrameDownloaded(FramePtr frame, const QByteArray &hash, const QVector<rational> ×)
|
||||
bool PreCacheTask::FrameDownloaded(FramePtr frame, const QByteArray &hash, const QVector<rational> ×)
|
||||
{
|
||||
// Do nothing. Pre-cache essentially just creates more frames in the cache, it doesn't need to do
|
||||
// anything else.
|
||||
@@ -93,14 +93,18 @@ void PreCacheTask::FrameDownloaded(FramePtr frame, const QByteArray &hash, const
|
||||
Q_UNUSED(frame)
|
||||
Q_UNUSED(hash)
|
||||
Q_UNUSED(times)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PreCacheTask::AudioDownloaded(const TimeRange &range, SampleBufferPtr samples)
|
||||
bool PreCacheTask::AudioDownloaded(const TimeRange &range, SampleBufferPtr samples)
|
||||
{
|
||||
// Pre-cache doesn't cache any audio
|
||||
|
||||
Q_UNUSED(range)
|
||||
Q_UNUSED(samples)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -38,9 +38,9 @@ public:
|
||||
protected:
|
||||
virtual bool Run() override;
|
||||
|
||||
virtual void FrameDownloaded(FramePtr frame, const QByteArray& hash, const QVector<rational>& times) override;
|
||||
virtual bool FrameDownloaded(FramePtr frame, const QByteArray& hash, const QVector<rational>& times) override;
|
||||
|
||||
virtual void AudioDownloaded(const TimeRange& range, SampleBufferPtr samples) override;
|
||||
virtual bool AudioDownloaded(const TimeRange& range, SampleBufferPtr samples) override;
|
||||
|
||||
private:
|
||||
Project* project_;
|
||||
|
||||
+28
-13
@@ -128,6 +128,8 @@ bool RenderTask::Render(ColorManager* manager,
|
||||
mode, cache, force_size, force_matrix, force_format, force_color_output);
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
|
||||
// Subtitle loop, loops over all blocks in sequence on all tracks
|
||||
if (!subtitle_range.length().isNull()) {
|
||||
Sequence *sequence = dynamic_cast<Sequence*>(viewer_);
|
||||
@@ -163,7 +165,10 @@ bool RenderTask::Render(ColorManager* manager,
|
||||
Block *this_block = this_track->Blocks().at(block_indexes.at(tracks_to_push.at(i)));
|
||||
|
||||
if (const SubtitleBlock *sub = dynamic_cast<const SubtitleBlock*>(this_block)) {
|
||||
EncodeSubtitle(sub);
|
||||
if (!EncodeSubtitle(sub)) {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
block_indexes[tracks_to_push.at(i)]++;
|
||||
@@ -174,8 +179,8 @@ bool RenderTask::Render(ColorManager* manager,
|
||||
|
||||
finished_watcher_mutex_.lock();
|
||||
|
||||
while (!IsCancelled()) {
|
||||
while (!finished_watchers_.empty() && !IsCancelled()) {
|
||||
while (result && !IsCancelled()) {
|
||||
while (!finished_watchers_.empty() && !IsCancelled() && result) {
|
||||
RenderTicketWatcher* watcher = finished_watchers_.front();
|
||||
finished_watchers_.pop_front();
|
||||
|
||||
@@ -188,7 +193,9 @@ bool RenderTask::Render(ColorManager* manager,
|
||||
|
||||
TimeRange range = watcher->property("range").value<TimeRange>();
|
||||
|
||||
AudioDownloaded(range, watcher->Get().value<SampleBufferPtr>());
|
||||
if (!AudioDownloaded(range, watcher->Get().value<SampleBufferPtr>())) {
|
||||
result = false;
|
||||
}
|
||||
|
||||
// Don't count audio progress, since it's generally a lot faster than video and is weighted at
|
||||
// 50%, which makes the progress bar look weird to the uninitiated
|
||||
@@ -197,9 +204,11 @@ bool RenderTask::Render(ColorManager* manager,
|
||||
|
||||
} else if (ticket_type == RenderManager::kTypeVideo && TwoStepFrameRendering()) {
|
||||
|
||||
DownloadFrame(&watcher_thread,
|
||||
watcher->Get().value<FramePtr>(),
|
||||
watcher->property("hash").toByteArray());
|
||||
if (!DownloadFrame(&watcher_thread,
|
||||
watcher->Get().value<FramePtr>(),
|
||||
watcher->property("hash").toByteArray())) {
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (native_progress_signalling_) {
|
||||
progress_counter += 0.5;
|
||||
@@ -210,7 +219,9 @@ bool RenderTask::Render(ColorManager* manager,
|
||||
|
||||
// Assume single-step video or video download ticket
|
||||
QByteArray rendered_hash = watcher->property("hash").toByteArray();
|
||||
FrameDownloaded(watcher->Get().value<FramePtr>(), rendered_hash, time_map.value(rendered_hash));
|
||||
if (!FrameDownloaded(watcher->Get().value<FramePtr>(), rendered_hash, time_map.value(rendered_hash))) {
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (native_progress_signalling_) {
|
||||
double progress_to_add = 1.0;
|
||||
@@ -237,7 +248,7 @@ bool RenderTask::Render(ColorManager* manager,
|
||||
finished_watcher_mutex_.lock();
|
||||
}
|
||||
|
||||
if (IsCancelled()) {
|
||||
if (IsCancelled() || !result) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -252,7 +263,7 @@ bool RenderTask::Render(ColorManager* manager,
|
||||
|
||||
finished_watcher_mutex_.unlock();
|
||||
|
||||
if (IsCancelled()) {
|
||||
if (IsCancelled() || !result) {
|
||||
// Cancel every watcher we created
|
||||
foreach (RenderTicketWatcher* watcher, running_watchers_) {
|
||||
disconnect(watcher, &RenderTicketWatcher::Finished, this, &RenderTask::TicketDone);
|
||||
@@ -263,10 +274,10 @@ bool RenderTask::Render(ColorManager* manager,
|
||||
watcher_thread.quit();
|
||||
watcher_thread.wait();
|
||||
|
||||
return true;
|
||||
return result;
|
||||
}
|
||||
|
||||
void RenderTask::DownloadFrame(QThread *thread, FramePtr frame, const QByteArray &hash)
|
||||
bool RenderTask::DownloadFrame(QThread *thread, FramePtr frame, const QByteArray &hash)
|
||||
{
|
||||
RenderTicketWatcher* watcher = new RenderTicketWatcher();
|
||||
watcher->setProperty("hash", hash);
|
||||
@@ -277,11 +288,15 @@ void RenderTask::DownloadFrame(QThread *thread, FramePtr frame, const QByteArray
|
||||
watcher->SetTicket(RenderManager::instance()->SaveFrameToCache(viewer_->video_frame_cache(),
|
||||
frame,
|
||||
hash));
|
||||
|
||||
// NOTE: Doesn't reflect the actual return result of SaveFrameToCache
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderTask::EncodeSubtitle(const SubtitleBlock *subtitle)
|
||||
bool RenderTask::EncodeSubtitle(const SubtitleBlock *subtitle)
|
||||
{
|
||||
Q_UNUSED(subtitle)
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderTask::PrepareWatcher(RenderTicketWatcher *watcher, QThread *thread)
|
||||
|
||||
@@ -49,13 +49,13 @@ protected:
|
||||
VideoParams::Format force_format = VideoParams::kFormatInvalid,
|
||||
ColorProcessorPtr force_color_output = nullptr);
|
||||
|
||||
virtual void DownloadFrame(QThread* thread, FramePtr frame, const QByteArray &hash);
|
||||
virtual bool DownloadFrame(QThread* thread, FramePtr frame, const QByteArray &hash);
|
||||
|
||||
virtual void FrameDownloaded(FramePtr frame, const QByteArray& hash, const QVector<rational>& times) = 0;
|
||||
virtual bool FrameDownloaded(FramePtr frame, const QByteArray& hash, const QVector<rational>& times) = 0;
|
||||
|
||||
virtual void AudioDownloaded(const TimeRange& range, SampleBufferPtr samples) = 0;
|
||||
virtual bool AudioDownloaded(const TimeRange& range, SampleBufferPtr samples) = 0;
|
||||
|
||||
virtual void EncodeSubtitle(const SubtitleBlock *subtitle);
|
||||
virtual bool EncodeSubtitle(const SubtitleBlock *subtitle);
|
||||
|
||||
ViewerOutput* viewer() const
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user