赞
踩
使用FFmpeg库前需要包含相应的头文件,并在C++中声明外部C函数的命名空间。
#ifdef __cplusplus
extern "C" {
#endif
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libavutil/log.h>
#ifdef __cplusplus
}
#endif
程序入口点,处理命令行参数。
int main(int argc, char *argv[]) {
// 参数检查
if (argc < 3) {
av_log(nullptr, AV_LOG_INFO, "参数必须多于3个\n");
exit(-1);
}
// 输入输出文件路径
char *src = argv[1];
char *dst = argv[2];
// ...
}
使用avformat_open_input
打开输入文件。
ret = avformat_open_input(&pFmtCtx, src, nullptr, nullptr);
if (ret < 0) {
av_log(nullptr, AV_LOG_ERROR, "打开输入文件失败\n");
exit(-1);
}
调用avformat_find_stream_info
获取多媒体文件的流信息。
if ((ret = avformat_find_stream_info(pFmtCtx, nullptr)) < 0) {
av_log(nullptr, AV_LOG_INFO, "获取文件信息失败\n");
exit(-1);
}
遍历所有流,找到音频流的索引。
for (int i = 0; i < pFmtCtx->nb_streams; ++i) {
if (pFmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
idx = i;
break;
}
}
使用avformat_alloc_context
分配输出文件的格式上下文。
oFmtCtx = avformat_alloc_context();
if (!oFmtCtx) {
av_log(nullptr, AV_LOG_ERROR, "分配输出文件上下文失败\n");
goto _ERROR;
}
使用av_guess_format
猜测输出文件的格式。
outFmt = av_guess_format(nullptr, dst, nullptr);
oFmtCtx->oformat = outFmt;
为输出文件创建一个新的音频流,并复制输入音频流的参数。
outStream = avformat_new_stream(oFmtCtx, nullptr);
avcodec_parameters_copy(outStream->codecpar, inStream->codecpar);
outStream->codecpar->codec_tag = 0;
使用avio_open2
打开输出文件准备写入。
ret = avio_open2(&oFmtCtx->pb, dst, AVIO_FLAG_WRITE, nullptr, nullptr);
if (ret < 0) {
av_log(nullptr, AV_LOG_ERROR, "打开输出文件失败\n");
goto _ERROR;
}
调用avformat_write_header
写入文件头信息。
ret = avformat_write_header(oFmtCtx, nullptr);
if (ret < 0) {
av_log(nullptr, AV_LOG_ERROR, "写入文件头失败\n");
goto _ERROR;
}
读取输入文件的音频数据,转换时间戳,并写入输出文件。
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);
pkt.dts = pkt.pts;
// 写入输出文件
av_interleaved_write_frame(oFmtCtx, &pkt);
}
av_packet_unref(&pkt);
}
写入文件尾部信息,关闭文件,并释放所有分配的资源。
av_write_trailer(oFmtCtx);
avio_close(oFmtCtx->pb);
avformat_free_context(oFmtCtx);
_ERROR:
// 清理资源
if (pFmtCtx) {
avformat_free_context(pFmtCtx);
# avformat_close_input(&pFmtCtx);
}
if (oFmtCtx) {
avformat_free_context(oFmtCtx);
# avformat_close_input(&oFmtCtx); // 注意:应使用 avformat_free_context 代替
}
}
请注意,错误处理部分应使用avformat_free_context
代替avformat_close_input
来正确释放oFmtCtx
资源。另外,程序中存在一些潜在的内存泄漏和错误处理问题,应进一步优化。
程序需要传入至少两个参数:输入文件路径和输出文件路径。例如:
./my_ffmpeg_tool input.mp3 output.aac
- 确保FFmpeg开发库已正确安装且可链接。
- 检查程序输出的错误信息以进行调试。
- 程序可能需要适当的读取和写入权限。
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) # 链接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 *pFmtCtx {nullptr}; AVFormatContext *oFmtCtx {nullptr}; AVOutputFormat *outFmt {nullptr}; AVStream *inStream {nullptr}; AVStream *outStream {nullptr}; AVPacket pkt {nullptr}; // 设置日志级别 av_log_set_level(AV_LOG_DEBUG); if(argc<3){ av_log(nullptr,AV_LOG_INFO,"arguments must be more than 3\n"); exit(-1); } src = argv[1]; dst = argv[2]; //2.打开输入多媒体文件 ret = avformat_open_input(&pFmtCtx,src,nullptr,nullptr); if (ret<0){ av_log(nullptr,AV_LOG_ERROR,"avformat_open_input failed\n"); exit(-1); } //3.获取多媒体文件信息 if ((ret= avformat_find_stream_info(pFmtCtx,nullptr))<0){ av_log(nullptr,AV_LOG_INFO,"avformat_find_stream_info failed\n"); exit(-1); } //4.遍历所有流,找到音频流 for (int i = 0; i < pFmtCtx->nb_streams; ++i) { if (pFmtCtx->streams[i]->codecpar->codec_type==AVMEDIA_TYPE_AUDIO){ idx = i; av_log(nullptr,AV_LOG_INFO,"find_stream_info Successed!\n"); break; } } if (idx<0){ av_log(nullptr,AV_LOG_ERROR,"can not find audio stream\n"); exit(-1); } // 打开目的文件上下文 oFmtCtx = avformat_alloc_context(); if(!oFmtCtx){ av_log(nullptr,AV_LOG_ERROR,"avformat_alloc_context failed\n"); goto _ERROR; } outFmt = av_guess_format(nullptr,dst,nullptr); oFmtCtx->oformat = outFmt; // 为目的文件,创建一个新的音频流 outStream = avformat_new_stream(oFmtCtx,nullptr); // 设置输出音频参数 inStream = pFmtCtx->streams[idx]; avcodec_parameters_copy(outStream->codecpar,inStream->codecpar); outStream->codecpar->codec_tag = 0; // 绑定 ret = avio_open2(&oFmtCtx->pb,dst,AVIO_FLAG_WRITE,nullptr,nullptr); if(ret<0){ av_log(nullptr,AV_LOG_ERROR,"avio_open2 failed\n"); goto _ERROR; } // 写多媒体文件到目的文件 ret = avformat_write_header(oFmtCtx,nullptr); if(ret<0){ av_log(nullptr,AV_LOG_ERROR, "error:%s",av_err2str(ret)); goto _ERROR; } // 读取输入文件中的音频数据 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,(AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX)); pkt.dts = pkt.pts; pkt.duration = av_rescale_q(pkt.duration,inStream->time_base,outStream->time_base); pkt.stream_index = 0; pkt.pos = -1; av_interleaved_write_frame(oFmtCtx,&pkt); } av_packet_unref(&pkt); } // 写入文件尾 av_write_trailer(oFmtCtx); // 释放资源 avio_close(oFmtCtx->pb); avformat_free_context(oFmtCtx); _ERROR: if(pFmtCtx){ // avformat_close_input(&pFmtCtx); avformat_free_context(pFmtCtx); pFmtCtx = nullptr; } if(oFmtCtx){ // avformat_close_input(&oFmtCtx); avformat_free_context(oFmtCtx); oFmtCtx = nullptr; } };
./FFmpeg_exercise demo.mp4 test.aac
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。