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 AVFrame
s 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!
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;
...