ffmpeg mp3解码为pcm数据

Posted 最喜欢《暗号》

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ffmpeg mp3解码为pcm数据相关的知识,希望对你有一定的参考价值。

代码没有问题,使用的是ffmpeg4版本,ubuntu20.04
配置是编译安装ffmpeg,不是install安装。
cmake进行配置,有其他办法配置最好。

#include <iostream>
#include <cmath>
extern "C"
{
#include <libavdevice/avdevice.h>
#include <libavcodec/avcodec.h>
#include <libavfilter/avfilter.h>
#include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
#include <libavutil/mathematics.h>
#include <libavutil/time.h>
#include <libavutil/audio_fifo.h>
#include <libswresample/swresample.h>
#include <libswscale/swscale.h>
}

using namespace std;

int main()
{
    const char in_file_name[] = "/home/workspace/myffmpeg/jay1.mp3";
    const char out_file_name[] = "jay.pcm";

    FILE *file = fopen(out_file_name, "w+b");
    if (!file)
    {
        cout << "打不开输出文件" << endl;
        return -1;
    }

    AVFormatContext *fmtctx = avformat_alloc_context();
    AVCodecContext *codecCtx = NULL;
    AVPacket *pkt = av_packet_alloc();
    AVFrame *frame = av_frame_alloc();
    int audio_index = -1;

    if (avformat_open_input(&fmtctx, in_file_name, NULL, NULL) < 0)
    {
        cout << " 打不开文件" << endl;
        return -1;
    }

    if (avformat_find_stream_info(fmtctx, NULL) < 0)
    {
        cout << "打不开文件流" << endl;
    }

    av_dump_format(fmtctx, 0, in_file_name, 0);

    for (size_t i = 0; i < fmtctx->nb_streams; i++)
    {
        if (fmtctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
        {
            audio_index = (int)i;
            break;
        }
    }

    if (audio_index == -1)
    {
        cout << "找不到音频流" << endl;
    }

    AVCodecParameters *avcp = fmtctx->streams[audio_index]->codecpar;
    AVCodec *codec = avcodec_find_decoder(avcp->codec_id);
    if (!codec)
    {
        cout << "找不到对应的解码器" << endl;
        return -1;
    }

    codecCtx = avcodec_alloc_context3(codec);
    if (avcodec_parameters_to_context(codecCtx, avcp) < 0)
    {
        printf("Cannot alloc codec context.\\n");
        return -1;
    }
    codecCtx->pkt_timebase = fmtctx->streams[audio_index]->time_base;

    if (avcodec_open2(codecCtx, codec, NULL) < 0)
    {
        printf("Cannot open audio codec.\\n");
        return -1;
    }

    while (av_read_frame(fmtctx, pkt) >= 0)
    {
        if (pkt->stream_index == audio_index)
        {
            if (avcodec_send_packet(codecCtx, pkt) >= 0)
            {
                while (avcodec_receive_frame(codecCtx, frame) >= 0)
                { 
                    /*
                        Planar(平面),其数据格式排列方式为 (特别记住,该处是以点nb_samples采样点来交错,不是以字节交错):
                        LLLLLLRRRRRRLLLLLLRRRRRRLLLLLLRRRRRRL...(每个LLLLLLRRRRRR为一个音频帧)
                        而不带P的数据格式(即交错排列)排列方式为:
                        LRLRLRLRLRLRLRLRLRLRLRLRLRLRLRLRLRLRL...(每个LR为一个音频样本)
                    */
                    if (av_sample_fmt_is_planar(codecCtx->sample_fmt))
                    {
                        int numBytes = av_get_bytes_per_sample(codecCtx->sample_fmt);
                        //pcm播放时是LRLRLR格式,所以要交错保存数据
                        for (int i = 0; i < frame->nb_samples; i++)
                        {
                            for (int ch = 0; ch < codecCtx->channels; ch++)
                            {
                                fwrite((char *)frame->data[ch] + numBytes * i, 1, numBytes, file);
                            }
                        }
                    }
                }
            }
        }
        av_packet_unref(pkt);
    }while (0);
    av_frame_free(&frame);
    av_packet_free(&pkt);
    avcodec_close(codecCtx);
    avcodec_free_context(&codecCtx);
    avformat_free_context(fmtctx);

    fclose(file);
    return 0;
    


}

使用ffplay播放pcm。
ffplay -ar 44100 -ac 2 -f f32le -i jay.pcm

以上是关于ffmpeg mp3解码为pcm数据的主要内容,如果未能解决你的问题,请参考以下文章

ffmpeg mp3解码为pcm数据

Qt-FFmpeg开发-音频解码为PCM文件

2023-03-12:mp3音频解码为pcm,代码用go语言编写,调用moonfdd/ffmpeg-go库。

ffmpeg 获取音频文件PCM切片

音视频开发9. 使用ffmpeg 将pcm转码mp3实践(C++)

音视频开发9. 使用ffmpeg 将pcm转码mp3实践(C++)