Guide to write a mplayer codec Introduction------------I've developed a number of open source decoders for the MPlayer project,for both audio and video data. As such, I feel I'm qualified to document afew notes about developing new codecs for the codebase.As always, the best way to learn how to incorporate a new codec is tostudy a bunch of existing code. This document is supplementary material tothe code, meant to give some tips, pointers, and a general roadmap.A note about terminology: "Codec" stands for coder/decoder (orcompressor/decompressor, if you prefer). The term refers to a module thatcan both encode and decode data. However, this document focuses primarilyon incorporating decoders. Still, the terms "decoder" and "codec" areoften used interchangeably.Necessary Materials-------------------So you've decided that you want to implement a new decoder forMPlayer. There are a few things you will need:- Knowledge of the codec to be implemented: You will need to know the dataformat of the chunks that MPlayer will pass to you. You will need to knowhow to take apart the data structures inside. You will need to know thealgorithmic operations that need to be performed on the data in order toreconstruct the original media.- Sample media: Preferably, lots of it. You will need media encoded inyour data format and stored in a media file format that MPlayer knows howto parse (these include AVI, ASF, MOV, RM, VIVO, among others). If theencoded data is stored in a media file format that MPlayer doesn'tunderstand, then you will either need to somehow convert the format to amedia file format that the program does understand, or write your ownMPlayer file demuxer that can handle the data. Writing a file demuxeris beyond the scope of this document.Try to obtain media that stresses all possible modes of adecoder. If an audio codec is known to work with both mono and stereodata, search for sample media of both types. If a video codec is known towork at 7 different bit depths, then, as painful as it may be, do what youcan to obtain sample media encoded for each of the 7 bit depths.- Latest CVS snapshot: It's always useful to develop code for the verylatest development version of MPlayer. Be sure to update your local CVScopy often.- General programming knowledge, working Linux development environment: Iwould hope that these items would go without saying, but you never know.Typical Development Cycle-------------------------1) Set up basic infrastructureFirst things first, there's a big song and dance to go through in order tolet the MPlayer program know that you have a new codec to incorporate.First, modify your local copy of codecs.conf. It may be system-shared orin your home directory. Add a new entry for your codec. If it's an opensource codec, it would be a good idea to place the new entry with the restof the open source codecs. When you're confident that you have the entryright, be sure to add it to etc/codecs.conf in your workspace. See thefile codecs.conf.txt for a detailed description of the format of thisfile. Create a new audiocodec or videocodec block with the proper info,FOURCCs/format numbers, output formats, and a unique driver name. Rememberthe driver name.Next, create a new source file which contains the main decoding functionthat MPlayer will call to decode data. Eventually, you may have multiplefiles which comprise your decoder, but let's start simple here. For audio codecs, see ad_sample.c skeleton. For video, choose one of theexisting vd_*.c files which you think is close to your codec in behaviour.Next, modify the Makefile so that it will compile your new source file.Also, add your codec to the array in ad.c (for audio) or vd.c (for video).Next, compile the project and see if you have everything correct so far.Next, you want to make sure that the encoded data is making it to yourdecoding function in the first place. This may sound like a trivialexercise, but there are a lot of things that can go wrong (and I'vewatched most of them go wrong in my experience). At the beginning of yourskeleton decoder function, enter the following code: int i; for (i = 0; i < 16; i++) printf ("X ", input[i]); printf ("/n");When you compile and run MPlayer, your decoder function will print thefirst 16 bytes of each data chunk that it receives. Open the sample mediain a hex editor and reconcile what you see on the screen with whatyou find in the file. If the decoder is printing the first 16 bytes ofeach block, that's a good sign that you're ready to move on to step2. Otherwise, you need to figure out why the data isn't getting to yourdecoder. Is your decoder even being invoked? If not, why not?2) Develop the decoderGo for it. Remember to make it work, first, then make it work fast. Somespecific tips:What output formats should you support in your decoder? Whatever makessense. YUV output is always preferable over RGB output. Generally, if acodec uses a YUV data as its source data, you will be able to decode aframe of YUV data. If a codec takes RGB data as its input, as many oldervideo codecs do, then there's no point in supporting YUV output; justoutput as many RGB formats as possible.The most preferred output format for video data is YV12. This is becauseMPlayer supports a multitude of hardware devices that can display, scale,and filter this type of data directly. MPlayer also has a bunch ofoptimized conversion functions that can convert YV12 data to any othertype of output data.If you do take the RGB output route, you should be aware that MPlayeractually orders packed RGB data as BGR. If you're decoding into a BGR24buffer, the output will look like: B G R B G R B G R B ...If you're decoding into a BGR32 buffer, there will need to be anadditional (unused) byte after each BGR triplet: B G R - B G R - B G ...Make liberal use of sanity checks. Start by including the file mp_msg.h atthe start of your decoder. Then you can use the mp_msg() function as youwould a normal printf() statement. Whenever your decoder notices a strangebit of data or an odd condition, print a message such as: mp_msg(MSGT_DECVIDEO, MSGL_WARN, "Odd data encountered: %d/n", data);Obviously, you should make the message a little moredescriptive, for your benefit. MSGL_WARN is a good message level for thistype of information. Look in mp_msg.h for all of the error levels. You caneven make MPlayer bail out completely by using MSGL_FATAL, but that shouldnever be necessary at the data decoder level.What conditions should trigger a warning? Anything, and I mean *anything*out of the ordinary. Many chunks of compressed video data contain headerswith data such as width, height, and chunk size. Reconcile these fieldswith the parameters passed into the decoding function (if you set it up totake those parameters). Such data should match up. If it doesn't, issue awarning and make an executive decision in the code about which data tobelieve (personally, I always lend more weight to the data that was passedinto the decoder function, the data that comes from the container file'sheader). If there's supposed to be a magic number embedded in, or computedfrom, the chunk's header, issue a warning if it isn't correct.Whenever you're about the index into a memory array with an index thatcould theoretically be out of range, then test that the index is in range,no matter how tedious it seems. Accessing outside of your memory range is,after all, the number 1 cause of segmentation faults. Never trust that allthe data passed to you will be correct. If an array index suddenly windsup out of range, it's probably best to issue a warning about it and bailout of the decoder (but not the whole application).Writing all of these warning statements may seem insipid, but considerthat if you don't do it when you start writing your decoder, you'llprobably end up doing it later on when your decoder isn't working properlyand you need to figure out why (believe me, I know).3) Debug and test the decoderIf you're extremely lucky, the decoder will work the first time. If you'revery lucky, it will work after you've reviewed your code a few times andcorrected a few obvious programming mistakes. Realistically, you willwrite the decoder, review it many times and fix many obvious and subtleprogramming errors, and still have to go through an elaborate debugprocess in order to get the decoder to a minimally functional state.Big hint: Ask for all warnings. You know, the -Wall option ingcc? It's very useful to develop your codec while running in debugmode. In order to compile MPlayer with debug support (which includes -Wallfor all gcc operations), use the --enable-debug option when configuringthe project. Pay attention to all warnings and make it a goal to getrid of every single one. I'll never forget when the compiler warned methat there was no point in clamping a signed 16-bit variable within asigned 16-bit range (the calculation to be clamped was supposed to bestored in a signed 32-bit variable and then stored in the signed 16-bitvariable). I sat stunned for a moment, feeling like I had just dodged abullet as I knew that would have taken me hours to debug that kind ofmistake.4) Contribute decoder to codebaseCreate a patch with the "diff -u" format and email it to the MPlayerdevelopment team for approval. You will likely need to diff the followingfiles:- Makefile- etc/codecs.conf- ad.c or vd.cOf course, you will need to include your newly-created file(s): vd_<name>.c -OR- ad_<name>.c. If you contribute enough decoders, thedevelopment team may even grant you write privileges to the CVS repository.5) Wait for bug reports to start rolling inYou may think you're finished when you release the codec and if you'reextremely lucky, you will be right. However, it's more likely that peoplewill start throwing all kinds of oddball media at your decoder that itnever counted on. Cheer up; take comfort in knowing that people aretesting your code and attempting to use it as a real world application. Download the problem media that people upload to the MPlayerFTP site and get back to work, implementing fixed code that addresses theissues. Contribute more patches and encourage people to hammer on yourdecoder even more. This is how you make your decoder rock-solid.