[技术探索者手记] C++自学之路 × linux下FFmpeg获取视频文件的基本信息
我是一名.NET开发者,最近开始学习C++。目前,我已经掌握了C++的基础语法和入门知识,并对FFmpeg产生了浓厚的兴趣。接下来,我计划自学与FFmpeg相关的技术内容,并记录自己的学习过程。欢迎大家提出宝贵意见,我会虚心接受并采纳大家的建议。谢谢!我是一名.NET开发者,最近开始学习C++。目前,我已经掌握了C++的基础语法和入门知识,并对FFmpeg产生了浓厚的兴趣。接下来,我计划自学与FFmpeg相关的技术内容,并记录自己的学习过程。欢迎大家提出宝贵意见,我会虚心接受并采纳大家的建议。谢谢!
基本操作流程
graph TB
Start[打开文件(avformat_open_input)] --> Parallel
subgraph Parallel [AVFormatContext]
direction TB
A[音频处理] --> A1[获取音频流的索引(av_find_best_stream)]
A1 --> A2[获取音频流(ctx->streams<audio_index>)] --> A3[获取编解码器ID(AVCodecID)]
A3 --> A5[获取编解码信息(avcodec_find_decoder)] --> A6[日志查看音频信息]
A6 --> A7[ ] --> A8[ ] --> A9[ ] --> A10[ ] --> A11[ ] --> A12[ ]
B[视频处理] --> B1[获取视频基本信息(avformat_find_stream_info)]
B1 --> B2[读取视频时长、比特率信息]
B2 --> B3[获取视频流索引(av_find_best_stream)] --> B4[根据索引获取视频流] --> B5[根据视频流获取编解码参数(video_stream->codecpar)]
B5 --> B6[查找视频解码器(avcodec_find_decoder)] --> B7[分配解码器实力(avcodec_alloc_context3)] --> B8[把视频流中的编解码参数复制给解码器的实例(avcodec_parameters_to_context)] --> B9[打开解码器实例(avcodec_open2)] --> B10[日志输出(视频宽,高)]
B10 -->B11[释放解码器资源(avcodec_free_context)]
end
Parallel --> Merge[关闭文件(avformat_close_input)]
Merge --> End[结束]
示例代码
void getVInfo(AVFormatContext *ctx)
{
//1. find stream info
int ret = avformat_find_stream_info(ctx,NULL);
if(ret<0){
av_log(NULL,AV_LOG_ERROR,"find stream info error!");
return;
}
av_log(NULL, AV_LOG_DEBUG,"video duration: %ld s \n",ctx->duration / (1000*1000)); //视频持续时间,微妙
av_log(NULL, AV_LOG_DEBUG,"video bit rate: %ld \n",ctx->bit_rate); // 视频比特率
av_log(NULL, AV_LOG_DEBUG,"video stream count: %d \n",ctx->nb_streams); //数据流的数量
av_log(NULL, AV_LOG_DEBUG,"video max stream count: %d \n",ctx->max_streams);//数据流的最大数量
av_log(NULL,AV_LOG_DEBUG,"video start time span: %" PRId64 " \n",ctx->start_time);
av_log(NULL,AV_LOG_DEBUG,"video start realtime span: %ld \n",ctx->start_time_realtime);
// 2. find video stream
int video_index = av_find_best_stream(ctx,AVMEDIA_TYPE_VIDEO,-1,-1,NULL,0);
if(video_index < 0){
av_log(NULL,AV_LOG_ERROR,"not found video index");
return;
}
//3. get codec info
AVStream *video_stream = ctx->streams[video_index];
AVCodecParameters *video_param = video_stream->codecpar;
av_log(NULL, AV_LOG_DEBUG, "codec info : %d \n", video_param->codec_id);
const AVCodec *video_codec = NULL;
video_codec = avcodec_find_decoder(video_param->codec_id);
if(video_codec == NULL )
{
av_log(NULL,AV_LOG_ERROR,"can not get video codec");
return;
}
av_log(NULL, AV_LOG_DEBUG, "codec name info : %s \n", video_codec->name);
av_log(NULL, AV_LOG_DEBUG, "codec long name info : %s \n", video_codec->long_name);
av_log(NULL, AV_LOG_DEBUG, "codec type : %d \n", video_codec->type);
int fps = video_stream->r_frame_rate.num / video_stream->r_frame_rate.den;
av_log(NULL,AV_LOG_DEBUG,"video fps : %d \n", fps);
//4. get codec param info
/*
打开编解码器实现的流程:avcodec_alloc_context3 → avcodec_parameters_to_context → avcodec_open2
关闭编解码器实现的流程:avcodec_close→avcodec_free_context
*/
AVCodecContext *video_decode_ctx = NULL;
video_decode_ctx = avcodec_alloc_context3(video_codec);
if(!video_decode_ctx){
av_log(NULL,AV_LOG_ERROR,"video codec ctx is NULL");
return;
}
avcodec_parameters_to_context(video_decode_ctx,video_stream->codecpar);
av_log(NULL, AV_LOG_DEBUG,"success copy param to context");
ret = avcodec_open2(video_decode_ctx,video_codec,NULL);
if(ret <0){
av_log(NULL,AV_LOG_ERROR,"can not open video_decode_ctx");
return;
}
av_log(NULL,AV_LOG_INFO, "video info :%d * %d, pix fmt %d \n", video_decode_ctx->width, video_decode_ctx->height, video_decode_ctx->pix_fmt);
av_log(NULL, AV_LOG_INFO, "video_decode_ctx profile=%d\n", video_decode_ctx->profile);
//avcodec_close(audio_decode_ctx); // 关闭解码器的实例
avcodec_free_context(&video_decode_ctx);
}
void getAInfo(AVFormatContext *ctx)
{
int audio_index = av_find_best_stream(ctx, AVMEDIA_TYPE_AUDIO, -1,-1,NULL,0);
if(audio_index < 0)
{
av_log(NULL, AV_LOG_ERROR ,"can not found audio stream!");
return;
}
av_log(NULL, AV_LOG_DEBUG,"audio duration %" PRId64 " s \n", ctx->duration /(1000*1000));
av_log(NULL, AV_LOG_DEBUG,"audio start time %" PRId64 " s \n", ctx->start_time);
AVStream *audio_stream = ctx->streams[audio_index];
AVCodecID id = audio_stream->codecpar->codec_id;
const AVCodec *audio_codec = avcodec_find_decoder(id);
av_log(NULL, AV_LOG_DEBUG, "audio codec name info : %s \n", audio_codec->name);
av_log(NULL, AV_LOG_DEBUG, "audio codec long name info : %s \n", audio_codec->long_name);
av_log(NULL, AV_LOG_DEBUG, "audio codec type : %d \n", audio_codec->type);
}
/// @brief get the info of "file"
/// @param file
void getVidoeInfo(std::string file)
{
av_log_set_level(AV_LOG_DEBUG);
//1. open file
AVFormatContext *ctx =NULL;
int ret = avformat_open_input(&ctx,file.c_str(),NULL,NULL);
if(ret< 0){
av_log(NULL,AV_LOG_ERROR,"open file failed!");
return;
}
getVInfo(ctx);
getAInfo(ctx);
avformat_close_input(&ctx);
}
浙公网安备 33010602011771号