gstreamer使用cairo实现视频OSD叠加

前言

gstreamer中视频叠加OSD有很多种方式,比如textoverlay添加文字,gdkpixbufoverlay添加图片,clockoverlay或timeoverlay插件显示时间,pango插件进行复杂文本渲染,使用cairo插件绘制图形或者文字。

今天使用最后一种:cairo

项目源码:

如果是QT,pro文件需要导入:

pro:

PKGCONFIG += cairo

INCLUDEPATH += /usr/include/cairo/

显示动态心♥

main.cpp


#include <gst/gst.h>
#include <gst/video/video.h>#include <cairo/cairo.h>
#include <cairo/cairo-gobject.h>#include <glib.h>static gboolean
on_message (GstBus * bus, GstMessage * message, gpointer user_data)
{GMainLoop *loop = (GMainLoop *) user_data;switch (GST_MESSAGE_TYPE (message)) {case GST_MESSAGE_ERROR:{GError *err = NULL;gchar *debug;gst_message_parse_error (message, &err, &debug);g_critical ("Got ERROR: %s (%s)", err->message, GST_STR_NULL (debug));g_main_loop_quit (loop);break;}case GST_MESSAGE_WARNING:{GError *err = NULL;gchar *debug;gst_message_parse_warning (message, &err, &debug);g_warning ("Got WARNING: %s (%s)", err->message, GST_STR_NULL (debug));g_main_loop_quit (loop);break;}case GST_MESSAGE_EOS:g_main_loop_quit (loop);break;default:break;}return TRUE;
}/* Datastructure to share the state we are interested in between* prepare and render function. */
typedef struct
{gboolean valid;GstVideoInfo vinfo;
} CairoOverlayState;/* Store the information from the caps that we are interested in. */
static void
prepare_overlay (GstElement * overlay, GstCaps * caps, gpointer user_data)
{CairoOverlayState *state = (CairoOverlayState *) user_data;state->valid = gst_video_info_from_caps (&state->vinfo, caps);
}/* Draw the overlay.* This function draws a cute "beating" heart. */
static void
draw_overlay (GstElement * overlay, cairo_t * cr, guint64 timestamp,guint64 duration, gpointer user_data)
{CairoOverlayState *s = (CairoOverlayState *) user_data;double scale;int width, height;if (!s->valid)return;width = GST_VIDEO_INFO_WIDTH (&s->vinfo);height = GST_VIDEO_INFO_HEIGHT (&s->vinfo);scale = 2 * (((timestamp / (int) 1e7) % 70) + 30) / 100.0;cairo_translate (cr, width / 2, (height / 2) - 30);/* FIXME: this assumes a pixel-aspect-ratio of 1/1 */cairo_scale (cr, scale, scale);cairo_move_to (cr, 0, 0);cairo_curve_to (cr, 0, -30, -50, -30, -50, 0);cairo_curve_to (cr, -50, 30, 0, 35, 0, 60);cairo_curve_to (cr, 0, 35, 50, 30, 50, 0);cairo_curve_to (cr, 50, -30, 0, -30, 0, 0);cairo_set_source_rgba (cr, 0.9, 0.0, 0.1, 0.7);cairo_fill (cr);
}static GstElement *
setup_gst_pipeline (CairoOverlayState * overlay_state)
{GstElement *pipeline;GstElement *cairo_overlay;GstElement *source, *adaptor1, *adaptor2, *sink;pipeline = gst_pipeline_new ("cairo-overlay-example");/* Adaptors needed because cairooverlay only supports ARGB data */source = gst_element_factory_make ("videotestsrc", "source");adaptor1 = gst_element_factory_make ("videoconvert", "adaptor1");cairo_overlay = gst_element_factory_make ("cairooverlay", "overlay");adaptor2 = gst_element_factory_make ("videoconvert", "adaptor2");sink = gst_element_factory_make ("ximagesink", "sink");if (sink == NULL)sink = gst_element_factory_make ("autovideosink", "sink");/* If failing, the element could not be created */g_assert (cairo_overlay);/* Hook up the necessary signals for cairooverlay */g_signal_connect (cairo_overlay, "draw",G_CALLBACK (draw_overlay), overlay_state);g_signal_connect (cairo_overlay, "caps-changed",G_CALLBACK (prepare_overlay), overlay_state);gst_bin_add_many (GST_BIN (pipeline), source, adaptor1,cairo_overlay, adaptor2, sink, NULL);if (!gst_element_link_many (source, adaptor1,cairo_overlay, adaptor2, sink, NULL)) {g_warning ("Failed to link elements!");}return pipeline;
}int
main (int argc, char **argv)
{GMainLoop *loop;GstElement *pipeline;GstBus *bus;CairoOverlayState *overlay_state;gst_init (&argc, &argv);loop = g_main_loop_new (NULL, FALSE);/* allocate on heap for pedagogical reasons, makes code easier to transfer */overlay_state = g_new0 (CairoOverlayState, 1);pipeline = setup_gst_pipeline (overlay_state);bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));gst_bus_add_signal_watch (bus);g_signal_connect (G_OBJECT (bus), "message", G_CALLBACK (on_message), loop);gst_object_unref (GST_OBJECT (bus));gst_element_set_state (pipeline, GST_STATE_PLAYING);g_main_loop_run (loop);gst_element_set_state (pipeline, GST_STATE_NULL);gst_object_unref (pipeline);g_free (overlay_state);return 0;
}

显示实时时间

main.cpp 

#include <gst/gst.h>
#include <gst/video/video.h>#include <cairo/cairo.h>
#include <cairo/cairo-gobject.h>#include <glib.h>
#include <time.h>
#include <string>
using std::string;static gboolean
on_message (GstBus * bus, GstMessage * message, gpointer user_data)
{GMainLoop *loop = (GMainLoop *) user_data;switch (GST_MESSAGE_TYPE (message)) {case GST_MESSAGE_ERROR:{GError *err = NULL;gchar *debug;gst_message_parse_error (message, &err, &debug);g_critical ("Got ERROR: %s (%s)", err->message, GST_STR_NULL (debug));g_main_loop_quit (loop);break;}case GST_MESSAGE_WARNING:{GError *err = NULL;gchar *debug;gst_message_parse_warning (message, &err, &debug);g_warning ("Got WARNING: %s (%s)", err->message, GST_STR_NULL (debug));g_main_loop_quit (loop);break;}case GST_MESSAGE_EOS:g_main_loop_quit (loop);break;default:break;}return TRUE;
}/* Datastructure to share the state we are interested in between* prepare and render function. */
typedef struct
{gboolean valid;GstVideoInfo vinfo;
} CairoOverlayState;/* Store the information from the caps that we are interested in. */
static void
prepare_overlay (GstElement * overlay, GstCaps * caps, gpointer user_data)
{CairoOverlayState *state = (CairoOverlayState *) user_data;state->valid = gst_video_info_from_caps (&state->vinfo, caps);
}/* Draw the overlay.* This function draws a cute "beating" heart. */
static void
draw_overlay (GstElement * overlay, cairo_t * cr, guint64 timestamp,guint64 duration, gpointer user_data)
{CairoOverlayState *s = (CairoOverlayState *) user_data;string text = "Current Time: ";time_t current_time = time(NULL); // 获取当前时间struct tm *tm_info = localtime(&current_time); // 将当前时间转换为本地时间char time_str[21]; // 足够存储 "YYYY-MM-DD HH:MM:SS" 格式的时间字符串double scale;int width, height;if (!s->valid)return;// 格式化时间为 "YYYY-MM-DD HH:MM:SS" 格式strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", tm_info);text.append(time_str);// 移动位置:到中心width = GST_VIDEO_INFO_WIDTH (&s->vinfo);height = GST_VIDEO_INFO_HEIGHT (&s->vinfo);cairo_translate (cr, width / 2, height / 2);// 比例调整//cairo_scale (cr, 2.0, 2.0);// 设置文本颜色和透明度cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 1.0); // 黑色文本cairo_select_font_face (cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);cairo_set_font_size (cr, 24);// 绘制文本cairo_show_text (cr, text.c_str());}static GstElement *
setup_gst_pipeline (CairoOverlayState * overlay_state)
{GstElement *pipeline;GstCaps *caps;GstElement *cairo_overlay;GstElement *source, *capsfilter, *adaptor1, *adaptor2, *sink;pipeline = gst_pipeline_new ("cairo-overlay-example");// 创建元素/* Adaptors needed because cairooverlay only supports ARGB data */source = gst_element_factory_make ("videotestsrc", "source");capsfilter = gst_element_factory_make ("capsfilter", "capsfilter");adaptor1 = gst_element_factory_make ("videoconvert", "adaptor1");cairo_overlay = gst_element_factory_make ("cairooverlay", "overlay");adaptor2 = gst_element_factory_make ("videoconvert", "adaptor2");sink = gst_element_factory_make ("glimagesink", "sink");if (sink == NULL)sink = gst_element_factory_make ("autovideosink", "sink");/* If failing, the element could not be created */g_assert (cairo_overlay);// 设置输出参数caps = gst_caps_new_simple ("video/x-raw","width", G_TYPE_INT, 960,"height", G_TYPE_INT, 480,"framerate", GST_TYPE_FRACTION, 60, 1,NULL);g_object_set (G_OBJECT (capsfilter), "caps", caps, NULL);gst_caps_unref (caps);// 联通信号和回调函数/* Hook up the necessary signals for cairooverlay */g_signal_connect (cairo_overlay, "draw",G_CALLBACK (draw_overlay), overlay_state);g_signal_connect (cairo_overlay, "caps-changed",G_CALLBACK (prepare_overlay), overlay_state);gst_bin_add_many (GST_BIN (pipeline), source, capsfilter,adaptor1,cairo_overlay, adaptor2, sink, NULL);if (!gst_element_link_many (source, capsfilter,adaptor1,cairo_overlay, adaptor2, sink, NULL)) {g_warning ("Failed to link elements!");}return pipeline;
}int main (int argc, char **argv)
{GMainLoop *loop;GstElement *pipeline;GstBus *bus;CairoOverlayState *overlay_state;gst_init (&argc, &argv);loop = g_main_loop_new (NULL, FALSE);/* allocate on heap for pedagogical reasons, makes code easier to transfer */overlay_state = g_new0 (CairoOverlayState, 1);pipeline = setup_gst_pipeline (overlay_state);bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));gst_bus_add_signal_watch (bus);g_signal_connect (G_OBJECT (bus), "message", G_CALLBACK (on_message), loop);gst_object_unref (GST_OBJECT (bus));gst_element_set_state (pipeline, GST_STATE_PLAYING);g_main_loop_run (loop);gst_element_set_state (pipeline, GST_STATE_NULL);gst_object_unref (pipeline);g_free (overlay_state);return 0;
}

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

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

相关文章

【React】详解样式控制:从基础到进阶应用的全面指南

文章目录 一、内联样式1. 什么是内联样式&#xff1f;2. 内联样式的定义3. 基本示例4. 动态内联样式 二、CSS模块1. 什么是CSS模块&#xff1f;2. CSS模块的定义3. 基本示例4. 动态应用样式 三、CSS-in-JS1. 什么是CSS-in-JS&#xff1f;2. styled-components的定义3. 基本示例…

ADS 使用教程(二十八)Working with FEM Mesh Field Data in ADS

ADS 使用教程&#xff08;二十七&#xff09;Getting Started with Full 3D FEM Simulation in ADS 在这一节中&#xff0c;我们来谈论一下在ADS中处理有限元法&#xff08;FEM&#xff09;网格和场数据的步骤。 在上一节中&#xff0c;我们进行了FEM仿真&#xff0c;并保存了…

在 MinIO 使用 SVE 将 ARM 带入人工智能数据基础设施领域

MinIO 性能如此之高的原因之一是&#xff0c;我们做了其他人不会或不能做的细粒度工作。从 SIMD 加速到 AVX-512 优化&#xff0c;我们已经完成了艰巨的任务。ARM CPU 架构的最新发展&#xff0c;特别是可扩展矢量扩展 &#xff08;SVE&#xff09;&#xff0c;为我们提供了比前…

【微信小程序】微信小程序设置本地背景图片在真机无法显示的解决方案

微信小程序设置本地背景图片在真机无法显示的解决方案 在开发微信小程序时&#xff0c;很多开发者会遇到一个常见的问题&#xff1a;在调试环境中设置本地背景图片可以正常显示&#xff0c;但在真机上却无法显示。本文将详细探讨这一问题的原因&#xff0c;并提供三种解决方案…

《Cross-Modal Dynamic Transfer Learning for Multimodal Emotion Recognition》

Multi-modal系列论文研读目录 文章目录 Multi-modal系列论文研读目录1.ABSTRACT2.INDEX TERMS3.INTRODUCTION4.RELATED WORKSA. MULTIMODAL EMOTION RECOGNITION 多模态情感识别1) CONVENTIONAL FUSION METHODS 常规融合方法2) TRANSFORMER-BASED FUSION METHODS 基于变压器的融…

2023河南萌新联赛第(二)场 南阳理工学院

A. 国际旅行Ⅰ 题目&#xff1a; 思路&#xff1a; 因为题意上每个国家可以相互到达&#xff0c;所以只需要排序&#xff0c;输出第k小的值就可以了。 AC代码&#xff1a; #include<bits/stdc.h> #define int long long #define IOS ios::sync_with_stdio(0);cin.tie…

接口自动化测试如何灵活地验证动态变化的response返回数据

嗨&#xff0c;我是兰若&#xff0c;很多小伙伴在针对动态返回的response&#xff0c;不知道怎么断言&#xff0c;今天教给大家几种方式&#xff0c;可以在接口自动化测试时确保测试的有效性和灵活性&#xff1a; 1. 断言静态字段 首先&#xff0c;您可以断言一些静态字段的值…

JS中map()使用记录

优点和缺点 总的来说&#xff0c;map() 方法是一个强大的工具&#xff0c;适合于需要将数组中的每个元素转换为新形式的情况。然而&#xff0c;对于性能敏感的应用或需要更复杂控制逻辑的场景&#xff0c;可能需要考虑其他方法。 优点&#xff1a; 函数式编程风格&#xff1a…

2024 微信小程序 学习笔记 第二天

1. WXML 模板语法 数据绑定 事件绑定 条件渲染 列表渲染 2. WXSS 模板样式 rpx 样式导入 全局和局部样式 3. 全局配置 window tabBar 配置tabBar案例 4. 网络数据请求 Get请求 Post 请求 加载时请求 5. 案例 -本地生活&#xff08;首页&#xff09; 导航栏 轮播图 九宫格效果…

webpack插件给所有的:src文件目录增加前缀

1.webpack4的版本写法 class AddPrefixPlugin {apply(compiler) {compiler.hooks.compilation.tap(AddPrefixPlugin, (compilation) > {HtmlWebpackPlugin.getHooks(compilation).beforeEmit.tapAsync(AddPrefixPlugin,(data, cb) > {// 使用正则表达式替换所有包含 /st…

【C语言】用队列实现栈

用两个队列&#xff08;先进先出&#xff09;实现一个栈&#xff08;后进先出&#xff09; 题目链接&#xff1a;https://leetcode.cn/problems/implement-stack-using-queues/description/ 1.C语言首先要造一个队列出来 2.两个队列实现栈&#xff0c;始终保持一个队列为空&…

无人机之环保监控篇

随着科技的不断进步&#xff0c;无人机作为一种创新的技术手段&#xff0c;在环保监控领域发挥着越来越重要的作用。 一、覆盖范围广 无人机能够轻松覆盖广阔的地理区域&#xff0c;无论是偏远的山区、广袤的森林还是大型的工业园区。相比传统的地面检测方式&#xff0c;其不…

关于promise的一些例题(运行步骤详细说明)

关于promise的一些例题(详细说明) 基本例题 // 直接运行 输出 1 2 const promise new Promise((resolve, reject) > {console.log(1);resolve();console.log(2); });// then后面放入微队列 promise.then(() > {console.log(3); });// 输出4 之后没有代码了所以运行为队…

vue中无法调试

vue.config.js中增加 devtool configureWebpack: {name: name,resolve: {alias: {: resolve(src)}},devtool: "cheap-module-source-map" // add},然后重启即可。 顺便招聘&#xff1a;1.需要会日语。2.Java&#xff0c;JS&#xff0c;Vue&#xff0c;DB任一会者皆…

Greenplum数据库中常用的赋予和回收权限

一 赋予表级权限&#xff1a; 使用GRANT语句可以向用户或角色赋予对指定表的权限。以下是一些常见的表级权限及其示例语句&#xff1a; 1 SELECT权限&#xff1a; 允许用户查询表中的数据。 GRANT SELECT ON table_name TO user_name; 2 INSERT权限&#xff1a; 允许用户向表中…

SpringBoot结合easypoi.excel,实现数据导出Excel

大多数业务项目中必然会遇到的一个需求&#xff0c;导出数据文件---Excel。 这里简单贴一下自己开发使用的方式方法&#xff0c;抛砖引玉。 也可小白直接大胆食用。 功能Maven依赖&#xff1a; <dependency><groupId>cn.afterturn</groupId><artifact…

mysql8.x 新增一个端口映射到当前服务(Windows)

1. 查看当前端口是否被占用。 netstat ano | findstr 33061 2.端口映射. netsh interface portproxy add v4tov4 listenport33061 listenaddress0.0.0.0 connectport3306 connectaddress192.168.1.xx 3. 创建一个用户&#xff08; myuser% %指的是所有IP都能访问&#xf…

17 敏捷开发—Scrum(2)

从上一篇 「16 敏捷开发实践&#xff08;1&#xff09;」中了解了Scrum是一个用于开发和维护复杂产品的框架&#xff0c;是一个增量的、迭代的开发过程。一般由多个Sprint&#xff08;迭代冲刺&#xff09;组成&#xff0c;每个Sprint长度一般为2-4周。下面全面介绍Scrumde 角色…

使用umi作为模板如何实现权限管理

三种权限管理的方法&#xff1a; 在做后台管理系统时&#xff0c;难免会使用到权限管理&#xff0c;权限管理方式有三种&#xff0c;分别是&#xff1a;路由、守卫、后端配合。 路由&#xff1a;通过动态路由&#xff0c;根据登录人员不同注册不同的路由&#xff0c;直接让没…

PostgreSQL 数据库 安装

1、官网下载 起源与发展&#xff1a;PostgreSQL最初起源于加州大学伯克利分校的Postgres项目&#xff0c;该项目始于1986年&#xff0c;并一直演进到1994年。在1995年&#xff0c;Postgres项目增加了SQL翻译程序&#xff0c;并更名为Postgres95。随后&#xff0c;在1996年&…