I can easily say that the major focus for the next release of xine-lib (1.1.5) is on portability. It wasn’t really my target when I started hacking at it, but I ended up merging patches for NetBSD support, for Solaris support, then the FreeBSD patches I wrote about, and today I finally merged the long standing Mac OS X on Intel patches that Martin Aumueller (from Amarok) sent some time ago already).
Unfortunately, I think there are still a lot of things that could be improved when it comes to supporting operating systems different from Linux. This is probably due to the major attention paid to ALSA output, rather than other audio outputs, as that is what most of the xine users use, most likely.
It is promising, though, that soon enough there will be a xine-lib release building and working natively on OS X with Intel CPUs. Most of the changes were on build system, as I had to fiddle a lot with the configure.ac file to be able to get the expected results on OS X, as for instance visibility support cannot be enabled, but the code as it was didn’t detect this, as
-fvisibility=hidden was accepted by GCC, it was the attribute that wasn’t available. There were a few minor code changes, but not really important by themselves.
One interesting thought is that, like Solaris, also OS X has a policy to enforce against TEXTRELs, like Gentoo Hardened would probably like to see on Linux. As it happen there, also on OS X the FFmpeg code produces text section’s relocations; to be able to link the FFmpeg plugin correctly, you has to use the
-read_only_relocs warning option (thanks exg for pointing me at that option). The code to support an opt-in flag for TEXTRELs was luckily already in place, as Solaris needs it too, as I said, so I just had to add the proper case on configure.ac, and it now builds (although I should probably clean it up, right now it assumes that you don’t use GNU ld on Mac OS X at all).
Of course, when it comes to editing configure.ac, I end up doing a lot of changes also to make it more readable and faster t run; I consider it an eternal work in progress, as I’ve probably spent more hours hacking at that than the rest of xine-lib code altogether. Tonight, beside rewriting the
-Werror check so that it caches it value run, I also decided to see if I could reduce the number of compile and link test ran for some trivial checks: I was able to cut out four link tests just by making sure that the preferred function for four different functions was the first one listed, rather than the last one, and then added a break statement to the action-if-found clause. It’s nice to see that you can spare some gcc call just by reordering the parameters.
Another important change that I’m trying to apply to configure.ac progressively is to cache the values. When you’re testing a change in a particular part of the configure logic, rather than in the checks logic, it makes sense to use the -C option to cache the options and avoid having to wait for all the gcc calls to complete (this is what cache is supposed to be used for, not for confcache). At the moment, there are a lot of checks in xine-lib’s configure that are not cached, so they are re-executed over and over even if their internal logic is never changed. One of the easiest way to improve this situation, now, is to avoid using
AC_TRY_CFLAGS (the old internal xine macro to find out if a flag is accepted by the compiler) and instead use
CC_CHECK_FLAGS (the new macro I added to the attributes.m4 file that is shared between xine, unieject and any other project I need it for).
And remaining in the theme of xine, I’ve started noticing a lot of people lately asking for supporting proprietary formats like Monkey Audio or OpenFROG or other similar lossless formats. Unfortunately there seems to be even hobbyists who design a compression format and don’t release a specific. I’m not sure if this happens because they hope to make money out of that, or because they don’t want someone else to use their ideas, or whatever else, but it’s not really good for the Free Software community. Supporting those formats wouldn’t be an issue for me or for xine if there was a FFmpeg decoder, as it’s quite simple once FFmpeg supports something to add the respective support in xine, but you shouldn’t even think of asking for using the “fake free software” mac-port library, or the totally closed and proprietary SDK of OpenFROG… and yes, I do think that even Real and Win32 codecs support are stretching the support a lot already.
On xine, I also seen there are a lot of areas which would probably be worth looking at for rewriting or at least cleaning up. For instance, we often memcpy data round, either because we’re reading data and then copying it somewhere else, or because we’re breaking up a frame in different buffers on the demuxer, and then reassembling it in its entirety in the decoder. Other than being waste of resources, it’s also quite difficult to follow after a while.
One solution for this would be to have a new abstraction similar to the buffer that is already available, but with a much more simple approach. I’ll call it memory fragment during this post and in the future unless I find a better name for it; I’ll probably write about it for a while until I find the time and the courage to start looking at implementing it. A memory fragment would just be a structure carrying a pointer to the memory area, a
size_t value containing the size of the allocated memory area, a R/W lock and a reference counter (this one with its own mutex); it can be opaque aside from the first two members.
When we read some data that has to be passed over to another component of xine, we just create a fragment, setting its refcount to one and locking it in write mode; once we have filled it with the data we need, and we don’t care about its content anymore, we unlock it; then we pass it over to the needed function, that will in turn increase the refcount, and starts using the fragement. After the function is called, the refcount of the fragment can be decremented.
If you need to have access to the fragment in read mode, you lock it for read; when it’s locked for read it can be locked by more threads at a time without problems, while only one thread can lock it for write (and there has not to be any other thread locking it for read either); if you need to edit the memory for some reason, and the fragment is locked, you have to copy it (copy-on-write) and it will now be a different fragment you’d have locked). Obviously, if the reference count reaches zero while it’s being decremented, the fragment is freed.
I’ve started thinking of this idea today, and I think it could be feasible, even if I don’t really know if what I wrote right now has much of a sense, nor I know how to handle more complex tasks like passing to a function a sub-fragment of a fragment you got (you should share the lock and the refcount, but you have a different memory pointer and/or a different size; you also cannot free the changed pointer anyway. And you might have race conditions on the reference count, making it quite hard to be sure that the buffer is not going to be freed before time.
There might as well be already a library supporting something like this, I don’t know, I never really informed myself about this, I might do so in the future. I think that such a vast change to xine, though, is not going to happen on 1.1.x series, but would probably require a jump to 1.2.0, thing that I cannot do by myself, and right now I’m almost the only one working on xine-lib.
And again, one thing I noticed while fixing the wav demuxer to be able to play in some way 24-bit wav files, is that the decoders mostly take care by their own to cut the bits per sample in the output, requiring similar code to be written all over… one thing that would be nice would be having a single part of code dealing with this kind of signal conditioning, that would also probably like being written using vector instructions like SSE and AltiVec.
But, okay, I start diverging with my topics, these are things not to be discussed this late at night! 🙂