ffmpeg4.0.4 api-threadmessage-test.c

使用FFmpeg库模拟消息传递的C程序。它创建了一个消息队列以及多个发送者和接收者线程,这些线程在队列中推送和弹出消息。

程序的主要功能包括:

定义了发送者和接收者数据的结构,以及消息的结构。
free_frame函数用于释放消息帧的内存。
sender_thread和receiver_thread函数分别模拟发送者和接收者线程的行为。发送者创建带有帧的消息并将其推送到队列中,而接收者从队列中弹出消息,处理其帧并释放消息。
get_workload函数生成发送者和接收者线程的随机工作负载。
在main函数中,程序从命令行参数中获取配置参数(例如队列大小、发送者/接收者数量、工作负载范围)。
为发送者和接收者数据数组分配内存并初始化消息队列。
程序使用pthread_create函数创建发送者和接收者线程。
在创建所有线程后,程序使用pthread_join函数等待它们完成。
最后,程序释放了分配的资源并检查是否有任何错误。

// 结构体:发送者数据
struct sender_data {int id;                     // 发送者的标识符pthread_t tid;              // 发送者线程的标识符int workload;               // 发送者的工作负载,即需要处理的消息数量AVThreadMessageQueue *queue;// 指向消息队列的指针,发送者通过该队列发送消息
};// 结构体:接收者数据
// 为了测试目的,将 sender_data 的成员顺序打乱
struct receiver_data {pthread_t tid;              // 接收者线程的标识符int workload;               // 接收者的工作负载,即需要处理的消息数量int id;                     // 接收者的标识符AVThreadMessageQueue *queue;// 指向消息队列的指针,接收者通过该队列接收消息
};// 结构体:消息
struct message {AVFrame *frame;             // 指向帧数据的指针,用于存储消息的帧数据int magic;                  // 用于添加垃圾数据以确保消息大小大于 sizeof(void*)
};// 宏定义:MAGIC
#define MAGIC 0xdeadc0de        // 用于表示消息中垃圾数据的值

sender_thread

// 函数:发送者线程函数
static void *sender_thread(void *arg)
{int i, ret = 0;struct sender_data *wd = arg; // 获取发送者数据结构体指针// 打印发送者的工作负载信息av_log(NULL, AV_LOG_INFO, "sender #%d: workload=%d\n", wd->id, wd->workload);// 循环发送消息,模拟发送者的工作for (i = 0; i < wd->workload; i++) {// 随机决定是否清空消息队列if (rand() % wd->workload < wd->workload / 10) {av_log(NULL, AV_LOG_INFO, "sender #%d: flushing the queue\n", wd->id);av_thread_message_flush(wd->queue); // 清空消息队列} else {char *val;AVDictionary *meta = NULL;struct message msg = {.magic = MAGIC,.frame = av_frame_alloc(), // 为消息分配帧数据内存};if (!msg.frame) {ret = AVERROR(ENOMEM); // 内存分配失败break;}// 为消息添加元数据,用于标识帧数据val = av_asprintf("frame %d/%d from sender %d", i + 1, wd->workload, wd->id);if (!val) {av_frame_free(&msg.frame);ret = AVERROR(ENOMEM); // 内存分配失败break;}ret = av_dict_set(&meta, "sig", val, AV_DICT_DONT_STRDUP_VAL); // 设置元数据if (ret < 0) {av_frame_free(&msg.frame);break;}msg.frame->metadata = meta; // 将元数据关联到帧数据中// 分配一个真实的帧数据以模拟“真实”的工作msg.frame->format = AV_PIX_FMT_RGBA;msg.frame->width  = 320;msg.frame->height = 240;ret = av_frame_get_buffer(msg.frame, 32); // 分配帧数据的缓冲区if (ret < 0) {av_frame_free(&msg.frame);break;}// 将消息推送到消息队列中av_log(NULL, AV_LOG_INFO, "sender #%d: sending my work (%d/%d frame:%p)\n",wd->id, i + 1, wd->workload, msg.frame);ret = av_thread_message_queue_send(wd->queue, &msg, 0); // 发送消息if (ret < 0) {av_frame_free(&msg.frame);break;}}}// 打印发送者的工作完成信息av_log(NULL, AV_LOG_INFO, "sender #%d: my work is done here (%s)\n",wd->id, av_err2str(ret));// 设置消息队列的错误状态av_thread_message_queue_set_err_recv(wd->queue, ret < 0 ? ret : AVERROR_EOF);return NULL;
}

receiver_thread

// 函数:接收者线程函数
static void *receiver_thread(void *arg)
{int i, ret = 0;struct receiver_data *rd = arg; // 获取接收者数据结构体指针// 循环处理消息,模拟接收者的工作for (i = 0; i < rd->workload; i++) {// 随机决定是否清空消息队列if (rand() % rd->workload < rd->workload / 10) {av_log(NULL, AV_LOG_INFO, "receiver #%d: flushing the queue\n", rd->id);av_thread_message_flush(rd->queue); // 清空消息队列} else {struct message msg;AVDictionary *meta;AVDictionaryEntry *e;// 从消息队列中接收消息ret = av_thread_message_queue_recv(rd->queue, &msg, 0);if (ret < 0)break;// 检查消息的合法性av_assert0(msg.magic == MAGIC);// 从消息的元数据中获取信息并打印meta = msg.frame->metadata;e = av_dict_get(meta, "sig", NULL, 0);av_log(NULL, AV_LOG_INFO, "got \"%s\" (%p)\n", e->value, msg.frame);// 释放消息的帧数据内存av_frame_free(&msg.frame);}}// 打印接收者的工作完成信息av_log(NULL, AV_LOG_INFO, "consumed enough (%d), stop\n", i);// 设置消息队列的错误状态av_thread_message_queue_set_err_send(rd->queue, ret < 0 ? ret : AVERROR_EOF);return NULL;
}

main

// 主函数
int main(int ac, char **av)
{int i, ret = 0;int max_queue_size;int nb_senders, sender_min_load, sender_max_load;int nb_receivers, receiver_min_load, receiver_max_load;struct sender_data *senders;struct receiver_data *receivers;AVThreadMessageQueue *queue = NULL;// 解析命令行参数if (ac != 8) {av_log(NULL, AV_LOG_ERROR, "%s <max_queue_size> ""<nb_senders> <sender_min_send> <sender_max_send> ""<nb_receivers> <receiver_min_recv> <receiver_max_recv>\n", av[0]);return 1;}// 从命令行参数中获取相关配置信息max_queue_size    = atoi(av[1]);nb_senders        = atoi(av[2]);sender_min_load   = atoi(av[3]);sender_max_load   = atoi(av[4]);nb_receivers      = atoi(av[5]);receiver_min_load = atoi(av[6]);receiver_max_load = atoi(av[7]);// 检查参数是否合法if (max_queue_size <= 0 ||nb_senders <= 0 || sender_min_load <= 0 || sender_max_load <= 0 ||nb_receivers <= 0 || receiver_min_load <= 0 || receiver_max_load <= 0) {av_log(NULL, AV_LOG_ERROR, "negative values not allowed\n");return 1;}// 打印配置信息av_log(NULL, AV_LOG_INFO, "qsize:%d / %d senders sending [%d-%d] / ""%d receivers receiving [%d-%d]\n", max_queue_size,nb_senders, sender_min_load, sender_max_load,nb_receivers, receiver_min_load, receiver_max_load);// 分配发送者和接收者数据结构体的内存空间senders = av_mallocz_array(nb_senders, sizeof(*senders));receivers = av_mallocz_array(nb_receivers, sizeof(*receivers));if (!senders || !receivers) {ret = AVERROR(ENOMEM);goto end;}// 分配消息队列的内存空间ret = av_thread_message_queue_alloc(&queue, max_queue_size, sizeof(struct message));if (ret < 0)goto end;// 设置消息队列的释放函数av_thread_message_queue_set_free_func(queue, free_frame);// 为每个发送者和接收者创建线程并开始工作
#define SPAWN_THREADS(type) do {                                                \for (i = 0; i < nb_##type##s; i++) {                                        \struct type##_data *td = &type##s[i];                                   \\// 初始化发送者或接收者的数据结构体td->id = i;                                                             \td->queue = queue;                                                      \td->workload = get_workload(type##_min_load, type##_max_load);          \\// 创建发送者或接收者线程ret = pthread_create(&td->tid, NULL, type##_thread, td);                \if (ret) {                                                              \const int err = AVERROR(ret);                                       \av_log(NULL, AV_LOG_ERROR, "Unable to start " AV_STRINGIFY(type)    \" thread: %s\n", av_err2str(err));                           \goto end;                                                           \}                                                                       \}                                                                           \
} while (0)// 创建并启动发送者线程SPAWN_THREADS(receiver);// 创建并启动接收者线程SPAWN_THREADS(sender);// 等待所有发送者和接收者线程结束
#define WAIT_THREADS(type) do {                                                 \for (i = 0; i < nb_##type##s; i++) {                                        \struct type##_data *td = &type##s[i];                                   \\// 等待发送者或接收者线程结束ret = pthread_join(td->tid, NULL);                                      \if (ret) {                                                              \const int err = AVERROR(ret);                                       \av_log(NULL, AV_LOG_ERROR, "Unable to join " AV_STRINGIFY(type)     \" thread: %s\n", av_err2str(err));                           \goto end;                                                           \}                                                                       \}                                                                           \
} while (0)// 等待所有发送者线程结束WAIT_THREADS(sender);// 等待所有接收者线程结束WAIT_THREADS(receiver);end:// 释放消息队列的内存空间和发送者、接收者数据结构体的内存空间av_thread_message_queue_free(&queue);av_freep(&senders);av_freep(&receivers);// 检查是否发生了错误if (ret < 0 && ret != AVERROR_EOF) {av_log(NULL, AV_LOG_ERROR, "Error: %s\n", av_err2str(ret));return 1;}return 0;
}

运行

要运行这个程序并传递参数,您可以在命令行中执行编译后的可执行文件,并在命令行中传递所需的参数。假设您已经编译了名为 your_program 的可执行文件,以下是如何在命令行中运行并传递参数的示例:bash
Copy code
./api-threadmessage-test100 3 1 5 2 2 4
在这个示例中,假设 your_program 是您编译后的可执行文件的名称。接下来是一系列参数:100:max_queue_size,消息队列的最大大小。
3:nb_senders,发送者的数量。
1:sender_min_send,每个发送者的最小工作量。
5:sender_max_send,每个发送者的最大工作量。
2:nb_receivers,接收者的数量。
2:receiver_min_recv,每个接收者的最小工作量。
4:receiver_max_recv,每个接收者的最大工作量。
您可以根据您的实际需求修改这些参数的值。执行命令后,程序将以这些参数运行,并根据参数配置的发送者和接收者数量、工作量等信息执行相应的操作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/652068.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《动手学深度学习(PyTorch版)》笔记4.9

Chapter4 Multilayer Perceptron 4.9 Environment and Distribution Shift 4.9.1 Types of Distribution Shift 在一个经典的情景中&#xff0c;假设训练数据是从某个分布 p S ( x , y ) p_S(\mathbf{x},y) pS​(x,y)中采样的&#xff0c;但是测试数据将包含从不同分布 p T …

leetcode 字符串相关题目

344. 反转字符串 - 力扣&#xff08;LeetCode&#xff09; 题解&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 541. 反转字符串 II - 力扣&#xff08;LeetCode&#xff09; 题解&#xff1a;https://leetcode.cn/problems/reverse-s…

Linux cat,tac,more,head,tail命令 查看文本

目录 一. cat 和 tac命令二. head 和 tail 命令三. more命令 一. cat 和 tac命令 cat&#xff1a;用来打开文本文件&#xff0c;从上到下的顺序显示文件内容。tac&#xff1a;用法和cat相同&#xff0c;只不过是从下到上逆序的方式显示文件内容。当文件的内容有很多的时候&…

《Python 简易速速上手小册》第6章:Python 文件和数据持久化(基于最新版 Python3.12 编写)

注意&#xff1a;本《Python 简易速速上手小册》 核心目的在于让零基础新手「快速构建 Python 知识体系」 文章目录 <mark >注意&#xff1a;本《Python 简易速速上手小册》<mark >核心目的在于让零基础新手「快速构建 Python 知识体系」 6.1 文件读写操作6.1.1 打…

【leetcode100-069到073】【栈】五题合集

【有效括号】 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 左括号必须用相同类型的右括号闭合。左括号必须以正确的顺序闭合。每个右括号都有一个对应的…

【Image captioning】论文阅读八—ClipCap: CLIP Prefix for Image Captioning_2021

中文标题&#xff1a;ClipCap: CLIP前缀用于图像描述&#xff08;ClipCap: CLIP Prefix for Image Captioning&#xff09; 文章目录 1. 介绍2. 相关工作3. 方法3.1 综述3.2 语言模型微调3.3 映射网络架构3.4 推理 4. 结果5. 结论 摘要&#xff1a;图像描述是视觉语言理解中的…

函数入门.

函数入门 1. 初识函数2. 函数的参数2.1 参数2.2 默认参数2.3 动态参数 3. 函数返回值总结作业 1. 初识函数 函数到底是个什么东西&#xff1f; 函数&#xff0c;可以当做是一大堆功能代码的集合。 def 函数名():函数内编写代码......函数名()例如&#xff1a; # 定义名字叫in…

【Axure高保真原型】可视化环形图

今天和大家可视化环形图的原型模板&#xff0c;&#xff0c;包括4种效果&#xff0c;移入变色在环形中部显示数据、移入变色在标签弹窗显示数据、移入放大在环形中部显示数据、移入放大在标签弹窗显示数据。这个原型是用Axure原生元件制作的&#xff0c;所以不需要联网或者调用…

项目中从需求分析到研发上线

一、背景 应用系统从设想到需求到研发到上线会经历一些列工程化过程。比如经典的瀑布模型工作流&#xff0c;其实就是一个经过很多经验总结下来的工程方法。本节阐述项目中从需求到研发上线的过程。但是也有些根据不同的行业&#xff0c;不同的公司&#xff0c;不同管理者的风…

Spring Boot使用AOP

一、为什么需要面向切面编程&#xff1f; 面向对象编程&#xff08;OOP&#xff09;的好处是显而易见的&#xff0c;缺点也同样明显。当需要为多个不具有继承关系的对象添加一个公共的方法的时候&#xff0c;例如日志记录、性能监控等&#xff0c;如果采用面向对象编程的方法&…

XMLHttpRequestUpload 对象

一、基本概念 XMLHttpRequestUpload 对象表示一个 XMLHttpRequest 的上传进程。它是 XMLHttpRequest 的一个属性&#xff0c;可以用来监视上传的进度。 XMLHttpRequestUpload 对象有一些事件监听器&#xff0c;可以用来处理上传过程中的各种事件&#xff1a; loadstart&#…

记录浏览器能打开github.com,android studio无法拉取github项目,并且ping github.com也拼不通的问题

问题&#xff1a; Android studio编译flutter工程突然碰上如下问题&#xff1a; 在浏览器打开该地址能正常打开&#xff0c;尝试ping&#xff1a; 解决方式 通过搜索&#xff0c;查到如下办法&#xff1a; 1、首先在ipaddress.com中查询github.com域名的固定ip地址&#xff…

LLM之RAG实战(二十一)| 使用LlamaIndex的Text2SQL和RAG的功能分析产品评论

亚马逊和沃尔玛等电子商务平台上每天都有大量的产品评论&#xff0c;这些评论是反映消费者对产品情绪的关键接触点。但是&#xff0c;企业如何从庞大的数据库获得有意义的见解&#xff1f; 我们可以使用LlamaIndex将SQL与RAG&#xff08;Retrieval Augmented Generation&#x…

【Go】Channel底层实现 ②

文章目录 channel底层实现channel发送、接收数据有缓冲 channelchannel 先写再读channel 先读再写(when the receiver comes first) 无缓冲channelchannel存在3种状态&#xff1a; channel底层实现 // channel 类型定义 type hchan struct {// channel 中的元素数量, lenqcoun…

【vue3源码】vue源码探索之旅:项目介绍

简言 记录下我眼中的vue源码项目。 gitHubvue3项目仓库 项目要求: vue版本 3.4.15nodeV18.12.0以上使用pnpm包管理器vitest测试框架Vue3 vue3是渐进式JavaScript框架,易学易用,性能出色,适用场景丰富的 Web 前端框架。 Vue 是一个框架,也是一个生态。其功能覆盖了大部分…

QGIS编译(跨平台编译)之二十六:giflib编译(Windows、Linux、MacOS环境下编译)

文章目录 1、giflib介绍2、giflib下载3、Windows下编译4、Linux下编译5、MacOS下编译1、giflib介绍 giflib(又称为Libgif)是一个开源的C语言库,用于处理GIF图像格式。它提供了一组函数和工具,使得开发者可以读取、写入和操作GIF图像文件。 GIFlib支持GIF87a和GIF89a两种版…

Transformer模型 | Pytorch实现Transformer模型进行时间序列预测

Transformer模型最初是为了处理自然语言处理任务而设计的,但它也可以用于时间序列预测。下面是将Transformer模型应用于时间序列预测的一般步骤: 数据准备:准备时间序列数据集,包括历史观测值和目标预测值。通常,你需要将时间序列转换为固定长度的滑动窗口序列,以便输入…

计算机网络之广播风暴

广播风暴&#xff08;Broadcast Storm&#xff09;是指在计算机网络中出现大量广播帧的现象&#xff0c;这通常会导致网络性能下降&#xff0c;甚至整个网络瘫痪。在一个广播风暴中&#xff0c;网络上的每个设备都会接收并处理这些广播帧&#xff0c;这会消耗大量的带宽和处理能…

解决 github.com port 443: Timed out 的问题

国内访问github.com总是那么不竟如人意&#xff0c;时而无法加载网页&#xff0c;时而等我们抽完了一根烟后&#xff0c;它还处于转圈的状态。 虽然国内有gitee.com等诸多的代码托管平台&#xff0c;但却鲜有国人愿意去呢&#xff1f;其中的缘由&#xff0c;想必也不用我多说&a…

openssl3.2 - 测试程序的学习 - test\aesgcmtest.c

文章目录 openssl3.2 - 测试程序的学习 - test\aesgcmtest.c概述笔记能学到的流程性内容END openssl3.2 - 测试程序的学习 - test\aesgcmtest.c 概述 openssl3.2 - 测试程序的学习 aesgcmtest.c 工程搭建时, 发现没有提供 test_get_options(), cleanup_tests(), 需要自己补上…