46

I use the FFmpeg library for a personnal project and I need help about one thing. I have a music file in stereo sound and I want to convert this stereo sound to mono sound ? Is it possible with this library ? Is there a function inside to do this job ? My project is in C/C++.

I searched on the Doxygen documentation on the FFmpeg website and on this forum but I didn't find something interesting.

Thanks for reading !

Meugiwara
  • 599
  • 1
  • 7
  • 13

3 Answers3

90

You can just use ffmpeg. Direct command is present for the purpose-

ffmpeg -i stereo.flac -ac 1 mono.flac

Would convert your stereo file into mono channel. For more details, you can look at this page-

https://trac.ffmpeg.org/wiki/AudioChannelManipulation

Neeraj Shukla
  • 1,271
  • 11
  • 13
  • 2
    Thanks, helped me a lot! Btw, if anybody else needs to convert bulk of files in a row, like I did: `find . -name '*.mp4' -exec ./convert.sh {} \;` – Marco Arruda Dec 10 '19 at 22:44
  • Then, inside the `convert.sh` file: – Marco Arruda Dec 10 '19 at 22:45
  • 1
    `ffmpeg -i $1 -ac 1 $1.mono.mp4` – Marco Arruda Dec 10 '19 at 22:45
  • 5
    @MarcoArruda You can skip the `convert.sh` file by invoking `ffmpeg` directly with: `find . -name '*.mp4' -exec ffmpeg -i '{}' -ac 1 '{}.mono.mp4' \;` – joshtch Mar 04 '21 at 00:12
  • This makes loud sections clip a lot. Is there a way to flatten it w/o clipping – theonlygusti Dec 11 '21 at 18:02
  • 5
    Note that `-ac 1` will **mix down** both stereo channels to a single mono one, which might not be what you want, especially if it’s just “a mono source erroneously recorded in stereo”. In that case, throw one of the channels away like this: `ffmpeg -i INPUT -filter_complex '[0:a]channelsplit=channel_layout=stereo:channels=FL[left]' -map '[left]' OUTPUT` (replace `INPUT` & `OUTPUT` of course). This will select the left channel, if you want the right one, use `FR` and `[right]` instead. – scy Mar 26 '22 at 09:21
  • `Unsupported channel layout "1 channels (FL)"` – Michel Jung Sep 12 '22 at 16:11
8

Use swr_convert from libswresample to convert between formats. Something like:

#include "libswresample/swresample.h"

au_convert_ctx = swr_alloc();

out_channel_layout = AV_CH_LAYOUT_MONO;
out_sample_fmt = AV_SAMPLE_FMT_S16;
out_sample_rate = 44100;
out_channels = av_get_channel_layout_nb_channels(out_channel_layout);

in_sample_fmt = pCodecCtx->sample_fmt;
in_channel_layout=av_get_default_channel_layout(pCodecCtx->channels);

au_convert_ctx=swr_alloc_set_opts(au_convert_ctx,out_channel_layout, out_sample_fmt, out_sample_rate,
            in_channel_layout, in_sample_fmt, pCodecCtx->sample_rate, 0, NULL);
swr_init(au_convert_ctx);
//Generate your frame of original audio, then use swr_convert to convert to mono,
//converted number of samples will now be in out_buffer.
int converted = swr_convert(au_convert_ctx, &out_buffer, MAX_AUDIO_FRAME_SIZE, (const uint8_t **)&pFrame->data , pFrame->nb_samples);
//...
swr_free(&au_convert_ctx);

to get you started. This will convert whatever the original format happens to be to 44100 kHz mono. You could also use pCodecCtx->sample_rate as the output sample rate as well.

It's the most flexible and easiest solution.

Steve M
  • 9,296
  • 11
  • 49
  • 98
1

As I mentioned in the comment, you could resample it yourself. It depends on what you already have and what format you use. I cannot give you code which would work instantly, but give you an example (pseudo/real code mix).

After you encoded the frame, and have done the things you have to do, your data buffer will be filled with the audio. Now it depends how your format is (see here) and how many channels you have. Let's assume it is signed 16bit stereo, than your buffer would look like:

+-----+-----+-----+-----+-----+
| LS1 | RS1 | LS2 | RS2 | ... |
+-----+-----+-----+-----+-----+
// LS = LEFT SAMPLE 16 Bit
// RS = RIGHT SAMPLE 16 Bit

Now iterate through the buffer and calculate left and right sample together.

for(int i=0; i<sample_size; i+=2) {
    auto r = (static_cast<int32_t>(buffer[i]) + buffer[i+1]) / 2;
    buffer[i] = buffer[i+1] = r;
}
user1810087
  • 5,146
  • 1
  • 41
  • 76
  • 2
    this just isn't a good strategy, the numbers in an audio signal aren't just numbers they represent a signal which involves the change in those numbers more than those numbers themselves... like if you had a sine wave where left and right were out of phase 180 degrees you would just have no signal in the mono mix down. – Grady Player Jul 01 '22 at 15:52