qt, ffmpge 抽取音频文件

介绍

接下去两篇文章介绍下通过qt+ffmpeg抽取音视频,然后单独播放出来。首先需要了解的ffmpeg的几个api。

抽取音频api介绍

av_init_packet():初始化一个数据包结构体,我们从多媒体文件中读取了每一个数据包,都可以放在被初始化的包结构体里。

av_find_best_stream(): 通过这个名字就能猜到,是在多媒体文件中找到最好的一路流,

av_read_frame(): 获取流中的数据包,获取到数据包之后就可以做一些逻辑处理。在这个例子中我们就会写入到aac文件中。

av_packet_unref() : packet 引用计数减一,ffmpeg观察到引用计数位0 就会释放相应资源。要是忘记了的话就会造成内存泄露。

avformat_alloc_context(): 分配一个空的 AVFormatContext 结构体的函数。在 FFmpeg 中,AVFormatContext 结构体用于表示音视频格式的上下文信息,包括输入/输出文件的格式、编解码器、流信息等。

av_guess_format(): 函数用于根据文件名猜测输出文件的格式。具体来说,它会根据文件名的后缀(例如 “.mp4”、“.avi” 等)来猜测文件的格式,然后返回相应的输出格式。如果无法确定文件格式,则返回 NULL。

avcodec_parameters_copy():函数用于将一个 AVCodecParameters 结构体的内容复制到另一个 AVCodecParameters 结构体中。这个函数通常用于在创建新的输出流时,从输入流中复制编解码器参数到输出流中,以确保输出流的编解码器参数与输入流相同。

avio_open():函数会根据提供的路径和选项打开文件,并创建一个 AVIOContext 结构体,以便后续的读写操作。在成功打开文件后,可以使用相关的 avio_read()、avio_write() 等函数进行数据的读写操作。

avformat_write_header() : 函数用于写入输出文件的文件头信息。在对输出文件进行写入操作之前,必须先调用该函数来写入文件的头部信息,以确保输出文件的格式正确并且包含所需的元数据。

av_write_trailer() : 用于写入输出文件的尾部信息。在完成对输出文件的所有写入操作后,必须调用该函数来完成输出文件的写入过程,并且确保尾部信息正确写入。

avio_close(): 用于关闭由 avio_open() 打开的 IO 上下文(AVIOContext)。在完成对文件的写入或读取操作后,应该调用此函数来关闭文件。

以上基本列出了所有需要使用的api,忽略了参数部分。
接下来就开始提取mp4中的音频数据了,我这边的demo直接写在了主窗口的构造函数往下写了,没有用一些拖动event,后面会做修改。把提取音频,提取视频,音视频合并放在一个项目中。这里直接贴上代码了 ,输入文件输出文件自己改动下。


int MainWindow::ExtraAACFFmpeg() {
    int err_code;
    char errors[1024];

    char *src_filename = "C:/Users/57102/Desktop/test/tttt.mp4";
    char *dst_filename ="C:/Users/57102/Desktop/test/ttss.aac";

    FILE *dst_fd = NULL;

    int audio_stream_index = -1;
    int len;

    AVFormatContext *ofmt_ctx = NULL;
    AVOutputFormat *output_fmt = NULL;

    AVStream *in_stream = NULL;
    AVStream *out_stream = NULL;

    AVFormatContext *fmt_ctx = NULL;
    //AVFrame *frame = NULL;
    AVPacket pkt;

    av_log_set_level(AV_LOG_DEBUG);

 
    if(src_filename == NULL || dst_filename == NULL){
        av_log(NULL, AV_LOG_DEBUG, "src or dts file is null, plz check them!\n");
        return -1;
    }
 
    av_register_all();

    /*open input media file, and allocate format context*/
    if((err_code = avformat_open_input(&fmt_ctx, src_filename, NULL, NULL)) < 0){
        av_strerror(err_code, errors, 1024);
        av_log(NULL, AV_LOG_DEBUG, "Could not open source file: %s, %d(%s)\n",
               src_filename,
               err_code,
               errors);
        return -1;
    }

    /*retrieve audio stream*/
    if((err_code = avformat_find_stream_info(fmt_ctx, NULL)) < 0) {
        av_strerror(err_code, errors, 1024);
        av_log(NULL, AV_LOG_DEBUG, "failed to find stream information: %s, %d(%s)\n",
               src_filename,
               err_code,
               errors);
        return -1;
    }

    /*dump input information*/
    av_dump_format(fmt_ctx, 0, src_filename, 0);

    in_stream = fmt_ctx->streams[1];
    AVCodecParameters *in_codecpar = in_stream->codecpar;
    if(in_codecpar->codec_type != AVMEDIA_TYPE_AUDIO){
        av_log(NULL, AV_LOG_ERROR, "The Codec type is invalid!\n");
        exit(1);
    }

    //out file
    ofmt_ctx = avformat_alloc_context();
    output_fmt = av_guess_format(NULL, dst_filename, NULL);
    if(!output_fmt){
        av_log(NULL, AV_LOG_DEBUG, "Cloud not guess file format \n");
        exit(1);
    }

    ofmt_ctx->oformat = output_fmt;

    out_stream = avformat_new_stream(ofmt_ctx, NULL);
    if(!out_stream){
        av_log(NULL, AV_LOG_DEBUG, "Failed to create out stream!\n");
        exit(1);
    }

    if(fmt_ctx->nb_streams<2){
        av_log(NULL, AV_LOG_ERROR, "the number of stream is too less!\n");
        exit(1);
    }


    if((err_code = avcodec_parameters_copy(out_stream->codecpar, in_codecpar)) < 0 ){
//        av_strerror(err_code, errors, ERROR_STR_SIZE);
        av_log(NULL, AV_LOG_ERROR,
               "Failed to copy codec parameter, %d(%s)\n",
               err_code, errors);
    }

    out_stream->codecpar->codec_tag = 0;

    if((err_code = avio_open(&ofmt_ctx->pb, dst_filename, AVIO_FLAG_WRITE)) < 0) {
        av_strerror(err_code, errors, 1024);
        av_log(NULL, AV_LOG_DEBUG, "Could not open file %s, %d(%s)\n",
               dst_filename,
               err_code,
               errors);
        exit(1);
    }

    

    /*dump output information*/
    av_dump_format(ofmt_ctx, 0, dst_filename, 1);

 

    /*initialize packet*/
    av_init_packet(&pkt);
    pkt.data = NULL;
    pkt.size = 0;

    /*find best audio stream*/
    audio_stream_index = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
    if(audio_stream_index < 0){
        av_log(NULL, AV_LOG_DEBUG, "Could not find %s stream in input file %s\n",
               av_get_media_type_string(AVMEDIA_TYPE_AUDIO),
               src_filename);
        return AVERROR(EINVAL);
    }

    if (avformat_write_header(ofmt_ctx, NULL) < 0) {
        av_log(NULL, AV_LOG_DEBUG, "Error occurred when opening output file");
        exit(1);
    }

    /*read frames from media file*/
    while(av_read_frame(fmt_ctx, &pkt) >=0 ){
        if(pkt.stream_index == audio_stream_index){
            //(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)
            pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, (AV_ROUND_NEAR_INF ));
            pkt.dts = pkt.pts;
            pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
            pkt.pos = -1;
            pkt.stream_index = 0;
            av_interleaved_write_frame(ofmt_ctx, &pkt);
            av_packet_unref(&pkt);
        }
    }

    av_write_trailer(ofmt_ctx);

    /*close input media file*/
    avformat_close_input(&fmt_ctx);
    if(dst_fd) {
        fclose(dst_fd);
    }

    avio_close(ofmt_ctx->pb);

    return 0;
}

总结

用ffmpeg提供的api还是比较简单的,但是你要想挑战下自己 ,都是自己手写,比如adts头这种就不是很简单了。需要对着文档,每个bit位都都需要注意。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值