FFmpeg被声明为已否决的解决方案
参考雷神的最简单的打印Hello World的程序:
#include <stdio.h> #include <string.h> extern "C" { #include "libavformat/avformat.h" #include "libavutil/dict.h" }; #pragma comment(lib, "avformat.lib") #pragma comment(lib, "avutil.lib") #pragma comment(lib, "avcodec.lib") int main() { AVFormatContext *pFormatCtx = NULL; AVCodecContext *pCodecCtx = NULL; AVCodec *pCodec; AVDictionaryEntry *dict = NULL; int iHour, iMinute, iSecond, iTotalSeconds;//HH:MM:SS int videoIndex, audioIndex; char *fileName = "bad.mp4"; //char *fileName = "Titanic.ts"; av_register_all();//注册所有组件 if (avformat_open_input(&pFormatCtx, fileName, NULL, NULL) != 0)//打开输入视频文件 { printf("Couldn't open input stream.\n"); return -1; } if (avformat_find_stream_info(pFormatCtx, NULL) < 0) { printf("Couldn't find stream information.\n"); return -1; } videoIndex = -1; for (int i = 0; i < pFormatCtx->nb_streams/*视音频流的个数*/; i++) { if (pFormatCtx->streams[i]/*视音频流*/->codec->codec_type == AVMEDIA_TYPE_VIDEO)//查找音频 { videoIndex = i; break; } } if (videoIndex == -1) { printf("Couldn't find a video stream.\n"); return -1; } pCodecCtx = pFormatCtx->streams[videoIndex]->codec; //指向AVCodecContext的指针 pCodec = avcodec_find_decoder(pCodecCtx->codec_id); //指向AVCodec的指针.查找解码器 if (pCodec == NULL) { printf("Codec not found.\n"); return -1; } //打开解码器 if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) { printf("Could not open codec.\n"); return -1; } audioIndex = -1; for (int i = 0; i < pFormatCtx->nb_streams; i++) { if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) { audioIndex = i; break; } } if (audioIndex == -1) { printf("Couldn't find a audio stream.\n"); return -1; } //打印结构体信息 puts("AVFormatContext信息:"); puts("---------------------------------------------"); printf("文件名:%s\n", pFormatCtx->filename); iTotalSeconds = (int)pFormatCtx->duration/*微秒*/ / 1000000; iHour = iTotalSeconds / 3600;//小时 iMinute = iTotalSeconds % 3600 / 60;//分钟 iSecond = iTotalSeconds % 60;//秒 printf("持续时间:%02d:%02d:%02d\n", iHour, iMinute, iSecond); printf("平均混合码率:%d kb/s\n", pFormatCtx->bit_rate / 1000); printf("视音频个数:%d\n", pFormatCtx->nb_streams); puts("---------------------------------------------"); puts("AVInputFormat信息:"); puts("---------------------------------------------"); printf("封装格式名称:%s\n", pFormatCtx->iformat->name); printf("封装格式长名称:%s\n", pFormatCtx->iformat->long_name); printf("封装格式扩展名:%s\n", pFormatCtx->iformat->extensions); printf("封装格式ID:%d\n", pFormatCtx->iformat->raw_codec_id); puts("---------------------------------------------"); puts("AVStream信息:"); puts("---------------------------------------------"); printf("视频流标识符:%d\n", pFormatCtx->streams[videoIndex]->index); printf("音频流标识符:%d\n", pFormatCtx->streams[audioIndex]->index); printf("视频流长度:%d微秒\n", pFormatCtx->streams[videoIndex]->duration); printf("音频流长度:%d微秒\n", pFormatCtx->streams[audioIndex]->duration); puts("---------------------------------------------"); puts("AVCodecContext信息:"); puts("---------------------------------------------"); printf("视频码率:%d kb/s\n", pCodecCtx->bit_rate / 1000); printf("视频大小:%d * %d\n", pCodecCtx->width, pCodecCtx->height); puts("---------------------------------------------"); puts("AVCodec信息:"); puts("---------------------------------------------"); printf("视频编码格式:%s\n", pCodec->name); printf("视频编码详细格式:%s\n", pCodec->long_name); puts("---------------------------------------------"); printf("视频时长:%d微秒\n", pFormatCtx->streams[videoIndex]->duration); printf("音频时长:%d微秒\n", pFormatCtx->streams[audioIndex]->duration); printf("音频采样率:%d\n", pFormatCtx->streams[audioIndex]->codec->sample_rate); printf("音频信道数目:%d\n", pFormatCtx->streams[audioIndex]->codec->channels); puts("AVFormatContext元数据:"); puts("---------------------------------------------"); while (dict = av_dict_get(pFormatCtx->metadata, "", dict, AV_DICT_IGNORE_SUFFIX)) { printf("[%s] = %s\n", dict->key, dict->value); } puts("---------------------------------------------"); puts("AVStream视频元数据:"); puts("---------------------------------------------"); dict = NULL; while (dict = av_dict_get(pFormatCtx->streams[videoIndex]->metadata, "", dict, AV_DICT_IGNORE_SUFFIX)) { printf("[%s] = %s\n", dict->key, dict->value); } puts("---------------------------------------------"); puts("AVStream音频元数据:"); puts("---------------------------------------------"); dict = NULL; while (dict = av_dict_get(pFormatCtx->streams[audioIndex]->metadata, "", dict, AV_DICT_IGNORE_SUFFIX)) { printf("[%s] = %s\n", dict->key, dict->value); } puts("---------------------------------------------"); av_dump_format(pFormatCtx, -1, fileName, 0); printf("\n\n编译信息:\n%s\n\n", avcodec_configuration()); avcodec_close(pCodecCtx); avformat_close_input(&pFormatCtx); return 0; }
虽然足够的简单,但是还是报了”被声明为已否决”的error
在网上搜索到了解决方案:将VS的SDL检查关闭
这样error被降低为warning C4996
这样的解决方案是很冒险的。根据报错g:\coding\poet\ffmpegstudy\study.cpp(44): warning C4996: 'AVStream::codec': 被声明为已否决
我们定位到所在代码:
if (pFormatCtx->streams[i]/*视音频流*/->codec->codec_type == AVMEDIA_TYPE_VIDEO)//查找音频 { videoIndex = i; break; }
#if FF_API_LAVF_AVCTX /** * @deprecated use the codecpar struct instead */ attribute_deprecated AVCodecContext *codec; #endifAVStream的codec成员不再推荐使用,反而要求使用codecpar。
从而我们知道FFmpeg中所谓的“被声明为已否决”就是因为函数或者结构体属性被标示为attribute_deprecated,很有可能在未来的版本中就删除了。
所以我们最好的解决方案就是使用新的被推荐使用的函数、结构体等。
修改版(开启SDL检查也没有error与warning):
#include <stdio.h> #include <string.h> extern "C" { #include "libavformat/avformat.h" #include "libavutil/dict.h" }; #pragma comment(lib, "avformat.lib") #pragma comment(lib, "avutil.lib") #pragma comment(lib, "avcodec.lib") int main() { AVFormatContext *pFormatCtx = NULL; AVCodecContext *pCodecCtx = NULL; AVCodec *pCodec; AVDictionaryEntry *dict = NULL; int iHour, iMinute, iSecond, iTotalSeconds;//HH:MM:SS int videoIndex, audioIndex; char *fileName = "bad.mp4"; //char *fileName = "Titanic.ts"; av_register_all();//注册所有组件 if (avformat_open_input(&pFormatCtx, fileName, NULL, NULL) != 0)//打开输入视频文件 { printf("Couldn't open input stream.\n"); return -1; } if (avformat_find_stream_info(pFormatCtx, NULL) < 0) { printf("Couldn't find stream information.\n"); return -1; } videoIndex = -1; for (int i = 0; i < pFormatCtx->nb_streams/*视音频流的个数*/; i++) { if (pFormatCtx->streams[i]/*视音频流*/->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)//查找音频 { videoIndex = i; break; } } if (videoIndex == -1) { printf("Couldn't find a video stream.\n"); return -1; } /** * 不赞成这样使用 * pCodecCtx = pFormatCtx->streams[videoIndex]->codec; //指向AVCodecContext的指针 */ pCodecCtx = avcodec_alloc_context3(NULL); if (pCodecCtx == NULL) { printf("Could not allocate AVCodecContext\n"); return -1; } avcodec_parameters_to_context(pCodecCtx, pFormatCtx->streams[videoIndex]->codecpar); pCodec = avcodec_find_decoder(pCodecCtx->codec_id); //指向AVCodec的指针.查找解码器 if (pCodec == NULL) { printf("Codec not found.\n"); return -1; } //打开解码器 if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) { printf("Could not open codec.\n"); return -1; } audioIndex = -1; for (int i = 0; i < pFormatCtx->nb_streams; i++) { if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { audioIndex = i; break; } } if (audioIndex == -1) { printf("Couldn't find a audio stream.\n"); return -1; } //打印结构体信息 puts("AVFormatContext信息:"); puts("---------------------------------------------"); printf("文件名:%s\n", pFormatCtx->filename); iTotalSeconds = (int)pFormatCtx->duration/*微秒*/ / 1000000; iHour = iTotalSeconds / 3600;//小时 iMinute = iTotalSeconds % 3600 / 60;//分钟 iSecond = iTotalSeconds % 60;//秒 printf("持续时间:%02d:%02d:%02d\n", iHour, iMinute, iSecond); printf("平均混合码率:%d kb/s\n", pFormatCtx->bit_rate / 1000); printf("视音频个数:%d\n", pFormatCtx->nb_streams); puts("---------------------------------------------"); puts("AVInputFormat信息:"); puts("---------------------------------------------"); printf("封装格式名称:%s\n", pFormatCtx->iformat->name); printf("封装格式长名称:%s\n", pFormatCtx->iformat->long_name); printf("封装格式扩展名:%s\n", pFormatCtx->iformat->extensions); printf("封装格式ID:%d\n", pFormatCtx->iformat->raw_codec_id); puts("---------------------------------------------"); puts("AVStream信息:"); puts("---------------------------------------------"); printf("视频流标识符:%d\n", pFormatCtx->streams[videoIndex]->index); printf("音频流标识符:%d\n", pFormatCtx->streams[audioIndex]->index); printf("视频流长度:%d微秒\n", pFormatCtx->streams[videoIndex]->duration); printf("音频流长度:%d微秒\n", pFormatCtx->streams[audioIndex]->duration); puts("---------------------------------------------"); puts("AVCodecContext信息:"); puts("---------------------------------------------"); printf("视频码率:%d kb/s\n", pCodecCtx->bit_rate / 1000); printf("视频大小:%d * %d\n", pCodecCtx->width, pCodecCtx->height); puts("---------------------------------------------"); puts("AVCodec信息:"); puts("---------------------------------------------"); printf("视频编码格式:%s\n", pCodec->name); printf("视频编码详细格式:%s\n", pCodec->long_name); puts("---------------------------------------------"); printf("视频时长:%d微秒\n", pFormatCtx->streams[videoIndex]->duration); printf("音频时长:%d微秒\n", pFormatCtx->streams[audioIndex]->duration); printf("音频采样率:%d\n", pFormatCtx->streams[audioIndex]->codecpar->sample_rate); printf("音频信道数目:%d\n", pFormatCtx->streams[audioIndex]->codecpar->channels); puts("AVFormatContext元数据:"); puts("---------------------------------------------"); while (dict = av_dict_get(pFormatCtx->metadata, "", dict, AV_DICT_IGNORE_SUFFIX)) { printf("[%s] = %s\n", dict->key, dict->value); } puts("---------------------------------------------"); puts("AVStream视频元数据:"); puts("---------------------------------------------"); dict = NULL; while (dict = av_dict_get(pFormatCtx->streams[videoIndex]->metadata, "", dict, AV_DICT_IGNORE_SUFFIX)) { printf("[%s] = %s\n", dict->key, dict->value); } puts("---------------------------------------------"); puts("AVStream音频元数据:"); puts("---------------------------------------------"); dict = NULL; while (dict = av_dict_get(pFormatCtx->streams[audioIndex]->metadata, "", dict, AV_DICT_IGNORE_SUFFIX)) { printf("[%s] = %s\n", dict->key, dict->value); } puts("---------------------------------------------"); av_dump_format(pFormatCtx, -1, fileName, 0); printf("\n\n编译信息:\n%s\n\n", avcodec_configuration()); avcodec_free_context(&pCodecCtx); //avcodec_close(pCodecCtx); avformat_close_input(&pFormatCtx); return 0; }参考自:ffplay.c
Keep it simple!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
2013-09-01 C语言中typedef用法
2013-09-01 C++ 中库函数bsearch的简单研究(含示例)
2013-09-01 命令行压缩解压缩一 7z