C++音视频03:媒体信息打印、提取音视频、转封装、剪辑

版本:FFMpeg6.0

媒体信息打印

c 复制代码
#include <libavformat/avformat.h>
#include <libavutil/log.h>

int main (int argc, char *argv[]) {
    AVFormatContext *fmt_cxt = NULL;
    int ret;
    av_log_set_level(AV_LOG_INFO);

    ret = avformat_open_input(&fmt_cxt, "/root/resource/1.mp4", NULL, NULL);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Can't open file: %s", av_err2str(ret));
        return -1;
    }
	// 打印媒体信息
    av_dump_format(fmt_cxt, 0, "/root/resource/1.mp4", 0);

    avformat_close_input(&fmt_cxt);
    
    return 0;
}

提取音视频

音频和视频的区别在于av_find_best_stream时将AVMEDIA_TYPE_VIDEO改为AVMEDIA_TYPE_AUDIO

c 复制代码
#include <libavformat/avformat.h>
#include <libavutil/log.h>
#include <libavutil/avutil.h>

int main (int argc, char *argv[]) {
    // 1. 处理参数
    char *src;
    char *dst;
    int ret;
    int idx = -1;
    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);
    if (argc < 3) {
        av_log(NULL, AV_LOG_ERROR, "argument must be more than 3\n");
        exit(-1);
    }

    src = argv[1];
    dst = argv[2];

    // 2. 打开多媒体文件
    ret = avformat_open_input(&pFmtCtx, src, NULL, NULL);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "%s\n", av_err2str(ret));
        exit(-1);
    }
    // 3. 从多媒体文件中找到音频流
    idx = av_find_best_stream(pFmtCtx, AVMEDIA_TYPE_VIDEO, -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(pFmtCtx, AV_LOG_ERROR, "No memory\n");
        goto _ERROR;
    }
    outFmt = av_guess_format(NULL, dst, NULL);
    oFmtCtx->oformat = outFmt;

    // 5. 为目的文件创建新的音频流
    outStream = avformat_new_stream(oFmtCtx, NULL);
    // 6. 设置输出视频参数
    inStream = pFmtCtx->streams[idx];
    avcodec_parameters_copy(outStream->codecpar, inStream->codecpar);
    // 设置为0,会自动去找对应的编码器
    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\n", av_err2str(ret));
        goto _ERROR;
    }
    
    // 7. 写多媒体文件头到目的文件
    ret = avformat_write_header(oFmtCtx, NULL);
    if (ret < 0) {
        av_log(oFmtCtx, AV_LOG_ERROR, "%s\n", 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_INF | AV_ROUND_PASS_MINMAX));
            pkt.dts = av_rescale_q_rnd(pkt.dts, inStream->time_base, outStream->time_base, (AV_ROUND_INF | AV_ROUND_PASS_MINMAX));
            pkt.duration = av_rescale_q(pkt.duration, inStream->time_base, outStream->time_base);
            pkt.stream_index = 0;
            // 设置成-1,自己会去计算
            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;
    }
    return 0;
}

转封装

c 复制代码
#include <libavformat/avformat.h>
#include <libavutil/log.h>
#include <libavutil/avutil.h>

int main (int argc, char *argv[]) {
    // 1. 处理参数
    char *src;
    char *dst;

    int *stream_map = NULL;
    int stream_idx = 0;

    int ret;
    int idx = -1;
    int i = 0;
    AVFormatContext *pFmtCtx = NULL;
    AVFormatContext *oFmtCtx = NULL;

    const AVOutputFormat *outFmt = NULL;
    
    AVPacket pkt;

    av_log_set_level(AV_LOG_DEBUG);
    if (argc < 3) {
        av_log(NULL, AV_LOG_ERROR, "argument must be more than 3\n");
        exit(-1);
    }

    src = argv[1];
    dst = argv[2];

    // 2. 打开多媒体文件
    ret = avformat_open_input(&pFmtCtx, src, NULL, NULL);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "%s\n", av_err2str(ret));
        exit(-1);
    }
    
    // 3. 打开目的文件的上下文
    avformat_alloc_output_context2(&oFmtCtx, NULL, NULL, dst);
    if (!oFmtCtx) {
        av_log(NULL, AV_LOG_ERROR, "NO MEMORY\n");
        goto _ERROR;
    }

    stream_map = av_calloc(pFmtCtx->nb_streams, sizeof(int));
    if (!stream_map) {
        av_log(NULL, AV_LOG_ERROR, "NO MEMORY\n");
        goto _ERROR;
    }

    for (i = 0; i < pFmtCtx->nb_streams; ++i) {
        AVStream *outStream = NULL;
        AVStream *inStream = pFmtCtx->streams[i];
        AVCodecParameters *inCodecPar = inStream->codecpar;
        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++;

        // 4. 为目的文件创建新的音频流
        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);
        // 设置为0,会自动去找对应的编码器
        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\n", av_err2str(ret));
        goto _ERROR;
    }
    
    // 5. 写多媒体文件头到目的文件
    ret = avformat_write_header(oFmtCtx, NULL);
    if (ret < 0) {
        av_log(oFmtCtx, AV_LOG_ERROR, "%s\n", av_err2str(ret));
        goto _ERROR;
    }
    // 6. 从源多媒体文件中读音频数据到目的文件中
    while (av_read_frame(pFmtCtx, &pkt) >= 0) {
        AVStream *outStream = NULL;
        AVStream *inStream = NULL;
        
        if (stream_map[pkt.stream_index] < 0) {
            av_packet_unref(&pkt);
            continue;
        }
        inStream = pFmtCtx->streams[pkt.stream_index];

        pkt.stream_index = stream_map[pkt.stream_index];

        outStream = oFmtCtx->streams[pkt.stream_index];
        av_packet_rescale_ts(&pkt, inStream->time_base, outStream->time_base);
        // 设置成-1,自己会去计算
        pkt.pos = -1;
        av_interleaved_write_frame(oFmtCtx, &pkt);
        av_packet_unref(&pkt);
        
    }
    // 7. 写多媒体文件尾到目的文件
    av_write_trailer(oFmtCtx);
    // 8. 将申请的资源释放掉
_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);
    }
    return 0;
}

剪辑

c 复制代码
#include <libavformat/avformat.h>
#include <libavutil/log.h>
#include <libavutil/avutil.h>
#include <stdlib.h>

int main (int argc, char *argv[]) {
    // 1. 处理参数
    char *src;
    char *dst;

    int *stream_map = NULL;
    int stream_idx = 0;

    int ret;
    int idx = -1;
    int i = 0;
    double startTime = 0;
    double endTime = 0;
    int64_t *dts_start_time = NULL;
    int64_t *pts_start_time = NULL;

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

    const AVOutputFormat *outFmt = NULL;
    
    AVPacket pkt;

    av_log_set_level(AV_LOG_DEBUG);
    // cut src dst start end
    if (argc < 5) {
        av_log(NULL, AV_LOG_ERROR, "argument must be more than 5\n");
        exit(-1);
    }

    src = argv[1];
    dst = argv[2];
    startTime = atof(argv[3]);
    endTime = atof(argv[4]);

    av_log(NULL, AV_LOG_INFO, "hello\n");

    // 2. 打开多媒体文件
    ret = avformat_open_input(&pFmtCtx, src, NULL, NULL);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "%s\n", av_err2str(ret));
        exit(-1);
    }
    
    // 4. 打开目的文件的上下文
    avformat_alloc_output_context2(&oFmtCtx, NULL, NULL, dst);
    if (!oFmtCtx) {
        av_log(NULL, AV_LOG_ERROR, "NO MEMORY\n");
        goto _ERROR;
    }

    stream_map = av_calloc(pFmtCtx->nb_streams, sizeof(int));
    if (!stream_map) {
        av_log(NULL, AV_LOG_ERROR, "NO MEMORY\n");
        goto _ERROR;
    }

    for (i = 0; i < pFmtCtx->nb_streams; ++i) {
        AVStream *outStream = NULL;
        AVStream *inStream = pFmtCtx->streams[i];
        AVCodecParameters *inCodecPar = inStream->codecpar;
        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);
        // 设置为0,会自动去找对应的编码器
        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\n", av_err2str(ret));
        goto _ERROR;
    }
    
    // 7. 写多媒体文件头到目的文件
    ret = avformat_write_header(oFmtCtx, NULL);
    if (ret < 0) {
        av_log(oFmtCtx, AV_LOG_ERROR, "%s\n", av_err2str(ret));
        goto _ERROR;
    }

    // seek
    ret = av_seek_frame(pFmtCtx, -1, startTime * AV_TIME_BASE, AVSEEK_FLAG_BACKWARD);
    if (ret < 0) {
        av_log(oFmtCtx, AV_LOG_ERROR, "%s\n", av_err2str(ret));
        goto _ERROR;
    }

    dts_start_time = av_calloc(pFmtCtx->nb_streams, sizeof(int64_t));
    pts_start_time = av_calloc(pFmtCtx->nb_streams, sizeof(int64_t));
    for (int t = 0; t < pFmtCtx->nb_streams; ++t) {
        dts_start_time[t] = -1;
        pts_start_time[t] = -1;
    }

    // 8. 从源多媒体文件中读音频数据到目的文件中
    while (av_read_frame(pFmtCtx, &pkt) >= 0) {
        AVStream *outStream = NULL;
        AVStream *inStream = NULL;
        
        if (dts_start_time[pkt.stream_index] == -1 && pkt.dts > 0) {
            dts_start_time[pkt.stream_index] = pkt.dts;
        }

        if (pts_start_time[pkt.stream_index] == -1 && pkt.pts > 0) {
            pts_start_time[pkt.stream_index] = pkt.pts;
        }

        if (stream_map[pkt.stream_index] < 0) {
            av_packet_unref(&pkt);
            continue;
        }

        pkt.pts = pkt.pts - pts_start_time[pkt.stream_index];
        pkt.dts = pkt.dts - dts_start_time[pkt.stream_index];

        if (pkt.dts > pkt.pts) {
            pkt.pts = pkt.dts;
        }

        inStream = pFmtCtx->streams[pkt.stream_index];
        if (av_q2d(inStream->time_base) * pkt.pts > endTime) {
            av_log(oFmtCtx, AV_LOG_INFO, "success\n");
            break;
        }
        pkt.stream_index = stream_map[pkt.stream_index];

        outStream = oFmtCtx->streams[pkt.stream_index];
        av_packet_rescale_ts(&pkt, inStream->time_base, outStream->time_base);

        // 设置成-1,自己会去计算
        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);
    }

    if (pts_start_time) {
        av_free(pts_start_time);
    }

    if (dts_start_time) {
        av_free(dts_start_time);
    }

    return 0;
}
相关推荐
小屁孩大帅-杨一凡2 小时前
Python-flet实现个人视频播放器
开发语言·python·音视频
EasyCVR5 小时前
私有化部署视频平台EasyCVR宇视设备视频平台如何构建视频联网平台及升级视频转码业务?
大数据·网络·音视频·h.265
天空中的野鸟5 小时前
Android音频采集
android·音视频
计算机毕设孵化场6 小时前
计算机毕设-基于springboot的高校网上缴费综合务系统视频的设计与实现(附源码+lw+ppt+开题报告)
java·spring boot·计算机外设·音视频·课程设计·高校网上缴费综合务系统视频·计算机毕设ppt
简鹿办公13 小时前
如何提取某站 MV 视频中的音乐为 MP3 音频
音视频·简鹿视频格式转换器·视频提取mp3音频
yufengxinpian13 小时前
集成了高性能ARM Cortex-M0+处理器的一款SimpleLink 2.4 GHz无线模块-RF-BM-2340B1
单片机·嵌入式硬件·音视频·智能硬件
runing_an_min15 小时前
ffmpeg视频滤镜:替换部分帧-freezeframes
ffmpeg·音视频·freezeframes
runing_an_min17 小时前
ffmpeg视频滤镜:提取缩略图-framestep
ffmpeg·音视频·framestep
小曲曲18 小时前
接口上传视频和oss直传视频到阿里云组件
javascript·阿里云·音视频
安静读书20 小时前
Python解析视频FPS(帧率)、分辨率信息
python·opencv·音视频