SSJX.CO.UK
Content

Converting Avi2Cvc from C to D

This is a summary of porting my Cybiko video conversion utility from C to the D Programming Language. The main reasons for this were to improve its memory safety (I had already found one memory issue) and to take advantage of any other benefits that using D provides.

Simple Stuff

In no particular order:

Extra Stuff

The original C version had support for the Microsoft Video 1 Codec (MSVC), the Pascal version did not but it did have Error Diffusion as a colour reduction option. The D version has both!

The quick port of MSVC decoder revealed an out of bounds error straight away, so that was fixed and the function had a general tidy up as well.

Garbage Collection

D uses a Garbage Collector to manage memory, this keeps track of memory and frees it when when no longer in use. This is great but it means we need to pay a little more attention to our allocations so we do not overwork it. By running the built-in profiler we can get an idea of when and what the GC is doing and try to help it.

To get a profile log, compile with -profile=gc and when you run the program you get a surprisingly easy to read profilegc.log file.

Running the profile enabled version and encoding a 240 frame video using ordered dithering gave this:

bytes allocated, allocations, type, function, file:line
         191376	             84	ubyte[] D main avi2cvc.d:515
          49152	              1	ubyte[] D main avi2cvc.d:462
          23040	            240	const(const(const(ubyte)[])[]) avi2cvc.ordered avi2cvc.d:166
           3840	            240	const(const(ubyte)[]) avi2cvc.ordered avi2cvc.d:167
           3840	            240	const(const(ubyte)[]) avi2cvc.ordered avi2cvc.d:168
           3840	            240	const(const(ubyte)[]) avi2cvc.ordered avi2cvc.d:169
           3840	            240	const(const(ubyte)[]) avi2cvc.ordered avi2cvc.d:170
           3840	            240	const(const(ubyte)[]) avi2cvc.ordered avi2cvc.d:171
           3840	            240	const(const(ubyte)[]) avi2cvc.ordered avi2cvc.d:172
           3840	            240	const(const(ubyte)[]) avi2cvc.ordered avi2cvc.d:173
           3840	            240	const(const(ubyte)[]) avi2cvc.ordered avi2cvc.d:174
             32	              1	immutable(char)[] D main avi2cvc.d:288

The 240 allocations is the ordered dither pattern (a 64 byte array - the bytes allocated seems high but I assume that includes size data and other things). As the array was inside the function, the array was being allocated and deallocated each time it was called, this is bad in general and even worse for a GC language! Luckily this was an easy fix - take the array out of the function!

For a 356 frame video using error diffusion this was the result:

bytes allocated, allocations, type, function, file:line
         221520	             56	ubyte[] D main avi2cvc.d:522
          49152	              1	ubyte[] D main avi2cvc.d:469
           5696	            356	const(const(ubyte)[]) avi2cvc.diffuse avi2cvc.d:219
             32	              1	immutable(char)[] D main avi2cvc.d:295

The 356 allocations was a 4 byte colour array, again the simple solution was to move it out of the function.

Conclusion

The result of all this is I now have a fast, safe and easy to read program. The program may still have bugs but at least they will not be due to memory corruption. Also note that this program does not make use of any of D's more advanced features and I am just using D as a nicer C compiler with some useful extras included!

Last Updated 20/05/2024
Created 15/02/2020