Skip to content

Season of KDE'24 - Blog 2

Updated: at 02:53 PM

Season Of KDE - Blog 2

Overview

If you’ve been following my previous blog posts, you may recall that I’ve been working on adding multi-format rendering support to Kdenlive. This feature allows users to export their videos in different aspect ratios, such as horizontal (16:9), vertical (9:16), and square (1:1), catering to the requirements of various platforms and use cases.

In the previous blog, I talked about the core implementation of the aspect ratio conversion logic, which calculates the necessary cropping parameters to achieve the desired format.

My Progess so far…

> Temporary File Handling and Refactoring

I initially implemented QTemporaryFile for cross-platform handling of temporary files, replacing hardcoded temp paths. However, this approach involved creating a new temporary file each time the method was called, which was inefficient. Based on the mentor’s feedback, I refactored the code to create an empty QTemporaryFile object and only set it up with a specific file template when an aspect ratio change is required. This improved the efficiency of the temporary file handling.1

> User Interface

My next goal was to create user interface elements where the user can select the desired aspect ratio, and then connect them to the backend logic, which I discussed in my first blog.

First, I added a setAspectRatio method in the RenderRequest class to store the selected aspect ratio.

void RenderRequest::setAspectRatio(const QString &aspectRatio)
{
    m_aspectRatio = aspectRatio;
}

This aspect ratio would then be passed to the projectSceneList method in the ProjectManager class:

QString ProjectManager::projectSceneList(const QString &outputFolder, const QString &overlayData, const QString &aspectRatio)
{
    // ...
}

In the render widget’s file, I added a new row with a label and a combo box for selecting the aspect ratio. In the rendering widget’s constructor.
Then, in the rendering widget’s constructor, I created the combo box with the available options:

m_view.aspect_ratio_type->addItem(i18n("Default"));
m_view.aspect_ratio_type->addItem(i18n("Horizontal (16:9)"), QStringLiteral("horizontal"));
m_view.aspect_ratio_type->addItem(i18n("Vertical (9:16)"), QStringLiteral("vertical"));
m_view.aspect_ratio_type->addItem(i18n("Square (1:1)"), QStringLiteral("square"));
m_view.aspect_ratio_type->setCurrentIndex(0);

Profiles with width or height that are not a multiple of 2 cause crashes. I’ve fixed the issue by ensuring that the video profile width and height are multiples of 2.

[libx264 @ 0x733910204380] width not divisible by 2 (607x1080)

I tried to find the reason behind why we need width and height as divisible of 2 in the first place.

As required by x264, the “divisible by 2 for width and height” is needed for YUV 4:2:0 chroma subsampled outputs. 4:2:2 would need “divisible by 2 for width”, and 4:4:4 does not have these restrictions. However, most non-FFmpeg based players can only properly decode 4:2:0, so that is why you often see ffmpeg commands with the -pix_fmt yuv420p option when outputting H.264 video. —source

Adding Multi-format Rendering

Finally, the selected aspect ratio is retrieved from the combo box and passed to the setAspectRatio method of the RenderRequest object:

request->setAspectRatio(m_view.aspect_ratio_type->currentData().toString());

With these changes, users can now select the desired aspect ratio from the combo box in the rendering widget before exporting their video.

> What I learned:

It was a learning experience; I’ve gained confidence to work on a large codebase and navigate through it, a better understanding of object-oriented programming (OOP) concepts, and the realization that I needed to get better at it. I learned the importance of efficient resource management, such as handling temporary files and much more. Beyond code, I learned how to better communicate with the mentors.

I’m grateful to the mentors who provided guidance and support throughout the project, helping me overcome the challenges I faced.