获取mediainfo
首先调用av_register_all将所有的编码器和解码器注册好
来看下具体的注册实现
void av_register_all(void)
{
ff_thread_once(&av_format_next_init, av_format_init_next);
}
// 看下av_format_init_next的实现
// 可以看到函数内部是实现了将编码器和解码器使用指针进行串联的操作
// 如果有输出或者输入列表,将输出或输入列表也进行串联
static void av_format_init_next(void)
{
AVOutputFormat *prevout = NULL, *out;
AVInputFormat *previn = NULL, *in;
ff_mutex_lock(&avpriv_register_devices_mutex);
// 编码器串联
for (int i = 0; (out = (AVOutputFormat*)muxer_list[i]); i++) {
if (prevout)
prevout->next = out;
prevout = out;
}
//实现输出列表的串联
if (outdev_list) {
for (int i = 0; (out = (AVOutputFormat*)outdev_list[i]); i++) {
if (prevout)
prevout->next = out;
prevout = out;
}
}
//实现解码器的串联
for (int i = 0; (in = (AVInputFormat*)demuxer_list[i]); i++) {
if (previn)
previn->next = in;
previn = in;
}
//实现输入列表的串联
if (indev_list) {
for (int i = 0; (in = (AVInputFormat*)indev_list[i]); i++) {
if (previn)
previn->next = in;
previn = in;
}
}
ff_mutex_unlock(&avpriv_register_devices_mutex);
}
调用avformat_open_input
调用 avformat_open_input根据输入的音视频内容构造 AVFormatContext结构体,函数功能如下:
/**
打开一个流,并读取头部信息
* Open an input stream and read the header. The codecs are not opened.
* The stream must be closed with avformat_close_input().
* ps可以用户提供,如果为NULL该函数会进行内存申请
* @param ps Pointer to user-supplied AVFormatContext (allocated by avformat_alloc_context).
* May be a pointer to NULL, in which case an AVFormatContext is allocated by this
* function and written into ps.
* Note that a user-supplied AVFormatContext will be freed on failure.
指向要打开的多媒体文件
* @param url URL of the stream to open.
不指定,使用自动侦测
* @param fmt If non-NULL, this parameter forces a specific input format.
* Otherwise the format is autodetected.
* @param options A dictionary filled with AVFormatContext and demuxer-private options.
* On return this parameter will be destroyed and replaced with a dict containing
* options that were not found. May be NULL.
*
* @return 0 on success, a negative AVERROR on failure.
*
* @note If you want to use custom IO, preallocate the format context and set its pb field.
*/
int avformat_open_input(AVFormatContext **ps, const char *url, ff_const59 AVInputFormat *fmt, AVDictionary **options);
调用av_dump_format打印文件信息
/**
* Print detailed information about the input or output format, such as
* duration, bitrate, streams, container, programs, metadata, side data,
* codec and time base.
*
* @param ic the context to analyze
* @param index index of the stream to dump information about
* @param url the URL to print, such as source or destination file
* @param is_output Select whether the specified context is an input(0) or output(1)
*/
void av_dump_format(AVFormatContext *ic,
int index,
const char *url,
int is_output);
调用av_dump_format(pFmtCtx, 0, pSrcName, 0);实现对基本信息的打印,这里为了方便观看,可以自己实现一个函数,对多媒体数据进行打印。
这为了更好理解媒体信息记录的格式,自己实现了一个简单的打印接口,仅用于参考
//
// Created by andrew on 2020/11/8.
//
#include <iostream>
#include <string>
extern "C" {
#include <libavformat/avformat.h>
#include <libavutil/log.h>
#include <libavutil/dict.h>
}
using namespace std;
// 声明一下 因为原函数是在.c中声明的结构体
struct AVDictionary {
int count;
AVDictionaryEntry *elems;
};
// 打印媒体信息的简单示例
void my_av_input_dump_format(AVFormatContext *ic, int index,
const char *url, int is_output){
string pSrt = (is_output != 0) ? "output":"input";
cout << "音视频输入输出类型:" << pSrt <<endl;
cout << "index = " << index << endl;
if(is_output){
cout << "fromat name:" << ic->oformat->name << endl;
}else
cout << "fromat name:" << ic->iformat->name << endl;
// url
cout << "from :" << url << endl;
//ic->metadata
int i = 0;
i = ic->metadata->count;
for (i = 0; i < ic->metadata->count; i++){
cout << " " <<ic->metadata->elems[i].key << ":" <<ic->metadata->elems[i].value << endl;
}
}
int main(int argc, char *argv[]){
// 设置日志等级
av_log_set_level(AV_LOG_DEBUG);
if(argc< 2)
{
av_log(NULL, AV_LOG_ERROR, "you should input media file!\n");
return -1;
}
// 所有获取音视频信息都要首先注册
av_register_all();
int errCode = -1;
AVFormatContext *pFmtCtx = NULL;
const char *pSrcName = argv[1];
if((errCode = avformat_open_input(&pFmtCtx, pSrcName, NULL, NULL)) < 0){
av_log(NULL, AV_LOG_ERROR, "avformat open input failed.\n");
exit(1);
}
//官方接口
// av_dump_format(pFmtCtx, 0, pSrcName, 0);
my_av_input_dump_format(pFmtCtx, 0, pSrcName, 0);
//释放资源
avformat_close_input(&pFmtCtx);
return 0;
}
执行输出结果:
音视频输入输出类型:input
index = 0
fromat name:mov,mp4,m4a,3gp,3g2,mj2
from :/work/test/test.mp4
major_brand:isom
minor_version:512
compatible_brands:isomiso2avc1mp41
track:0
artist:段奥娟
album:
comment:163 key(Don't modify):ZWxeTBkln0EQUjdDVUZQXrJzMh33POt0FgWTvjgge2X8BzXmyZaXb9C8+H2VGrdLG7XRTMrkXzzfV9VNH7sp0KlFimbjkVbsWksXY5YrzqFNXeJX1gvrBWCV+m3aYddkvy0HxucdcxCoCrYsrnzxL97sgxi0M2VHh6PREC3j6Uz4hfWkIMGhul9aszAuzEvbUUIQXSZRHgpkVW3g3oTEwqY5CexOWMIgIZAjlFIMxafAnGU8ujxA+ufq/l/r+dQMW9OmRQVt2n4Gz1t83TrPZg==
title:元気满分
encoder:Lavf57.71.100
[AVIOContext @ 0x55bf28f2d080] Statistics: 200364 bytes read, 0 seeks
libgcov profiling error:/work/ffmpeg_doc/cmake-build-debug-coverage/src/CMakeFiles/ffmpeg_mediainfo.dir/ffmpeg_avformat/ffmpeg_mediainfo.cpp.gcda:overwriting an existing profile data with a different timestamp
本文介绍如何使用FFmpeg库中的函数来解析音视频文件的基本信息,包括注册编解码器、打开并读取音视频文件头信息及打印媒体格式详情。
3万+

被折叠的 条评论
为什么被折叠?



