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

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

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);
}
相关推荐
EasyCVR4 小时前
EHOME视频平台EasyCVR视频融合平台使用OBS进行RTMP推流,WebRTC播放出现抖动、卡顿如何解决?
人工智能·算法·ffmpeg·音视频·webrtc·监控视频接入
冷凝女子6 小时前
【QT】海康视频及openCv抓拍正脸接口
qt·opencv·音视频·海康
安步当歌7 小时前
【WebRTC】视频编码链路中各个类的简单分析——VideoStreamEncoder
音视频·webrtc·视频编解码·video-codec
顾北川_野7 小时前
Android CALL关于电话音频和紧急电话设置和获取
android·音视频
顶呱呱程序7 小时前
2-143 基于matlab-GUI的脉冲响应不变法实现音频滤波功能
算法·matlab·音视频·matlab-gui·音频滤波·脉冲响应不变法
EasyCVR8 小时前
萤石设备视频接入平台EasyCVR多品牌摄像机视频平台海康ehome平台(ISUP)接入EasyCVR不在线如何排查?
运维·服务器·网络·人工智能·ffmpeg·音视频
runing_an_min8 小时前
ffmpeg 视频滤镜:屏蔽边框杂色- fillborders
ffmpeg·音视频·fillborders
我喜欢就喜欢21 小时前
基于qt vs下的视频播放
开发语言·qt·音视频
安步当歌1 天前
【WebRTC】视频采集模块中各个类的简单分析
音视频·webrtc·视频编解码·video-codec
EasyGBS1 天前
国标GB28181公网直播EasyGBS国标GB28181软件管理解决方案
大数据·网络·音视频·媒体·视频监控·gb28181