FFmpeg and ALSA

I’m trying to record a video with sound through FFmpeg, and while it records the system sounds just fine, it doesn’t record the microphone (in fact, it crashes on doing so!). The strange thing is that if I use arecord, it works just perfectly, but through ffmpeg it crashes.

This is the command that I use to launch FFmpeg:

/usr/bin/ffmpeg \
 -f x11grab \
 -xerror \
 -r 25 \
 -s 588x572 \
 -i :0.0+798,115 \
 -vcodec libvpx \
 -f alsa \
 -i hw:1,0 \
 -acodec pcm_s16le \
 -y /home/dainius/temp/qx11grab-160723.avi

This is the log of ffmpeg crashing:

[x11grab @ 0x6376d0] device: :0.0+798,115  -> display: :0.0 x: 798 y: 115 width: 588 height: 572
[x11grab @ 0x6376d0] shared memory extension  found
[x11grab @ 0x6376d0] Estimating duration from bitrate, this may be inaccurate
Input #0, x11grab, from ':0.0+798,115 ':
  Duration: N/A, start: 1288271247.509504, bitrate: 269068 kb/s
    Stream #0.0: Video: rawvideo, bgra, 588x572, 269068 kb/s, 25 tbr, 1000k tbn, 25 tbc
[alsa @ 0x646f10] cannot set channel count to 1 (Invalid argument)
hw:1,0: Input/output error

If I change the "-i hw:1,0 " part to "-i hw:0,0 " it records the system sounds, and does it just fine. But both of these commands succeed in arecord:

arecord -d 10 -f cd -t wav -D hw:0,0 test.wav
arecord -d 10 -f cd -t wav -D hw:1,0 test.wav

So what’s wrong? Why does ffmpeg report an error, yet arecord does it just fine?

Another question that is related to this topic: is there a way to use ffmpeg to record both system sounds and the microphone? Or mix two sources into one with ALSA?

For the record, here is my ALSA configuration (using OpenSUSE 11.3):
http://greatemerald.pastebin.com/bJ8i95qD

I must confess I didn’t quite understand at first why you think you are recording from the Mic. I had a look at your output of ‘arecord -l’ and can see no mention of anything remotely called a Mic. However read on.

You appear to have 3 (virtual?) sound cards: XFi (#0) , SB (#1) and HDMI (#2). Only XFi and SB have capture facilities. When you tell ffmpeg to record from ‘hw:1,0’, this is the first device on the SB card, which is ‘ALC888 Analog’. Is that supposed to be the Mic? However, ‘hw:0,0’ is the first device on the XFi card which is ‘ctxfi [Front/Wave in]’.

Googling for ACL888, it does appear to be a hardware standard that provides two ADCs: one for microphone and one for a mixer. Interestingly, the microphone is stereo not mono. Ffmpeg only provides one channel by default, which may explain the “cannot set channel count to 1 (Invalid argument)” message.

Further, as I understand it, when you use ffmepg, as in your case, the command should be of the form:

ffmpeg <video options> -i <video source> <audio options> -i <audio source> <output options> <output destination>

In your command, ‘-vcodec libvpx’, may be seen as an audio option, which may also explain the “(invalid argument)” part of the error message.

First try rearranging the command to bring ‘-vcodec libvpx’ after the ‘-i hw:1,0’ item and see if that works. If it doesn’t try adding ‘-ac 2’ as an audio option to force two audio channels, just before the ‘-i hw:1,0’, and try again. I think arecord also defaults to 1 audio channel but maybe arecord is more flexible than ffmpeg here.

Note: it is a good idea, in these sorts of cases, to simplify and isolate the problem as much as possible so, if the above fails, concentrate on getting:

ffmpeg <audio options> -i <audio source> <output options> <output destination>

working first, before constructing the final command.

The above may help I hope but I am not an expert.

To clarify: those three soundcards are real. The first one is my Creative X-Fi XtremeGamer which is my primary sound card; the second is the integrated Intel/Realtek sound card; the third one is the HDMI output of the graphics card. I have the microphone plugged into the integrated card and I have speakers plugged into the dedicated card. The microphone is registered as hw:1,0 since, well, I found that out by trial and error with arecord.

I highly doubt that the arrangement would work, since vcodec implies video while acodec implies audio. Forcing two channels is a good idea, though, I’ll try it and report what I get later. Simplifying the command for debugging is a good idea as well.

I’ve tried this now:

dainius@linux:~> /usr/bin/ffmpeg \
>  -xerror \
>  -f alsa \
>  -i hw:1,0 \
>  -ac 2 \
>  -acodec pcm_s16le \
>  -y /home/dainius/temp/audiotest.wav
FFmpeg version SVN-r25512, Copyright (c) 2000-2010 the FFmpeg developers
  built on Oct 21 2010 21:36:34 with gcc 4.5.0 20100604 [gcc-4_5-branch revision 160292]
  configuration: --shlibdir=/usr/lib64 --prefix=/usr --mandir=/usr/share/man --libdir=/usr/lib64 --enable-shared --enable-libmp3lame --enable-libvorbis --enable-libtheora --enable-libspeex --enable-libfaac --enable-nonfree --enable-libxvid --enable-postproc --enable-gpl --enable-x11grab --extra-cflags='-fmessage-length=0 -O2 -Wall -D_FORTIFY_SOURCE=2 -fstack-protector -funwind-tables -fasynchronous-unwind-tables -fPIC -I/usr/include/gsm' --enable-debug --disable-stripping --enable-libschroedinger --enable-libdirac --enable-libgsm --enable-avfilter --enable-libvpx --enable-version3 --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libx264 --enable-libdc1394 --enable-pthreads
  libavutil     50.32. 3 / 50.32. 3
  libavcore      0. 9. 1 /  0. 9. 1
  libavcodec    52.92. 0 / 52.92. 0
  libavformat   52.83. 0 / 52.83. 0
  libavdevice   52. 2. 2 / 52. 2. 2
  libavfilter    1.52. 0 /  1.52. 0
  libswscale     0.12. 0 /  0.12. 0
  libpostproc   51. 2. 0 / 51. 2. 0
[alsa @ 0x6376d0] cannot set channel count to 1 (Invalid argument)
hw:1,0: Input/output error       

As you can see, still no go. It doesn’t even acknowledge the ac parameter, it seems… At least I’m certain it does find the device, because if I enter hw:2,0 it says that the device is not found, not that it cannot set the channel count.

No, I think that is the wrong order. If you re-read my first post you will see that you now have the ‘-ac 2’ parameter after the ‘-i hw:1,0’ parameter so it forces 2 channels on the output. I was suggesting you need to force 2 channels on the input. Parameter order is important here!

So you need:

/usr/bin/ffmpeg
> -xerror
> -f alsa
> -ac 2
> -i hw:1,0
> -acodec pcm_s16le
> -y /home/dainius/temp/audiotest.wav

Try that and see what happens.

As regard your second post I did not understand what you meant by:

I highly doubt that the arrangement would work, since vcodec implies video while acodec implies audio.

Again you have the ‘-vcodec’ as a parameter for the audio input. Obviously you are defining the video codec for the overall output so it should go after all the ‘-i *’ declarations. At least that is my take on the matter.

HTH. :slight_smile:

Before, you mean :slight_smile: All right, I’ll try that. I wonder if by the same logic it would be possible to record two audio streams at once, with another -f -i set.

Ooh, it works! Thanks!

So, is it possible to get two audio streams recorded into one? If I try this:

/usr/bin/ffmpeg \
 -xerror \
 -f alsa \
 -ac 2 \
 -i hw:1,0 \
 -f alsa \
 -i hw:0,0 \
 -acodec pcm_s16le \
 -y /home/dainius/temp/test.wav

I get this console output:

FFmpeg version SVN-r25512, Copyright (c) 2000-2010 the FFmpeg developers
  built on Oct 21 2010 21:36:34 with gcc 4.5.0 20100604 [gcc-4_5-branch revision 160292]
  configuration: --shlibdir=/usr/lib64 --prefix=/usr --mandir=/usr/share/man --libdir=/usr/lib64 --enable-shared --enable-libmp3lame --enable-libvorbis --enable-libtheora --enable-libspeex --enable-libfaac --enable-nonfree --enable-libxvid --enable-postproc --enable-gpl --enable-x11grab --extra-cflags='-fmessage-length=0 -O2 -Wall -D_FORTIFY_SOURCE=2 -fstack-protector -funwind-tables -fasynchronous-unwind-tables -fPIC -I/usr/include/gsm' --enable-debug --disable-stripping --enable-libschroedinger --enable-libdirac --enable-libgsm --enable-avfilter --enable-libvpx --enable-version3 --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libx264 --enable-libdc1394 --enable-pthreads
  libavutil     50.32. 3 / 50.32. 3
  libavcore      0. 9. 1 /  0. 9. 1
  libavcodec    52.92. 0 / 52.92. 0
  libavformat   52.83. 0 / 52.83. 0
  libavdevice   52. 2. 2 / 52. 2. 2
  libavfilter    1.52. 0 /  1.52. 0
  libswscale     0.12. 0 /  0.12. 0
  libpostproc   51. 2. 0 / 51. 2. 0
[alsa @ 0x6376d0] Estimating duration from bitrate, this may be inaccurate
Input #0, alsa, from 'hw:1,0':                                                  
  Duration: N/A, start: 7886.368401, bitrate: N/A
    Stream #0.0: Audio: pcm_s16le, 44100 Hz, 2 channels, s16, 1411 kb/s
[alsa @ 0x638950] Estimating duration from bitrate, this may be inaccurate
Input #1, alsa, from 'hw:0,0':                                                  
  Duration: N/A, start: 7886.381408, bitrate: N/A
    Stream #1.0: Audio: pcm_s16le, 44100 Hz, 2 channels, s16, 1411 kb/s
Output #0, wav, to '/home/dainius/temp/test.wav':
  Metadata:
    encoder         : Lavf52.83.0
    Stream #0.0: Audio: pcm_s16le, 44100 Hz, 2 channels, s16, 1411 kb/s
Stream mapping:
  Stream #0.0 -> #0.0
Press [q] to stop encoding
size=    2090kB time=12.13 bitrate=1411.2kbits/s    
video:0kB audio:2090kB global headers:0kB muxing overhead 0.002056%

And I get only the first device recorded. It seems that it’s capturing both, but it outputs only one… Is there a way to tell it to output both of them to a single file? Or a few different files, and then combine them into one?

Ooh, it works! Thanks!

Great - glad I could help.

So, is it possible to get two audio streams recorded into one? If I try this:

I am not an expert on this. However, you seem to have the basic setup correct. The things I am not sure about are:

1: The container type used to store the output. I think ‘.wav’ files can only store one track, although the track can have multiple channels (1 for mono, 2 for stereo etc). You would have to use a more sophisticated container such as ‘.avi’, which can store multiple multiple tracks for audio and video (I think). To force ffmpeg to store multiple tracks, you have to use the ‘-newaudio’ parameter after the definition of the output container, otherwise only one track (probably the first) gets stored. Thus your command should be:

/usr/bin/ffmpeg \
 -xerror \
 -f alsa \
 -ac 2 \
 -i hw:1,0 \
 -f alsa \
 -i hw:0,0 \
 -acodec pcm_s16le \
 -y /home/dainius/temp/test.avi
 -newaudio

2: Playing both tracks together could be a problem. Most players would probably play only the first track and ignore the second. MPlayer looks as though it can select one track from a pair but I don’t think it can play both together. VLC (VideoLan Client) may be able to do that but I am not sure. Obviously, the best thing to do is to try and mix the two tracks together and store that. I am not sure how to do this. Hopefully, at this juncture, a guru will appear in a puff of green smoke on the thread and tell us.

Sorry I can’t be of more help. I would like to know what the solution is so, if you can get back to us when you have it working, that would be good.

PS look at this web page for the ffmpeg documentation:

http://www.ffmpeg.org/ffmpeg-doc.html Plodder.

I wrote to FFmpeg mailing list and people there are saying that FFmpeg can’t mix audio, but it can use piped input from things like SoX. So that’s what I’m going to use. Still not certain about the command, though, so I’ll keep you posted.

There we go:

sox \
 -t alsa hw:0,0 \
 -t alsa hw:1,0 \
 -m -p gain | \
 /usr/bin/ffmpeg \ 
 -f x11grab \
 -xerror \
 -r 25 \
 -s 808x628 \
 -i :0.0+0,408 \
 -vcodec flv \
 -qmax 5 \
 -f sox \
 -i - \
 -acodec pcm_s16le \
 -y /home/dainius/temp/test.avi

First, SoX grabs the ALSA output from both channels, mixes it, uses pipe as the output, applies the gain effect, pipes it to FFmpeg, which sets up the graphics options, then uses sox as the format and pipe as the input, sets the codec and finally outputs the thing. Works just nicely, and the gain effect is very useful.

Neat !! Thanks for sharing that.