improved interlacing

This commit is contained in:
itsmattkc
2021-05-03 22:08:05 +10:00
parent 5af00496c5
commit eb0cbea108
5 changed files with 124 additions and 79 deletions
+5 -16
View File
@@ -836,24 +836,13 @@ bool FFmpegDecoder::InitScaler(const RetrieveVideoParams& params)
AVFilterContext *last_filter = buffersrc_ctx_;
// Add interlacing filter if necessary
if (filter_params_.src_interlacing != filter_params_.dst_interlacing) {
// Determine what kind of interlacing we'll be doing
if (filter_params_.src_interlacing != VideoParams::kInterlaceNone) {
// Footage is interlaced, our renderer works in progressive so we'll need to de-interlace
AVFilterContext* interlace_filter;
if (filter_params_.dst_interlacing == VideoParams::kInterlaceNone) {
// Deinterlace source
snprintf(filter_args, kFilterArgSz, "mode=1:parity=%s",
GetInterlacingModeInFFmpeg(filter_params_.src_interlacing));
avfilter_graph_create_filter(&interlace_filter, avfilter_get_by_name("yadif"), "yadif", filter_args, nullptr, filter_graph_);
} else if (filter_params_.src_interlacing == VideoParams::kInterlaceNone) {
// We will be interlacing an originally progressive source
snprintf(filter_args, kFilterArgSz, "scan=%s", GetInterlacingModeInFFmpeg(filter_params_.dst_interlacing));
avfilter_graph_create_filter(&interlace_filter, avfilter_get_by_name("interlace"), "interlace", filter_args, nullptr, filter_graph_);
} else {
// We will simply be flipping the fields
snprintf(filter_args, kFilterArgSz, "fieldorder=%s", GetInterlacingModeInFFmpeg(filter_params_.dst_interlacing));
avfilter_graph_create_filter(&interlace_filter, avfilter_get_by_name("fieldorder"), "fieldorder", filter_args, nullptr, filter_graph_);
}
snprintf(filter_args, kFilterArgSz, "mode=1:parity=%s",
GetInterlacingModeInFFmpeg(filter_params_.src_interlacing));
avfilter_graph_create_filter(&interlace_filter, avfilter_get_by_name("yadif"), "yadif", filter_args, nullptr, filter_graph_);
avfilter_link(last_filter, 0, interlace_filter, 0);
last_filter = interlace_filter;
+24
View File
@@ -60,6 +60,30 @@ void Frame::set_video_params(const VideoParams &params)
linesize_pixels_ = linesize_ / params_.GetBytesPerPixel();
}
FramePtr Frame::Interlace(FramePtr top, FramePtr bottom)
{
if (top->video_params() != bottom->video_params()) {
qCritical() << "Tried to interlace two frames that had incompatible parameters";
return nullptr;
}
FramePtr interlaced = Frame::Create();
interlaced->set_video_params(top->video_params());
interlaced->allocate();
int linesize = interlaced->linesize_bytes();
for (int i=0; i<interlaced->height(); i++) {
FramePtr which = (i%2 == 0) ? top : bottom;
memcpy(interlaced->data() + i*linesize,
which->const_data() + i*linesize,
linesize);
}
return interlaced;
}
int Frame::generate_linesize_bytes(int width, VideoParams::Format format, int channel_count)
{
// Align to 32 bytes (not sure if this is necessary?)
+2
View File
@@ -51,6 +51,8 @@ public:
const VideoParams& video_params() const;
void set_video_params(const VideoParams& params);
static FramePtr Interlace(FramePtr top, FramePtr bottom);
static int generate_linesize_bytes(int width, VideoParams::Format format, int channel_count);
int linesize_pixels() const
+91 -63
View File
@@ -40,6 +40,78 @@ RenderProcessor::RenderProcessor(RenderTicketPtr ticket, Renderer *render_ctx, S
{
}
FramePtr RenderProcessor::GenerateFrame(const rational& time, const rational& frame_length)
{
ViewerOutput* viewer = Node::ValueToPtr<ViewerOutput>(ticket_->property("viewer"));
NodeValueTable table;
NodeOutput texture_output = viewer->GetConnectedTextureOutput();
if (texture_output.IsValid()) {
table = GenerateTable(texture_output.node(), texture_output.output(),
TimeRange(time, time + frame_length));
}
TexturePtr texture = table.Get(NodeValue::kTexture).value<TexturePtr>();
// Set up output frame parameters
VideoParams frame_params = GetCacheVideoParams();
QSize frame_size = ticket_->property("size").value<QSize>();
if (!frame_size.isNull()) {
frame_params.set_width(frame_size.width());
frame_params.set_height(frame_size.height());
}
VideoParams::Format frame_format = static_cast<VideoParams::Format>(ticket_->property("format").toInt());
if (frame_format != VideoParams::kFormatInvalid) {
frame_params.set_format(frame_format);
}
frame_params.set_channel_count(texture ? texture->channel_count() : VideoParams::kRGBChannelCount);
FramePtr frame = Frame::Create();
frame->set_timestamp(time);
frame->set_video_params(frame_params);
frame->allocate();
if (!texture) {
// Blank frame out
memset(frame->data(), 0, frame->allocated_size());
} else {
// Dump texture contents to frame
ColorProcessorPtr output_color_transform = ticket_->property("coloroutput").value<ColorProcessorPtr>();
const VideoParams& tex_params = texture->params();
if (tex_params.effective_width() != frame_params.effective_width()
|| tex_params.effective_height() != frame_params.effective_height()
|| tex_params.format() != frame_params.format()
|| output_color_transform) {
TexturePtr blit_tex = render_ctx_->CreateTexture(frame_params);
QMatrix4x4 matrix = ticket_->property("matrix").value<QMatrix4x4>();
if (output_color_transform) {
// Yes color transform, blit color managed
render_ctx_->BlitColorManaged(output_color_transform, texture, true, blit_tex.get(), true, matrix);
} else {
// No color transform, just blit
ShaderJob job;
job.InsertValue(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(texture)));
job.InsertValue(QStringLiteral("ove_mvpmat"), NodeValue(NodeValue::kMatrix, matrix));
render_ctx_->BlitToTexture(default_shader_, job, blit_tex.get());
}
// Replace texture that we're going to download in the next step
texture = blit_tex;
}
render_ctx_->DownloadFromTexture(texture.get(), frame->data(), frame->linesize_pixels());
}
return frame;
}
void RenderProcessor::Run()
{
// Depending on the render ticket type, start a job
@@ -48,74 +120,30 @@ void RenderProcessor::Run()
switch (type) {
case RenderManager::kTypeVideo:
{
ViewerOutput* viewer = Node::ValueToPtr<ViewerOutput>(ticket_->property("viewer"));
const VideoParams& video_params = ticket_->property("vparam").value<VideoParams>();
SetCacheVideoParams(video_params);
SetCacheVideoParams(ticket_->property("vparam").value<VideoParams>());
rational time = ticket_->property("time").value<rational>();
NodeValueTable table;
NodeOutput texture_output = viewer->GetConnectedTextureOutput();
if (texture_output.IsValid()) {
table = GenerateTable(texture_output.node(), texture_output.output(),
TimeRange(time, time + video_params.frame_rate_as_time_base()));
rational frame_length = GetCacheVideoParams().frame_rate_as_time_base();
if (GetCacheVideoParams().interlacing() != VideoParams::kInterlaceNone) {
frame_length /= 2;
}
TexturePtr texture = table.Get(NodeValue::kTexture).value<TexturePtr>();
FramePtr frame = GenerateFrame(time, frame_length);
// Set up output frame parameters
VideoParams frame_params = ticket_->property("vparam").value<VideoParams>();
if (GetCacheVideoParams().interlacing() != VideoParams::kInterlaceNone) {
// Get next between frame and interlace it
FramePtr next_frame = GenerateFrame(time + frame_length, frame_length);
QSize frame_size = ticket_->property("size").value<QSize>();
if (!frame_size.isNull()) {
frame_params.set_width(frame_size.width());
frame_params.set_height(frame_size.height());
}
VideoParams::Format frame_format = static_cast<VideoParams::Format>(ticket_->property("format").toInt());
if (frame_format != VideoParams::kFormatInvalid) {
frame_params.set_format(frame_format);
}
frame_params.set_channel_count(texture ? texture->channel_count() : VideoParams::kRGBChannelCount);
FramePtr frame = Frame::Create();
frame->set_timestamp(time);
frame->set_video_params(frame_params);
frame->allocate();
if (!texture) {
// Blank frame out
memset(frame->data(), 0, frame->allocated_size());
} else {
// Dump texture contents to frame
ColorProcessorPtr output_color_transform = ticket_->property("coloroutput").value<ColorProcessorPtr>();
const VideoParams& tex_params = texture->params();
if (tex_params.effective_width() != frame_params.effective_width()
|| tex_params.effective_height() != frame_params.effective_height()
|| tex_params.format() != frame_params.format()
|| output_color_transform) {
TexturePtr blit_tex = render_ctx_->CreateTexture(frame_params);
QMatrix4x4 matrix = ticket_->property("matrix").value<QMatrix4x4>();
if (output_color_transform) {
// Yes color transform, blit color managed
render_ctx_->BlitColorManaged(output_color_transform, texture, true, blit_tex.get(), true, matrix);
} else {
// No color transform, just blit
ShaderJob job;
job.InsertValue(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(texture)));
job.InsertValue(QStringLiteral("ove_mvpmat"), NodeValue(NodeValue::kMatrix, matrix));
render_ctx_->BlitToTexture(default_shader_, job, blit_tex.get());
}
// Replace texture that we're going to download in the next step
texture = blit_tex;
FramePtr top, bottom;
if (GetCacheVideoParams().interlacing() == VideoParams::kInterlacedTopFirst) {
top = frame;
bottom = next_frame;
} else {
top = next_frame;
bottom = frame;
}
render_ctx_->DownloadFromTexture(texture.get(), frame->data(), frame->linesize_pixels());
frame = Frame::Interlace(top, bottom);
}
ticket_->Finish(QVariant::fromValue(frame));
@@ -272,7 +300,7 @@ QVariant RenderProcessor::ProcessVideoFootage(const FootageJob &stream, const ra
// Check the still frame cache. On large frames such as high resolution still images, uploading
// and color managing them for every frame is a waste of time, so we implement a small cache here
// to optimize such a situation
const VideoParams& render_params = ticket_->property("vparam").value<VideoParams>();
const VideoParams& render_params = GetCacheVideoParams();
VideoParams stream_data = stream.video_params();
ColorManager* color_manager = Node::ValueToPtr<ColorManager>(ticket_->property("colormanager"));
@@ -448,7 +476,7 @@ QVariant RenderProcessor::ProcessShader(const Node *node, const TimeRange &range
}
}
VideoParams tex_params = ticket_->property("vparam").value<VideoParams>();
VideoParams tex_params = GetCacheVideoParams();
tex_params.set_channel_count(GetChannelCountFromJob(job));
@@ -499,7 +527,7 @@ QVariant RenderProcessor::ProcessFrameGeneration(const Node *node, const Generat
{
FramePtr frame = Frame::Create();
VideoParams frame_params = ticket_->property("vparam").value<VideoParams>();
VideoParams frame_params = GetCacheVideoParams();
frame_params.set_channel_count(GetChannelCountFromJob(job));
frame->set_video_params(frame_params);
frame->allocate();
+2
View File
@@ -62,6 +62,8 @@ protected:
private:
RenderProcessor(RenderTicketPtr ticket, Renderer* render_ctx, StillImageCache* still_image_cache, DecoderCache* decoder_cache, ShaderCache* shader_cache, QVariant default_shader);
FramePtr GenerateFrame(const rational &time, const rational &frame_length);
void Run();
DecoderPtr ResolveDecoderFromInput(const QString &decoder_id, const Decoder::CodecStream& stream);