mplayer and matroska metadata

I’ve been playing with Matroska in general a lot more, seeing what I can do, and in the past week and a half, I’ve found some really cool things. I’m completely braindead after staring at the mplayer code all day, so if I come across a little confusing, now you know why. It’s one of those instances where I wanna get this documented though, if nothing else than for a small marker of a pretty big milestone for me. :)

I’m too tired to lay this down in story format, so I’m just gonna dump it out best I can.

The other week, I noticed that a new version of mkvtoolnix had come out (the tool to mux audio/video files into the Matroska container), and it totally flew under my radar. I started playing with it, and noticed some real improvements in speed, with regards to parsing MPEG-2 video. After playing around a bit, I started reading some more of the documentation, and found out about this excellent tagging system that the specification declares.

You can read all the gory details about it here, but basically, when building a Matroska file, you can create an XML file that has global tags that can store pretty much every metadata tag I could ever dream of possibly wanting.

I never really had the itch to pack much metadata into the container up until this time, when I realized just how much factual data I could stuff in there and not depend on the database for. Pretty much the only thing I really cared about was the title. In fact, all I wanted originally was to be able to get MPlayer to display the metadata title that was in the file.

Going off on a tangent here, I poked an open bug I have on MPlayer’s bugzilla, and Reimar, an mplayer dev, was kind enough to oblige me once more and updated the code so that I could pull it out. If you’re using a recent snapshot (for Gentoo, the 20090530 one has it), you can pull it out using “get_property metadata/title” in slave mode. If you wanted to display it on-screen, you would map a keypress event or LIRC event to this: osd_show_property_text “${metadata/title}”. Quotes and all.

Anyway, Reimar added that in for me (thanks, man), so I started poking around with mplayer’s features to see what else it could pull out for me. Now that I was going to be storing lots more data in the container, I wanted to be able to pull it out, too.

Jump forward a bit to today, where I woke up this morning and was determined to get it out somehow. My original plan that I had decided on was, since I can’t really hack on C code, to just work around the limitation by using a fifo for mplayer. I’ll spare you the ugly details, but basically I was going to have an event send a command to an external script that would query the .mkv file for the metadata tag I requested, and send a command back through the pipe to print that out to the screen. Quite a run around.

Well, I’ve tried before to grep the code of mplayer a bit to see if I could wrap my head around the stuff and see if I could figure it out for myself, but it hasn’t worked out real well. I decided to give it another whirl today, though. This time, however, my approach was a little bit different. Normally I would just search for keywords where I *think* mplayer would be doing what I would think it was doing, tinker with the code, recompile it, run it, and see what it does. A really slow process, but sometimes it works. And I really don’t mind spending the time on it, either.

This time, I did things a little bit differently. I found a file where I was sure that it was accessing matroska metadata, and I read the entire thing, and took copious notes, explaining to myself the whole time, basically what I thought the purpose of each major element was, trying to figure out the pattern to this. Now, bear in mind, that I’m still learning some C++ myself, and the C syntax is pretty similar (in fact … I still can hardly tell the difference, myself), so a lot of times I have a vague understanding of what it *might* be doing, but never enough to be sure … so there is still a lot of guesswork involved.

Anyway, after about 10 hours of going back and forth, making notes, testing code, printing out functions and variables and metadata, I got it figured out. And the final patch is something like 2 lines long, heh. All I did was add one if statement. But, that was enough to get me going, and it solved a nagging issue for me. But, what is far more valuable, is the fact that I’ve learned how I can go into this code and figure out how to fix things myself. That’s gonna really come in handy. I’m sure I won’t be submitting patches upstream anytime soon, but if I can get what I want hacked in there, and working, I’ll be happy as a clam.

For the record, the problem with the metadata was this: MPlayer has a single key=value pair that it assigns to metadata values with it is parsing it with the libavformat demuxer. That is normally well and good, except in the case of Matroska, the tags can be nested with similar names.

So, for example, say you have two target tags in your matroska container: Collection and Episode. If it were a TV show, let’s say it’s CHiPs. Great show, btw. Now, in the tagging specification, both of them can have a title. The title for the collection would be CHiPs. If you had a Matroska A/V file that was just one episode, then the title for that would be “Ponch Delivers A Baby on the Disco Floor” or whatever (which really does happen, I kid you not). They key for both of those would be “title”, but the values would be different. The LAVF demuxer just overwrites the old value and assigns it to whatever comes last. Kind of a problem.

So all I did was told the demuxer to prefix the key names with whatever the name of the target tag was (Collection, Season, Episode, etc.). That way you can have distinct key value pairs, but they are just more verbose. The metadata property names now are metadata/collection/title instead of metadata/title. Pretty simple, really.

That was the easy part. The second part, I haven’t figured out yet — how to get it out. The metadata is all in a separate object created by the LAVF demuxer, which I don’t know enough C to figure out how to access that outside of that class. So, I just hacked it to add it to the metadata myself in a rather ugly, but working fashion. Upstream probably wouldn’t be interested in that patch.

Another hard day’s work, and I’m still not done. And I’ve got a lot more to write about it, so I’ll just stop here for now. I’m gonna go port the patches to my frontends. :)

Edit: For reference, the clean version of the patch, a sample XML file of what I would mux in with an episode, and the ugly hack I personally am using to get it all out where my lack of C knowledge is very much publicly exposed.  Note that you have to use -demuxer lavf with mplayer for it to work.

Advertisements

mplayer and vdpau in portage

I was hoping to write a lengthy post about VDPAU support for MPlayer in the portage tree, but since my harddrive crashed this week and I’m still recovering from that, a small announcement will have to suffice for now.

I just added a new ebuild to the tree this week for MPlayer, which has support for the much talked about VDPAU which comes with nvidia video cards and binary drivers.  If you don’t know what that is, it is probably most simply described as XvMC for more codecs: MPEG1, MPEG2, MPEG4 (H264), WMV, VC1.  The player offloads a lot of CPU decoding to the video card instead of your processor, meaning cheap video cards and cheap computers can playback HD without any hiccups.

In theory, at least.  I don’t know how well it works since I haven’t been able to test it much, and whenever I do, I can’t get it under 50% CPU anyway.

Anyway, you are free to try it of course.  The latest mplayer ebuild is 20090226.28734.  The naming scheme changed to reflect both the release date of the snapshot (Feb 26 2009) and the SVN revision from upstream (28734).  There is a “vdpau” use flag you’ll need to enable on the ebuild, and you’ll need  v180.22 or higher of nvidia-drivers.  In this case, nvidia is releasing updates with new drivers, so the more recent the better.

Here’s some cool stuff to read about VDPAU and what it can do:

NVIDIA 180.35 Driver Update Brings Changes

HD Video Playback With A $20 CPU & $30 GPU On Linux

Wikipedia entry

MythTV Wiki: Supported Cards

nvnews forum thread: mplayer and vdpau – see the third post for samples to test and mplayer command lines.

Oh yes, using it is pretty much a matter of mplayer -vo vdpau foo.wmv.  You may or may not need to use the -vc argument.  I haven’t looked closely.  See “mplayer -vc help | grep vdpau” for a reference, or the man page.

As far as the mplayer ebuild goes, there have been a lot of changes.  I’d been queuing them up for a good while waiting to push them live.  I had hoped to have a finished document accompany the release, but I haven’t given much time to it, and since VDPAU came out, I figured it would be better to release the ebuild.

It’s currently masked, but won’t be for long.  One nice thing it does is it splits up the real use flag into two: real and realcodecs.  I found that some users were confused and thought that they had to enable the realcodecs use flag to get any support for real codec playback, but that was never the case, as libavcodec always had support for some.  Now, the real flag will enable the internal support, and realcodecs will still use the external binary ones (not recommended).

Also, since libdvdnav got accepted into the mainstream build, we no longer have to rely on a masked, external dependency, so the dvdnav use flag is unmasked, available, and enabled by default.  You can playback DVDs browsing the navigation menus by using mplayer dvdnav:// instead of mplayer dvd://.

Other use flags that were added were faac, faad, and tremor.  If you want native support for AAC playback, just enable the aac use flag.  If you want to use the external libraries instead (faac and faad), then just disable the aac use flag and enable the other ones.  Tremor is the internal support for Vorbis playback.

The last change to the ebuild is that now lots more use flags are enabled by default.  I found out that a lot of people were going in #mplayer complaining that their builds weren’t working when really it was just not compiled with much in it.  As a result, I’ve changed it so it will enable just about every internal library and external codec.  That should make things simpler for users who want things to “just work” out of the box.

That’s it for now.  I’ll be bumping the ebuild again, soon, and regularly as long as the VDPAU development in mplayer keeps moving at a hectic pace.

mplayer patch: -use-dir-conf option

I just made a really small patch to MPlayer for something I’ve been wanting to do for a while. MPlayer has long supported a playback option -use-filedir-conf that will include a config file if you have it named <filename>.conf. I’ve taken that and just created an option for the current directory instead.

The issue I run into with my TV shows is that sometimes I need to use different deinterlacing filters or different audio delays for different series. It would be a pain to create a config file for each individual file, so this patch fits the bill. If you just use -use-dir-conf, it will look for an mplayer.conf file in the existing directory, and include that.

Pretty simple, really. I hope I wrote the patch right, since I’m no master of C. I just copied the old functionality, dropped what it didn’t look like was relevant and removed unused variables. And hey, works for me.

Patches cleanly against latest SVN (28348).

Edit: Well, crap, I just realized that it only works if you have mplayer.conf in the same directory as you are running mplayer from …. so doing mplayer -use-dir-conf /foo/movie.mp4 wouldn’t work if you’re not in /foo. Unlike -use-filedir-conf, you can’t call it from some other directory. Someone wanna help me out? :)

mplayer-resume-1.6

I just finished updating and pushing mplayer-resume-1.6 into the tree.  I’ve actually been sitting on the update for a long time, just never got around to releasing it.

There has only been a small change — the script will check mplayer’s exit code to see if it died on something.  I added it since I hit a bug on my frontend where some files wouldn’t resume, and it would delete my resume point anyway.  Kind of annoying.  This update fixes that, and really, that’s it.

mplayer, dvdnav support

Oh yah, I remembered what the other thing was on MPlayer — dvdnav support is back in.  Duh.  How could I miss that one?

The use flag is masked, so you’ll have to unmask it to use it, but if you do it will pull in the forked libdvdnav and libdvdread as a dependency.  After that, you can use mplayer dvdnav:// to get funky, sexy menus when watching DVDs.  Whee!

Here’s how to unmask a use flag:

mkdir -p /etc/portage/profile/

echo media-video/mplayer -dvdnav >> /etc/portage/profile/package.use.mask

Then just set enable the dvdnav use flag for the package as normal.  Personally, I like flagedit.

flagedit media-video/mplayer dvdnav

mplayer, real support

MPlayer got bumped yesterday to a new snapshot (1.0_rc2_p28058), which isn’t all that interesting in itself, but there is one notable update for real codecs.

I’ve been busy masking realplayer support in portage due to issues, but libavcodec now has it’s own native decoder for RealVideo 4 (RV40).  Thanks, Kostya. :)

Read about it here:

Mike summarized it pretty well on his blog post:

“Also, do you dare ask why this is useful in the grand scheme of multimedia hacking? Seriously? Have you not learned by now? While it may be true that absolutely no one likes Real or their formats, there is still a huge legacy of media in the wild encoded in their formats, media that will need to be manipulated for many years to come.”

One other thing that got fixed in MPlayer that naturally only I and very few others are going to care about, is that mplayer dumpstream now supports ending chapters again.  It was removed a while back and readded recently.  It was pretty much the only reason the 1.0_rc2_p24929-r4 ebuild is still in the tree.  A specific example would be that you can do something like this: mplayer dvd:// -dumpstream -dumpfile movie.vob -chapter 2-5

Seems like there was something else that changed.  Can’t remember now, oh well.