51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

FFmpeg AVCodecContext

当我们打开一个多媒体文件时,FFmpeg 会用 AVCodecContext 结构体来存储文件的一些信息和参数,用于后续对文件的一系列操作。本篇就简单介绍下,如何使用 FFmpeg 打开和关闭一个多媒体文件。我们的操作步骤如下:

  1. 打开多媒体文件
  2. 探索多媒体文件更多信息
  3. 关闭多媒体文件

在这个过程中涉及到如下的函数:

  1. 打开:avformat_open_input
  2. 探索:avformat_find_stream_info
  3. 关闭: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 {#title-0} =================================

FFmpeg 中的 avformat_open_input 函数用于打开一个多媒体文件,并读取多媒体文件的头信息。

多媒体文件内的数据大致分为两部分,第一部分存储了文件的一些信息和参数,第二部存储文件的流数据。头信息指的是第一部分的内容。

该函数的声明如下:

int avformat_open_input(AVFormatContext **ps, const char *url, const AVInputFormat *fmt, AVDictionary **options);
  1. 第一个参数 ps 就是专门用于存储多媒体文件的信息的。该参数是个二级指针,这就是说,ps 的内存不需要我们申请,而是由 avformat_open_input 申请,并将读取到的头信息初始化 ps 结构。
  2. 第二个参数 url 指的是多媒体的文件路径。
  3. 第三个参数 fmt 是文件的格式。如果该参数为 nullptr,avformat_open_input 函数会自动去探测输入多媒体文件相关的信息,并将信息存储到 ps 中,如果设置了该参数,那么将会使用用户指定的 fmt 来设置 ps 中的信息。
  4. 第四个参数 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);
}
  1. avformat_find_stream_info {#title-1} =======================================

函数 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。

  1. avformat_close_input {#title-2} ==================================

函数 avformat_close_input 的作用就是在最后释放 AVFormatContext 指针占用的内存,函数声明如下:

void avformat_close_input(AVFormatContext **s);

注意该函数传递的是 AVFormatContext 类型的二级指针,即:当 avformat_close_input 释放内存之后,会将传递进来的指针设置为 nullptr,避免悬挂指针(野指针)问题。

赞(2)
未经允许不得转载:工具盒子 » FFmpeg AVCodecContext