赞
踩
在C++程序中使用FFmpeg之前,需要包含相应的头文件,并根据是否使用C++编译器,可能需要添加extern "C"
块。
```cpp
#ifdef __cplusplus
extern "C" {
#endif
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libavutil/log.h>
#ifdef __cplusplus
}
#endif
程序入口点是main
函数,它处理命令行参数并设置日志级别。
int main(int argc, char *argv[]) {
// 参数检查
if (argc < 3) {
av_log(nullptr, AV_LOG_ERROR, "Usage: %s <input file> <output file>\n", argv[0]);
exit(-1);
}
// 输入输出文件路径
char *src = argv[1];
char *dst = argv[2];
// 设置日志级别
av_log_set_level(AV_LOG_DEBUG);
}
使用avformat_open_input
打开输入文件,并检查返回值。
int ret = avformat_open_input(&pFormatCtx, src, nullptr, nullptr);
if (ret < 0) {
av_log(nullptr, AV_LOG_ERROR, "Could not open input file: %s\n", src);
exit(-1);
}
调用av_find_best_stream
找到最佳的视频流。
ret = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0);
if (ret < 0) {
av_log(nullptr, AV_LOG_ERROR, "Failed to retrieve input stream information\n");
goto _ERROR;
}
使用avformat_alloc_context
分配输出文件的格式上下文。
oFormatCtx = avformat_alloc_context();
if (oFormatCtx == nullptr) {
av_log(nullptr, AV_LOG_ERROR, "Failed to allocate output context\n");
goto _ERROR;
}
使用av_guess_format
猜测输出文件的格式。
outFmt = av_guess_format(nullptr, dst, nullptr);
if (outFmt == nullptr) {
av_log(nullptr, AV_LOG_ERROR, "Failed to guess output format\n");
goto _ERROR;
}
oFormatCtx->oformat = outFmt;
为输出文件创建视频流,并复制输入视频流的参数。
outStream = avformat_new_stream(oFormatCtx, nullptr);
avcodec_parameters_copy(outStream->codecpar, pFormatCtx->streams[ret]->codecpar);
outStream->codecpar->codec_tag = 0;
使用avio_open2
打开输出文件,并使用avformat_write_header
写入文件头信息。
ret = avio_open2(&oFormatCtx->pb, dst, AVIO_FLAG_WRITE, nullptr, nullptr);
if (ret < 0) {
av_log(nullptr, AV_LOG_ERROR, "Failed to open output file: %s\n", dst);
goto _ERROR;
}
ret = avformat_write_header(oFormatCtx, nullptr);
if (ret < 0) {
av_log(nullptr, AV_LOG_ERROR, "Failed to write output file header\n");
goto _ERROR;
}
读取输入文件的视频帧,转换时间戳,并使用av_interleaved_write_frame
写入输出文件。
while (av_read_frame(pFormatCtx, &pkt) >= 0) {
if (pkt.stream_index == ret) {
// 转换时间戳等
pkt.pts = av_rescale_q_rnd(pkt.pts, inSteam->time_base, outStream->time_base, AV_ROUND_NEAR_INF);
pkt.dts = av_rescale_q_rnd(pkt.dts, inSteam->time_base, outStream->time_base, AV_ROUND_NEAR_INF);
pkt.duration = av_rescale_q(pkt.duration, inSteam->time_base, outStream->time_base);
// 写入帧数据
av_interleaved_write_frame(oFormatCtx, &pkt);
}
av_packet_unref(&pkt);
}
使用av_write_trailer
写入文件尾信息,并释放所有资源。
av_write_trailer(oFormatCtx); _ERROR: // 清理资源 if (oFormatCtx && oFormatCtx->pb) { avio_close(oFormatCtx->pb); oFormatCtx->pb = nullptr; } if (oFormatCtx) { avformat_free_context(oFormatCtx); oFormatCtx = nullptr; } if (pFormatCtx) { avformat_free_context(pFormatCtx); pFormatCtx = nullptr; }
程序需要传入两个参数:输入文件路径和输出文件路径。例如:
./my_ffmpeg_tool input.mp4 output.mkv
确保替换为您的实际文件名和所需的输出格式。
cmake_minimum_required(VERSION 3.27) project(FFmpeg_exercise) set(CMAKE_CXX_STANDARD 14) # 定义FFmpeg的安装路径变量 set(FFMPEG_INSTALL_DIR "/usr/local/ffmpeg") # 将FFmpeg的头文件目录添加到包含路径 include_directories(${FFMPEG_INSTALL_DIR}/include) # 定义FFmpeg库的基础名称(根据你的需要调整) set(FFMPEG_LIBS "avcodec;avformat;avutil") # 用分号分隔库名 # 寻找并链接FFmpeg库 foreach(FFMPEG_LIB ${FFMPEG_LIBS}) find_library(${FFMPEG_LIB}_LIBRARY NAMES ${FFMPEG_LIB} PATHS ${FFMPEG_INSTALL_DIR}/lib NO_DEFAULT_PATH) list(APPEND FFMPEG_LIBRARIES ${${FFMPEG_LIB}_LIBRARY}) endforeach() add_executable(FFmpeg_exercise # main.cpp # extra_audic.cpp extra_video.cpp ) # 链接FFmpeg库 target_link_libraries(FFmpeg_exercise ${FFMPEG_LIBRARIES})
// // Created by 陈伟峰 on 2024/6/22. // #ifdef __cplusplus extern "C" { #endif // 包含FFmpeg的头文件 #include <libavformat/avformat.h> #include <libavutil/avutil.h> #include <libavutil/log.h> #ifdef __cplusplus } #endif #include <iostream> int main(int argc,char *argv[]){ int ret {-1}; int idx {-1}; //1.处理一些参数 char *src {nullptr}; char *dst {nullptr}; AVFormatContext *pFormatCtx {nullptr}; AVFormatContext *oFormatCtx {nullptr}; AVOutputFormat *outFmt {nullptr}; AVStream *outStream {nullptr}; AVStream *inSteam {nullptr}; AVPacket pkt {nullptr}; // 日志信息 av_log_set_level(AV_LOG_DEBUG); if(argc<3){ av_log(nullptr,AV_LOG_ERROR,"Usage:%s <input file> <output file>\n",argv[0]); exit(-1); } src = argv[1]; dst = argv[2]; // 2.打开多媒体输入文件 ret = avformat_open_input(&pFormatCtx,src,nullptr,nullptr); if(ret<0){ av_log(nullptr,AV_LOG_ERROR,"Could not open input file:%s\n",src); exit(-1); } // 3.获取多媒体文件信息 ret = av_find_best_stream(pFormatCtx,AVMEDIA_TYPE_VIDEO,-1,-1,nullptr,0); if(ret<0){ av_log(nullptr,AV_LOG_ERROR,"Failed to retrieve input stream information\n"); goto _ERROR; } // 打开目的多媒体文件 oFormatCtx = avformat_alloc_context(); if(oFormatCtx==nullptr){ av_log(nullptr,AV_LOG_ERROR,"Failed to allocate output context\n"); goto _ERROR; } outFmt = av_guess_format(nullptr,dst,nullptr); if(outFmt==nullptr){ av_log(nullptr,AV_LOG_ERROR,"Failed to guess output format\n"); goto _ERROR; } oFormatCtx->oformat = outFmt; // 为目的文件,创建一个新的视频流 outStream = avformat_new_stream(oFormatCtx,nullptr); // 设置视频参数 inSteam = pFormatCtx->streams[idx]; avcodec_parameters_copy(outStream->codecpar,pFormatCtx->streams[ret]->codecpar); outStream->codecpar->codec_tag = 0; // 绑定 ret = avio_open2(&oFormatCtx->pb,dst,AVIO_FLAG_WRITE, nullptr, nullptr); if(ret<0){ av_log(nullptr,AV_LOG_ERROR,"Failed to open output file:%s\n",dst); goto _ERROR; } // 写入头信息 ret = avformat_write_header(oFormatCtx,nullptr); if(ret<0){ av_log(nullptr,AV_LOG_ERROR,"Failed to write output file header\n"); goto _ERROR; } // 写多媒体文件到目的文件 ret = avformat_write_header(oFormatCtx,nullptr); if(ret<0){ av_log(nullptr,AV_LOG_ERROR,"Failed to write output file header:%s\n", av_err2str(ret)); goto _ERROR; } while(av_read_frame(pFormatCtx,&pkt)>=0) { if (pkt.stream_index == idx) { pkt.pts = av_rescale_q_rnd(pkt.pts, inSteam->time_base, outStream->time_base, (AVRounding) (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); pkt.dts = av_rescale_q_rnd(pkt.dts, inSteam->time_base, outStream->time_base, (AVRounding) (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); pkt.duration = av_rescale_q(pkt.duration, inSteam->time_base, outStream->time_base); pkt.stream_index = 0; pkt.pos = -1; av_interleaved_write_frame(oFormatCtx, &pkt); } av_packet_unref(&pkt); } // 写入尾信息 av_write_trailer(oFormatCtx); _ERROR: if(oFormatCtx->pb){ avio_close(oFormatCtx->pb); oFormatCtx->pb = nullptr; } if(oFormatCtx){ avformat_free_context(oFormatCtx); oFormatCtx = nullptr; } if(pFormatCtx){ avformat_free_context(pFormatCtx); pFormatCtx = nullptr; } return 0; }
./main demo.mp4 demo2.h264
ffplay demo2.h264
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。