Libavutil详解:理论与实战

2023-11-30 09:23:13 浏览数 (2)

前言

libavutil 是一个实用库,用于辅助多媒体编程,本文记录 libavutil 库学习及 demo 例程展示。

一、Libavutil 简介

libavutil 是一个实用库,用于辅助多媒体编程。此库包含安全的可移植字符串函数、随机数生成器、数据结构、附加数学函数、加密和多媒体相关功能(如像素和样本格式的枚举)。

libavcodec 和 libavformat 并不依赖此库

从 FFmpeg 官网的文档 -libavutil 来看, avutil 主要有以下几种功能:

  • 数学函数
  • 字符串操作
  • 内存管理相关
  • 数据结构相关
  • 错误码及错误处理
  • 日志输出
  • 其他辅助信息,比如密钥、哈希值、宏、库版本、常量等

FFmpeg 中 libavutil 的示例,目前包含:

  • AVLog
  • AVOption (AVClass)
  • AVDictionary
  • ParseUtil

二、AVLog 测试

AVLog 是 FFmpeg(音视频处理库)中的一个日志系统,用于记录和输出日志信息。它提供了一种可配置的方式,使开发者能够根据自己的需求控制日志输出的详细程度和目标。

AVLog 的设计目标是提供一个灵活和可扩展的日志系统,以便在音视频处理过程中记录各种事件、错误和调试信息。它可以用于调试和分析应用程序或库的运行时行为,特别是在处理音视频数据时。

AVLog 提供了多个日志级别,包括:

  • QUIET(静默):最低日志级别,不输出任何日志信息。
  • PANIC(紧急):当发生严重错误时触发,可能导致程序崩溃或不可恢复的错误。
  • FATAL(致命):当发生严重错误时触发,但程序可能还能继续执行。
  • ERROR(错误):记录错误信息,表示发生了一些操作失败或异常情况,但程序仍然可以继续执行。
  • WARNING(警告):记录警告信息,表示发生了一些潜在问题或不符合预期的情况。
  • INFO(信息):记录一般的信息,用于追踪应用程序的运行状态。
  • VERBOSE(详细):记录更详细的信息,用于调试和排查问题。
  • DEBUG(调试):记录详细的调试信息,包括函数调用、变量值等。

1、示例源码

代码语言:javascript复制
#include <stdio.h>

extern "C" {
    #include "libavcodec/avcodec.h"
    #include "libavformat/avformat.h"
    #include "libavutil/opt.h"
    #include "libavutil/parseutils.h"
    #include "libavutil/avutil.h"
};

void test_log(){
    / av_register_all();
    AVFormatContext *pAVFmtCtx = NULL;
    pAVFmtCtx = avformat_alloc_context();

	printf("====================================n");
    av_log(pAVFmtCtx,AV_LOG_PANIC, "Panic: Something went really wrong and we will crash now.n");
    av_log(pAVFmtCtx,AV_LOG_FATAL, "Fatal: Something went wrong and recovery is not possible.n");
    av_log(pAVFmtCtx,AV_LOG_ERROR, "Error: Something went wrong and cannot losslessly be recovered.n");
    av_log(pAVFmtCtx,AV_LOG_WARNING, "Warning: This may or may not lead to problems.n");
    av_log(pAVFmtCtx,AV_LOG_INFO, "Info: Standard information.n");
    av_log(pAVFmtCtx,AV_LOG_VERBOSE, "Verbose: Detailed information.n");
    av_log(pAVFmtCtx,AV_LOG_DEBUG, "Debug: Stuff which is only useful for libav* developers.n");
	printf("====================================n");

    avformat_free_context(pAVFmtCtx);
}

int main(int argc, char* argv[])
{
    av_log_set_level(AV_LOG_DEBUG);
    test_log();

	return 0;
}
  • avformat_alloc_context():分配一个 AVFormatContext;
  • avformat_free_context():可用于释放上下文以及其中由框架分配的所有内容;
  • av_log():如果 level 小于或等于当前 av_log_level,则将指定的消息发送到日志。默认情况下,所有日志消息都发送到 stderr。可以通过设置不同的日志回调函数来更改此行为。

2、运行结果

代码语言:javascript复制
====================================
====================================
[NULL @ 01e0fc40] Panic: Something went really wrong and we will crash now.
[NULL @ 01e0fc40] Fatal: Something went wrong and recovery is not possible.
[NULL @ 01e0fc40] Error: Something went wrong and cannot losslessly be recovered.
[NULL @ 01e0fc40] Warning: This may or may not lead to problems.
[NULL @ 01e0fc40] Info: Standard information.
[NULL @ 01e0fc40] Verbose: Detailed information.
[NULL @ 01e0fc40] Debug: Stuff which is only useful for libav* developers.

三、AVDictionary 测试

AVDictionary 是 FFmpeg(音视频处理库)中的一个字典结构,用于存储键值对的元数据信息。它提供了一种通用的方式来管理和操作多种类型的元数据,例如音视频流的元数据、编解码器的参数、封装格式的选项等。

AVDictionary 的设计目标是提供一种灵活和可扩展的数据结构,用于表示和传递各种元数据信息。它可以用于读取和写入多种音视频文件格式,并且支持动态添加、修改和查询字典中的元素。

AVDictionary 提供了一系列的函数来对字典进行操作,包括:

  • av_dict_set():向字典中添加或修改键值对。
  • av_dict_get():根据键查询字典中的值。
  • av_dict_count():获取字典中键值对的数量。
  • av_dict_copy():复制一个字典。
  • av_dict_free():释放字典及其内部分配的内存。

除了基本的操作函数外,AVDictionary 还支持迭代器遍历字典中的键值对,以及支持将字典转换为字符串格式进行打印或保存。

1、示例源码

代码语言:javascript复制
#include <stdio.h>

extern "C" {
    #include "libavcodec/avcodec.h"
    #include "libavformat/avformat.h"
    #include "libavutil/opt.h"
    #include "libavutil/parseutils.h"
    #include "libavutil/avutil.h"
};

void test_avdictionary(){

    AVDictionary *d = NULL;
    AVDictionaryEntry *t = NULL;

    av_dict_set(&d, "name", "zhangsan", 0);
    av_dict_set(&d, "age", "22", 0);
    av_dict_set(&d, "gender", "man", 0);
    av_dict_set(&d, "email", "www@www.com", 0);
    //av_strdup()
    char *k = av_strdup("location");
    char *v = av_strdup("Beijing-China");
    av_dict_set(&d, k, v, AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL);

    printf("====================================n");
    int dict_cnt = av_dict_count(d);
    printf("dict_count:%dn",dict_cnt);

    printf("dict_element:n");
    while (t = av_dict_get(d, "", t, AV_DICT_IGNORE_SUFFIX)) {
        printf("key:s  |  value:%sn",t->key,t->value);
    }

    t = av_dict_get(d, "email", t, AV_DICT_IGNORE_SUFFIX);
    printf("email is %sn",t->value);
    printf("====================================n");
    av_dict_free(&d);
}

int main(int argc, char* argv[])
{
    test_avdictionary();

	return 0;
}

2、运行结果

代码语言:javascript复制
====================================
dict_count:5
dict_element:
key:      name  |  value:zhangsan
key:       age  |  value:22
key:    gender  |  value:man
key:     email  |  value:www@www.com
key:  location  |  value:Beijing-China
email is www@www.com
====================================

四、ParseUtil 测试

ParseUtil 提供了一些实用的函数和方法,用于解析和转换编解码器参数字符串,以及处理编解码器参数的操作。它主要用于解析编解码器的选项和参数,并将它们转换为适当的数据结构供 FFmpeg 使用。

一些常见的功能和用途包括:

  • 解析编解码器参数:ParseUtil 可以解析编解码器参数字符串,将其拆分为键值对或特定格式的数据。
  • 转换参数数据类型:它可以将参数字符串中的数值或其他特定格式的数据转换为适当的数据类型,如整数、浮点数等。
  • 构建编解码器参数结构:ParseUtil 可以根据解析的结果构建编解码器参数的数据结构,以便在 FFmpeg 中使用。
  • 错误处理:它提供了一些错误处理机制,用于检测和处理无效的参数字符串或错误的参数格式。

1、示例源码

代码语言:javascript复制
#include <stdio.h>

extern "C" {
    #include "libavcodec/avcodec.h"
    #include "libavformat/avformat.h"
    #include "libavutil/opt.h"
    #include "libavutil/parseutils.h"
    #include "libavutil/avutil.h"
};

void test_parseutil(){
    char input_str[100] = {0};
    printf("========= Parse Video Size =========n");
    int output_w = 0;
    int output_h = 0;
    strcpy(input_str, "1920x1080");
    av_parse_video_size(&output_w,&output_h,input_str);
    printf("w:M | h:Mn",output_w,output_h);

    //strcpy(input_str,"vga");//640x480(4:3)
    //strcpy(input_str,"hd1080");//high definition
    strcpy(input_str,"pal");//ntsc(N制720x480), pal(啪制720x576)
    av_parse_video_size(&output_w, &output_h, input_str);
    printf("w:M | h:Mn",output_w,output_h);


    printf("========= Parse Frame Rate =========n");
    AVRational output_rational = {0,0};
    strcpy(input_str,"15/1");
    av_parse_video_rate(&output_rational,input_str);
    printf("framerate:%d/%dn",output_rational.num,output_rational.den);

    strcpy(input_str,"pal");//fps:25/1
    av_parse_video_rate(&output_rational,input_str);
    printf("framerate:%d/%dn",output_rational.num,output_rational.den);


    printf("=========== Parse Time =============n");
    int64_t output_timeval;//单位:微妙, 1S=1000MilliSeconds, 1MilliS=1000MacroSeconds
    strcpy(input_str,"00:01:01");
    av_parse_time(&output_timeval,input_str,1);
    printf("microseconds:%lldn",output_timeval);
    printf("====================================n");
}

int main(int argc, char* argv[])
{
    test_parseutil();

	return 0;
}
  • av_parse_video_size():用于解析视频大小字符串并将其转换为对应的宽度和高度;
  • av_parse_video_rate():用于解析视频帧率字符串并将其转换为对应的帧率值;
  • av_parse_time():用于解析时间字符串并将其转换为对应的时间值(以微秒为单位)

2、运行结果

代码语言:javascript复制
========= Parse Video Size =========
w:1920 | h:1080
w: 720 | h: 576
========= Parse Frame Rate =========
framerate:15/1
framerate:25/1
=========== Parse Time =============
microseconds:61000000
====================================

0 人点赞