音视频开发十:多媒体格式转换

转换原理

主要就是,对多媒体文件解封装,换一个新封装格式,相比与之前单独抽取音频流数据或者视频流数据,格式转换是把解封装后所有需要的流给它写入到新的封装格式中。

逻辑流程

实现代码

把一个mp4的多媒体文件转换为mov格式。

#include <stdio.h>
#include <libavutil/log.h>
#include <libavutil/avutil.h>
#include <libavformat/avformat.h>

/*转封装格式*/
int remux() {
    
    

    int ret = -1;
    int idx = -1;
    int stream_idx = 0;
    int i = 0;
    char* src;
    char* dst;

   

    int* stream_map = NULL;

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

    const AVOutputFormat* outFmt = 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.mov";

    //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. 现在是抽取所有的流,所以省去了抽取某一个流的步骤

    //4. 打开目的文件的上下文,同时指定格式
    avformat_alloc_output_context2(&oFmtCtx, NULL, NULL, dst);
    if (!oFmtCtx) {
    
    
        av_log(NULL, AV_LOG_ERROR, "NO MEMORY!\n");
        goto _ERROR;
    }

    // ffmpeg 分配空间方法
    stream_map = av_calloc(pFmtCtx->nb_streams, sizeof(int));
    if (!stream_map) {
    
    
        av_log(NULL, AV_LOG_ERROR, "NO MEMORY!\n");
        goto _ERROR;
    }

    // 对输入文件所有的流进行遍历操作
    // 注意,在输入文件中,可能不只包含音频、视频流和字幕流,
    // 还有可能meta数据的流,这部分的流是对我们来说是没有意义的。转封装的话,meta信息会改变。
    for (i = 0; i < pFmtCtx->nb_streams; i++) {
    
    
        AVStream* outStream = NULL;
        AVStream* inStream = pFmtCtx->streams[i];
        AVCodecParameters* inCodecPar = inStream->codecpar;
        // 如果不是音频 视频或者字幕流 就把改流标记位-1
        if (inCodecPar->codec_type != AVMEDIA_TYPE_AUDIO &&
            inCodecPar->codec_type != AVMEDIA_TYPE_VIDEO &&
            inCodecPar->codec_type != AVMEDIA_TYPE_SUBTITLE) {
    
    
            stream_map[i] = -1;
            continue;
        }
        stream_map[i] = stream_idx++;

        //5. 为目的文件,创建一个新的多媒体流 每次创建都会在输出上下文中添加一项
        outStream = avformat_new_stream(oFmtCtx, NULL);
        if (!outStream) {
    
    
            av_log(oFmtCtx, AV_LOG_ERROR, "NO MEMORY!\n");
            goto _ERROR;
        }

        avcodec_parameters_copy(outStream->codecpar, inStream->codecpar);
        outStream->codecpar->codec_tag = 0;
    }

    //绑定
    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) {
    
    
        AVStream* inStream, * outStream;
        int tmepIndex = pkt.stream_index;

        // av_read_frame 读取这个数据帧,存储在pkt包中
        // pkt.stream_index 表示 这个包所在的媒体流的索引
        inStream = pFmtCtx->streams[tmepIndex];

        // stream_map[pkt.stream_index] < 0 表示该流不是音视频流和字幕流
        if (stream_map[tmepIndex] < 0) {
    
    
            av_packet_unref(&pkt);
            continue;
        }

        // stream_map[pkt.stream_index] 返回的一个ID值 ,表示输出文件所在媒体流所在的索引ID
        pkt.stream_index = stream_map[tmepIndex];

        outStream = oFmtCtx->streams[tmepIndex];

        // 更好用的修改时间基的用法。替代了之前抽取音/视频 对pts和dts时间戳修改的步骤
        av_packet_rescale_ts(&pkt, inStream->time_base, outStream->time_base);
        pkt.pos = -1;
        av_interleaved_write_frame(oFmtCtx, &pkt);
        av_packet_unref(&pkt);

    }
    //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;
    }

    if (stream_map) {
    
    
        av_free(stream_map);
    }
    printf("hello, world!\n");
    return 0;
}

猜你喜欢

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