Archive for June, 2018

#chemicalexperiments — Cream

Monday, June 18th, 2018

So it has come to this. Let’s talk about a stuff one usually finds in sweets: various kinds of cream (and my experience with it).

I can divide the cream I’ve encountered or made so far into three categories:

  1. Swedish cream;
  2. Lazy cream;
  3. Custards.

Swedish cream is very easy to make: whip cream, optionally sprinkle cinnamon on top. It’s found in virtually every Swedish cake and serves as a base for some other cream variants. In Germany it’s common to use Sahnesteif—essentially a mix of starch and dextrose—that makes whipped cream stay thick and not runny longer.

Lazy cream is essentially a mix of some dairy product with powdered sugar and maybe something else for flavour (I use lemon juice): it can be butter, mascarpone, quark or something else. You simply mix those two ingredients together and use immediately. I believe the other term for this kind of cream is butter-cream.

And custards is the trickiest one since you have to cook it. It’s essentially a mix of egg yolks and milk with some thickening agent (can be starch or less commonly gelatine). When making it you have to keep in mind that if you simply put yolks into the hot milk they’ll curdle and you’ll end with a very runny omelette so you have to be extra careful and mix them (first you mix yolks with sugar and starch) by pouring a thin stream of one ingredient into another and mixing (some say you should first add some hot milk to yolks and then pour the mix back to milk, others claim it’s enough to pour yolks into milk). Afterwards you have to let it cool in a sealed container and maybe mix with whipped cream. It can be used in tarts, cakes, smaller pastry or eaten as it (preferably with something else though like berries or biscuits).

There’s a variation of it called Bavarian cream which you make by mixing yolks and milk, adding gelatine and mixing with whipped cream after it’s half-set (and then waiting even more hours until it’s fully set). The result is good as a standalone dessert but I heard it can be used in cakes too.

Overall I find all those cream varieties good but it’s better to eat them with something else and in moderation (or you’ll end having my shape).

NihAV: progress report

Sunday, June 10th, 2018

Well, since I had no incentive to work on NihAV and recently the weather is not very encouraging for any kind of intellectual activity there was almost no progress. And yet now I have something to write about: NihAV has finally managed to decode non-trivial (i.e not fully black) RealVideo 3 I-frame properly (i.e. without any visible distortions). Loop filter is still missing but it’s a start. And it’s not a small feat considering one has to implement both coefficients decoding and intra prediction. So essentially it’s just motion vector juggling and motion compensation are all the things that are missing for P- and B-frames support. Maybe it will go faster from here (but most likely not).

And since doing that involved rewriting some C code into Rust here are some notes on how oxidising went:

  • match is a nice replacement for the cases when you have to partly remap values—in my case I had to adjust intra prediction directions in case top or left or bottom reference were missing and that means changing three or four values into other values, match looks more compact than several } else if (itype == FOO) { and does not lose readability either;
  • while in C foo = bar = 42; is a common thing, Rust does not allow this (I can understand why) and I’m surprised I ran into it only now (with intra prediction functions that assign the same calculated value to several output pixels at once);
  • loops in Rust are fine for basic use but when you need to deal with something more complex like for (i = 0; i < block_size; i += 4) or for (i = 99; i > 0; i--) you need either to write a simpler loop and remap indices inside or to remember it's Rust and permute range in less intuitive ways like for i in (0..block_size).filter(|x| x&3 == 0) and for i in (1..99+1).rev(). While this works and even somewhat conveys the meaning it's a bit unwieldy IMO;
  • and it might be a bit too esoteric but looks like I cannot easily write fn clip_u8(val: N) -> u8 that would take any primitive numeric type as input, do comparisons inside and return value either clipped to converted to u8. The best answer on how to do it I found was "you can't, it's against Rust practices". I don't need it much and I care even less, so I'll just mark it as a neutral language feature and forget about it.

And now the small but constantly irritating thing: arrays. While slices are nice and easy to use (including extracting sub-slices), in my area I often need a slice with arbitrary start and end bounds. To clarify my use case: quite often you need a piece of memory that's addressable with both positive and negative indices and those make sense on certain interval.

One of such common arrays is clipping array which essentially takes input index and returns it clipped usually to 0-255 range. So you have part [-255..-1] filled with zeroes, [0..255] filled with values in the same range and [256..511] filled with 255. I repeat, such clipping table is very common and useful thing that's currently not easy to implement in Rust.

Another less common case is the block of pixels we process may require information from its top, left and top-left neighbours—and those are addressed as src[-stride + i], src[-1 + stride*i] and src[-stride - 1]. Or a whole frame of GDI-related codec (no, not from Westwood) or even simple BMP/DIB that stores lines upside-down so after you process line 0 you have to move to line -1.

I currently deal with it by keeping an additional variable pointing to the current position in array that I use as a reference and from which I can subtract other numbers if needed, but it's a bit clunky and error-prone. Since Rust checks indices on slice access I wonder if extending it to work with e.g. negative indices is possible. IIRC FORTRAN and Pascal allowed you to define an array starting with arbitrary index, it might be possible in Rust too.

Oh well, I'll just keep using my approach meanwhile and waiting to see what rust-av does in this regard.