0%

文章 音视频封装 - PS 封装格式 中分析了 PS 流的结构,但文章中中涉及到的元素过多,难以理解,故通过一段真实的码流的分析来加强对 PS 流结构的理解。

注 1:本文中的 PS 码流 A 截取自一段经 ffmpeg 转码的网络视频,码流 B 截取自海康摄像机的 GB28181 码流。 注 2:本文中的数字一般为十进制表示,如果是其他进制数据,会在数字后携带 (2) 代表二进制,在数字前添加 0x 代表十六进制 注 3:截图中的码流信息均使用十六进制

libevent 中,事件主循环的作用就是执行一个循环,在循环中监听事件以及超时的事件并且将这些激活的事件进行处理。libevent 提供了对用户开放了两种执行事件主循环的函数:

int event_base_dispatch(struct event_base *);
int event_base_loop(struct event_base *, int);

LeetCode 刷题时,经常会用到 C++ 的一些位运算函数,在此记录下防止需要用时忘记。

需要注意,以下函数均为 gcc 提供的内置位运算函数,在其他编译环境上无法使用。

对于只需要触发一次的事件,libevent 提供了一种方案:event_once,让使用者不需要手动管理 event,并且也保证了事件被触发后,内存会被自动被释放。

libevent 中,使用 min_heap 这一数据结构来管理各个 event 的超时,也就是小根堆,整个堆是根据各个 event 的超时时间来构成的,因此堆顶肯定就对应超时时间最小的 event,这样就可以按照超时顺序进行处理了。

不管使用的是什么多路 IO 复用模型,这些复用模型本身都是只支持读写 IO 事件的,而 libevent 支持的信号事件处理,就必须单独开发一套信号事件的处理逻辑,或者用某种办法将信号事件转换为 IO 事件进行处理。而 libevent 选择了后者,即统一事件源的方式。

Post not found: 源码阅读 libevent - event_io_mapPost not found: 源码阅读 libevent - event_signal_map 中,无论是哈希表还是普通数组,都是将一个 fd 或者 sig 映射到了一个双向链表的表头上:

LIST_HEAD (event_dlist, event);
/* 以上宏定义展开后结果为如下所示 */
struct event_dlist {
    struct event *lh_first;  /* first element */
}

该双向量表的表头为结构体 struct event_dlist,链表中元素的结构体为 struct event,其中每个 struct event 链表元素代表着一个事件,本文主要分析这个事件结构体:struct event

在之前的文章中提到过:libevent 中的哈希表只会用于 Windows 系统,像遵循 POSIX 标准的 OS 是不会用到哈希表的。那么在遵循 POSIX 标准的 OS 中 event_io_map 是怎么实现的呢?答案就在下面的宏定义中:

#define event_io_map event_signal_map

从该宏定义中可以看出,此时 event_io_map 被定义为了 event_signal_map 结构体。本文就分析一下 event_signal_map 结构体。

libevent 源码中除了 queue.h 文件中定义了 5 种数据结构,在 ht-internal.h 文件中定义了另一个重要的数据结构:哈希表。

本系列大部分文章介绍 linux 系统下 libevent 的源码,但 libeventlinux 环境下并没有用到哈希表结构,但学习 libevent 中哈希表的实现非常有助于对哈希表结构的理解。

要实现 libevent 的事件处理,最关键的就是 event_baseevent_base 就像是一棵树,而需要进行处理的事件 event 就像是树上的果子,因此,在分析 libevent 的事件处理之前,先来分析一下 event_base

由于 event_base 结构体中包含了三十多个成员,直接去分析每个成员是在当前没有对了 libevent 代码做足够深入理解的话是很难分析每个成员的作用,因此我们先从 event_base 的使用中去了解 event_base 各个结构体成员的作用会比较好,本文先来看看 event_base 的创建。

Post not found: 源码阅读 libevent - 结构体:event_base