音视频开发八:抽取音频数据流程

抽取音频数据流程

一般步骤为:

  1. 打开多媒体文件
  2. 从多媒体文件中找到音频流
  3. 打开目的文件的上下文
  4. 为目的文件,创建一个新的音频流
  5. 设置输出音频参数
  6. 写多媒体文件头到目的文件
  7. 从源多媒体文件中读取音/视频数据到目的文件中
  8. 写多媒体文件尾到文件中
  9. 将申请的资源释放掉

流程图如下:

从一个MP4文件中,抽取音频数据输出为aac音频文件。

#include <stdio.h>
#include <libavutil/log.h>
#include <libavutil/avutil.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avio.h>
#include <libavutil/opt.h>
#include <SDL.h>
#include <stdbool.h>

/*抽取音频*/
void getAudio() {
    
    
    int ret = -1;
    int idx = -1;

    //1. 处理一些参数;
    char* src;
    char* dst;

    AVFormatContext* pFmtCtx = NULL;
    AVFormatContext* oFmtCtx = NULL;

    const AVOutputFormat* outFmt = NULL;
    AVStream* outStream = NULL;
    AVStream* inStream = NULL;

    AVPacket pkt;

    av_log_set_level(AV_LOG_DEBUG);


    src = "F:\\test_data\\crop_jiuzhe_summer.mp4";//输入文件
    dst = "F:\\test_data\\crop_jiuzhe_summer.aac";//输出文件

    //2. 打开多媒体文件,得到输入文件的封装格式上下文
    if ((ret = avformat_open_input(&pFmtCtx, src, NULL, NULL)) < 0) {
    
    
        av_log(NULL, AV_LOG_ERROR, "%s\n", av_err2str(ret));
        exit(-1);
    }

    //3. 从多媒体文件中找到音频流
    idx = av_find_best_stream(pFmtCtx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
    if (idx < 0) {
    
    
        av_log(pFmtCtx, AV_LOG_ERROR, "Does not include audio stream!\n");
        goto _ERROR;
    }

    //4. 创建分配输出封装格式上下文
    //oFmtCtx = avformat_alloc_context();
    //if (!oFmtCtx) {
    
    
    //    av_log(NULL, AV_LOG_ERROR, "NO Memory!\n");
    //    goto _ERROR;
    //}
    //outFmt = av_guess_format(NULL, dst, NULL); // 获取输出文件的基本格式信息。
    //oFmtCtx->oformat = outFmt; // 输出目标文件的格式的基本信息赋值给输出格式的上下文。
    
    // 相当于 oFmtCtx = avformat_alloc_context();和outFmt = av_guess_format(NULL, dst, NULL); 这两个步骤
    ret = avformat_alloc_output_context2(&oFmtCtx, NULL, NULL, dst);
    if (ret < 0) {
    
    
        av_log(NULL, AV_LOG_ERROR, "alloc output context fail \n");
    }
    //5. 创建一个新的音频流,这个流要被写入到目的文件中
    outStream = avformat_new_stream(oFmtCtx, NULL);
    //6. 设置输出音频参数
    inStream = pFmtCtx->streams[idx];//获取输入音频流
    avcodec_parameters_copy(outStream->codecpar, inStream->codecpar);// 把输入音频流的编码器参数内容拷贝到目输出音频流编码器中
    outStream->codecpar->codec_tag = 0; //ffmpeg根据你的多媒体文件自动适配编解码器



    //绑定  将输出封装格式上下文和目的文件进行绑定,绑定之后才可以对于目的文件进行操作
    // AVIOContext *pb 是一个输入输出文件上下文
    ret = avio_open2(&oFmtCtx->pb, dst, AVIO_FLAG_WRITE, NULL, NULL);
    if (ret < 0) {
    
    
        av_log(oFmtCtx, AV_LOG_ERROR, "%s", av_err2str(ret));
        goto _ERROR;
    }

    //7. 写多媒体文件头到目的文件
    ret = avformat_write_header(oFmtCtx, NULL);

    if (ret < 0) {
    
    
        av_log(oFmtCtx, AV_LOG_ERROR, "%s", av_err2str(ret));
        goto _ERROR;
    }
    //8. 从源多媒体文件中不停的读音频数据写入到目的文件中
    while (av_read_frame(pFmtCtx, &pkt) >= 0) {
    
     // 非负值说明读到数据了
        if (pkt.stream_index == idx) {
    
     // 存在多个流,读取数据所属的流是不是我们想要的流
            
            // 时间基计算 因为输出流的时间基可能和输入的时间基不一样。这样做的目的是让输出流的时间戳与输入流的时间戳保持同步
            //pkt.pts = av_rescale_q_rnd(pkt.pts, inStream->time_base, outStream->time_base, (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); 
            //pkt.dts = pkt.pts; // 音频的pts和dts一般是相等的 因为没有B帧。
            // 设置音频帧时长
            //pkt.duration = av_rescale_q(pkt.duration, inStream->time_base, outStream->time_base);
            pkt.stream_index = 0; // 因为我们只有一路音频,流的索引是从0开始递增的,不按照递增顺序来,会报错(无效的流索引),所以设置音频流的索引设置为0
            pkt.pos = -1; // pos字段可以用于表示该数据包在文件中的偏移量。pos字段的值为-1时,表示该数据包的偏移量未知。让它自己进行计算
            av_interleaved_write_frame(oFmtCtx, &pkt);// 将音频数据写入目标文件中
            av_packet_unref(&pkt);// 释放packet下次再用。
        }
    }
    //9. 写多媒体文件尾到文件中
    av_write_trailer(oFmtCtx);

    //10. 将申请的资源释放掉
_ERROR:
    if (pFmtCtx) {
    
    
        avformat_close_input(&pFmtCtx);
        pFmtCtx = NULL;
    }
    if (oFmtCtx->pb) {
    
    
        avio_close(oFmtCtx->pb);
    }

    if (oFmtCtx) {
    
    
        avformat_free_context(oFmtCtx);
        oFmtCtx = NULL;
    }
    printf("hello, world!\n");

}

猜你喜欢

转载自blog.csdn.net/qq_38056514/article/details/130190763