What I trying to do : convert PCM data to mp3 data(should be AV_SAMPLE_FMT_S16P--16bit signed) What I actually get: AV_SAMPLE_FMT_FLTP
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) Paul B Mahol <[email protected]>于2019年5月17日 周五下午9:48写道: > On 5/17/19, 雷京颢 <[email protected]> wrote: > > I am trying to encode pcm data to mp3 format(exactly should be mono, > s16p, > > 24k) But I always get fltp as result. What I do wrong? > > There is mp3 and mp3float decoder. Do you mean that? > > > > > My code is below > > > > ```cpp > > #include "encoder.h" > > #include <string> > > > > #include <stdint.h> > > #include <stdio.h> > > #include <stdlib.h> > > #include <vector> > > #include <deque> > > #include <iostream> > > > > #include "encoder_err_code.h" > > > > extern "C" { > > #include <libavutil/opt.h> > > #include <libavcodec/avcodec.h> > > #include <libavutil/channel_layout.h> > > #include <libavutil/common.h> > > #include <libavutil/frame.h> > > #include <libavutil/samplefmt.h> > > #include <libswresample/swresample.h> > > } > > > > using namespace std; > > > > const int PCM_SAMPLE_RATE = 24000; > > > > class Encoder { > > private: > > AVCodec *codec = nullptr; > > AVCodecContext *context = nullptr; > > AVFrame *frame = nullptr; > > AVPacket *pkt = nullptr; > > SwrContext *swrContext = nullptr; > > deque<uint8_t> pcmBuffer; > > > > int createCodec(const char* outputFormat) { > > // find codec by outputFormat > > AVCodecID avCodecId = AV_CODEC_ID_NONE; > > > > if (strcmp(outputFormat, "mp3") == 0) { > > avCodecId = AV_CODEC_ID_MP3; > > } > > > > if (AV_CODEC_ID_NONE == avCodecId) { > > return ENCODER_FORMAT_NOT_SUPPORT; > > } else { > > codec = avcodec_find_encoder(avCodecId); > > } > > > > if (!codec) { > > return ENCODER_CODEC_NOT_FOUND; > > } > > > > return ENCODER_SUCCESS; > > } > > > > int createContext(int sampleRate) { > > // check sampleRate support > > int ret = ENCODER_SAMPLE_RATE_NOT_SUPPORT; > > auto p = codec->supported_samplerates; > > while(*p) { > > if (*(p++) == sampleRate) { > > ret = ENCODER_SUCCESS; > > break; > > } > > } > > > > if(ret) { > > return ret; > > } > > > > // create context > > context = avcodec_alloc_context3(codec); > > > > if (!context) { > > return ENCODER_CODEC_CONTEXT_CREATE_ERROR; > > } > > > > // set output format > > context->audio_service_type = AV_AUDIO_SERVICE_TYPE_MAIN; > > context->sample_fmt = AV_SAMPLE_FMT_S16P; > > context->sample_rate = sampleRate; > > context->channel_layout = AV_CH_LAYOUT_MONO; > > context->channels = > > av_get_channel_layout_nb_channels(context->channel_layout); > > > > // check PCM sampleRate > > const enum AVSampleFormat *f = codec->sample_fmts; > > while( *f != AV_SAMPLE_FMT_NONE) { > > if (*f == context->sample_fmt) { > > break; > > } > > f++; > > } > > > > if (*f == AV_SAMPLE_FMT_NONE) { > > return ENCODER_SAMPLE_FMT_NOT_SUPPORT; > > } > > > > // check PCM layout > > auto l = codec->channel_layouts; > > while(l) { > > if (*l == context->channel_layout) { > > break; > > } > > l++; > > } > > > > if (!l) { > > return ENCODER_SAMPLE_LAYOUT_NOT_SUPPORT; > > } > > > > if (avcodec_open2(context, codec, nullptr) < 0 ) { > > return ENCODER_CODEC_OPEN_ERROR; > > } > > > > return ENCODER_SUCCESS; > > } > > > > int createSwrContext(int sampleRate){ > > swrContext = swr_alloc(); > > if (!swrContext) { > > return ENCODER_SWR_ALLOC_ERROR; > > } > > > > /* set options */ > > av_opt_set_int(swrContext, "in_channel_layout", > > AV_CH_LAYOUT_MONO, 0); > > av_opt_set_int(swrContext, "in_sample_rate", > PCM_SAMPLE_RATE, > > 0); > > av_opt_set_sample_fmt(swrContext, "in_sample_fmt", > > context->sample_fmt, 0); > > > > av_opt_set_int(swrContext, "out_channel_layout", > > AV_CH_LAYOUT_MONO, 0); > > av_opt_set_int(swrContext, "out_sample_rate", sampleRate, > 0); > > av_opt_set_sample_fmt(swrContext, "out_sample_fmt", > > context->sample_fmt, 0); > > > > int ret = swr_init(swrContext); > > if (ret) { > > return ENCODER_SWR_INIT_ERROR; > > } > > return ENCODER_SUCCESS; > > } > > > > int createPacket(){ > > pkt = av_packet_alloc(); > > > > if (!pkt) { > > return ENCODER_PACKET_ALLOC_ERROR; > > } > > return ENCODER_SUCCESS; > > } > > > > int createFrame(){ > > frame = av_frame_alloc(); > > if (!frame) { > > return ENCODER_FRAME_ALLOC_ERROR; > > } > > frame->nb_samples = context->frame_size; > > frame->format = context->sample_fmt; > > frame->channel_layout = context->channel_layout; > > frame->channels = context->channels; > > frame->linesize[0] = context->frame_size*2; > > > > int ret = av_frame_get_buffer(frame, 0); > > if (ret < 0) { > > return ENCODER_FRAME_ALLOC_ERROR; > > } > > return ENCODER_SUCCESS; > > } > > > > int encode(AVFrame *frame, vector<uint8_t> &output){ > > int ret; > > > > // send PCM rawData > > ret = avcodec_send_frame(context, frame); > > if (ret) { > > return ENCODER_FRAME_SEND_ERROR; > > } > > > > // read data > > while (ret >= 0) { > > ret = avcodec_receive_packet(context, pkt); > > if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) > > return ENCODER_SUCCESS; > > else if (ret < 0) { > > return ENCODER_ENCODE_ERROR; > > } > > > > auto p = pkt->data; > > for (int i=0; i<pkt->size;i++) { > > output.emplace_back(*(p++)); > > } > > av_packet_unref(pkt); > > } > > return ENCODER_SUCCESS; > > } > > > > public: > > Encoder() { > > codec = nullptr; > > context = nullptr; > > } > > > > int init(const char* outputFormat, int sampleRate) { > > int ret; > > ret = createCodec(outputFormat); > > if (ret) { > > return ret; > > } > > > > ret = createContext(sampleRate); > > if (ret) { > > return ret; > > } > > > > ret = createSwrContext(sampleRate); > > if (ret) { > > return ret; > > } > > > > ret = createPacket(); > > if (ret) { > > return ret; > > } > > > > ret = createFrame(); > > if (ret) { > > return ret; > > } > > > > return ENCODER_SUCCESS; > > } > > > > int reSample(const char* inputPcm, int length) { > > // 代码参考 > > > https://github.com/FFmpeg/FFmpeg/blob/master/doc/examples/resampling_audio.c > > const int srcRate = PCM_SAMPLE_RATE; > > const int dstRate = context->sample_rate; > > int srcSampleNum = length / 2; > > > > uint8_t **dstData = nullptr; > > int dstLineSize; > > > > // 计算重采样后的采样数目 > > int dst_nb_samples = av_rescale_rnd(swr_get_delay(swrContext, > > srcRate) + srcSampleNum, dstRate, srcRate, > > AV_ROUND_UP); > > > > // 使用 API 申请空间用于存储重采样结果 > > if (av_samples_alloc_array_and_samples(&dstData, &dstLineSize, 1, > > dst_nb_samples, context->sample_fmt, 0) < 0) { > > return ENCODER_SWR_ALLOC_ARRAY_ERROR; > > } > > > > // 转换采样率 > > auto convertSampleNum = swr_convert(swrContext, > > dstData, dst_nb_samples, > > (const uint8_t **) (&inputPcm), srcSampleNum); > > if (convertSampleNum < 0) { > > av_freep(&dstData); > > return ENCODER_SWR_CONVERT_ERROR; > > } > > > > // 将结果转存到 pcmBuffer > > int dstBuffSize = av_samples_get_buffer_size(&dstLineSize, 1, > > convertSampleNum, context->sample_fmt, 1); > > if (dstBuffSize < 0) { > > av_freep(&dstData); > > return ENCODER_SWR_GET_ERROR; > > } > > > > for (int i = 0; i < dstBuffSize;i++) { > > pcmBuffer.emplace_back(*(dstData[0]+i)); > > } > > > > return ENCODER_SUCCESS; > > } > > > > > > int process(const char* inputPcm, int length, bool isFinal, char** > > output, int* outputLength) { > > > > // 先进行重采样 > > int ret = reSample(inputPcm, length); > > if (ret) { > > return ret; > > } > > > > // 编码,参考 > > https://github.com/FFmpeg/FFmpeg/blob/master/doc/examples/encode_audio.c > > vector<uint8_t> buffer; > > while(true) { > > if (pcmBuffer.size() < context->frame_size*2) > > break; > > > > ret = av_frame_make_writable(frame); > > if (ret) { > > return ENCODER_FRAME_NOT_WRITEABLE; > > } > > > > // 从pcmBuffer 取出足够的数据填充一个 frame > > auto samples = frame->data[0]; > > for (int i=0;i<context->frame_size*2;i++) { > > samples[i] = pcmBuffer.front(); > > pcmBuffer.pop_front(); > > } > > > > encode(frame, buffer); > > } > > > > // 最后的数据需要 flush > > if (isFinal) { > > encode(nullptr, buffer); > > } > > > > // 输出 > > *output = (char*)malloc(buffer.size()*sizeof(char)); > > if (*output) { > > *outputLength = buffer.size(); > > memcpy(*output, buffer.data(), buffer.size()); > > return ENCODER_SUCCESS; > > } else { > > return ENCODER_MEN_ALLOC_ERROR; > > } > > } > > > > virtual ~Encoder() { > > if (context) { > > avcodec_free_context(&context); > > } > > if (frame) { > > av_frame_free(&frame); > > } > > if (pkt) { > > av_packet_free(&pkt); > > } > > if (swrContext) { > > swr_free(&swrContext); > > } > > } > > }; > > > > int createEncoder(const char* outputFormat, int sampleRate, void** > > encoderPtr) { > > int ret; > > auto encoder = new Encoder(); > > ret = encoder->init(outputFormat, sampleRate); > > if (ret) { > > delete encoder; > > *encoderPtr = nullptr; > > return ret; > > } else { > > *encoderPtr = encoder; > > return ENCODER_SUCCESS; > > } > > } > > > > int destroyEncoder(void* encoder) { > > if (encoder != nullptr) { > > auto e = (Encoder *) encoder; > > delete e; > > return ENCODER_SUCCESS; > > } > > } > > > > // 该函数会 malloc 内存到 output,记得释放 > > int processEncoder(void* e, const char* inputPcm, int length, bool > isFinal, > > char** output, int* outputLength) { > > auto encoder = (Encoder*)e; > > return encoder->process(inputPcm, length, isFinal, output, > > outputLength); > > } > > ``` > > > _______________________________________________ > Libav-user mailing list > [email protected] > https://ffmpeg.org/mailman/listinfo/libav-user > > To unsubscribe, visit link above, or email > [email protected] with subject "unsubscribe".
_______________________________________________ Libav-user mailing list [email protected] https://ffmpeg.org/mailman/listinfo/libav-user To unsubscribe, visit link above, or email [email protected] with subject "unsubscribe".
