基于发布-订阅模型的音视频流分发框架

有时需要同时网络推流和把流封装为某格式,或做一些其它操作。这就需要一个分发流的机制,把同一路流分发给多个使用者去操作,下面实现了一个简易的线程安全的音视频流分发框架。代码如下:

avStreamHub.h

cpp 复制代码
#ifndef STREAMHUB_H
#define STREAMHUB_H

#include <stddef.h>
#include <pthread.h>

typedef void (*AVStreamCallback)(void *data, size_t size, void *arg);

typedef struct Subscriber
{
    AVStreamCallback callback;
    void *arg;
} Subscriber;

typedef struct AVStreamHub
{
    Subscriber *subscribers; // 存储订阅者的数组
    size_t size;             // 当前订阅者数量
    size_t capacity;         // 动态数组容量
    pthread_mutex_t lock;    // 互斥锁
} AVStreamHub;

/**
 * @brief 初始化AVStreamHub
 * @param hub 指向AVStreamHub结构体的指针
 * @param initial_capacity 初始分配的订阅者容量
 * @return 0 成功,-1 失败
 */
int avStreamHub_init(AVStreamHub *hub, size_t initial_capacity);

/**
 * @brief 添加订阅者
 * @param hub 指向AVStreamHub结构体的指针
 * @param callback 订阅者的回调函数
 * @param arg 回调携带的参数
 * @return 0 成功,< 0 失败
 */
int avStreamHub_addSub(AVStreamHub *hub, AVStreamCallback callback, void *arg);

/**
 * @brief 删除订阅者
 * @param hub 指向AVStreamHub结构体的指针
 * @param callback 要移除的订阅者的回调函数
 * @return 无
 */
void avStreamHub_removeSub(AVStreamHub *hub, AVStreamCallback callback);

/**
 * @brief 将数据流分发给所有已注册的订阅者
 * @param hub 指向AVStreamHub结构体的指针
 * @param data 指向要分发的数据的指针
 * @param size 数据的大小
 * @return 无
 */
void avStreamHub_publish(AVStreamHub *hub, void *data, size_t size);

/**
 * @brief 销毁AVStreamHub
 * @param hub 指向AVStreamHub结构体的指针
 * @return 无
 */
void avStreamHub_destroy(AVStreamHub *hub);

#endif // STREAMHUB_H

avStreamHub.c

cpp 复制代码
#include "avStreamHub.h"
#include <stdlib.h>
#include <string.h>

#define INITIAL_CAPACITY 2

int avStreamHub_init(AVStreamHub *hub, size_t initial_capacity)
{
    hub->size = 0;
    hub->capacity = 0;

    if (initial_capacity == 0)
    {
        initial_capacity = INITIAL_CAPACITY;
    }
    hub->subscribers = (Subscriber *)malloc(initial_capacity * sizeof(Subscriber));
    if (!hub->subscribers)
    {
        return -1;
    }
    memset(hub->subscribers, 0, initial_capacity * sizeof(Subscriber));

    hub->capacity = initial_capacity;
    pthread_mutex_init(&hub->lock, NULL);

    return 0;
}

// 添加订阅者
int avStreamHub_addSub(AVStreamHub *hub, AVStreamCallback callback, void *arg)
{
    pthread_mutex_lock(&hub->lock);

    // 检查该回调是否已存在
    for (size_t i = 0; i < hub->size; i++)
    {
        if (hub->subscribers[i].callback == callback)
        {
            pthread_mutex_unlock(&hub->lock);
            return -1; // 回调已存在
        }
    }

    // 如果容量不足则扩展容量
    if (hub->size == hub->capacity)
    {
        hub->subscribers = (Subscriber *)realloc(hub->subscribers,
                                                 hub->capacity * 2 * sizeof(Subscriber));
        if (!hub->subscribers)
        {
            pthread_mutex_unlock(&hub->lock);
            return -2;
        }
        hub->capacity *= 2;
    }

    // 添加新订阅者
    hub->subscribers[hub->size].callback = callback;
    hub->subscribers[hub->size].arg = arg;
    hub->size++;

    pthread_mutex_unlock(&hub->lock);
    return 0;
}

// 删除订阅者
void avStreamHub_removeSub(AVStreamHub *hub, AVStreamCallback callback)
{
    pthread_mutex_lock(&hub->lock);

    for (size_t i = 0; i < hub->size; i++)
    {
        if (hub->subscribers[i].callback == callback)
        {
            size_t j = i;
            for (; j < hub->size - 1; j++)
            {
                hub->subscribers[j] = hub->subscribers[j + 1];
            }
            hub->subscribers[j].callback = NULL;
            hub->subscribers[j].arg = NULL;
            hub->size--;
            break;
        }
    }

    pthread_mutex_unlock(&hub->lock);
}

// 分发数据
void avStreamHub_publish(AVStreamHub *hub, void *data, size_t size)
{
    pthread_mutex_lock(&hub->lock);

    for (size_t i = 0; i < hub->size; i++)
    {
        hub->subscribers[i].callback(data, size, hub->subscribers[i].arg);
    }

    pthread_mutex_unlock(&hub->lock);
}

// 销毁AVStreamHub
void avStreamHub_destroy(AVStreamHub *hub)
{
    free(hub->subscribers);
    hub->subscribers = NULL;
    hub->size = 0;
    hub->capacity = 0;
    pthread_mutex_destroy(&hub->lock);
}
相关推荐
benbenAItalk2 小时前
数字人口播视频的批量生产实践:素材规范、任务编排与质量验收
java·前端·音视频
AI创界者6 小时前
前沿多模态大模型 MiniMax-H3无审查 本地部署与深度实测指南
人工智能·aigc·音视频
世岩清上11 小时前
展厅数字内容同质化严重,怎样打造专属叙事风格?
大数据·前端·javascript·人工智能·html·音视频·展厅改造
LCG元11 小时前
STM32F407 I2S驱动WM8978音频播放实战:PLLI2S时钟整定、DMA双缓冲防爆音与WAV采样率实测
stm32·嵌入式硬件·音视频
jbk331112 小时前
PixiuCut「视频批量分割」支持智能镜头分割、按时长、按数量分割,可定义最小时长避免无效片段等多可选参数可设置
人工智能·音视频·剪辑软件·剪映自动化软件
投票竞赛12 小时前
作品投票版权注意事项,线上评选上传图片视频须知
python·音视频
byte轻骑兵15 小时前
【AVDTP】规范精讲[13]: 吃透内容保护机制,打通蓝牙音视频版权加密全流程
人工智能·音视频·avrcp·蓝牙耳机·蓝牙音频
世岩清上17 小时前
文旅历史展厅纪录片式视频,怎样弱化说教感提升自主观看欲?
人工智能·音视频·宣传片·展厅改造
言乐617 小时前
Python加速器2视频网页加速器
前端·javascript·css·python·音视频