Posts Tagged ‘trick’

20091124 Linking with ffmpeg’s libav

Every single tutorial linked from ffmpeg’s documentation suggests using simple library linking switches when compiling against libav, for example:

gcc -o main.o main.c -lavcodec -lavformat

but for whatever the reason, that didn’t work in my case. I was just getting a bunch of undefined references to the functions that I was using in my code. Horrible.

After browsing and searching for hours I eventually stumbled upon a post in libav mailing list* that suggested the use of pkg-config, so I typed this in:

gcc -o main.o main.c `pkg-config --cflags --libs libavformat libswscale`

and voilà, my program was compiled with libavformat and libswscale in it!

It is pretty similar to SDL’s sdl-config, and thankfully you can even use both at the same time:

gcc -o main.o main.c `pkg-config --cflags --libs libavformat libswscale` `sdl-config --cflags --libs`

The only thing I have noticed is that this is statically linking and therefore entirely including those libraries into the executable, so I’m ending with an executable which is 40 Megabytes in size. Not that I am worried about statically linking, but I wonder if it’s possible to only include the functions it’s really using or needs.

Bonus: libav with C++

By the way, now that we are on helping people so that they don’t waste an entire afternoon looking for info, if you want to use libav in a C++ program, be sure to surround the includes with the traditional extern C block, so that C++ doesn’t mangle what it doesn’t have to mangle. For example:

#ifdef __cplusplus
extern "C"
{
    #include <libavcodec/avcodec.h>
    #include <libavformat/avformat.h>
    #include <libswscale/swscale.h>
}
#endif

The sublibraries you include depend entirely on what you want to do in your project. I.e. you could include libavcodec or not, libswscale or not, and so on.

*By the way, let me use this opportunity to bash against mailing lists as the main support asset in a project. Nowadays they are probably the worst idea ever, right after newsgroups, of course. I tried posting a message to the libav list and it was rejected, days after, because “non members cannot post to the list”. Hooray for accessibility, proper sorting of topics, searchability and etc.

20091110 Too many open files

I am doing something that requires manipulating a lot of files, and I fell in the classical too many open files error trap.

A way of finding out which files are being used by a process is to type

ps -ax

in a terminal, then identify the guilty process and its PID. Let’s imagine its PID is 9090. Now to list every one of its open files you just run this (again, in the terminal):

lsof -p 9090

Or you can get a raw estimate by piping that through wc and getting the number of lines in the return value of lsof:

lsof -p 9090 | wc -l

That will return a number, like for example “33″.

It’s interesting to know that the output from lsof does not only show files in the windows way of referring to a file as a folder or data written in the disk, but returns files in the UNIX way, i.e., everything is a file, including pipes, sockets, files-files, etc.

I have changed my code meanwhile to be a bit more austere in regards to the number of open files, but this is an interesting tool nevertheless. If you run it for example with Firefox, you can even see which font files Firefox is using:

...
firefox 3847 sole  mem    REG                8,1   224692   272248 /usr/share/fonts/truetype/msttcorefonts/Arial_Bold_Italic.ttf
firefox 3847 sole  mem    REG                8,1   622020     6209 /usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf
...

Or which plug-ins has it loaded:

...
firefox 3847 sole  mem    REG                8,1   101536    13774 /usr/lib/mozilla/plugins/libtotem-cone-plugin.so
firefox 3847 sole  mem    REG                8,1   117960      741 /var/lib/flashplugin-installer/npwrapper.libflashplayer.so
...

etc etc :)

20091026 av_interleaved_write_frame(): I/O error occurred

Usually that means that input file is truncated and/or corrupted., complains ffmpeg.

No, there’s not any problem with the input file. What really happened is that ffmpeg was asked for a sequence of files but you failed to provide an appropriate file mask that ffmpeg could expand into a sequence of file names.

For example:

ffmpeg -i video.mov -r 12 -y -sameq -t 1 -f image2 frame.jpg

will output that error and won’t generate anything.

The correct form is

ffmpeg -i video.mov -r 12 -y -sameq -t 1 -f mjpeg frame.jpg

Note that the format is now forced to mjpeg, for obtaining a single frame. It actually looks very simple if you look at the format list and note that the image2 output format is described as image sequence. But… you need to find out the available formats list (with ffmpeg -formats).

The funny thing is that it actually performs all the required work for generating the frame you require. But it simply can’t complete the operation because of the wrong file mask.

If anybody knows how to generate a single png, please let me know. It seems the only way of generating png’s is via image2, but I don’t want to generate several images each time I just want one…

EDIT: From their FAQ:

Instead of relying on file format self-recognition, you may also use

`-vcodec ppm’
`-vcodec png’
`-vcodec mjpeg’

to force the encoding.

So here’s how to extract a single PNG from a movie with ffmpeg:

ffmpeg -i video.mov -r 12 -y -sameq -t 1 -vcodec png frame.png

20091022 dig

I normally go to webs like dnsstuff to find the IP address of a domain. But since I found this command, I think I’ll stop visiting them so often!

An example is worth one thousand words:

sole@courgette:~$ dig google.com

; <<>> DiG 9.5.1-P2 <<>> google.com
;; global options:  printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 15808
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;google.com.                    IN      A

;; ANSWER SECTION:
google.com.             239     IN      A       74.125.53.100
google.com.             239     IN      A       74.125.45.100
google.com.             239     IN      A       74.125.67.100

;; Query time: 12 msec
;; SERVER: 208.67.222.222#53(208.67.222.222)
;; WHEN: Thu Oct 22 09:50:01 2009
;; MSG SIZE  rcvd: 76

By default it returns type A DNS records, which are the ones for translating domain names to IP addresses. But you can also ask it to retrieve other record types. For example, for retrieving every record that it can find:

sole@courgette:~$ dig -t ANY google.com

; <<>> DiG 9.5.1-P2 <<>> -t ANY google.com
;; global options:  printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 15253
;; flags: qr rd ra; QUERY: 1, ANSWER: 13, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;google.com.                    IN      ANY

;; ANSWER SECTION:
google.com.             175     IN      A       74.125.45.100
google.com.             175     IN      A       74.125.67.100
google.com.             175     IN      A       74.125.53.100
google.com.             807     IN      MX      10 google.com.s9a1.psmtp.com.
google.com.             807     IN      MX      10 google.com.s9a2.psmtp.com.
google.com.             807     IN      MX      100 smtp1.google.com.
google.com.             807     IN      MX      10 google.com.s9b1.psmtp.com.
google.com.             807     IN      MX      10 google.com.s9b2.psmtp.com.
google.com.             807     IN      MX      100 smtp2.google.com.
google.com.             171315  IN      NS      ns1.google.com.
google.com.             171315  IN      NS      ns2.google.com.
google.com.             171315  IN      NS      ns3.google.com.
google.com.             171315  IN      NS      ns4.google.com.

;; Query time: 14 msec
;; SERVER: 208.67.222.222#53(208.67.222.222)
;; WHEN: Thu Oct 22 09:51:05 2009
;; MSG SIZE  rcvd: 326

There it shows now the name servers (NS column) and the mail servers (MX column) too.

Go play around with its options and see what you can find. Of course this is very raw and could do with a bit of makeover, but it’s a command line option and there are lots of pages/scripts out there who use dig as its base for a more attractive result. But for what I usually need this is more than enough.

Something to note is that these results are taken from your current DNS cache. I.e. let’s say you’ve changed the DNS values for a domain and want to make sure that the changes have been applied… then do not expect this tool to show instant changes, because the results would still be in your DNS cache. You either reset your router or wait until the cache expires and your query shows the updated results. And of course you also have to wait until the change propagates :)

I didn’t have to install any new package for running this program, I guess it comes by default with ubuntu. But I haven’t investigated it either :D

Happy digging! ;)

20091001 Roll your own ffmpeg build

I like to have my own build of ffmpeg. That way I don’t have to worry about not having this or that codec available. What I do is keep it in my ~/Applications/ffmpeg folder. Some people suggest using a ~/bin directory but I hate to drop every binary into the same place.

Here are the magic lines:

cd ~/Applications

svn checkout svn://svn.ffmpeg.org/ffmpeg/trunk ffmpeg

cd ffmpeg

sudo apt-get install libmp3lame-dev libfaad-dev libfaac-dev\
 libxvidcore4-dev liba52-0.7.4 liba52-0.7.4-dev libx264-dev\
 libtheora-dev libvorbis-dev

./configure --enable-gpl --enable-nonfree --enable-libmp3lame\
--enable-libfaac --enable-libfaad --enable-libtheora \
--enable-libvorbis --enable-libx264 --enable-libxvid

make

Once that finishes, you get an ffmpeg executable in the ~/Applications/ffmpeg folder. So you can explicitly call from your scripts with ~/Applications/ffmpeg/ffmpeg. And because it has a ton of enabled codecs, it’s less problematic to read videos from different sources than it is with the default build which comes with Ubuntu. Or even output videos using codecs such as mp3.

This will probably surely fail in a future version of Ubuntu, but it works as of today. Of course, if the libraries’ names change, you’ll have to adjust as appropriate too. It might also fail if the very svn checkout you do is not compiling properly, but hey! that’s the fun of living in the bleeding edge :-P