<div dir="ltr"><div><div>What I trying to do : convert PCM data to mp3 data(should be AV_SAMPLE_FMT_S16P--16bit signed)</div></div><div>What I actually get: AV_SAMPLE_FMT_FLTP</div><div><br></div><div>I think 'context->sample_fmt = AV_SAMPLE_FMT_S16P;' should set output format to AV_SAMPLE_FMT_S16P(16bit signed), but it turns out to be AV_SAMPLE_FMT_FLTP.(32bit float)</div><div><br></div><div><div class="gmail_quote"><div dir="ltr" class="gmail_attr">Paul B Mahol <<a href="mailto:onemda@gmail.com" target="_blank">onemda@gmail.com</a>>于2019å¹´5月17æ—¥ 周五下åˆ9:48写é“:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On 5/17/19, 雷京颢 <<a href="mailto:leijinghaog@gmail.com" target="_blank">leijinghaog@gmail.com</a>> wrote:<br>
> I am trying to encode pcm data to mp3 format(exactly should be mono, s16p,<br>
> 24k) But I always get fltp as result. What I do wrong?<br>
<br>
There is mp3 and mp3float decoder. Do you mean that?<br>
<br>
><br>
> My code is below<br>
><br>
> ```cpp<br>
> #include "encoder.h"<br>
> #include <string><br>
><br>
> #include <stdint.h><br>
> #include <stdio.h><br>
> #include <stdlib.h><br>
> #include <vector><br>
> #include <deque><br>
> #include <iostream><br>
><br>
> #include "encoder_err_code.h"<br>
><br>
> extern "C" {<br>
>Â Â Â #include <libavutil/opt.h><br>
>Â Â Â #include <libavcodec/avcodec.h><br>
>Â Â Â #include <libavutil/channel_layout.h><br>
>Â Â Â #include <libavutil/common.h><br>
>Â Â Â #include <libavutil/frame.h><br>
>Â Â Â #include <libavutil/samplefmt.h><br>
>Â Â Â #include <libswresample/swresample.h><br>
> }<br>
><br>
> using namespace std;<br>
><br>
> const int PCM_SAMPLE_RATE = 24000;<br>
><br>
> class Encoder {<br>
> private:<br>
>Â Â Â AVCodec *codec = nullptr;<br>
>Â Â Â AVCodecContext *context = nullptr;<br>
>Â Â Â AVFrame *frame = nullptr;<br>
>Â Â Â AVPacket *pkt = nullptr;<br>
>Â Â Â SwrContext *swrContext = nullptr;<br>
>Â Â Â deque<uint8_t> pcmBuffer;<br>
><br>
>Â Â Â int createCodec(const char* outputFormat) {<br>
>Â Â Â Â Â // find codec by outputFormat<br>
>Â Â Â Â Â AVCodecID avCodecId = AV_CODEC_ID_NONE;<br>
><br>
>Â Â Â Â Â if (strcmp(outputFormat, "mp3") == 0) {<br>
>Â Â Â Â Â Â Â avCodecId = AV_CODEC_ID_MP3;<br>
>Â Â Â Â Â }<br>
><br>
>Â Â Â Â Â if (AV_CODEC_ID_NONE == avCodecId) {<br>
>Â Â Â Â Â Â Â return ENCODER_FORMAT_NOT_SUPPORT;<br>
>Â Â Â Â Â } else {<br>
>Â Â Â Â Â Â Â codec = avcodec_find_encoder(avCodecId);<br>
>Â Â Â Â Â }<br>
><br>
>Â Â Â Â Â if (!codec) {<br>
>Â Â Â Â Â Â Â return ENCODER_CODEC_NOT_FOUND;<br>
>Â Â Â Â Â }<br>
><br>
>Â Â Â Â Â return ENCODER_SUCCESS;<br>
>Â Â Â }<br>
><br>
>Â Â Â int createContext(int sampleRate) {<br>
>Â Â Â Â Â // check sampleRate support<br>
>Â Â Â Â Â int ret = ENCODER_SAMPLE_RATE_NOT_SUPPORT;<br>
>Â Â Â Â Â auto p = codec->supported_samplerates;<br>
>Â Â Â Â Â while(*p) {<br>
>Â Â Â Â Â Â Â if (*(p++) == sampleRate) {<br>
>Â Â Â Â Â Â Â Â Â ret = ENCODER_SUCCESS;<br>
>Â Â Â Â Â Â Â Â Â break;<br>
>Â Â Â Â Â Â Â }<br>
>Â Â Â Â Â }<br>
><br>
>Â Â Â Â Â if(ret) {<br>
>Â Â Â Â Â Â Â return ret;<br>
>Â Â Â Â Â }<br>
><br>
>Â Â Â Â Â // create context<br>
>Â Â Â Â Â context = avcodec_alloc_context3(codec);<br>
><br>
>Â Â Â Â Â if (!context) {<br>
>Â Â Â Â Â Â Â return ENCODER_CODEC_CONTEXT_CREATE_ERROR;<br>
>Â Â Â Â Â }<br>
><br>
>Â Â Â Â Â // set output format<br>
>Â Â Â Â Â context->audio_service_type = AV_AUDIO_SERVICE_TYPE_MAIN;<br>
>Â Â Â Â Â context->sample_fmt = AV_SAMPLE_FMT_S16P;<br>
>Â Â Â Â Â context->sample_rate = sampleRate;<br>
>Â Â Â Â Â context->channel_layout = AV_CH_LAYOUT_MONO;<br>
>Â Â Â Â Â context->channels =<br>
> av_get_channel_layout_nb_channels(context->channel_layout);<br>
><br>
>Â Â Â Â Â // check PCM sampleRate<br>
>Â Â Â Â Â const enum AVSampleFormat *f = codec->sample_fmts;<br>
>Â Â Â Â Â while( *f != AV_SAMPLE_FMT_NONE) {<br>
>Â Â Â Â Â Â Â if (*f == context->sample_fmt) {<br>
>Â Â Â Â Â Â Â Â Â break;<br>
>Â Â Â Â Â Â Â }<br>
>Â Â Â Â Â Â Â f++;<br>
>Â Â Â Â Â }<br>
><br>
>Â Â Â Â Â if (*f == AV_SAMPLE_FMT_NONE) {<br>
>Â Â Â Â Â Â Â return ENCODER_SAMPLE_FMT_NOT_SUPPORT;<br>
>Â Â Â Â Â }<br>
><br>
>Â Â Â Â Â // check PCM layout<br>
>Â Â Â Â Â auto l = codec->channel_layouts;<br>
>Â Â Â Â Â while(l) {<br>
>Â Â Â Â Â Â Â if (*l == context->channel_layout) {<br>
>Â Â Â Â Â Â Â Â Â break;<br>
>Â Â Â Â Â Â Â }<br>
>Â Â Â Â Â Â Â l++;<br>
>Â Â Â Â Â }<br>
><br>
>Â Â Â Â Â if (!l) {<br>
>Â Â Â Â Â Â Â return ENCODER_SAMPLE_LAYOUT_NOT_SUPPORT;<br>
>Â Â Â Â Â }<br>
><br>
>Â Â Â Â Â if (avcodec_open2(context, codec, nullptr) < 0 ) {<br>
>Â Â Â Â Â Â Â return ENCODER_CODEC_OPEN_ERROR;<br>
>Â Â Â Â Â }<br>
><br>
>Â Â Â Â Â return ENCODER_SUCCESS;<br>
>Â Â Â }<br>
><br>
>Â Â Â int createSwrContext(int sampleRate){<br>
>Â Â Â Â Â swrContext = swr_alloc();<br>
>Â Â Â Â Â if (!swrContext) {<br>
>Â Â Â Â Â Â Â return ENCODER_SWR_ALLOC_ERROR;<br>
>Â Â Â Â Â }<br>
><br>
>Â Â Â Â Â /* set options */<br>
>Â Â Â Â Â av_opt_set_int(swrContext, "in_channel_layout",<br>
>Â AV_CH_LAYOUT_MONO, 0);<br>
>     av_opt_set_int(swrContext, "in_sample_rate",    PCM_SAMPLE_RATE,<br>
> 0);<br>
>Â Â Â Â Â av_opt_set_sample_fmt(swrContext, "in_sample_fmt",<br>
> context->sample_fmt, 0);<br>
><br>
>Â Â Â Â Â av_opt_set_int(swrContext, "out_channel_layout",<br>
>Â AV_CH_LAYOUT_MONO, 0);<br>
>     av_opt_set_int(swrContext, "out_sample_rate",    sampleRate, 0);<br>
>Â Â Â Â Â av_opt_set_sample_fmt(swrContext, "out_sample_fmt",<br>
> context->sample_fmt, 0);<br>
><br>
>Â Â Â Â Â int ret = swr_init(swrContext);<br>
>Â Â Â Â Â if (ret) {<br>
>Â Â Â Â Â Â Â return ENCODER_SWR_INIT_ERROR;<br>
>Â Â Â Â Â }<br>
>Â Â Â Â Â return ENCODER_SUCCESS;<br>
>Â Â Â }<br>
><br>
>Â Â Â int createPacket(){<br>
>Â Â Â Â Â pkt = av_packet_alloc();<br>
><br>
>Â Â Â Â Â if (!pkt) {<br>
>Â Â Â Â Â Â Â return ENCODER_PACKET_ALLOC_ERROR;<br>
>Â Â Â Â Â }<br>
>Â Â Â Â Â return ENCODER_SUCCESS;<br>
>Â Â Â }<br>
><br>
>Â Â Â int createFrame(){<br>
>Â Â Â Â Â frame = av_frame_alloc();<br>
>Â Â Â Â Â if (!frame) {<br>
>Â Â Â Â Â Â Â return ENCODER_FRAME_ALLOC_ERROR;<br>
>Â Â Â Â Â }<br>
>     frame->nb_samples   = context->frame_size;<br>
>     frame->format     = context->sample_fmt;<br>
>Â Â Â Â Â frame->channel_layout = context->channel_layout;<br>
>     frame->channels    = context->channels;<br>
>Â Â Â Â Â frame->linesize[0]Â Â = context->frame_size*2;<br>
><br>
>Â Â Â Â Â int ret = av_frame_get_buffer(frame, 0);<br>
>Â Â Â Â Â if (ret < 0) {<br>
>Â Â Â Â Â Â Â return ENCODER_FRAME_ALLOC_ERROR;<br>
>Â Â Â Â Â }<br>
>Â Â Â Â Â return ENCODER_SUCCESS;<br>
>Â Â Â }<br>
><br>
>Â Â Â int encode(AVFrame *frame, vector<uint8_t> &output){<br>
>Â Â Â Â Â int ret;<br>
><br>
>Â Â Â Â Â // send PCM rawData<br>
>Â Â Â Â Â ret = avcodec_send_frame(context, frame);<br>
>Â Â Â Â Â if (ret) {<br>
>Â Â Â Â Â Â Â return ENCODER_FRAME_SEND_ERROR;<br>
>Â Â Â Â Â }<br>
><br>
>Â Â Â Â Â // read data<br>
>Â Â Â Â Â while (ret >= 0) {<br>
>Â Â Â Â Â Â Â ret = avcodec_receive_packet(context, pkt);<br>
>Â Â Â Â Â Â Â if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)<br>
>Â Â Â Â Â Â Â Â Â return ENCODER_SUCCESS;<br>
>Â Â Â Â Â Â Â else if (ret < 0) {<br>
>Â Â Â Â Â Â Â Â Â return ENCODER_ENCODE_ERROR;<br>
>Â Â Â Â Â Â Â }<br>
><br>
>Â Â Â Â Â Â Â auto p = pkt->data;<br>
>Â Â Â Â Â Â Â for (int i=0; i<pkt->size;i++) {<br>
>Â Â Â Â Â Â Â Â Â output.emplace_back(*(p++));<br>
>Â Â Â Â Â Â Â }<br>
>Â Â Â Â Â Â Â av_packet_unref(pkt);<br>
>Â Â Â Â Â }<br>
>Â Â Â Â Â return ENCODER_SUCCESS;<br>
>Â Â Â }<br>
><br>
> public:<br>
>Â Â Â Encoder() {<br>
>Â Â Â Â Â codec = nullptr;<br>
>Â Â Â Â Â context = nullptr;<br>
>Â Â Â }<br>
><br>
>Â Â Â int init(const char* outputFormat, int sampleRate) {<br>
>Â Â Â Â Â int ret;<br>
>Â Â Â Â Â ret = createCodec(outputFormat);<br>
>Â Â Â Â Â if (ret) {<br>
>Â Â Â Â Â Â Â return ret;<br>
>Â Â Â Â Â }<br>
><br>
>Â Â Â Â Â ret = createContext(sampleRate);<br>
>Â Â Â Â Â if (ret) {<br>
>Â Â Â Â Â Â Â return ret;<br>
>Â Â Â Â Â }<br>
><br>
>Â Â Â Â Â ret = createSwrContext(sampleRate);<br>
>Â Â Â Â Â if (ret) {<br>
>Â Â Â Â Â Â Â return ret;<br>
>Â Â Â Â Â }<br>
><br>
>Â Â Â Â Â ret = createPacket();<br>
>Â Â Â Â Â if (ret) {<br>
>Â Â Â Â Â Â Â return ret;<br>
>Â Â Â Â Â }<br>
><br>
>Â Â Â Â Â ret = createFrame();<br>
>Â Â Â Â Â if (ret) {<br>
>Â Â Â Â Â Â Â return ret;<br>
>Â Â Â Â Â }<br>
><br>
>Â Â Â Â Â return ENCODER_SUCCESS;<br>
>Â Â Â }<br>
><br>
>Â Â Â int reSample(const char* inputPcm, int length) {<br>
>     // 代ç å‚考<br>
> <a href="https://github.com/FFmpeg/FFmpeg/blob/master/doc/examples/resampling_audio.c" rel="noreferrer" target="_blank">https://github.com/FFmpeg/FFmpeg/blob/master/doc/examples/resampling_audio.c</a><br>
>Â Â Â Â Â const int srcRate = PCM_SAMPLE_RATE;<br>
>Â Â Â Â Â const int dstRate = context->sample_rate;<br>
>Â Â Â Â Â int srcSampleNum = length / 2;<br>
><br>
>Â Â Â Â Â uint8_t **dstData = nullptr;<br>
>Â Â Â Â Â int dstLineSize;<br>
><br>
>     // 计算é‡é‡‡æ ·åŽçš„é‡‡æ ·æ•°ç›®<br>
>Â Â Â Â Â int dst_nb_samples = av_rescale_rnd(swr_get_delay(swrContext,<br>
> srcRate) + srcSampleNum, dstRate, srcRate,<br>
>Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â AV_ROUND_UP);<br>
><br>
>     // 使用 API 申请空间用于å˜å‚¨é‡é‡‡æ ·ç»“æžœ<br>
>Â Â Â Â Â if (av_samples_alloc_array_and_samples(&dstData, &dstLineSize, 1,<br>
> dst_nb_samples, context->sample_fmt, 0) < 0) {<br>
>Â Â Â Â Â Â Â return ENCODER_SWR_ALLOC_ARRAY_ERROR;<br>
>Â Â Â Â Â }<br>
><br>
>     // 转æ¢é‡‡æ ·çŽ‡<br>
>Â Â Â Â Â auto convertSampleNum = swr_convert(swrContext,<br>
>Â Â Â Â Â Â Â Â Â dstData, dst_nb_samples,<br>
>Â Â Â Â Â Â Â Â Â (const uint8_t **) (&inputPcm), srcSampleNum);<br>
>Â Â Â Â Â if (convertSampleNum < 0) {<br>
>Â Â Â Â Â Â Â av_freep(&dstData);<br>
>Â Â Â Â Â Â Â return ENCODER_SWR_CONVERT_ERROR;<br>
>Â Â Â Â Â }<br>
><br>
>     // 将结果转å˜åˆ° pcmBuffer<br>
>Â Â Â Â Â int dstBuffSize = av_samples_get_buffer_size(&dstLineSize, 1,<br>
> convertSampleNum, context->sample_fmt, 1);<br>
>Â Â Â Â Â if (dstBuffSize < 0) {<br>
>Â Â Â Â Â Â Â av_freep(&dstData);<br>
>Â Â Â Â Â Â Â return ENCODER_SWR_GET_ERROR;<br>
>Â Â Â Â Â }<br>
><br>
>Â Â Â Â Â for (int i = 0; i < dstBuffSize;i++) {<br>
>Â Â Â Â Â Â Â pcmBuffer.emplace_back(*(dstData[0]+i));<br>
>Â Â Â Â Â }<br>
><br>
>Â Â Â Â Â return ENCODER_SUCCESS;<br>
>Â Â Â }<br>
><br>
><br>
>Â Â Â int process(const char* inputPcm, int length, bool isFinal, char**<br>
> output, int* outputLength) {<br>
><br>
>     // 先进行é‡é‡‡æ ·<br>
>Â Â Â Â Â int ret = reSample(inputPcm, length);<br>
>Â Â Â Â Â if (ret) {<br>
>Â Â Â Â Â Â Â return ret;<br>
>Â Â Â Â Â }<br>
><br>
>     // ç¼–ç ,å‚考<br>
> <a href="https://github.com/FFmpeg/FFmpeg/blob/master/doc/examples/encode_audio.c" rel="noreferrer" target="_blank">https://github.com/FFmpeg/FFmpeg/blob/master/doc/examples/encode_audio.c</a><br>
>Â Â Â Â Â vector<uint8_t> buffer;<br>
>Â Â Â Â Â while(true) {<br>
>Â Â Â Â Â Â Â if (pcmBuffer.size() < context->frame_size*2)<br>
>Â Â Â Â Â Â Â Â Â break;<br>
><br>
>Â Â Â Â Â Â Â ret = av_frame_make_writable(frame);<br>
>Â Â Â Â Â Â Â if (ret) {<br>
>Â Â Â Â Â Â Â Â Â return ENCODER_FRAME_NOT_WRITEABLE;<br>
>Â Â Â Â Â Â Â }<br>
><br>
>       // 从pcmBuffer å–出足够的数æ®å¡«å……一个 frame<br>
>Â Â Â Â Â Â Â auto samples = frame->data[0];<br>
>Â Â Â Â Â Â Â for (int i=0;i<context->frame_size*2;i++) {<br>
>Â Â Â Â Â Â Â Â Â samples[i] = pcmBuffer.front();<br>
>Â Â Â Â Â Â Â Â Â pcmBuffer.pop_front();<br>
>Â Â Â Â Â Â Â }<br>
><br>
>Â Â Â Â Â Â Â encode(frame, buffer);<br>
>Â Â Â Â Â }<br>
><br>
>     // 最åŽçš„æ•°æ®éœ€è¦ flush<br>
>Â Â Â Â Â if (isFinal) {<br>
>Â Â Â Â Â Â Â encode(nullptr, buffer);<br>
>Â Â Â Â Â }<br>
><br>
>     // 输出<br>
>Â Â Â Â Â *output = (char*)malloc(buffer.size()*sizeof(char));<br>
>Â Â Â Â Â if (*output) {<br>
>Â Â Â Â Â Â Â *outputLength = buffer.size();<br>
>Â Â Â Â Â Â Â memcpy(*output, buffer.data(), buffer.size());<br>
>Â Â Â Â Â Â Â return ENCODER_SUCCESS;<br>
>Â Â Â Â Â } else {<br>
>Â Â Â Â Â Â Â return ENCODER_MEN_ALLOC_ERROR;<br>
>Â Â Â Â Â }<br>
>Â Â Â }<br>
><br>
>Â Â Â virtual ~Encoder() {<br>
>Â Â Â Â Â if (context) {<br>
>Â Â Â Â Â Â Â avcodec_free_context(&context);<br>
>Â Â Â Â Â }<br>
>Â Â Â Â Â if (frame) {<br>
>Â Â Â Â Â Â Â av_frame_free(&frame);<br>
>Â Â Â Â Â }<br>
>Â Â Â Â Â if (pkt) {<br>
>Â Â Â Â Â Â Â av_packet_free(&pkt);<br>
>Â Â Â Â Â }<br>
>Â Â Â Â Â if (swrContext) {<br>
>Â Â Â Â Â Â Â swr_free(&swrContext);<br>
>Â Â Â Â Â }<br>
>Â Â Â }<br>
> };<br>
><br>
> int createEncoder(const char* outputFormat, int sampleRate, void**<br>
> encoderPtr) {<br>
>Â Â Â int ret;<br>
>Â Â Â auto encoder = new Encoder();<br>
>Â Â Â ret = encoder->init(outputFormat, sampleRate);<br>
>Â Â Â if (ret) {<br>
>Â Â Â Â Â delete encoder;<br>
>Â Â Â Â Â *encoderPtr = nullptr;<br>
>Â Â Â Â Â return ret;<br>
>Â Â Â } else {<br>
>Â Â Â Â Â *encoderPtr = encoder;<br>
>Â Â Â Â Â return ENCODER_SUCCESS;<br>
>Â Â Â }<br>
> }<br>
><br>
> int destroyEncoder(void* encoder) {<br>
>Â Â Â if (encoder != nullptr) {<br>
>Â Â Â Â Â auto e = (Encoder *) encoder;<br>
>Â Â Â Â Â delete e;<br>
>Â Â Â Â Â return ENCODER_SUCCESS;<br>
>Â Â Â }<br>
> }<br>
><br>
> // 该函数会 malloc 内å˜åˆ° output,记得释放<br>
> int processEncoder(void* e, const char* inputPcm, int length, bool isFinal,<br>
> char** output, int* outputLength) {<br>
>Â Â Â auto encoder = (Encoder*)e;<br>
>Â Â Â return encoder->process(inputPcm, length, isFinal, output,<br>
> outputLength);<br>
> }<br>
> ```<br>
><br>
_______________________________________________<br>
Libav-user mailing list<br>
<a href="mailto:Libav-user@ffmpeg.org" target="_blank">Libav-user@ffmpeg.org</a><br>
<a href="https://ffmpeg.org/mailman/listinfo/libav-user" rel="noreferrer" target="_blank">https://ffmpeg.org/mailman/listinfo/libav-user</a><br>
<br>
To unsubscribe, visit link above, or email<br>
<a href="mailto:libav-user-request@ffmpeg.org" target="_blank">libav-user-request@ffmpeg.org</a> with subject "unsubscribe".</blockquote></div></div>
</div>