Files
oak-editor/app/task/export/export.cpp
T
itsmattkc 1d61f89920 large scale renderer rework
- Abstracts all OpenGL functionality including UI objects
- Cleans up several rendering codepaths
- Improves threading functionality
- Removes old code and problematic functions
2020-11-10 11:24:51 +11:00

180 lines
5.0 KiB
C++

/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "export.h"
#include "common/timecodefunctions.h"
#include "render/colormanager.h"
OLIVE_NAMESPACE_ENTER
ExportTask::ExportTask(ViewerOutput* viewer_node,
ColorManager* color_manager,
const ExportParams& params) :
RenderTask(viewer_node, params.video_params(), params.audio_params()),
color_manager_(color_manager),
params_(params)
{
SetTitle(tr("Exporting \"%1\"").arg(viewer_node->media_name()));
}
bool ExportTask::Run()
{
TimeRange range;
encoder_ = Encoder::CreateFromID(params_.encoder(), params_);
if (!encoder_) {
SetError(tr("Failed to create encoder"));
return false;
}
if (!encoder_->Open()) {
SetError(tr("Failed to open file"));
encoder_->deleteLater();
return false;
}
if (params_.has_custom_range()) {
// Render custom range only
range = params_.custom_range();
} else {
// Render entire sequence
range = TimeRange(0, viewer()->GetLength());
}
frame_time_ = Timecode::time_to_timestamp(range.in(), viewer()->video_params().time_base());
if (params_.video_enabled()) {
// If a transformation matrix is applied to this video, create it here
if (params_.video_scaling_method() != ExportParams::kStretch) {
// FIXME: Re-implement this
/*QMatrix4x4 mat = ExportParams::GenerateMatrix(params_.video_scaling_method(),
viewer()->video_params().width(),
viewer()->video_params().height(),
params_.video_params().width(),
params_.video_params().height());*/
}
// Create color processor
color_processor_ = ColorProcessor::Create(color_manager_,
color_manager_->GetReferenceColorSpace(),
params_.color_transform());
}
if (params_.audio_enabled()) {
audio_data_.SetParameters(audio_params());
}
// Start render process
TimeRangeList video_range, audio_range;
if (params_.video_enabled()) {
video_range = {range};
}
if (params_.audio_enabled()) {
audio_range = {range};
audio_data_.SetLength(range.length());
}
Render(video_range, audio_range, RenderMode::kOnline, false);
bool success = true;
if (params_.audio_enabled()) {
// Write audio data now
encoder_->WriteAudio(audio_params(), audio_data_.CreatePlaybackDevice(encoder_));
}
encoder_->Close();
encoder_->deleteLater();
return success;
}
void FrameColorConvert(ColorProcessorPtr processor, FramePtr frame)
{
// OCIO conversion requires a frame in 32F format
if (frame->format() != PixelFormat::PIX_FMT_RGBA32F) {
frame = PixelFormat::ConvertPixelFormat(frame, PixelFormat::PIX_FMT_RGBA32F);
}
// Color conversion must be done with unassociated alpha, and the pipeline is always associated
ColorManager::DisassociateAlpha(frame);
// Convert color space
processor->ConvertFrame(frame);
// Re-associate alpha
ColorManager::ReassociateAlpha(frame);
}
QFuture<void> ExportTask::DownloadFrame(FramePtr frame, const QByteArray &hash)
{
rendered_frame_.insert(hash, frame);
return QtConcurrent::run(FrameColorConvert, color_processor_, frame);
}
void ExportTask::FrameDownloaded(const QByteArray &hash, const std::list<rational> &times, qint64 job_time)
{
Q_UNUSED(job_time)
FramePtr f = rendered_frame_.value(hash);
foreach (const rational& t, times) {
time_map_.insert(t, f);
}
forever {
rational real_time = Timecode::timestamp_to_time(frame_time_,
viewer()->video_params().time_base());
if (!time_map_.contains(real_time)) {
break;
}
// 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);
frame_time_++;
}
}
void ExportTask::AudioDownloaded(const TimeRange &range, SampleBufferPtr samples, qint64 job_time)
{
Q_UNUSED(job_time)
TimeRange adjusted_range = range;
if (params_.has_custom_range()) {
adjusted_range -= params_.custom_range().in();
}
audio_data_.WritePCM(adjusted_range, samples, QDateTime::currentMSecsSinceEpoch());
}
OLIVE_NAMESPACE_EXIT