###### tags: `stream` `multiple camera streams` thread` `multithread` `串流` --- ## Streaming 系列筆記 - [[Streaming] GStreamer簡介與筆記](https://hackmd.io/@YungHuiHsu/ryhRTZpt3) - [[Streaming] 使用GStreamer Python API解析RTP與RTCP封包](https://hackmd.io/@YungHuiHsu/ryEMq3BT3) 其他stream相關文章 - [[python - speed up] How to speed up multiple camera streams simultaneously with multithreading<br>如何使用多執行序加速視訊(相機/錄影)串流](https://hackmd.io/@YungHuiHsu/BJr5SyYQn) --- [gstreamer/documentation](https://gstreamer.freedesktop.org/documentation/) # 基本概念 - chatgpt > GStreamer是一個基於管道的多媒體框架,用於創建流媒體應用程序。它具有以下基本概念: > > - 元素(Elements):GStreamer的基本組件被稱為元素。元素可以執行特定的多媒體操作,例如音頻解碼、視頻編碼、效果處理等。它們可以單獨工作或與其他元素連接以構建處理流媒體數據的管道[1]. > > - 管道(Pipeline):GStreamer使用管道來連接和處理多個元素,以完成複雜的工作流程。一個管道可以包含多個元素,並定義了數據的流向和處理步驟。開發者可以通過手動組裝元素來構建管道[1]. > > - 接口(Pad):元素之間的連接通過接口(pad)實現。pad是元素的輸入或輸出端口,負責接收和發送數據。每個元素可以有一個或多個輸入驅動和輸出驅動,用於與其他元素進行數據交換[4]. > > - 狀態(State):GStreamer的元素可以處於不同的狀態,例如停止狀態、播放狀態、暫停狀態等。狀態控制元素的執行和數據流動[6]. > > - 時鐘(Clock):GStreamer使用時鐘來控制媒體數據的同步和時間進度。時鐘提供精確的時序信息,確保音頻和視頻等媒體數據按預定的速率播放[1]. > > 通過組合不同的元素、設定管道和狀態,開發者可以使用GStreamer來實現各種多媒體應用程序,包括音頻回放、音頻和視頻播放、錄音、流媒體和音頻編輯等功能 ## FFmpeg v.s. GStreamer 熱門多媒體框架比較 | | FFmpeg | GStreamer | | -------- | --------------------------------------------------------------------------------- |:------------------------------------------------------------------------------------------------------------------------- | | 定義 | - 開源的跨平台多媒體框架 | - 開源的多媒體處理框架 | | 語言支持 | - 主要使用C語言<br>- 提供了多種語言的綁定和API | - 主要使用C語言<br>- 提供了多種語言的綁定和API | | 影音格式 | - 支持廣泛的音頻和視頻格式 | - 支持廣泛的音頻和視頻格式 | | 功能 | - 提供媒體處理、編解碼、轉換等功能 | - 提供媒體處理、編解碼、轉換等功能 | | 優點 | - 成熟穩定,有廣泛的社區支持<br>- 易於集成和使用<br>- 低級API,可以進行細粒度控制 | - 彈性配置和擴展性,易於自定義和擴展<br>- 跨平台支持,可在多種操作系統上運行<br>- 高級API和元素管道模型,更容易開發和管理 | | 缺點 | - 配置和使用複雜<br>- 缺乏內置的多媒體流管理和串流支持 | - 學習曲線較陡峭<br>- 部分元素的效能較低 | | 適用情境 | - 媒體編碼、解碼、格式轉換等基礎任務<br>- 要求對底層細節進行更多控制 | - 多媒體流管理和串流需求 <br>- 較靈活的配置和自定義的多媒體處理 | # 重要名詞簡介 ## 組件的基本定義和功能 階層式的管線設計Hierarchical pipelines - 容器中包含組件,以pads相連(Bins containing Elements, linked by Pads) <div style="text-align: center;"> <figure> <img src="https://gstreamer.freedesktop.org/documentation/application-development/basics/images/bin-element.png" alt="bin-element.png" width="600"> <figcaption><span style="color: grey; ">Gstreamer 中的Bin 、 Element 、 Pad關係圖</span></figcaption> </figure> </div> | 名稱 | 定義 | 功能 | | -------- | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------ | | pipeline | - GStreamer 的主要數據結構<br>- 用於建構元素的容器 | - 管理元素的流程和同步<br>- 提供播放、暫停、停止等控制功能 | | bin | - 特殊的 element<br>- 可以包含其他的 element 和 bin (子容器) | - 管理其內部的元素<br>- 提供元素間的連接和數據流動 | | element | - GStreamer 的基本組件<br>- 處理媒體數據的物件 | - 執行特定的媒體處理任務<br>- 如解碼、編碼、播放、捕獲等 | | pad | - 連接 element 的接口<br>- 允許數據在 element 之間流動 | - 提供元素間的數據傳輸<br>- 可以動態創建和釋放<br>- 有 "source" (輸出) 和 "sink" (輸入) 兩種類型 | ### Pad 在GStreamer中,Pad是用於元素之間數據傳輸的接口。每個元素可以包含一個或多個Pad,這些Pad負責接收和發送數據。Pad扮演著連接元素的橋梁,它將數據從一個元素的輸出/生產端(source pad)傳輸到另一個元素的輸入/消費端(sink pad) Pad具有以下特性和功能: * 數據傳輸:Pad負責管理數據的傳輸。源Pad從元素輸出數據,而接收器Pad接收並處理輸入數據 - Source(輸出/生產):輸出元素,產生和發送數據流 - Sink(輸入/消費):輸入元素,接收和處理來自其他元素的數據流 * Capabilities * Pad Capabilities定義了Pad所支持的數據類型和格式 * 通過定義Capabilities,Pad可以指定其所能處理的數據種類,如圖像格式、視頻分辨率、音頻采樣率等 * 靜態和動態Pad * 靜態Pad是在元素創建時就存在的,可以通過gst_element_get_static_pad()方法獲取 * 動態Pad是在運行時動態創建和刪除的。 * 連接 * Pad通過連接來實現元素之間的數據流 * 一個源Pad可以連接到一個或多個接收器Pad,但一個接收器Pad只能連接到一個源Pad - 探針 Pad Probes - 允許GStreamer應用程序監視和控制元素之間的數據流 ![](https://hackmd.io/_uploads/SkSTAO3B2.png =400x) - Ghost pad - 由於bin沒有pad,所以實際上仍得借助element的pad - 把element的pad轉給bin使用,這個過程就是建立ghost pad ![](https://hackmd.io/_uploads/HJUcXuYa3.png) 通過Pad的連接,GStreamer的元素可以形成數據處理管道。每個Pad都有特定的角色和功能,它們在數據傳輸和處理過程中發揮重要作用,使得不同元素能夠協同工作來完成多媒體數據的處理和流轉 ## Pipeline - 管道(Pipeline) - 一種bin - 通用容器(generic container),用於管理所含元素的同步和總線信息(bus messages)。頂層容器必須是一個管道(The toplevel bin has to be a pipeline),因此每個應用程序至少需要一個管道。 - 最高層的bin,和一般bin的差別是它提供介面給應用程式控制 - 實作上,每個pipe都是一個thread ![](https://hackmd.io/_uploads/rkNx-YnS2.png =800x) (https://en.wikipedia.org/wiki/GStreamer) ## Communication f ![](https://hackmd.io/_uploads/SJdbHuF63.png) ### Bus & Message ### Buffer --- ### [Basic tutorial](https://gstreamer.freedesktop.org/documentation/tutorials/basic/index.html?gi-language=python) #### [Basic tutorial 2: GStreamer concepts](https://gstreamer.freedesktop.org/documentation/tutorials/basic/concepts.html?gi-language=python) 元素是GStreamer的基本構造模組。 在數據從輸出(source)元素(數據生產者)流向輸入(sink)元素(數據消費者)的過程中,它們通過過濾元素對數據進行處理。 > The elements are GStreamer's basic construction blocks. They process the data as it flows downstream from the source elements (data producers) to the sink elements (data consumers), passing through filter elements. ![](https://hackmd.io/_uploads/HySHG_0Yn.png) 用來Gstreamer框架與應用程式間的溝通 ##### Element creation ``` # Create the elements source = Gst.ElementFactory.make("videotestsrc", "source") sink = Gst.ElementFactory.make("autovideosink", "sink") ``` ![](https://hackmd.io/_uploads/rynrG_RF2.png) ##### Error checking `GStreamer Bus`是 GStreamer 框架中的一個重要元件,它提供了一個機制來監視和處理 GStreamer pipeline 中的事件、訊息和錯誤。 ``` # Wait for EOS or error bus = pipeline.get_bus() msg = bus.timed_pop_filtered(Gst.CLOCK_TIME_NONE, Gst.MessageType.ERROR | Gst.MessageType.EOS) # Parse message if msg: if msg.type == Gst.MessageType.ERROR: err, debug_info = msg.parse_error() logger.error(f"Error received from element {msg.src.get_name()}: {err.message}") logger.error(f"Debugging information: {debug_info if debug_info else 'none'}") elif msg.type == Gst.MessageType.EOS: logger.info("End-Of-Stream reached.") else: # This should not happen as we only asked for ERRORs and EOS logger.error("Unexpected message received.") ``` > GStreamer Bus 的主要功能包括: > > - 事件(Events):Bus 可以接收來自 pipeline 的事件,例如 EOS(End of Stream)、EOS(End of Stream)、Seek 等。這些事件可以通知應用程式發生了什麼情況,並觸發適當的操作。 > > - 訊息(Messages):Bus 可以接收來自 pipeline 的各種訊息,例如警告、錯誤、狀態改變等。這些訊息提供了關於 pipeline 狀態和操作的資訊,應用程式可以根據這些訊息做出適當的回應。 > > - 監聽(Listening):應用程式可以透過註冊一個 Bus 監聽器(Bus Listener)來監聽 Bus 上的事件和訊息。監聽器可以接收並處理各種事件和訊息,以便應用程式做出適當的反應。 > > - 錯誤處理(Error Handling):當發生錯誤時,Bus 可以捕獲錯誤訊息並通知應用程式。這樣應用程式就可以採取適當的措施,例如回報錯誤、重新啟動 pipeline 或清理資源。 > > 使用 GStreamer Bus 可以讓應用程式更有效地監控和管理 GStreamer pipeline 的狀態和操作。通過監聽 Bus 上的事件和訊息,應用程式可以根據需要做出相應的處理,例如更新使用者介面、執行特定的動作或回報錯誤。 ### [Basic tutorial 3: Dynamic pipelines](https://gstreamer.freedesktop.org/documentation/tutorials/basic/dynamic-pipelines.html?gi-language=python) #### Muxer :::info 在流處理中,Muxer(多路复用器)是一個元件,用於將多個獨立的數據流合併成一個輸出數據流。 Muxer 的作用是將來自不同源的數據流進行整合,並根據特定的容器格式,將它們組織成一個單一的輸出流。它將不同類型的數據流進行交錯(interleave),以創建一個包含多個數據流的復合流。 在流處理中,Muxer 常用於創建多媒體容器格式(如 AVI、MP4、MKV)的文件。它將來自視訊、音訊、字幕等不同類型的數據流合併到單個容器文件中。這樣可以確保這些數據流在播放或傳輸過程中按照正確的順序進行處理。 Muxer 還可以為每個數據流提供時間戳、元數據和其他必要的信息,以確保在解封裝過程中正確解析和處理數據。 總結來說,Muxer 是一個用於合併多個獨立數據流的元件。它將不同類型的數據流整合成一個輸出流,常用於創建多媒體容器文件。Muxer 可以確保數據流按照正確的順序進行處理,並提供必要的信息以確保正確的解析和處理 ::: ![](https://hackmd.io/_uploads/S1hFtKAtn.png) Figure 2. A demuxer with two source pads. #### `Demuxer` 在 GStreamer 中,Demuxer 是一種元件(component),用於解析多媒體容器(例如 AVI、MP4、MKV 等)中的資料流。Demuxer 的作用是將容器中的多個資料流(例如視訊、音訊、字幕等)解析為獨立的資料流,以便後續元件進行相應的處理。 如果容器中包含多个stream(例如一段影片和2個音檔),Demuxer 會將它們分開,並通過不同的輸出埠(src pad)呈現出來。 這樣就可以在pipeline中創建不同的分支,分別處理不同類型的數據 > Demuxer 的工作原理是根據容器格式的規範,解析容器中的標頭(header)和資料(data)部分。它能夠識別出不同類型的資料流,並將這些資料流提供給相應的解碼器(Decoder)或其他元件進行後續處理。 > > Demuxer 具有以下特點和功能: > > * 容器解析:Demuxer 能夠識別不同的多媒體容器格式,包括但不限於 AVI、MP4、MKV、FLV 等。它能夠解析容器的結構,識別資料流的類型和位置。 > * > * 資料分離:Demuxer 能夠將容器中的多個資料流(如視訊、音訊、字幕等)分離出來。這樣後續的處理元件可以針對每個資料流進行不同的處理,例如解碼、播放、轉碼等。 > * > * 時序同步:Demuxer 在解析容器時,也會獲取相關的時間信息,以便進行時序同步。它能夠確定不同資料流之間的時間關係,以確保正確的時序和同步播放。 > * > * 元資料提取:Demuxer 可以提取容器中的元資料(metadata),如標題、作者、創建日 ![](https://hackmd.io/_uploads/rylqtYCF3.png) Figure 3. Example pipeline with two branches. ### [Basic tutorial 6: Media formats and Pad Capabilities](https://gstreamer.freedesktop.org/documentation/tutorials/basic/media-formats-and-pad-capabilities.html?gi-language=python#) #### Pads - `Pad Capabilities` from Chatgpt > 在GStreamer中,Pad Capabilities(端點能力)是一個重要的概念,用於描述媒體元件(例如視訊解碼器或音訊播放器)的端點(Pad)所支援的數據格式和屬性。 > > Pad是GStreamer中元件之間的連接點,用於數據的輸入和輸出。每個Pad都有一個或多個Capabilities,表示該Pad能夠處理的數據類型。Capabilities定義了數據的格式、編碼方式、解析度、幀率、聲道數等相關屬性。 > > Pad Capabilities具有以下功能和用法: > > - 數據格式支援:Pad Capabilities描述了Pad可以處理的數據格式。例如,一個視訊解碼器的輸入Pad的Capabilities可能指定它可以處理H.264或VP9編碼的視訊數據。 > > - 選擇最佳連接:在建立GStreamer管線時,根據元件的Pad Capabilities,系統可以自動選擇合適的連接關係。它會檢查不同元件的Pad Capabilities,找到能夠互相匹配的Pad,以確保數據能夠正確流動。 > > - 動態協商:當兩個元件的Pad Capabilities不完全匹配時,GStreamer提供了動態協商的機制。透過Caps Negotiation,元件可以通過交換和修改Capabilities的方式來協商合適的數據格式,以實現有效的數據流動。 > > - 功能擴展:Pad Capabilities還可以用於擴展元件的功能。例如,一個音訊解碼器的輸出Pad的Capabilities可以指定支援特定的音頻格式和聲道數,這樣其他元件可以根據這些Capabilities進行相應的後續處理。 > > 在使用GStreamer時,開發人員可以通過查詢、設置和比較Pad Capabilities來控制和管理數據流。這使得GStreamer具有靈活且高度可配置的特性,能夠處理各種不同的媒體數據格式和要求。 #### Pad templates #### 使用 `gst-inspect-1.0` 檢視pad的 Capabilities(簡寫為caps) --- ## [2020。Paul McWhorter。Jetson Xavier NX Lesson 4: Understanding Gstreamer for Absolute Beginners](https://www.youtube.com/watch?v=_yU1kfcC6rY) 白髮白鬍長得像肯德基爺爺,觀念講得很不錯,比起官方tutorial好上手,推! 以下為課程筆記 ### `gst-launch` 使用`gst-launch`建立stream 的 pipelie #### 執行範例音頻/音檔 ``` gst-launch-1.0 audiotestsrc ! alsasink ``` - 指令說明 `audiotestsrc` 是 `GStreamer` 中的元件(element),用於生成測試音頻數據。 `alsasink` 是 `GStreamer` 中的另一個元件,它用於將音頻數據寫入 `ALSA`(Advanced Linux Sound Architecture)音頻系統,並通過 `ALSA` 將數據播放到音頻設備。 它使用 `audiotestsrc` 作為輸出源,將測試音頻數據生成並輸出到 `alsasink`,然後 `alsasink` 將數據寫入 `ALSA` 音頻系統,從而使聲音播放出來。 使用 gst-launch-1.0 命令運行這個管道,您可以在命令行中執行此命令,以測試您的音頻設備是否正常工作,並聽到由 audiotestsrc 生成的測試音頻。 ### `gst-inspect` 檢視元件模塊的說明檔,會進入vim模式檢視(可用`q`退出) ``` gst-inspect-1.0 audiotestsrc ``` 由於是音訊,所以只有輸出(`src` pad),沒有輸入後面還可見音訊檔支援的格式(`audio/x-raw`) ``` Pad Templates: SRC template: 'src' Availability: Always Capabilities: audio/x-raw ``` ![](https://hackmd.io/_uploads/BJ6iC4TFn.png =600x) ![](https://hackmd.io/_uploads/B1Z004aYh.png =600x) ![](https://hackmd.io/_uploads/rJ9lyrpK3.png =600x) ##### 參數設置範例 - :warning: 參數的設置間一定要有` `空格(space)格開 - :o: `gst-launch-1.0 audiotestsrc ! alsasink` - :x: `gst-launch-1.0 audiotestsrc !alsasink` - no space between :`!` and `alsasink` 說明文件往下可看到`wave` 參數用於設置振盪器(oscillator)的波形類型 ``` wave : Oscillator waveform flags: readable, writable, controllable Enum "GstAudioTestSrcWave" Default: 0, "sine" (0): sine - Sine (1): square - Square ``` 在`audiotestsrc`元件後面加入`wave`參數即可指定用不同的聲波播放 ref : [精神時光屋 vol 1 - 3 "振盪器 Oscillator"](http://www.live4school.com/class/vol-1-3-oscillator.html) 可用 `wave=square` 或 `wave=1` ``` gst-launch-1.0 audiotestsrc wave=1 ! alsasink ``` ###### 其他參數範例: 這次加入`audio/x-raw`、`audioconvert`等,進行音頻格式轉換 ```bash (base) yunghui@tpea90113473:~$ gst-launch-1.0 audiotestsrc wave=0 freq=300 volume=0.5 ! audio/x-raw,format=U18LE ! audioconvert ! audio/x-raw,format=U8 ! alsasink Setting pipeline to PAUSED ... Pipeline is PREROLLING ... Redistribute latency... Pipeline is PREROLLED ... Setting pipeline to PLAYING ... New clock: GstAudioSinkClock ``` - chatgpt解釋 > 這個指令是使用 GStreamer 的 `gst-launch-1.0` 工具來建立一個音訊處理的流程。以下是指令中各個元件的功能與連接方式的簡要說明: > > - `audiotestsrc` 元件是一個內建的音訊測試源,它可以產生不同特徵的音訊信號。 > - `wave=0` 參數表示使用正弦波形。 > - `freq=300` 參數設定了輸出信號的頻率為 300 Hz。 > - `volume=0.5` 參數設定了輸出信號的音量為 0.5(範圍為 0.0 到 1.0)。 > > - `audioconvert` 元件用於進行音訊格式轉換,將來自 `audiotestsrc` 的音訊資料轉換為指定的格式。 > - `audio/x-raw,format=U18LE` 參數指定了音訊格式為 18 位元的無符號整數(little-endian)。 > > - `alsasink` 元件是 GStreamer 提供的 ALSA 音訊輸出元件,它將音訊資料輸出至 ALSA 音訊系統。 > - `audio/x-raw,format=U8` 參數指定了音訊格式為 8 位元的無符號整數。 > > 元件之間的連接使用 `!` 符號,表示將前一個元件的輸出連接到下一個元件的輸入。在這個指令中,從 `audiotestsrc` 元件的輸出,通過 `audioconvert` 元件的轉換,最終將音訊資料輸出到 `alsasink` 元件,再透過 ALSA 音訊系統播放出來。 > > 總結起來,這個指令的功能是產生一個頻率為 300 Hz 的正弦波音訊信號,將其轉換為 8 位元的無符號整數格式,並透過 ALSA 音訊系統播放出來。 #### 執行範例視頻/影片 ``` gst-launch-1.0 videotestsrc pattern=0 ! ximagesink ``` ![](https://hackmd.io/_uploads/HJOOP4CFh.png) - 參數說明 * `videotestsrc `元件是一個內建的視訊測試源,它可以產生不同類型的測試視訊圖案。 * `pattern=0` 參數表示使用標準的測試圖案(Pattern 0)。 * `ximagesink` 元件是 GStreamer 提供的 `X11` 視窗系統輸出元件,它可以將視訊資料顯示在 `X11` 視窗中。 * 元件之間的連接使用 `!` 符號,表示將前一個元件的輸出連接到下一個元件的輸入。在這個指令中,從 `videotestsrc` 元件的輸出,直接將視訊資料傳送到 `ximagesink` 元件,並在 `X11` 視窗中顯示出來。 * 總結起來,這個指令的功能是從內建的視訊測試源產生視訊圖案,並將其顯示在 `X11` 視窗中。 - 進一步設置輸出影片的參數,並用自動影片格式轉換元件 - `video/x-raw,format=RGB` 是 `videotestsrc` 元件的輸出格式,指定了輸出視訊的像素格式為 RGB。 - `autovideoconvert` 元件是一個自動視訊格式轉換元件。它會根據連接的元件需求,自動進行視訊格式的轉換,以確保連接的元件之間的視訊格式匹配。 ``` gst-launch-1.0 videotestsrc pattern=0 ! video/x-raw,format=RGB ! autovideoconvert ! ximagesink ``` - 指定影片的輸出尺寸與幀率 - `video/x-raw,width=1280,height=960,framerate=1/2`:這是指定視訊格式的輸出設定。這裡使用了 video/x-raw 格式,並設定了寬度為 1280 像素、高度為 960 像素,以及幀率為每秒 1/2 幀 ``` gst-launch-1.0 videotestsrc pattern=0 ! video/x-raw,format=RGB ! autovideoconvert ! video/x-raw,width=1280, height=960, framerate=1/2 ! ximagesink ``` - 如果參數中有`(`或`)` - 在 Bash shell 中,括號` (` 和 `)` 是有特殊含義的字符,因此在使用這些字符時需要進行適當的轉義或引用 - 使用引號`'`處理 ``` gst-launch-1.0 v4l2src ! nvvidconv ! 'video/ x-raw(memory:NVMM),width=640' ! autovideoconvert ! ximagesink ``` #### 建立一個簡單的音訊與視訊播放管線,並顯示頻譜分析圖 ``` gst-launch-1.0 audiotestsrc ! audioconvert ! autoaudiosink audiotestsrc wave=pink-noise ! spacescope ! videoconvert ! autovideosink ``` > `audiotestsrc ! audioconvert ! autoaudiosink` > 這部分建立了一個音訊播放器的部分。audiotestsrc 是一個 GStreamer 元件,用於生成測試音訊。`audioconvert` 是另一個元件,用於轉換音訊格式。`autoaudiosink` 則是音訊的輸出元件,會自動選擇系統上可用的音訊輸出裝置。整個部分的作用是將測試音訊生成並輸出到音訊輸出裝置。 > > `audiotestsrc wave=pink-noise ! spacescope` > 這部分也是建立音訊播放器的一部分。audiotestsrc 是一個測試音訊生成元件,而 `wave=pink-noise` 參數指定生成粉色噪音的音訊。spacescope 是一個 GStreamer 元件,用於顯示音訊的頻譜分析圖。這裡的作用是生成粉色噪音音訊並顯示其頻譜分析。 > ![](https://hackmd.io/_uploads/SJLebNz93.png) > `videoconvert ! autovideosink` > 這部分建立了視訊播放器的部分。videoconvert 是一個元件,用於轉換視訊格式。autovideosink 是視訊的輸出元件,會自動選擇系統上可用的視訊輸出裝置。整個部分的作用是將音訊的頻譜分析結果轉換為視訊並輸出到視訊輸出裝置。 --- # 學習資源 ## [gstreamer/Tutorials](https://gstreamer.freedesktop.org/documentation/tutorials/index.html?gi-language=python) ## [Guide to GStreamer Application Development Manual: CH1 to CH10](https://speakerdeck.com/wen_liao/guide-to-gstreamer-application-development-manual-ch1-to-ch10?slide=2) ## [LinuxConfAu 2018 - Sydney, Australia](https://www.youtube.com/watch?v=ZphadMGufY8)