GStreamer —— 2.5、Windows下Qt加載GStreamer庫后運行 - “教程5:GUI 工具包集成(gtk)“(附:完整源碼)

運行效果

在這里插入圖片描述

?

簡介

?????上一個教程演示了時間管理及seek操作。本教程介紹如何將 GStreamer 集成到圖形用戶中 接口 (GUI) 工具包,如 GTK+。基本上 GStreamer 負責媒體播放,而 GUI 工具包處理 用戶交互。最有趣的部分是那些 庫必須進行交互:指示 GStreamer 將視頻輸出到 GTK+ 窗口并將用戶作轉發到 GStreamer。特別是,您將學習:

??????????? 如何告訴 GStreamer 將視頻輸出到特定窗口 (而不是創建自己的窗口)。

??????????? 如何使用來自 GStreamer 的信息持續刷新 GUI。

??????????? 如何從 GStreamer 的多個線程更新 GUI,一個 在大多數 GUI 工具包上禁止作。

??????????? 一種僅訂閱您感興趣的消息的機制, 而不是收到所有通知。

?????我們將使用 GTK+ 工具包構建一個媒體播放器,但這些概念適用于其他 例如,像 Qt 這樣的工具包。最小值 了解 GTK+ 將有助于理解這一點 教程。重點是告訴 GStreamer 將視頻輸出到 我們的選擇。一個常見的問題是 GUI 工具包通常只允許對 通過主(或應用程序)線程的圖形“小部件”, 而 GStreamer 通常會生成多個線程來處理 不同的任務。從 的 SET SET THE S Ransomware 通常會失敗,因為回調在 調用 thread,它不需要是主線程。此問題 可以通過在回調中的 GStreamer 總線上發布消息來解決: 消息將由主線程接收,然后主線程將做出反應 因此。最后,到目前為止,我們已經注冊了一個函數,該函數得到了 每次公交車上出現消息時都打電話,這迫使我們 解析每條消息,看看我們是否對此感興趣。在本教程中 使用不同的方法為每種 消息,因此解析更少,整體代碼也更少。

?

GStreamer相關運行庫
INCLUDEPATH += D:/Software/GStreamer/1.0/mingw_x86_64/include/gstreamer-1.0/gst
INCLUDEPATH += D:/Software/GStreamer/1.0/mingw_x86_64/include
INCLUDEPATH += D:/Software/GStreamer/1.0/mingw_x86_64/include/gstreamer-1.0
INCLUDEPATH += D:/Software/GStreamer/1.0/mingw_x86_64/include/glib-2.0
INCLUDEPATH += D:/Software/GStreamer/1.0/mingw_x86_64/lib/glib-2.0/includeLIBS += D:/Software/GStreamer/1.0/mingw_x86_64/lib/gstreamer-1.0.lib
LIBS += D:/Software/GStreamer/1.0/mingw_x86_64/lib/glib-2.0.lib
LIBS += D:/Software/GStreamer/1.0/mingw_x86_64/lib/gobject-2.0.lib

?

GTK3 相關運行庫 - gtk官網下載安裝教程

?

完整源碼
#include <string.h>#include <gtk.h>
#include <gst.h>
#include <gdk.h>typedef struct _CustomData
{GstElement *playbin;            /* playbin元素 */GtkWidget *sink_widget;         /* 顯示視頻的窗口 */GtkWidget *slider;              /* 進度條滑塊控件 */GtkWidget *streams_list;        /* 顯示流信息的文本控件 */gulong slider_update_signal_id; /* 更新進度滑塊信號的ID */GstState state;                 /* 管道狀態 */gint64 duration;                /* 進度持續時間 */
} CustomData;/* 單擊“播放”按鈕時調用此函數 */
static void play_cb (GtkButton *button, CustomData *data)
{gst_element_set_state (data->playbin, GST_STATE_PLAYING);
}/* 單擊PAUSE按鈕時調用此函數 */
static void pause_cb (GtkButton *button, CustomData *data)
{gst_element_set_state (data->playbin, GST_STATE_PAUSED);
}/* 單擊STOP按鈕時調用此函數 */
static void stop_cb (GtkButton *button, CustomData *data)
{gst_element_set_state (data->playbin, GST_STATE_READY);
}/* 當主窗口關閉時調用此函數 */
static void delete_event_cb (GtkWidget *widget, GdkEvent *event, CustomData *data)
{stop_cb (NULL, data);gtk_main_quit ();
}/* 當滑塊改變其位置時,會調用此函數。我們在這里尋求新的職位。 */
static void slider_cb (GtkRange *range, CustomData *data)
{gdouble value = gtk_range_get_value (GTK_RANGE (data->slider));gst_element_seek_simple (data->playbin, (GstFormat)(GST_FORMAT_TIME), (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT), (gint64)(value * GST_SECOND));
}/* 這將創建組成我們應用程序的所有GTK+小部件,并注冊回調 */
static void create_ui (CustomData *data)
{/* 主窗口 */GtkWidget *main_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);g_signal_connect (G_OBJECT (main_window), "delete-event", G_CALLBACK (delete_event_cb), data);/* 播放按鈕 */GtkWidget *play_button = gtk_button_new_from_icon_name ("media-playback-start", GTK_ICON_SIZE_SMALL_TOOLBAR);g_signal_connect (G_OBJECT (play_button), "clicked", G_CALLBACK (play_cb), data);/* 暫停按鈕 */GtkWidget *pause_button = gtk_button_new_from_icon_name ("media-playback-pause", GTK_ICON_SIZE_SMALL_TOOLBAR);g_signal_connect (G_OBJECT (pause_button), "clicked", G_CALLBACK (pause_cb), data);/* 停止按鈕 */GtkWidget *stop_button = gtk_button_new_from_icon_name ("media-playback-stop", GTK_ICON_SIZE_SMALL_TOOLBAR);g_signal_connect (G_OBJECT (stop_button), "clicked", G_CALLBACK (stop_cb), data);/* 進度條滑塊控件 */data->slider = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL, 0, 100, 1);gtk_scale_set_draw_value (GTK_SCALE (data->slider), 0);data->slider_update_signal_id = g_signal_connect (G_OBJECT (data->slider), "value-changed", G_CALLBACK (slider_cb), data);/* 顯示流信息的文本控件 */data->streams_list = gtk_text_view_new ();gtk_text_view_set_editable (GTK_TEXT_VIEW (data->streams_list), FALSE);/* HBox用于按住按鈕和滑塊 */GtkWidget *controls = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);gtk_box_pack_start (GTK_BOX (controls), play_button, FALSE, FALSE, 2);gtk_box_pack_start (GTK_BOX (controls), pause_button, FALSE, FALSE, 2);gtk_box_pack_start (GTK_BOX (controls), stop_button, FALSE, FALSE, 2);gtk_box_pack_start (GTK_BOX (controls), data->slider, TRUE, TRUE, 2);/* HBox,用于容納視頻接收器和流信息文本小部件 */GtkWidget *main_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);gtk_box_pack_start (GTK_BOX (main_hbox), data->sink_widget, TRUE, TRUE, 0);gtk_box_pack_start (GTK_BOX (main_hbox), data->streams_list, FALSE, FALSE, 2);/* VBox用于容納main_hbox和控件 */GtkWidget *main_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);gtk_box_pack_start (GTK_BOX (main_box), main_hbox, TRUE, TRUE, 0);gtk_box_pack_start (GTK_BOX (main_box), controls, FALSE, FALSE, 0);gtk_container_add (GTK_CONTAINER (main_window), main_box);gtk_window_set_default_size (GTK_WINDOW (main_window), 640, 480);/* 顯示主窗口 */gtk_widget_show_all (main_window);
}/* 定期調用此函數以刷新GUI */
static gboolean refresh_ui (CustomData *data)
{gint64 current = -1;/* 除非我們處于暫停或播放狀態,否則我們不想更新任何內容 */if (data->state < GST_STATE_PAUSED){return TRUE;}/* 如果我們還不知道,請查詢流持續時間 */if (!GST_CLOCK_TIME_IS_VALID (data->duration)){if (!gst_element_query_duration (data->playbin, GST_FORMAT_TIME, &data->duration)){g_printerr ("Could not query current duration.\n");}else{/* 將滑塊的范圍設置為剪輯持續時間,單位為秒 */gtk_range_set_range (GTK_RANGE (data->slider), 0, (gdouble)data->duration / GST_SECOND);}}if (gst_element_query_position (data->playbin, GST_FORMAT_TIME, &current)){/* 阻止“值已更改”信號,因此不調用slider_cb函數(這將觸發用戶未請求的尋道) */g_signal_handler_block (data->slider, data->slider_update_signal_id);/* 將滑塊的位置設置為當前管道位置,單位為秒 */gtk_range_set_value (GTK_RANGE (data->slider), (gdouble)current / GST_SECOND);/* 重新啟用信號 */g_signal_handler_unblock (data->slider, data->slider_update_signal_id);}return TRUE;
}/* 當在流中發現新的元數據時,會調用此函數 */
static void tags_cb (GstElement *playbin, gint stream, CustomData *data)
{/* 我們可能處于GStreamer工作線程中,因此我們通過總線中的消息通知主線程此事件 */gst_element_post_message (playbin, gst_message_new_application (GST_OBJECT (playbin), gst_structure_new_empty ("tags-changed")));
}/* 當總線上發布錯誤消息時,會調用此函數 */
static void error_cb (GstBus *bus, GstMessage *msg, CustomData *data)
{GError *err;gchar *debug_info;/* 在屏幕上打印錯誤詳細信息 */gst_message_parse_error (msg, &err, &debug_info);g_printerr ("Error received from element %s: %s\n", GST_OBJECT_NAME (msg->src), err->message);g_printerr ("Debugging information: %s\n", debug_info ? debug_info : "none");g_clear_error (&err); g_free (debug_info);/* 將管道設置為READY(停止播放) */gst_element_set_state (data->playbin, GST_STATE_READY);
}/* 當總線上發布流結束消息時,會調用此函數。我們只是將管道設置為READY(停止播放) */
static void eos_cb (GstBus *bus, GstMessage *msg, CustomData *data)
{g_print ("End-Of-Stream reached.\n");gst_element_set_state (data->playbin, GST_STATE_READY);
}/* 當管道狀態發生變化時,會調用此函數。我們用它來跟蹤當前狀態。 */
static void state_changed_cb (GstBus *bus, GstMessage *msg, CustomData *data)
{GstState old_state, new_state, pending_state;gst_message_parse_state_changed (msg, &old_state, &new_state, &pending_state);if (GST_MESSAGE_SRC (msg) == GST_OBJECT (data->playbin)){data->state = new_state;g_print ("State set to %s\n", gst_element_state_get_name (new_state));if (old_state == GST_STATE_READY && new_state == GST_STATE_PAUSED){/* 為了提高響應速度,我們在達到PAUSED狀態后立即刷新GUI */refresh_ui (data);}}
}/* 從所有流中提取元數據并將其寫入GUI中的文本小部件 */
static void analyze_streams (CustomData *data)
{/* 清理小部件的當前內容 */GtkTextBuffer *text = gtk_text_view_get_buffer (GTK_TEXT_VIEW (data->streams_list));gtk_text_buffer_set_text (text, "", -1);/* 閱讀一些屬性 */gint n_video, n_audio, n_text;g_object_get (data->playbin, "n-video", &n_video, NULL);g_object_get (data->playbin, "n-audio", &n_audio, NULL);g_object_get (data->playbin, "n-text", &n_text, NULL);guint rate;gchar *str, *total_str;GstTagList *tags;for (gint i = 0; i < n_video; i++){tags = NULL;/* 檢索流的視頻標簽 */g_signal_emit_by_name (data->playbin, "get-video-tags", i, &tags);if (tags){total_str = g_strdup_printf ("video stream %d:\n", i);gtk_text_buffer_insert_at_cursor (text, total_str, -1);g_free (total_str);gst_tag_list_get_string (tags, GST_TAG_VIDEO_CODEC, &str);total_str = g_strdup_printf ("  codec: %s\n", str ? str : "unknown");gtk_text_buffer_insert_at_cursor (text, total_str, -1);g_free (total_str);g_free (str);gst_tag_list_free (tags);}}for (gint i = 0; i < n_audio; i++){tags = NULL;/* 檢索流的音頻標簽 */g_signal_emit_by_name (data->playbin, "get-audio-tags", i, &tags);if (tags){total_str = g_strdup_printf ("\naudio stream %d:\n", i);gtk_text_buffer_insert_at_cursor (text, total_str, -1);g_free (total_str);if (gst_tag_list_get_string (tags, GST_TAG_AUDIO_CODEC, &str)){total_str = g_strdup_printf ("  codec: %s\n", str);gtk_text_buffer_insert_at_cursor (text, total_str, -1);g_free (total_str);g_free (str);}if (gst_tag_list_get_string (tags, GST_TAG_LANGUAGE_CODE, &str)){total_str = g_strdup_printf ("  language: %s\n", str);gtk_text_buffer_insert_at_cursor (text, total_str, -1);g_free (total_str);g_free (str);}if (gst_tag_list_get_uint (tags, GST_TAG_BITRATE, &rate)){total_str = g_strdup_printf ("  bitrate: %d\n", rate);gtk_text_buffer_insert_at_cursor (text, total_str, -1);g_free (total_str);}gst_tag_list_free (tags);}}for (gint i = 0; i < n_text; i++){tags = NULL;/* 檢索流的字幕標簽 */g_signal_emit_by_name (data->playbin, "get-text-tags", i, &tags);if (tags){total_str = g_strdup_printf ("\nsubtitle stream %d:\n", i);gtk_text_buffer_insert_at_cursor (text, total_str, -1);g_free (total_str);if (gst_tag_list_get_string (tags, GST_TAG_LANGUAGE_CODE, &str)){total_str = g_strdup_printf ("  language: %s\n", str);gtk_text_buffer_insert_at_cursor (text, total_str, -1);g_free (total_str);g_free (str);}gst_tag_list_free (tags);}}
}/* 當總線上發布“應用程序”消息時,會調用此函數。在這里,我們檢索tags_cb回調發出的消息 */
static void application_cb (GstBus *bus, GstMessage *msg, CustomData *data)
{if (g_strcmp0 (gst_structure_get_name (gst_message_get_structure (msg)), "tags-changed") == 0){/* 如果消息是“標簽已更改”(我們目前只發布一個),請更新流信息GUI */analyze_streams (data);}
}int main(int argc, char *argv[])
{CustomData data;memset (&data, 0, sizeof (data));data.duration = GST_CLOCK_TIME_NONE;/* 初始化GTK */gtk_init (&argc, &argv);/* 初始化GStreamer */gst_init (&argc, &argv);/* 創建元素 */data.playbin = gst_element_factory_make ("playbin", "playbin");GstElement *videosink = gst_element_factory_make ("glsinkbin", "glsinkbin");GstElement *gtkglsink = gst_element_factory_make ("gtkglsink", "gtkglsink");/* 創建了GTK Sink元素,它將為我們提供一個GTK小部件,GStreamer將在其中渲染視頻,我們可以將其添加到UI中。嘗試創建OpenGL版本的視頻接收器,如果失敗則回退*/if (gtkglsink != NULL && videosink != NULL){g_printerr ("Successfully created GTK GL Sink");g_object_set (videosink, "sink", gtkglsink, NULL);/* gtkglsink為我們創建gtk小部件。這可以通過屬性訪問。 */g_object_get (gtkglsink, "widget", &data.sink_widget, NULL);}else{g_printerr ("Could not create gtkglsink, falling back to gtksink.\n");videosink = gst_element_factory_make ("gtksink", "gtksink");g_object_get (videosink, "widget", &data.sink_widget, NULL);}if (!data.playbin || !videosink) { g_printerr ("Not all elements could be created.\n"); return -1; }/* 設置播放源 */g_object_set (data.playbin, "uri", "https://gstreamer.freedesktop.org/data/media/sintel_trailer-480p.webm", NULL);/* 設置video-sink  */g_object_set (data.playbin, "video-sink", videosink, NULL);/* 連接到playbin中的信號 */g_signal_connect (G_OBJECT (data.playbin), "video-tags-changed", (GCallback) tags_cb, &data);g_signal_connect (G_OBJECT (data.playbin), "audio-tags-changed", (GCallback) tags_cb, &data);g_signal_connect (G_OBJECT (data.playbin), "text-tags-changed", (GCallback) tags_cb, &data);/* 創建ui */create_ui (&data);/* 指示總線為每條接收到的消息發出信號,并連接到感興趣的信號 */GstBus *bus = gst_element_get_bus (data.playbin);gst_bus_add_signal_watch (bus);g_signal_connect (G_OBJECT (bus), "message::error", (GCallback)error_cb, &data);g_signal_connect (G_OBJECT (bus), "message::eos", (GCallback)eos_cb, &data);g_signal_connect (G_OBJECT (bus), "message::state-changed", (GCallback)state_changed_cb, &data);g_signal_connect (G_OBJECT (bus), "message::application", (GCallback)application_cb, &data);gst_object_unref (bus);/* 開始播放 */GstStateChangeReturn ret = gst_element_set_state (data.playbin, GST_STATE_PLAYING);if (ret == GST_STATE_CHANGE_FAILURE){g_printerr ("Unable to set the pipeline to the playing state.\n");gst_object_unref (data.playbin); gst_object_unref (videosink); return -1;}/* 注冊一個每秒都會調用的定時器函數 */g_timeout_add_seconds (1, (GSourceFunc)refresh_ui, &data);/* 啟動GTK主循環。在調用gtk_main_quit之前,我們不會重新獲得控制權 */gtk_main ();/* 釋放資源 */gst_element_set_state (data.playbin, GST_STATE_NULL);gst_object_unref (data.playbin);gst_object_unref (videosink);return 0;
}

?

關注

筆者 - jxd

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/71753.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/71753.shtml
英文地址,請注明出處:http://en.pswp.cn/web/71753.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

NLTK和jieba

NLTK與jieba概述 自然語言處理&#xff08;NLP&#xff09;領域是計算機科學領域與人工智能領域中的一個重要方向&#xff0c;主要研究方向是實現人與計算機之間用自然語言進行有效通信的各種理論和方法。 在自然語言處理領域中&#xff0c;文本類型的數據占據著很大的市場&a…

linux查看定時任務與設置定時任務

一、查看定時任務 使用 cron 查看當前用戶的定時任務&#xff1a; bash crontab -l # 查看當前用戶的cron任務 查看系統級定時任務&#xff1a; bash 系統級任務通常存放在以下位置&#xff1a; cat /etc/crontab # 系統主配置文件 ls /etc/cron.d/ # 系統級任務片段 ls /…

DeepSeek-R1本地化部署(Mac)

一、下載 Ollama 本地化部署需要用到 Ollama&#xff0c;它能支持很多大模型。官方網站&#xff1a;https://ollama.com/ 點擊 Download 即可&#xff0c;支持macOS,Linux 和 Windows&#xff1b;我下載的是 mac 版本&#xff0c;要求macOS 11 Big Sur or later&#xff0c;Ol…

支持向量簡要理解

決策方程符合感知機區分理論&#xff0c;我們基于線性代數來看這滿足子空間理論&#xff0c;可以獲取得到超平面。 支持向量機的目標是尋找最與超平面最近的點的最大距離&#xff0c;而距離計算如上&#xff0c;符合數學上計算點到線&#xff08;面&#xff09;的距離公式。 …

使用OpenCV和MediaPipe庫——實現人體姿態檢測

目錄 準備工作如何在Windows系統中安裝OpenCV和MediaPipe庫&#xff1f; 安裝Python 安裝OpenCV 安裝MediaPipe 驗證安裝 代碼邏輯 整體代碼 效果展示 準備工作如何在Windows系統中安裝OpenCV和MediaPipe庫&#xff1f; 安裝Python 可以通過命令行運行python --versio…

5G學習筆記之BWP

我們只會經歷一種人生&#xff0c;我們選擇的人生。 參考&#xff1a;《5G NR標準》、《5G無線系統指南:如微見著&#xff0c;賦能數字化時代》 目錄 1. 概述2. BWP頻域位置3. 初始與專用BWP4. 默認BWP5. 切換BWP 1. 概述 在LTE的設計中&#xff0c;默認所有終端均能處理最大2…

創建Electron35 + vue3 + electron-builder項目,有很過坑,記錄過程

環境&#xff1a; node v20.18.0 npm 11.1.0 用到的所有依賴&#xff1a; "dependencies": {"core-js": "^3.8.3","vue": "^3.2.13","vue-router": "^4.5.0"},"devDependencies": {"ba…

Linux下安裝elasticsearch(Elasticsearch 7.17.23)

Elasticsearch 是一個分布式的搜索和分析引擎&#xff0c;能夠以近乎實時的速度存儲、搜索和分析大量數據。它被廣泛應用于日志分析、全文搜索、應用程序監控等場景。 本文將帶你一步步在 Linux 系統上安裝 Elasticsearch 7.17.23 版本&#xff0c;并完成基本的配置&#xff0…

NVIDIA顯卡驅動、CUDA、cuDNN 和 TensorRT 版本匹配指南

一、驅動安裝 1、下載驅動 前往NVIDIA驅動下載頁&#xff0c;輸入顯卡型號和操作系統類型&#xff0c;選擇≥目標CUDA版本要求的驅動版本?。 2、安裝驅動? ?Windows?&#xff1a;雙擊安裝包按向導操作。?Linux?&#xff1a;建議使用apt或官方.run文件安裝?。 3、驗證…

plt和cv2有不同的圖像表示方式和顏色通道順序

在處理圖像時&#xff0c;matplotlib.pyplot (簡稱 plt) 和 OpenCV (簡稱 cv2) 有不同的圖像表示方式和顏色通道順序。了解這些區別對于正確處理和顯示圖像非常重要。 1. 圖像形狀和顏色通道順序 matplotlib.pyplot (plt) 形狀&#xff1a;plt 通常使用 (height, width, cha…

基于PyTorch的深度學習5——神經網絡工具箱

可以學習如下內容&#xff1a; ? 介紹神經網絡核心組件。 ? 如何構建一個神經網絡。 ? 詳細介紹如何構建一個神經網絡。 ? 如何使用nn模塊中Module及functional。 ? 如何選擇優化器。 ? 動態修改學習率參數。 5.1 核心組件 神經網絡核心組件不多&#xff0c;把這些…

模擬調制技術詳解

內容摘要 本文系統講解模擬調制技術原理及Matlab實現&#xff0c;涵蓋幅度調制的四種主要類型&#xff1a;雙邊帶抑制載波調幅&#xff08;DSB-SC&#xff09;、含離散大載波調幅&#xff08;AM&#xff09;、單邊帶調幅&#xff08;SSB&#xff09;和殘留邊帶調幅&#xff08;…

aws(學習筆記第三十一課) aws cdk深入學習(batch-arm64-instance-type)

aws(學習筆記第三十一課) aws cdk深入學習 學習內容&#xff1a; 深入練習aws cdk下部署batch-arm64-instance-type 1. 深入練習aws cdk下部署batch-arm64-instance-type 代碼鏈接 代碼鏈接 代碼鏈接 -> batch-arm64-instance-type之前代碼學習 之前學習代碼鏈接 -> aw…

讀書報告」網絡安全防御實戰--藍軍武器庫

一眨眼&#xff0c;20天過去了&#xff0c;刷完了這本書「網絡安全防御實戰--藍軍武器庫」&#xff0c;回味無窮&#xff0c;整理概覽如下&#xff0c;可共同交流讀書心得。在閱讀本書的過程中&#xff0c;我深刻感受到網絡安全防御是一個綜合性、復雜性極高的領域。藍軍需要掌…

生成任務,大模型

一個生成項目 輸入&#xff1a;文字描述&#xff08;但是給的數據集是一串數字&#xff0c;id&#xff0c;ct描述&#xff0c;醫生描述&#xff09; 輸出&#xff1a;診斷報告 一、數據處理 import pandas as pd #處理表格數據pre_train_file "data/train.csv"tr…

Spring Boot API 項目中 HAProxy 與 Nginx 的選擇與實踐

在開發 Spring Boot 構建的 RESTful API 項目時&#xff0c;負載均衡和反向代理是提升性能與可用性的關鍵環節。HAProxy 和 Nginx 作為兩種流行的工具&#xff0c;經常被用于流量分發&#xff0c;但它們各有側重。究竟哪一個更適合你的 Spring Boot API 項目&#xff1f;本文將…

Java常用集合與映射的線程安全問題深度解析

Java常用集合與映射的線程安全問題深度解析 一、線程安全基礎認知 在并發編程環境下&#xff0c;當多個線程同時操作同一集合對象時&#xff0c;若未采取同步措施&#xff0c;可能導致以下典型問題&#xff1a; 數據競爭&#xff1a;多個線程同時修改數據導致結果不可預測狀…

DeepLabv3+改進6:在主干網絡中添加SegNext_Attention|助力漲點

??【DeepLabv3+改進專欄!探索語義分割新高度】 ?? 你是否在為圖像分割的精度與效率發愁? ?? 本專欄重磅推出: ? 獨家改進策略:融合注意力機制、輕量化設計與多尺度優化 ? 即插即用模塊:ASPP+升級、解碼器 PS:訂閱專欄提供完整代碼 目錄 論文簡介 步驟一 步驟二…

使用 Elastic-Agent 或 Beats 將 Journald 中的 syslog 和 auth 日志導入 Elastic Stack

作者&#xff1a;來自 Elastic TiagoQueiroz 我們在 Elastic 一直努力將更多 Linux 發行版添加到我們的支持矩陣中&#xff0c;現在 Elastic-Agent 和 Beats 已正式支持 Debian 12&#xff01; 本文演示了我們正在開發的功能&#xff0c;以支持使用 Journald 存儲系統和身份驗…

3.9[A]csd

在傳統CPU中心架構中&#xff0c;中央處理器通過內存訪問外部存儲器&#xff0c;而數據必須經過網絡接口卡才能到達外部存儲器。這種架構存在集中式計算、DRAM帶寬和容量挑戰、大量數據移動&#xff08;服務器內和網絡&#xff09;以及固定計算導致工作負載容量增長等問題。 而…