ffmpeg把pcm编码为mp3

version

#define LIBSWRESAMPLE_VERSION_MAJOR 2

#define LIBSWRESAMPLE_VERSION_MINOR 9

#define LIBSWRESAMPLE_VERSION_MICRO 100

#define LIBAVCODEC_VERSION_MINOR 31

#define LIBAVCODEC_VERSION_MICRO 102

code

void CFfmpegOps::EncodePCMToMP3(const char *pcm_file, const char *mp3_file)
{
    if ((!pcm_file) || (!mp3_file))
    {
        return;
    }

    FILE *in_fp = nullptr;
    FILE *out_fp = nullptr;
    AVCodecContext *codec_ctx = nullptr;
    const AVCodec *codec = nullptr;
    AVFrame *pcm_avframe = nullptr;   // pcm file里的AVFrame
    AVFrame *codec_avframe = nullptr; // 编码器接受的AVFrame
    int pcm_data_bytes = 0;
    AVPacket *mp3_avpacket = nullptr;
    int ret = -1;
    size_t n = 0;
    int sample_fmt_is_planar = 0;
    int64_t pts = 0;
    struct SwrContext *swr_ctx = nullptr; // 音频帧转换器
    AVChannelLayout src_channel_layout;
    AVChannelLayout dest_channel_layout;

    in_fp = fopen(pcm_file, "rb");
    if (!in_fp)
    {
        printf("fopen error\n");
        goto END;
    }

    out_fp = fopen(mp3_file, "wb");
    if (!out_fp)
    {
        printf("fopen error\n");
        goto END;
    }

    codec = avcodec_find_encoder(AV_CODEC_ID_MP3);
    if (!codec)
    {
        printf("avcodec_find_encoder error\n");
        goto END;
    }

    // mp3编码器是否支持变化的采样样本数量
    if (codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE)
    {
        printf("codec AV_CODEC_CAP_VARIABLE_FRAME_SIZE\n");
    }

    codec_ctx = avcodec_alloc_context3(codec);
    if (!codec_ctx)
    {
        printf("avcodec_alloc_context3 error\n");
        goto END;
    }
    codec_ctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
    codec_ctx->channel_layout = AV_CH_LAYOUT_STEREO;
    codec_ctx->sample_rate = 44100;
    codec_ctx->channels = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO);
    codec_ctx->bit_rate = 128000;
    codec_ctx->time_base.num = 1;
    codec_ctx->time_base.den = codec_ctx->sample_rate;

    // 打开编码器
    ret = avcodec_open2(codec_ctx, codec, nullptr);
    if (ret < 0)
    {
        printf("avcodec_open2 error:%s\n", GetFfmpegERR(ret));
        goto END;
    }

    codec_avframe = av_frame_alloc();
    if (!codec_avframe)
    {
        printf("av_frame_alloc error\n");
        goto END;
    }
    codec_avframe->format = codec_ctx->sample_fmt;
    codec_avframe->sample_rate = codec_ctx->sample_rate;
    codec_avframe->channel_layout = codec_ctx->channel_layout;
    codec_avframe->channels = codec_ctx->channels;
    codec_avframe->nb_samples = codec_ctx->frame_size;

    ret = av_frame_get_buffer(codec_avframe, 0);
    if (ret < 0)
    {
        printf("av_frame_get_buffer error(%s)\n", CFfmpegOps::GetFfmpegERR(ret));
        goto END;
    }

    pcm_avframe = av_frame_alloc();
    if (!pcm_avframe)
    {
        printf("av_frame_alloc error\n");
        goto END;
    }
    pcm_avframe->format = AV_SAMPLE_FMT_FLT;
    pcm_avframe->sample_rate = 44100;
    pcm_avframe->channel_layout = AV_CH_LAYOUT_STEREO;
    pcm_avframe->channels = av_get_channel_layout_nb_channels(pcm_avframe->channel_layout);
    pcm_avframe->nb_samples = 1024;

    // 一帧pcm的相关参数计算
    pcm_data_bytes = av_get_bytes_per_sample((AVSampleFormat)(pcm_avframe->format)) * pcm_avframe->channels * pcm_avframe->nb_samples;
    ret = av_samples_get_buffer_size(nullptr,
                                     pcm_avframe->channels,
                                     pcm_avframe->nb_samples,
                                     (AVSampleFormat)(pcm_avframe->format),
                                     0);
    if (ret != pcm_data_bytes)
    {
        printf("pcm_data_bytes != av_samples_get_buffer_size\n");
        goto END;
    }

    ret = av_frame_get_buffer(pcm_avframe, 0);
    if (ret < 0)
    {
        printf("av_frame_get_buffer error(%s)\n", CFfmpegOps::GetFfmpegERR(ret));
        goto END;
    }

    mp3_avpacket = av_packet_alloc();
    if (!mp3_avpacket)
    {
        printf("av_packet_alloc error\n");
        goto END;
    }

    ret = av_channel_layout_from_mask(&src_channel_layout, pcm_avframe->channel_layout);
    if (ret < 0)
    {
        printf("av_channel_layout_from_mask error(%s)\n", GetFfmpegERR(ret));
        goto END;
    }

    ret = av_channel_layout_from_mask(&dest_channel_layout, codec_avframe->channel_layout);
    if (ret < 0)
    {
        printf("av_channel_layout_from_mask error(%s)\n", GetFfmpegERR(ret));
        goto END;
    }

    ret = swr_alloc_set_opts2(&swr_ctx,
                              &dest_channel_layout, (AVSampleFormat)(codec_avframe->format), codec_avframe->sample_rate,
                              &src_channel_layout, (AVSampleFormat)(pcm_avframe->format), pcm_avframe->sample_rate,
                              0, nullptr);
    if (ret < 0)
    {
        printf("swr_alloc_set_opts2 error(%s)\n", GetFfmpegERR(ret));
        goto END;
    }

    ret = swr_init(swr_ctx);
    if (ret < 0)
    {
        printf("swr_init error(%s)\n", GetFfmpegERR(ret));
        goto END;
    }

    while (1)
    {
        if (feof(in_fp))
        {
            printf("feof\n");
            break;
        }

        sample_fmt_is_planar = av_sample_fmt_is_planar((AVSampleFormat)(pcm_avframe->format));

        if (sample_fmt_is_planar)
        {
            n = fread(pcm_avframe->data[0], sizeof(uint8_t), pcm_data_bytes / 2, in_fp);
            if ((int)n != (pcm_data_bytes / 2))
            {
                printf("n != pcm_data_bytes/2\n");
            }

            n = fread(pcm_avframe->data[1], sizeof(uint8_t), pcm_data_bytes / 2, in_fp);
            if ((int)n != (pcm_data_bytes / 2))
            {
                printf("n != pcm_data_bytes/2\n");
            }
        }
        else
        {
            n = fread(pcm_avframe->data[0], sizeof(uint8_t), pcm_data_bytes, in_fp);
            if ((int)n != pcm_data_bytes)
            {
                printf("n != bytes_per_frame\n");
            }
        }

#if 0
        ret = swr_convert_frame(swr_ctx, codec_avframe, pcm_avframe);
        if (ret < 0)
        {
            printf("swr_convert_frame error(%s)\n", GetFfmpegERR(ret));
            goto END;
        }
#else
        ret = swr_convert(swr_ctx, 
                        (uint8_t**)(codec_avframe->data), codec_avframe->nb_samples, 
                        (const uint8_t**)(pcm_avframe->data), pcm_avframe->nb_samples);
        if (ret < 0)
        {
            printf("swr_convert error(%s)\n", GetFfmpegERR(ret));
            goto END;
        }
#endif

        codec_avframe->pts = pts;
        pts++;

        ret = avcodec_send_frame(codec_ctx, codec_avframe);
        if (ret < 0)
        {
            if (ret == AVERROR(EAGAIN))
            {
                printf("read output first\n");
            }
            else
            {
                printf("avcodec_send_frame error(%s)\n", GetFfmpegERR(ret));
                goto END;
            }
        }
        else if (ret == 0)
        {
            // printf("avcodec_send_frame succeed\n");
        }

        while (1)
        {
            ret = avcodec_receive_packet(codec_ctx, mp3_avpacket);
            if (ret < 0)
            {
                if (ret == AVERROR(EAGAIN))
                {
                    printf("send input first\n");
                    break;
                }
                else
                {
                    printf("avcodec_receive_packet error(%s)\n", GetFfmpegERR(ret));
                    break;
                }
            }
            else if (ret == 0)
            {
                // printf("avcodec_receive_packet succeed\n");

                n = fwrite(mp3_avpacket->data, sizeof(uint8_t), mp3_avpacket->size, out_fp);
                if ((int)n != mp3_avpacket->size)
                {
                    printf("n != mp3_avpacket->size\n");
                }

                av_packet_unref(mp3_avpacket);
            }
        }
    }

    ret = avcodec_send_frame(codec_ctx, nullptr);
    while (1)
    {
        ret = avcodec_receive_packet(codec_ctx, mp3_avpacket);
        if (ret < 0)
        {
            if (ret == AVERROR(EAGAIN))
            {
                break;
            }
            else
            {
                break;
            }
        }
        else if (ret == 0)
        {
            n = fwrite(mp3_avpacket->data, sizeof(uint8_t), mp3_avpacket->size, out_fp);
            av_packet_unref(mp3_avpacket);
        }
    }

END:
    if (swr_ctx)
    {
        swr_free(&swr_ctx);
        swr_ctx = nullptr;
    }

    if (mp3_avpacket)
    {
        av_packet_free(&mp3_avpacket);
        mp3_avpacket = nullptr;
    }

    if (codec_avframe)
    {
        av_frame_free(&codec_avframe);
        codec_avframe = nullptr;
    }

    if (pcm_avframe)
    {
        av_frame_free(&pcm_avframe);
        pcm_avframe = nullptr;
    }

    if (codec_ctx)
    {
        avcodec_free_context(&codec_ctx);
        codec_ctx = nullptr;
    }

    if (out_fp)
    {
        fclose(out_fp);
        out_fp = nullptr;
    }

    if (in_fp)
    {
        fclose(in_fp);
        in_fp = nullptr;
    }
}

performance

相关推荐
强哥之神3 分钟前
Nexa AI发布OmniAudio-2.6B:一款快速的音频语言模型,专为边缘部署设计
人工智能·深度学习·机器学习·语言模型·自然语言处理·音视频·openai
汤姆和杰瑞在瑞士吃糯米粑粑4 分钟前
【C++学习篇】AVL树
开发语言·c++·学习
DARLING Zero two♡12 分钟前
【优选算法】Pointer-Slice:双指针的算法切片(下)
java·数据结构·c++·算法·leetcode
CodeClimb26 分钟前
【华为OD-E卷-木板 100分(python、java、c++、js、c)】
java·javascript·c++·python·华为od
奶香臭豆腐1 小时前
C++ —— 模板类具体化
开发语言·c++·学习
不想当程序猿_1 小时前
【蓝桥杯每日一题】分糖果——DFS
c++·算法·蓝桥杯·深度优先
cdut_suye1 小时前
Linux工具使用指南:从apt管理、gcc编译到makefile构建与gdb调试
java·linux·运维·服务器·c++·人工智能·python
EasyDSS1 小时前
国标GB28181-2022平台EasyGBS:安防监控中P2P的穿透方法
网络协议·php·音视频·p2p
波音彬要多做2 小时前
41 stack类与queue类
开发语言·数据结构·c++·学习·算法
捕鲸叉2 小时前
C++软件设计模式之外观(Facade)模式
c++·设计模式·外观模式