DaVinci Resolve 18 on Ubuntu 23.10 with Intel GPU

While I am not really a video editing guy I do occassionally play with DaVinci Resolve. Unfortunately, installation was not really straightforward under Ubuntu. Even worse, as I switched to AMD laptop with internal GPU, Resolve didn’t work at all.

As one of those video editing opportunities arose, I decided to try my luck on Kubuntu 26.04. Since this OS is quite newer than my current DaVinci resolve machine (Ubuntu 24.04), I decided to scratch previous procedure and try installation from scratch. Once basic install is done, I can figure which libraries are missing and need adjustment.

So, I downloaded DaVinci Resolve 23.0.1 and executed the following commands:

cd ~/Downloads
unzip DaVinci_Resolve_21.0.3_Linux.zip
chmod +x DaVinci_Resolve_21.0.3_Linux.run
sudo SKIP_PACKAGE_CHECK=1 ./DaVinci_Resolve_21.0.3_Linux.zip

Once install was done, I started the application expecting errors but everything worked just fine. Yes, even on AMD internal GPU.

Now, free version still doesn’t deal with MP4 files and AAC under Linux - darn licenses. Regardless, I am happy to do some pre-conversion before editing rather then dealing with Windows.

Not All Rotates Are Made Equal

If you are dealing with encryption algorithms at all, you will notice bitwise rotate operation is used with regularity. While most processors have it available, not all languages do. For example, C# will force you to use shifting and or alternative, something like this:

(value >> count) | (value << (64 - count))

What might come as a surprise is that this incurs no performance penalty as compared to the native rotate operation. How come?

Well, a couple of years ago issue 4519 dealt with this exact problem. While it was deemed to disruptive to introduce rotate operation to the whole .NET system, it was possible to make JIT smarter. Whenever JIT notices operation pattern above, it will call upon native rotate operation, thus drastically improving performance.

However, since we’re talking about pattern recognition, you need to be careful how you write it. While we can write rotate operation in multitude of ways, not all of them will result in performance improvement. If you want rotate, better stick with the “official” pattern.

Avalonia ShowDialog and a Minimize Button

If you use ShowDialog in Avalonia, you will notice that under KDE/Wayland, window will retain minimize button. Even worse, minimize will hide the window, leaving its owner visible but not clickable. Slightly annoying and user might not even understand immediatelly why clicks on the main window are not working until they restore minimized dialog.

And, try as I might, I found no way to remove minimize box without removing the whole title. Since I was not in the mood to handle titleless windows, the next best thing was to close dialog window on minimize. Of course, detecting when window gets minimized is not really straightforward.

In the end, this is the code I ended up using:

PropertyChanged += (sender, e) => {
  if (e.Property == Window.WindowStateProperty && WindowState == WindowState.Minimized) {
    Dispatcher.UIThread.InvokeAsync(() => {
      WindowState = WindowState.Normal;
      Close();
    });
  }
};

We inject our check into the general PropertyChanged event handling. However, we cannot directly close window here as it will not revert focus to the owner. What we need is to ask dispatcher to invoke our code once UI thread has a spare moment. Then we restore the freshly minimized window, followed by close.

Not great, but not terrible either.

Synchronous Wait for Avalonia Dialog

Ideally, showing Avalonia dialog would be called from async method:

var frm = new Window(owner);
await frm.ShowDialog(this);

And 90% of time you’re good with that.

However, what if we don’t have async method handy? What if we really need to ShowDialog from non-async code?

Well, a bit more convoluted code can be used.

using var source = new CancellationTokenSource();
window.ShowDialog(owner).ContinueWith(t => source.Cancel(),
                                      TaskScheduler.FromCurrentSynchronizationContext());
Dispatcher.UIThread.MainLoop(source.Token);

A bit of handful and not really portable, but it does the job.

3GPP-Session-Stop-Indicator

Illustration

Fair amount of my time is spent in 3GPP specification world. Quite often I do that to figure out some minor details of random AVP I am analyzing. And no, I won’t probably go to the specification directly if search can work as well. So, imagine my surprise when I found 3GPP-Session-Stop-Indicator is specified incorrectly wherever I looked for it.

Want examples? Check it here, or here, or even here. Every time you see it specified, you will find the same data type: UTF8String. Which sounds plausible until you see it in the real world diameter snoop. There you’ll find its content is always 0xFF. So, what’s wrong with that?

If you read through RFC 6733, you will see that UTF8String data type is defined to use UTF-8. Guess what bytes sequence can NEVER appear in UTF-8? Darn 0xFF. As per RFC 3629, the highest byte value actually defined would be 0xF3. If you know anything about Diameter, the only sane answer is that this AVP is supposed to be of OctetString data type. So, where is this confusion coming?

I would place blame on ETSI TS 129.061 aka 3GPP 29.061. Incidentally, you won’t find 3GPP-Session-Stop-Indicator text anywhere in the specification. But you will find 3GPP-Session Stop Indicator defined with the following text:

3GPP Type: 11
Length: 3
Value is set to all 1.
3GPP-Session Stop Indicator value: Bit String type

Both 3GPP-Session Stop Indicator and 3GPP-Session-Stop-Indicator share code 11 with vendor 10415 (yes, we’ll ignore 3GPP calling it a “type” instead of “code”). They are the same AVP. Interestingly, length is specified as 3 which makes no sense as far as diameter goes. This is because this wasn’t originally specified for Diameter but for RADIUS. And, in RADIUS, length is indeed 3 bytes (or octets if you want to be fancy) once we add header to the single data byte. When Diameter came, 3GPP just promoted it into the new world without bothering to redefine it in any follow-up specification.

Now that we know we’re looking at the correct AVP, despite slight differences in name and length, what is the definition? It is defined as a bit string with all bits set to 1. Not UTF-8. Bit string. Which, in Diameter world, would mean its type is OctetString. And something that’s a single byte with all ones set is also known as 0xFF.

My guess is that someone originally misinterpreted “bit string” for “string” and thus it got written as UTF8String in the dictionary. Since 0xFF is just a single byte, nobody actually bothered to set it as string but they assign direct value when it comes from the sender. On consumer side, why would you even read this AVP when its value is always the same - there is no other value that 0xFF defined in any of 3FPP specifications as far as I can see. Thus, received only checks if AVP is present. Maybe some also check content but don’t bother converting to UTF-8 for a single byte. And that’s it - mystery solved - this was an OctetString all along.

Am I the first person to find this issue? I doubt it - anybody converting this to UTF-8 would see the issue. It is clearly visible in the darn Wireshark as text converts to “�” which is what UTF-8 decoder would return when it CANNOT convert. But I guess that most people looking at this were smart enough to just let it go. :)