使用 FFmpeg 获取音频文件编码格式、采样率等信息

参考博客:用FFmpeg获取视频流+音频流的信息(编码格式、分辨率、帧率、播放时长...)_zhoubotong2012的博客-CSDN博客_ffmpeg获取视频编码格式

参考博客:用AVCodecParameters代替AVCodecContext_luotuo44的博客-CSDN博客_avcodec_parameters_to_context

我是在 Qt 里跑的,所以路径用了 QString 传递,然后 FFmpeg 使用的 4.2 版本进行测试。对于相关函数的含义,一般 FFmpeg 源文件有注释。

(2020-12-30 修改)之前用的 AVFormatContext 来获取的比特率,如果是视频文件这就不能作为音频的比特率了,所以改为了 AVCodecContext 来获取。不过有些文件的 AVCodecContext 可能获取不到比特率信息,这时候再使用 AVFormatContext 提供的信息。

(2022-08-25 修改)之前用av_get_bytes_per_sample(guard.codecCtx->sample_fmt)获取采样精度,因为参数枚举AVSampleFormat并不对应文件实际的采样精度,所以读取出来的信息如24bit时会识别成32bit,现在用av_get_bits_per_sample(guard.codecParam->codec_id)来获取。

extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/dict.h>
}

#include <QString>
#include <QDebug>

//通过一个guard对象来确保资源释放
struct AudioInfoGuard {
    //格式化I/O上下文
    AVFormatContext *formatCtx = NULL;
    //解码器
    AVCodec *codec = NULL;
    //解码器上下文
    AVCodecContext *codecCtx = NULL;
    //参数信息
    AVCodecParameters *codecParam = NULL;

    ~AudioInfoGuard() {
        if(codecCtx){
            avcodec_free_context(&codecCtx);
        }
        if(formatCtx){
            avformat_close_input(&formatCtx);
            avformat_free_context(formatCtx);
        }
    }
};

//是在Qt中使用的,所以传递的QString
bool getAudioInfo(const QString &filepath)
{
    //用的utf8编码,这里转换下
    QByteArray temp=filepath.toUtf8();
    const char *path=temp.constData();
    //const char *filepath="D:/Download/12.wav";

    //借助析构函数来释放
    AudioInfoGuard guard;

    //打开输入流并读取头
    //流要使用avformat_close_input关闭
    //成功时返回=0
    int result=avformat_open_input(&guard.formatCtx, path, NULL, NULL);
    if (result!=0||guard.formatCtx==NULL){
        return false;
    }

    //读取文件获取流信息,把它存入AVFormatContext中
    //正常时返回>=0
    if (avformat_find_stream_info(guard.formatCtx, NULL) < 0) {
        return false;
    }

    //获取元信息,曲名,歌手等
    //AVDictionaryEntry *tag = NULL;
    //while (tag = av_dict_get(fmt_ctx->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))
    //{
    //    qDebug()<<tag->key<<tag->value;
    //}

    qDebug()<<"filepath"<<filepath;
    //时长
    //duration/AV_TIME_BASE单位为秒
    qDebug()<<"duration"<<guard.formatCtx->duration/(AV_TIME_BASE/1000.0)<<"ms";
    //文件格式,如wav
    qDebug()<<"format"<<guard.formatCtx->iformat->name<<":"<<guard.formatCtx->iformat->long_name;
    //这是容器的比特率
    qDebug()<<"bit rate"<<guard.formatCtx->bit_rate<<"bps";
    qDebug()<<"n stream"<<guard.formatCtx->nb_streams;

    for (unsigned int i = 0; i < guard.formatCtx->nb_streams; i++)
    {
#if 1
        //AVStream是存储每一个视频/音频流信息的结构体
        AVStream *in_stream = guard.formatCtx->streams[i];

        //类型为音频
        if(in_stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO){
            //参数信息
            guard.codecParam = in_stream->codecpar;
            //查找具有匹配编解码器ID的已注册解码器
            //失败返回NULL
            guard.codec = avcodec_find_decoder(in_stream->codecpar->codec_id);
            if(guard.codec==NULL){
                return false;
            }

            //分配AVCodecContext并将其字段设置为默认值
            //需要使用avcodec_free_context释放生成的对象
            //如果失败,则返回默认填充或者 NULL
            guard.codecCtx = avcodec_alloc_context3(guard.codec);
            if(guard.codecCtx==NULL){
                return false;
            }

            //根据编码器填充上下文参数
            //事实上codecpar包含了大部分解码器相关的信息,这里是直接从AVCodecParameters复制到AVCodecContext
            //成功时返回值>=0
            if(avcodec_parameters_to_context(guard.codecCtx, in_stream->codecpar)<0){
                return false;
            }

            //某些AVCodecContext字段的访问器,已弃用
            //av_codec_set_pkt_timebase(codec_ctx, in_stream->time_base);

            //打开解码器
            //使用给定的AVCodec初始化AVCodecContext
            //在之前必须使用avcodec_alloc_context3()分配上下文
            //成功时返回值=0
            if(avcodec_open2(guard.codecCtx, guard.codec, nullptr)!=0){
                return false;
            }

            //采样率
            qDebug()<<"sample rate"<<guard.codecParam->sample_rate;
            //通道数
            qDebug()<<"channels"<<guard.codecParam->channels;
            //采样精度
            qDebug()<<"sample bit"<<av_get_bits_per_sample(guard.codecParam->codec_id);
            //音频的比特率
            qDebug()<<"bit rate"<<guard.codecCtx->bit_rate;
            //编码,如pcm
            qDebug()<<"codec name"<<guard.codec->name<<":"<<guard.codec->long_name;
            return true;
        }
#else
        //新的版本这种获取方式已弃用
        AVStream *in_stream = fmt_ctx->streams[i];
        AVCodecContext *avctx=in_stream->codec;
        if (avctx->codec_type == AVMEDIA_TYPE_VIDEO){
            //视频信息略
        }else if (avctx->codec_type == AVMEDIA_TYPE_AUDIO){
            //音频信息
            qDebug()<<"sample rate"<<guard.codecParam->sample_rate;
            qDebug()<<"channels"<<guard.codecParam->channels;
            qDebug()<<"sample bit"<<av_get_bits_per_sample(guard.codecParam->codec_id);

            AVCodec *codec=avcodec_find_decoder(avctx->codec_id);
            if(codec==NULL){
                return;
            }
            qDebug()<<"codec name"<<codec->name<<":"<<codec->long_name;
            return true;
        }
#endif
    }
    return false;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龚建波

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值