1

I'm trying to encode raw PCM audio data to u-law and it's sound very weird (when it sounds...). I don't understand pretty much how to initialize my AVCodecContext structure (and my input AVFrame).

Here are my parameters:

  • Input : PCM (16bits signed), MONO, 44,1kHz (sample rate) (from my Android device MIC)

  • Required output : G.711 u-law, MONO, 8kHz (sample rate), 64 kbits/s (bitrate) (from my output target device's documentation)

I also know my input nb samples and this is all informations I have.

So I initialize my AVCodecContext like that:

AVCodec* pCodec = avcodec_find_encoder(AV_CODEC_ID_PCM_MULAW);
// ...
AVCodecContext* pCodecContext = avcodec_alloc_context3(pCodec);
// ...
// Do I need input or output params in following lines?
pCodecContext->channels = 1:
pCodecContext->channel_layout = AV_CH_LAYOUT_MONO;
pCodecContext->sample_rate = 8000;
pCodecContext->bit_rate = 64000
pCodecContext->sample_fmt = AV_SAMPLE_FMT_S16;

And my AVFrames like:

AVFrame* pFrame = av_frame_alloc();
pFrame->channels = 1;
pFrame->channel_layout = AV_CH_LAYOUT_MONO;
pFrame->sample_rate = 44100;
pFrame->format = AV_SAMPLE_FMT_S16;
pFrame->nb_samples = /*my audio data samples count*/;
avcodec_fill_audio_frame(pFrame, 1, AV_SAMPLE_FMT_S16, /*my audio data*/, /*my audio data size*/, 0);

Then, I encode with avcodec_send_frame() and avcodec_receive_packet().

So my problem is that I'm not sure if I have to put input or output desired values in different parameters. Probably I have to encode on a way then "resample" using swresample lib. But for now, I'm pretty sure that I don't encode properly. Any advise please? Thanks!

N0un
  • 868
  • 8
  • 31

1 Answers1

1

G.711 requires that your input be 8kHz mono (e.g. sample_rate of 8000). So, before passing your raw pcm audio samples to libavcodec you have to convert them to 8kHz with swresample or any other lib that can do that. If you capture your raw pcm yourself usually you can request 8kHz sampling rate from the os sound api.

I'm pretty sure on android devices you can request 8kHz audio. G.711 is such a simple codec, you don't need libavcodec for that. You can use any available g711.c and simply call linear2alaw or linear2ulaw for each sample. Basically linear2alaw or linear2ulaw convert each 16-bit audio sample into a byte of g711 bitstream.

You should also ensure that you init your AVCodecContext properly:

pCodecContext->channels = 1;
pCodecContext->channel_layout = AV_CH_LAYOUT_MONO; 
...
Pavel P
  • 15,789
  • 11
  • 79
  • 128
  • 1
    Thank you for your answer, I understand my problem and can work with that knowledge. I thought libavcodec ables to "encode" in a different sample rate! I need libavcodec because I could have other output devices with other supported formats. – N0un May 15 '17 at 09:36
  • Is it normal that I can't open a U-law codec (`AVCodec` encoder) with a 8kHz sample rate? – N0un May 15 '17 at 13:35
  • @N0un does `avcodec_find_encoder(AV_CODEC_ID_PCM_MULAW);` return NULL? – Pavel P May 15 '17 at 13:44
  • @N0un note, also `pCodecContext->channels(1)` seems strange, it should be `pCodecContext->channels = 1;` – Pavel P May 15 '17 at 13:47
  • Sorry I fix syntax in an edit. No it not returns NULL, but `pCodec->samples_fmts()` only returns one format: `AV_SAMPLE_FMT_S16`. It is a problem if a pre-resample my audio sample in `AV_SAMPLE_FMT_U8`, strange isn't it? Is `pCodecContext->sample_fmt` a mandatory parameter for encoding? – N0un May 15 '17 at 14:21
  • Yes, g.711 it requires only `AV_SAMPLE_FMT_S16` on input. How is that you have `AV_SAMPLE_FMT_U8` as input? – Pavel P May 15 '17 at 17:51
  • No, I have S16 on input but I asked myself if I should have U8 instead? I mean, how can I have 64kBits/s bitrate required on output device specs? Is this bitrate important? – N0un May 15 '17 at 20:18
  • You have to have `S16` input. That's what you usually get from os. You feed it 8kHz of S16 (which is 128kbps), and g711 converts each 16-bit audio sample to a byte and you'll get 64kbps g711 audio bitstream. Not sure if you can omit `bit_rate = 64000` for g711, but this field is important for codecs that have multiple bitrates (like mp3). – Pavel P May 15 '17 at 20:52
  • Ok I get it now. A last question: resample using SwResample is an operation which has to be made before (with raw PCM) or after encoding? Even if it looks like I don't need it in my example... – N0un May 16 '17 at 07:23
  • @N0un you may need to resample your input pcm to make it acceptable by the codec. So, yes, resampling should be done before encoding. – Pavel P May 16 '17 at 07:26
  • Ok. So you can confirm that in my example, I can have PCM/S16/8kHz in input, and just need to encode it to U-law/U8/8kHz, no need to resample? But if I have 44,4kHz in input, I should resample it to 8kHz then encode, right? – N0un May 16 '17 at 07:30
  • Looks ok, just change `pFrame->sample_rate = 44100;` to 8000. – Pavel P May 16 '17 at 07:36