当我们打开一个多媒体文件时,FFmpeg 会用 AVCodecContext 结构体来存储文件的一些信息和参数,用于后续对文件的一系列操作。本篇就简单介绍下,如何使用 FFmpeg 打开和关闭一个多媒体文件。我们的操作步骤如下:
- 打开多媒体文件
- 探索多媒体文件更多信息
- 关闭多媒体文件
在这个过程中涉及到如下的函数:
- 打开:avformat_open_input
- 探索:avformat_find_stream_info
- 关闭:avformat_close_input
完整的示例代码如下:
#include <iostream> extern "C" { #include <libavformat/avformat.h> } void test() { const AVInputFormat* pInputFormat = nullptr; AVDictionary* pOptionDict = nullptr; AVFormatContext* pFormatContex = nullptr; // 打开多媒体文件 int err_num = avformat_open_input(&pFormatContex, "demo.mp4", pInputFormat, &pOptionDict); printf("pFormatContex: %p\n", pFormatContex); // 错误码处理 if (err_num < 0) { char error[128] = { 0 }; int ret = av_strerror(err_num, error, sizeof(errno)); if (ret < 0) { fprintf(stderr, "未知的错误!\n"); } else { fprintf(stderr, "错误信息: %s\n", error); } return; } // 文件信息探测 avformat_find_stream_info(pFormatContex, nullptr); // 关闭多媒体文件 avformat_close_input(&pFormatContex); printf("pFormatContex: %p\n", pFormatContex); } int main() { test(); return 0; }
程序输出结果:
pFormatContex: 000001F9AE09F900 pFormatContex: 0000000000000000
接下来详细讲解下这三个函数的作用和参数含义。
1. avformat_open_input
FFmpeg 中的 avformat_open_input 函数用于打开一个多媒体文件,并读取多媒体文件的头信息。
多媒体文件内的数据大致分为两部分,第一部分存储了文件的一些信息和参数,第二部存储文件的流数据。头信息指的是第一部分的内容。
该函数的声明如下:
int avformat_open_input(AVFormatContext **ps, const char *url, const AVInputFormat *fmt, AVDictionary **options);
- 第一个参数 ps 就是专门用于存储多媒体文件的信息的。该参数是个二级指针,这就是说,ps 的内存不需要我们申请,而是由 avformat_open_input 申请,并将读取到的头信息初始化 ps 结构。
- 第二个参数 url 指的是多媒体的文件路径。
- 第三个参数 fmt 是文件的格式。如果该参数为 nullptr,avformat_open_input 函数会自动去探测输入多媒体文件相关的信息,并将信息存储到 ps 中,如果设置了该参数,那么将会使用用户指定的 fmt 来设置 ps 中的信息。
- 第四个参数 options 从名字来看就是可选参数,它用于设置一些文件的额外参数。
对于第四个参数,我们暂时用不到,先不关心可以设置哪些参数,但是需要了解下,该参数如何设置。
void test() { AVDictionary* dict = nullptr; /* #define AV_DICT_MATCH_CASE 1 // Only get an entry with exact-case key match. Only relevant in av_dict_get(). #define AV_DICT_IGNORE_SUFFIX 2 // Return first entry in a dictionary whose first part corresponds to the search key, ignoring the suffix of the found key string. Only relevant in av_dict_get(). allocated with av_malloc() or another memory allocation function. #define AV_DICT_DONT_STRDUP_VAL 8 // Take ownership of a value that's been allocated with av_malloc() or another memory allocation function. #define AV_DICT_DONT_OVERWRITE 16 // Don't overwrite existing entries. #define AV_DICT_APPEND 32 // If the entry already exists, append to it. Note that no delimiter is added, the strings are simply concatenated. #define AV_DICT_MULTIKEY 64 // Allow to store several equal keys in the dictionary */ // 添加配置 av_dict_set(&dict, "Name", "Trump", AV_DICT_MATCH_CASE); // 该版本的函数会将 int 转换为字符串之后再进行存储 av_dict_set_int(&dict, "Age", 100, AV_DICT_MATCH_CASE); // 获得配置 AVDictionaryEntry* entry = av_dict_get(dict, "Name", nullptr, AV_DICT_MATCH_CASE); printf("Key: %s Value: %s\n", entry->key, entry->value); entry = av_dict_get(dict, "Age", nullptr, AV_DICT_MATCH_CASE); printf("Key: %s Value: %s\n", entry->key, entry->value); // 元素个数 printf("Count: %d\n", av_dict_count(dict)); // 销毁字典 av_dict_free(&dict); }
2. avformat_find_stream_info
函数 avformat_find_stream_info 用于探索文件更多的信息。我们前面提到的 avformat_open_input 函数可以读取多媒体文件头信息,从而获得输入文件的信息。那么,为什么还要用 avformat_find_stream_info 函数呢?
如果所有的多媒体文件都把信息和参数写到头,那我们就用 avformat_open_input 就可以了,但是有些格式的多媒体文件中,有些信息,或者我们后续操作需要的信息并没有放到头位置,这就导致了 avformat_find_stream_info 函数无法获得需要的信息。此时就可以使用 avformat_find_stream_info 函数对输入的多媒体文件进行更深入的读取、探索,从而获得这些我们需要的必要信息。
所以,使用时,一般就在 avformat_open_input 函数调用之后,接着调用 avformat_find_stream_info 函数,从而获得更为详细、有用的多媒体文件信息,便于后期对该文件的操作。
函数的声明如下:
int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options);
注意:第一个参数为 avformat_open_input 调用成功之后的 AVFormatContext 类型指针,第二个参数可选参数,不需要设置的话,可以设置为 nullptr。
3. avformat_close_input
函数 avformat_close_input 的作用就是在最后释放 AVFormatContext 指针占用的内存,函数声明如下:
void avformat_close_input(AVFormatContext **s);
注意该函数传递的是 AVFormatContext 类型的二级指针,即:当 avformat_close_input 释放内存之后,会将传递进来的指针设置为 nullptr,避免悬挂指针(野指针)问题。