Posted on

OBS開啟時可使用的相關指令

官方介紹

官方啟動指令介紹頁面: https://obsproject.com/kb/launch-parameters

如何使用啟動指令

要使用自定義啟動參數創建 OBS Studio 的捷徑:

  1. 複製一個指向 OBS Studio 的捷徑,或選擇一個已存在的捷徑(從「開始」菜單、工作欄等處)。
  2. 右鍵點擊捷徑,然後點擊「屬性」。
  3. 在目標欄位中,obs64.exe 路徑後面添加啟動參數(如左圖所示)。

若要通過計劃任務或其他自動方式啟動 OBS Studio,請確保也設置了工作目錄(「開始於…」),該目錄必須指向 obs64.exe 所在的文件夾。

啟動參數介紹

OBS Studio 支援的啟動參數(Launch Parameters)。這些參數用於自動化和便攜式使用。每個參數都有特定的功能,可以在啟動 OBS Studio 時進行特定的操作或設定。

參數及其描述如下:

  • --help, -h:獲取可用參數的列表。
  • --version, -v:獲取 OBS 的版本。
  • --startstreaming:自動開始直播。
  • --startrecording:自動開始錄影。
  • --startvirtualcam:自動開始虛擬攝影機。
  • --startreplaybuffer:自動開始重播緩存。
  • --collection "name":使用指定的場景集合啟動。
  • --profile "name":使用指定的配置檔啟動。
  • --scene "name":使用指定的場景啟動。
  • --studio-mode:啟動時啟用 Studio 模式。
  • --minimize-to-tray:啟動時最小化到系統托盤。
  • --portable, -p:使用便攜模式。
  • --multi, -m:啟動多個實例時不顯示警告。
  • --always-on-top:啟動時開啟「總在最前面」模式。
  • --verbose:使日誌更詳細。
  • --unfiltered_log:禁用日誌過濾(不抑制重複行)。
  • --disable-updater:禁用內置更新器(僅限 Windows/macOS)。
  • --allow-opengl:在 Windows 上允許 OpenGL 渲染器。
  • --only-bundled-plugins:僅使用內建模組啟動。
  • --safe-mode:強制 OBS 以安全模式啟動,禁用所有第三方插件、腳本和 WebSockets。
  • --disable-shutdown-check:禁用不潔關機檢測,該檢測會提示以安全模式啟動。
  • --disable-missing-files-check:禁用啟動時可能出現的缺失文件對話框。

這些參數提供了更多的控制和靈活性,使使用者可以根據自己的需求和工作流程自定義 OBS Studio 的啟動和運行方式。

Posted on

JavaScript H.264 解碼器介紹 – Broadway

Broadway介紹

Broadway 是一個 JavaScript H.264 解碼器。H.264 是一個廣泛使用的視頻壓縮標準,Broadway 提供了一種在瀏覽器中,特別是不支持該格式的瀏覽器中,直接解碼 H.264 視頻的能力。

主要特點

  1. 純JavaScript:Broadway 是完全用 JavaScript 寫的,這意味著它可以在任何支持 JavaScript 的平台上運行,不需要任何外部插件或擴展。
  2. 多線程支持:Broadway 可以在主線程上運行,也可以在背景工作線程上運行,從而提高性能和響應性。
  3. 網頁集成:使用 Broadway,開發者可以輕鬆地在網頁上集成 H.264 視頻播放功能,無需依賴外部播放器或插件。

Live Demo

當首次訪問上述示範頁面時,可能會感覺視頻播放器的速度有點慢,這是因為它需要首先下載整個視頻才能開始播放。但請有耐心,一旦視頻下載完畢,您可以點擊播放器來觀看視頻。

上面的左上角播放器在主線程上運行,而其餘的播放器在背景工作線程上運行。

本機端使用範例

把Player資料夾內的檔案下載下來,放進本地端的node.js專案的Player資料夾內

檔案連結: https://github.com/mbebenita/Broadway/tree/master/Player

接著撰寫node.js程式

const express = require('express');
const http = require('http');
const path = require('path');
const socketio = require('socket.io');

let eApp = express();
let server = http.Server(eApp);
let io = socketio(server, { pingInterval: 3000, pingTimeout: 60000 });

// 設定靜態檔案的路徑
eApp.use(express.static(path.join(__dirname, '..', 'Player')));

io.on('connection', (socket) => {
    console.log('A user connected');
    socket.on('disconnect', () => {
        console.log('A user disconnected');
    });
});

let config = {
    port: 8080  // 依您的URL端口設定為8080
};
server.listen(config.port, '0.0.0.0', () => {
    let address = server.address();
    console.log(`Server running at ${address.address}:${address.port}`);
});

接著開啟電腦的http://127.0.0.1:8080/treeDemo.html,就可以在本機運行可動的範例了

Posted on

幾個使用PYAV的簡單範例

使用PYAV的前提

PyAV 是FFmpeg函式庫的 Pythonic 綁定。目標是提供底層庫的所有功能和控制,但盡可能管理細節。

PyAV 可透過容器、串流、封包、編解碼器和影格直接、精確地存取您的媒體。它公開了該資料的一些轉換,並幫助您將資料傳入/傳出其他套件(例如 Numpy 和 Pillow)。

這種權力確實伴隨著一些責任,因為與媒體合作非常複雜,PyAV 無法將其抽象化或為您做出所有最佳決策。如果該ffmpeg命令無需您竭盡全力即可完成工作,那麼 PyAV 可能會成為障礙而不是幫助。

所以如果我們想要在推流前處理串流、或者是拉流後處理串流內容,或者是更改串流編碼的相關資訊等【較難直接使用ffmpeg指令達到的事情時】,才較適合使用PYAV。

用RTMP的方式推流

範例程式碼如下:

import av
import asyncio
import cv2
import numpy as np
import threading
import time
from av import VideoFrame
from av.codec import CodecContext

# Define the RTMP server URL
rtmp_url = 'rtmp://127.0.0.1/live/test1'  # Replace with your RTMP server URL

# Function to capture webcam frames and push to RTMP server
def capture_and_push():
    # Open the video capture device (webcam)
    cap = cv2.VideoCapture(0)

    # Create an output container for the RTMP stream
    output_container = av.open(rtmp_url, 'w', format='flv')

    # Set up video stream parameters
    video_stream = output_container.add_stream('h264', rate=30)
    video_stream.width = 640
    video_stream.height = 480
    # Create a codec context for H.264 encoding
    codecContext = CodecContext.create('h264', 'w')

    # Create a thread for encoding and pushing frames
    def encode_and_push_frames():
        while True:
            ret, frame = cap.read()
            if not ret:
                break

            # Convert the frame to a VideoFrame
            frame = VideoFrame.from_ndarray(frame, format='bgr24')
            frame.pts = frame.pts
            frame.time_base = frame.time_base

            # Encode the frame and write it to the output container
            packet = video_stream.encode(frame)
            
            output_container.mux(packet)

    encode_thread = threading.Thread(target=encode_and_push_frames)
    encode_thread.start()

    # Wait for the encode thread to finish
    encode_thread.join()

    # Release the video capture device and close the output container
    cap.release()
    output_container.close()

if __name__ == "__main__":
    capture_and_push()

輸出透明背景的影片

若要使用 pyav (Python 的 ffmpeg/avconv 綁定) 來輸出具有透明背景的影片,你通常會使用像 ProRes 4444 或者 VP9 (與 WebM 容器一同使用) 這類的編碼器,因為它們支持 alpha 通道 (透明度)。

import av
import numpy as np

# 定義影片參數
width, height = 640, 480
duration = 5  # seconds
fps = 30
total_frames = duration * fps

# 創建輸出容器和流
container = av.open('output.webm', mode='w')
stream = container.add_stream('libvpx-vp9', rate=fps)
stream.width = width
stream.height = height
stream.pix_fmt = 'yuv420p'

# 產生影片框,這裡僅作為範例用透明背景
for frame_idx in range(total_frames):
    # 創建一個全透明的框
    img = np.zeros((height, width, 4), dtype=np.uint8)
    
    # 只是一個範例,所以在畫面中央畫一個半透明的紅色圓
    center_x, center_y = width // 2, height // 2
    radius = min(width, height) // 4
    y, x = np.ogrid[-center_y:height-center_y, -center_x:width-center_x]
    mask = x*x + y*y <= radius*radius
    img[mask] = [255, 0, 0, 128]  # Semi-transparent red
    
    # 轉換成 AVFrame 和寫入流
    frame = av.VideoFrame.from_ndarray(img, format='rgba')
    for packet in stream.encode(frame):
        container.mux(packet)

# 結束編碼
for packet in stream.encode():
    container.mux(packet)

container.close()

在串流裡增加自定義的變數

pyav裡面的frame.side_data是一個屬性,它通常包含與該幀(幀)相關的附加資訊。這些資訊可能包括但不限於:

  1. 動態範圍資訊
  2. 運動向量資訊(對於某些視訊編解碼器)
  3. 其他 FFmpeg 內部為特定編解碼器或格式定義的元數據

舉個例子,如果你正在解碼一個使用 HEVC(或稱為 H.265)編碼的視訊串流,frame.side_data可能會包含關於這一幀的 HDR 元資料(如果該視訊支援 HDR)。

通常情況下,大多數應用程式可能不需要直接讀取side_data。但是,對於需要細節控製或分析的應用程序,這是一個非常有用的屬性。

import av
import pyav
import threading

# Define the source RTMP URL and destination RTMP URL
source_url = 'rtmp://127.0.0.1/live/test1'
destination_url = 'rtmp://127.0.0.1/live/test2'

# Create an input container for the source RTMP stream
input_container = av.open(source_url, mode='r')

# Create an output container for the destination RTMP stream
output_container = av.open(destination_url, mode='w')

# Set up a video encoder for H.264
video_stream = output_container.add_stream('h264', rate=30)
video_stream.options['x264opts'] = 'nal-hrd=cbr'
video_stream.options['c:v'] = 'libx264'

# Define a SEI message to add to the video frames (modify this as needed)
sei_data = b'Some SEI Data'

# Function to add SEI data to frames and write to the output
def process_frames():
    for packet in input_container.demux():
        if packet.stream.type == 'video':
            for frame in packet.decode():
                # Add SEI data to the frame
                frame.side_data['sei'] = sei_data
                # Encode and write the frame to the output
                output_container.mux(packet)

# Create a thread to process and write frames
frame_thread = threading.Thread(target=process_frames)

try:
    # Start the frame processing thread
    frame_thread.start()

    # Run the main loop to write the output to the destination RTMP stream
    while True:
        output_container.mux(output_container.recv())
except (KeyboardInterrupt, pyav.AVError):
    pass
finally:
    # Clean up resources and close the containers
    frame_thread.join()
    input_container.close()
    output_container.close()

Posted on

pyav介紹

甚麼是pyav

PyAV是FFmpeg的Python封裝,旨在提供底層庫的全部功能和控制,同時盡可能管理繁瑣的細節。PyAV用於直接和精確地訪問媒體,包括容器、流、封包、編解碼器和幀。它還提供了一些數據轉換功能,並幫助您在其他程序之間傳送數據(例如Numpy和Pillow)。

然而,由於媒體處理非常複雜,PyAV無法完全抽像或為您做出所有最佳決策。 如果FFmpeg命令可以滿足您的需求,那麼PyAV可能會成為阻礙。 但在必要時,PyAV是一項關鍵工具。安裝PyAV可能有一些複雜的依賴關係,但現在可以在PyPI上找到針對Linux、Mac和Windows的二進位安裝套件。

官方網站: https://pyav.org/docs/stable/

GitHub位置: https://github.com/PyAV-Org/PyAV

建議使用場景

pyAVffmpeg 都是用來處理影音的工具,但它們的使用場景和方法有所不同。以下是對兩者的比較,以及根據不同情境的建議:

  1. 使用介面
    • pyAV:是一個 Python 函式庫,允許開發者使用 Python 語言來操作影音資料。
    • ffmpeg:是一個命令行工具,通常被用於進行批量處理或在沒有 Python 環境的系統上執行。
  2. 易用性和彈性
    • pyAV:由於是 Python 函式庫,使用者可以利用 Python 語言的所有特性來進行更複雜的操作,比如條件式處理、迴圈等。這使得對於需要更細緻操作的場景,例如資料分析、特定範圍的編輯等,pyAV 更有優勢。
    • ffmpeg:對於直接和簡單的影音轉換、剪裁、合併等操作,ffmpeg 的命令行界面非常適用。它能夠快速完成大部分的基本任務。
  3. 整合和擴展性
    • 如果你正在開發一個 Python 應用程序,並且希望直接在程式中處理影音,那麼 pyAV 可能是更好的選擇。
    • 如果只是簡單的一次性任務,或者需要在不同的平台或系統上腳本化影音處理,那麼 ffmpeg 可能更為適合。

結論

  • 如果你是 Python 開發者,且希望在程式中進行複雜的影音操作,那麼 pyAV 是個不錯的選擇。
  • 如果你只需要執行基本的影音轉換、剪裁或合併等操作,且希望能在多種平台上快速執行,那麼直接使用 ffmpeg 命令行工具可能更加適合。

安裝方法

使用以下方式安裝(如果下面的指令失敗的話,請參考此頁面安裝: https://pyav.org/docs/stable/overview/installation.html)

pip install av

後來我是使用下面這方法安裝成功的(windows)

pip install av --no-binary av
git clone https://github.com/PyAV-Org/PyAV.git
cd PyAV-main
python setup.py build --ffmpeg-dir=C:\ffmpeg

簡單的拉取RTMP源流的範例

以下的範例會拉取rtmp://127.0.0.1/live/testStream並使用OpenCV的函數顯示影像在視窗裡

import av
import cv2
import numpy as np
import os
import signal

def exit(*args,**kwargs):
    os.kill( os.getpid(), 9 )
signal.signal(signal.SIGINT,exit)

print('opening video...')
video = av.open('rtmp://127.0.0.1/live/testStream', 'r')

print('start streaming')
try:
    for packet in video.demux():
        for frame in packet.decode():
            if packet.stream.type == 'video':
                img = frame.to_ndarray(format='bgr24')
                cv2.imshow("Test", img)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
except KeyboardInterrupt:
    print(KeyboardInterrupt)
    pass
cv2.destroyAllWindows()
Posted on

使用ffmpeg濾鏡功能做影片合成

下載ffmpeg

https://ffmpeg.org/download.html

推一個時鐘文字的影片

ffmpeg的指令如下

ffmpeg  -f lavfi -i color=c=0x00ff00:s=800x450 -vf "settb=AVTB, setpts='trunc(PTS/1K)*1K+st(1,trunc(RTCTIME/1K))-1K*trunc(ld(1)/1K)', drawtext=text='STREAM2-%{localtime}.%{eif\:1M*t-1K*trunc(t*1K)\:d}':x=100:y=100:fontsize=32:fontcolor=white" -c:v libx264 -f flv rtmp://192.168.189.11/live/test2
  1. -f lavfi -i color=c=0x00ff00:s=800×450:這部分使用lavfi作為輸入來源,並創建一個顏色填充的視頻流。 c=0x00ff00指定填充的顏色為綠色,s=800×450指定分辨率為 800×450。
  2. -vf “settb=AVTB, setpts=’trunc(PTS/1K)1K+st(1,trunc(RTCTIME/1K))-1Ktrunc(ld(1)/1K)’, drawtext=text=’STREAM2 -%{localtime}.%{eif\:1Mt-1Ktrunc(t*1K)\:d}’:x=100:y=100:fontsize=32:fontcolor=white”:這部分使用- vf標誌來應用視頻過濾器。其中有兩個主要的過濾器:
    • settb=AVTB, setpts=’trunc(PTS/1K)1K+st(1,trunc(RTCTIME/1K))-1Ktrunc(ld(1)/1K)’:這個過濾器設置視頻時間戳。 settb=AVTB設置時間基準,setpts用於計算新的時間戳,其中包括根據PTS(顯示時間戳)和RTCTIME(實時時鐘時間)進行一些計算。
    • drawtext=text=’STREAM2-%{localtime}.%{eif\:1Mt-1Ktrunc(t1K)\:d}’:x=100:y=100:fontsize=32:fontcolor=white “:這個過濾器使用drawtext來在視頻上繪製文本。它在視頻左上角繪製了一個文本,其中包含了時間戳信息。%{localtime}插入本地時間,%{eif\:1Mt-1K* trunc(t*1K)\:d}用於插入一個經過格式化的時間戳。
  3. -c:v libx264:這部分設置視頻編碼器為libx264,用於將視頻編碼為H.264格式。
  4. -f flv rtmp://192.168.189.11/live/test2:這部分設置輸出格式為FLV,並指定RTMP服務器的地址。視頻會通過RTMP流式傳輸到指定的地址。在這裡,rtmp://192.168.189.11/live/test2是RTMP服務器的地址。

使用虛擬鏡頭來推流

ffmpeg -f dshow -rtbufsize 200M -i video=OBS-Camera -pix_fmt yuv420p -c:v libx264 -profile:v baseline -level:v 3.1 -preset:v ultrafast -s 480x270 -g 240 -an -f flv -y rtmp://172.16.46.89/live/0101_dealerPC1 
  1. -f dshow -rtbufsize 200M -i video=OBS-Camera:這部分設置輸入來源為DirectShow,並指定攝像頭的名稱為 “OBS-Camera”。 -rtbufsize 200M 設置了實時緩衝區的大小為 200MB。
  2. -pix_fmt yuv420p:這部分設置輸出視頻的像素格式為YUV 4:2:0,這是常見的視頻格式。
  3. -c:v libx264 -profile:v baseline -level:v 3.1 -preset:v ultrafast:這部分設置視頻編碼器為libx264,使用baseline配置文件,3.1級別,並設置預設(編碼速度)為ultrafast,這意味著編碼速度非常快。
  4. -s 480×270:這部分設置輸出視頻的分辨率為 480×270,即寬度為480,高度為270。
  5. -g 240:這部分設置關鍵幀(I幀)之間的間隔為 240 幀,用於控制視頻的GOP結構。
  6. -an:這部分錶示不捕獲音頻。
  7. -f flv:這部分設置輸出格式為FLV格式。
  8. -y:這部分錶示在輸出文件存在時覆蓋已存在的文件。
  9. rtmp://172.16.46.89/live/0101_dealerPC1:這部分是輸出URL,指定了通過RTMP傳輸的目標地址。視頻將會通過RTMP協議傳輸到 rtmp://172.16.46.89/live/0101_dealerPC1 這個地址。

極低延遲播放串流

ffplay -fflags nobuffer -flags low_delay -rtmp_buffer 0 -rtmp_live live -framedrop -infbuf %desc%
  1. -fflags nobuffer: 禁用緩衝。這意味著ffplay將盡可能地減少緩衝,以減少播放的延遲。
  2. -flags low_delay: 啟用低延遲模式。這將優化播放以減少延遲,適用於實時音視頻流。
  3. -rtmp_buffer 0: 設置 RTMP 緩衝大小為 0。 RTMP 是一種流媒體協議,這個選項設置緩衝大小為 0 表示盡可能地減少緩衝,從而減少延遲。
  4. -rtmp_live live: 表示要播放的是實時流。
  5. -framedrop: 如果幀太多,ffplay 將刪除一些幀以避免播放過慢。這有助於保持播放的實時性。
  6. -infbuf: 禁用緩衝輸入。與 -fflags nobuffer 相似,這有助於減少延遲。
  7. %desc%: 這可能是一個佔位符,用於指定音視頻流的 URL 或描述符。

把虛擬鏡頭和某個線上串流做綠幕合成

ffmpeg -f dshow -rtbufsize 1M -i video="OBS Virtual Camera" -f flv -i rtmp://172.17.22.89/live/test1 -filter_complex "[0:v]colorkey=0x00ff00:0.3:0.2[keyed];[1:v][keyed]overlay[o]" -map "[o]" -c:v h264_nvenc -f flv rtmp://127.0.0.1/live/test3
  1. -f dshow: 指定輸入的多媒體設備類型為 DirectShow(Windows 平台上的多媒體框架)。
  2. -rtbufsize 1M: 設置輸入緩衝區大小為 1MB。這可能有助於減少輸入的延遲。
  3. -i video=”OBS Virtual Camera”: 指定輸入的視頻設備名稱為 “OBS Virtual Camera”。這是一個虛擬攝像頭,通常由 OBS(Open Broadcaster Software)等軟件創建,用於虛擬攝像頭設備的捕獲。
  4. -f flv -i rtmp://172.17.22.89/live/test1: 指定輸入的媒體流為 RTMP 流,其 URL 為 rtmp://172.17.22.89/live/test1。這是從另一個 RTMP 流獲取的視頻。
  5. -filter_complex “[0:v]colorkey=0x00ff00:0.3:0.2[keyed];[1:v][keyed]overlay[o]”: 使用濾鏡複雜處理,這裡進行了以下操作:
  6. [0:v]colorkey=0x00ff00:0.3:0.2[keyed]:應用顏色鍵(chroma key)效果來移除綠色(0x00ff00)背景。生成一個帶有透明背景的圖像。
    [1:v][keyed]overlay[o]:將第一個輸入流(來自虛擬攝像頭)與經過顏色鍵處理的圖像進行疊加,產生混合後的圖像。
    -map “[o]”: 從混合後的圖像中選擇 [o] 這個輸出流。
  7. -c:v h264_nvenc: 使用 NVIDIA GPU 的硬件編碼器 h264_nvenc 進行視頻編碼。這將利用 GPU 進行加速,提高編碼效率。
  8. -f flv rtmp://172.17.22.89/live/test3: 指定輸出為 RTMP 流,其 URL 為 rtmp://172.17.22.89/live/test3。這是輸出混合後的視頻流。

更多詳細設置串流的方式

set ffmpegBin=C:\apps\ffmpeg\
set PATH=%PATH%;%ffmpegBin%

set camName="OBS Virtual Camera"
set camBufferSize=1000
set desc=rtmp://127.0.0.1:1935/live/demo

set codec=libx264
set fps=24
set /a "keyint=%fps%*5"
set x264opts=keyint=120:min-keyint=%fps%:scenecut=0
set preset=medium
set profile=baseline
set level=3.1
set resolution=800x450
set bitrate=700

:: publish stream
ffmpeg -f dshow -rtbufsize %camBufferSize%M -i video=%camName% ^
       -vf format=yuv420p ^
       -vcodec %codec% -x264-params %x264opts% ^
       -preset %preset% -profile:v %profile% -level:v %level% ^
       -tune:v zerolatency ^
       -s %resolution% ^
       -r %fps% ^
       -b:v %bitrate%k -minrate %bitrate%k -maxrate %bitrate%k -bufsize %bitrate%k ^
       -an ^
       -f flv %desc%

`-r` 轉成多少 fps

`-y` (global) Overwrite output files without asking.

`-i` 輸入檔案

`-c:v` video codec

`-profile:v` video profile, streaming 用 baseline

`-level:v` video level, streaming 用 3.1

`-preset:v` 編碼速度 streaming 用 ultrafast

`-b:v` 設定 bitrate, 例如 700k 486k

`-s` 尺寸

`-g` GOP size (-4 24 -g 240 相當於 Keyframe frequency = 10s)

`-an` 不需要 audio

`-f flv` flv 格式

`-f dshow -i video=OBS-Camera` window 使用 direct show來抓 camera

`-rtbufsize 200M` 設定 buffer size 避免 drop frame

`-re` 串流轉碼會變慢 因為要求 encoder 根據 native frame rate 讀檔按維持品值,要做串流轉發不要延遲時要拿掉。

https://www.wowza.com/docs/how-to-restream-using-ffmpeg-with-wowza-streaming-engine

FFREPORT 環境變數設好 ffmpeg 就會根據設定存log

linux format for date
https://www.opencli.com/linux/linux-date-format-shell-script

偵測 video frame 資訊

取得 stream 資訊

ffprobe -v quiet -show_streams -select_streams v:0 input.flv

抓出所有 i-frame

ffprobe -show_frames input.flv | grep pict_type | grep -n I

FME 設定 24fps, keyframe frequency = 10s
在理想狀況,會每 240 frame 插入一個 i-frame

example:

1:pict_type=I
241:pict_type=I
481:pict_type=I
721:pict_type=I
961:pict_type=I
1201:pict_type=I
Posted on

限制ffmpeg初始連接的時間

ffmpeg中的analyzeduration和probesize

在FFmpeg中,-analyzeduration和-probesize是用於設置媒體分析的參數。

-analyzeduration參數用於指定分析媒體文件的持續時間。當你在FFmpeg中打開一個媒體文件時,它需要一些時間來分析文件的內容,以確定其格式、編解碼器和其他相關的信息。這個參數設置了分析的時間長度。較長的-analyzeduration值可能會導致更準確的分析結果,但同時也會增加打開文件的時間。預設值為5,000,000微秒(5秒)。

-probesize參數用於指定分析媒體文件時讀取的數據大小。當FFmpeg分析媒體文件時,它會從文件中讀取一些數據並進行分析。這個參數設置了從媒體文件中讀取的數據大小。較大的-probesize值可能會導致更準確的分析結果,但同時也會增加分析的時間和記憶體使用量。預設值為50,000字節。

前置metadata

播放器在網絡點播場景下去請求MP4 視頻數據,需要先獲取到文件的metadata,解析出該文件的編碼、幀率等信息後才能開始邊下邊播。如果MP4 的metadata 數據塊被編碼在文件尾部,這種情況會導致播放器只有下載完整個文件後才能成功解析並播放這個視頻。對於這種視頻,我們最好能夠在服務端將其重新編碼,將metadata 數據塊轉移到靠近文件頭部的位置,保證播放器在線請求時能較快播放。比如FFmpeg 的下列命令就可以支持這個操作:

ffmpeg -i bad.mp4 -movflags faststart good.mp4

控制讀取的數據量大小

在外部可以通過設置 probesize 和 analyzeduration 兩個參數來控制該函數讀取的數據量大小和分析時長為比較小的值來降低 avformat_find_stream_info 的耗時,從而優化播放器首屏秒開。但是,需要注意的是這兩個參數設置過小時,可能會造成預讀數據不足,無法解析出碼流信息,從而導致播放失敗、無音頻或無視頻的情況。所以,在服務端對視頻格式進行標準化轉碼,從而確定視頻格式,進而再去推算 avformat_find_stream_info 分析碼流信息所兼容的最小的 probesize 和analyzeduration,就能在保證播放成功率的情況下最大限度地區優化首屏秒開。

probesize 和 analyzeduration太短的可能影響


如果將-probesize和-analyzeduration設置得太短,可能會導致以下問題:

  • 不準確的媒體分析:probesize和analyzeduration參數用於指定媒體分析的數據大小和時間長度。如果這兩個值設置得太短,FFmpeg可能無法讀取足夠的數據或分析足夠長的時間,從而導致分析結果的不準確性。這可能會影響到媒體文件的正確解碼、格式識別和相關信息的獲取。
  • 遺漏關鍵信息:媒體文件中的關鍵信息通常在文件的早期部分或特定位置。如果probesize和analyzeduration設置得太短,FFmpeg可能無法讀取到這些關鍵信息,進而影響解碼、播放或處理過程的正確性和完整性。
  • 性能問題:probesize和analyzeduration參數的值也會影響處理媒體文件所需的時間和資源。如果值設置得太短,FFmpeg可能需要更頻繁地從媒體文件中讀取數據或進行分析,增加了I/O操作和CPU負載,進而導致性能下降。
Posted on

Chunked Encoding介紹

甚麼是Chunked Encoding

Chunked encoding(分塊編碼)是一種HTTP/1.1協議中的傳輸編碼方式,用於將HTTP消息主體分成多個塊(chunks),以便在網絡上進行有效傳輸。分塊編碼主要用於動態生成的內容,以及在事先不知道內容大小的情況下傳輸數據。

分塊編碼的工作原理如下:

  1. 服務器將HTTP消息主體分成多個大小可變的塊。每個塊由兩部分組成:塊大小(十六進制表示)和實際數據。
  2. 每個塊都以塊大小開頭,然後是一個回車換行符(CRLF),接著是實際數據。在每個塊的數據之後,還有另一個回車換行符(CRLF)。
  3. 數據傳輸完成後,服務器會發送一個大小為0的塊,表示數據已經全部傳輸完畢。接著,服務器可以選擇性地傳輸附加的HTTP頭部,以提供更多關於已傳輸數據的信息。
  4. 客戶端接收到分塊編碼的數據後,將各個塊重新組合成完整的HTTP消息主體。

要使用分塊編碼,服務器需要在HTTP響應頭中設置Transfer-Encoding字段為chunked。這告訴客戶端,接收到的數據將使用分塊編碼格式。

分塊編碼的主要優點是允許服務器在不知道最終內容大小的情況下開始傳輸數據。這對於動態生成的內容、實時數據流和大文件傳輸非常有用。此外,分塊編碼還可以實現數據的即時壓縮和傳輸,從而提高傳輸效率。

設定nginx以支持Chunked Encoding

以下是一個簡單的nginx.conf範例,用於支持在http://127.0.0.1/live下的文件開啟chunked encoding。此配置檔案會將請求代理到後端應用伺服器(例如:Node.js、Python或其他後端應用)進行處理。請注意,這裡假設後端應用伺服器已經正確配置並支持分塊編碼。

http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;
    keepalive_timeout  65;

    gzip  on;
    gzip_min_length 1024;
    gzip_proxied any;
    gzip_types text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml application/xml+rss;

    server {
        listen       80;
        server_name  127.0.0.1;

        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }

        location /live {
            proxy_pass http://backend:3000; # 請將 "backend" 替換為您的後端應用伺服器地址(IP 或 域名),並將 "3000" 替換為您的後端應用伺服器的端口

            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;

            proxy_http_version 1.1;
            proxy_set_header Connection "";
            chunked_transfer_encoding on;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }
    }
}
events {
    worker_connections  1024;
}

這個配置檔案將Nginx設置為代理位於http://127.0.0.1/live的請求,並將請求轉發到後端應用伺服器。在location /live部分,使用chunked_transfer_encoding on;指令開啟分塊編碼。

觀察你的檔案是否有啟用Chunked Encoding

我們可以從伺服器的回應看到這個伺服器的檔案傳輸是否有支持Chunked Encoding,如下圖

Posted on

CMAF – 媒體封裝格式介紹

CMAF介紹(Common Media Application Format)

CMAF(Common Media Application Format,通用媒體應用格式)是一種專為網絡媒體傳輸設計的標準。CMAF旨在簡化不同裝置和網絡環境之間的媒體流適配和交付,從而提高流媒體的性能和覆蓋範圍。CMAF是一種媒體封裝格式。CMAF被設計為簡化在不同裝置和網絡環境之間的媒體流適配和交付,從而提高流媒體的性能和覆蓋範圍。CMAF檔案通常具有.cmf.mp4擴展名。

CMAF(Common Media Application Format,通用媒體應用格式)是一種媒體封裝格式,類似於FLV(Flash Video)和MP4(MPEG-4 Part 14)。CMAF旨在簡化在不同裝置和網絡環境之間的媒體流適配和交付,以提高流媒體的性能和覆蓋範圍。

與FLV和MP4等其他封裝格式相比,CMAF的一個主要優勢在於它的兼容性和靈活性。CMAF可以應對各種不同的網絡環境和裝置能力,並且可以與多種流媒體協議(如HLS和MPEG-DASH)無縫地配合使用。

CMAF的特點

CMAF的主要特點包括:

  1. 單一檔案格式:CMAF允許使用單一檔案格式來適配多種媒體流協議,例如HLS(HTTP Live Streaming)和MPEG-DASH(Dynamic Adaptive Streaming over HTTP)。這使得內容提供商能夠更容易地在各種裝置和網絡上傳輸和管理媒體內容。
  2. 切片:CMAF將媒體流切成較小的片段(通常稱為chunks),這些片段可以在不同品質層次之間進行無縫切換,以適應不同的網絡條件和裝置能力。這有助於實現更低的延遲和更高的播放質量。
  3. 編碼效率:CMAF支持各種編解碼器,例如H.264(AVC)和H.265(HEVC),以實現高效的媒體編碼。此外,CMAF還支持多種音頻編解碼器,例如AAC和Opus。
  4. 整合DRM(數字版權管理):CMAF允許整合各種DRM技術,如Widevine、PlayReady和FairPlay,以保護內容的版權。

總之,CMAF是一種簡化網絡媒體傳輸的標準,它有助於提高流媒體的性能、覆蓋範圍和兼容性。

CMAF的延遲

CMAF(Common Media Application Format,通用媒體應用格式)主要用於適配和交付HLS(HTTP Live Streaming)和MPEG-DASH(Dynamic Adaptive Streaming over HTTP)等流媒體協議。CMAF的目標是在不同裝置和網絡環境之間提供高效的媒體流適配和交付,而非專注於低延遲。

由於CMAF依賴於HTTP,其延遲通常會比使用基於UDP的協議(如SRT或RTP)高。HTTP協議需要較長的時間來建立連接、請求和接收數據,這導致了較大的延遲。此外,CMAF通常用於分段媒體流,每個分段的持續時間也會增加延遲。

然而,CMAF的延遲性能可以通過使用CMAF的低延遲模式(CMAF-LLC)來改善。CMAF-LLC使用chunked encoding傳輸技術來實現低延遲,這允許客戶端在接收到完整的媒體分段之前開始解碼和播放。這樣可以將延遲降低到可接受的範圍,但仍然可能高於使用基於UDP的協議,如SRT。

總之,儘管使用CMAF的延遲可能較長,但通過使用CMAF-LLC可以改善延遲性能。然而,對於實時應用或低延遲要求非常嚴格的場景,使用基於UDP的協議,如SRT或RTP,可能是更合適的選擇。

Posted on

Publish HEVC live streaming by OBS to SRS via RTMP

After OBS Studio 29.1, they added support for Enhanced RTMP, it is now possible to push HEVC streaming via RTMP, and SRS also support HEVC over RTMP and HTTP-FLV v6.0.2+.

Here is a simple tutorial on how to use OBS to push HEVC streams to SRS.

OBS support H.265 over RTMP v29.1+

The original RTMP protocol cannot support high-compression video formats such as HEVC or AV1. But from OBS Studio 29.1 Beta, OBS adds support for the updated: Enhanced RTMP. For more detail, please refer to: Enable AV1, HEVC via RTMP to YouTube.

Therefore, the first step to push an HEVC stream via RTMP from OBS is to download the latest version of OBS. (Download here: OBS Studio 29.1 Beta Release Page).

SRS support H.265 over RTMP v6.0.42+

  • RTMP: Support enhanced RTMP specification for HEVC, v6.0.42.
  • Player: Upgrade mpegts.js to support it.

Enhanced RTMP specification: https://github.com/veovera/enhanced-rtmp

First, start SRS v6.0.42+ with HTTP-TS support:

./objs/srs -c conf/http.ts.live.conf

Pulish HEVC via RTMP from OBS

  1. Your OBS version should be greater than v29.1, than open File -> Setting
  2. Select Stream -> Service to Custom…
  3. Select Output -> Output Mode to Advanced, than choice Encoder to HEVC
  4. Click Start Streaming
  5. Check your streaming from SRS console
  6. Preview your streaming by SRS Player
Posted on

什麼是WebRTC

文章轉載

這篇文章翻譯自: What is WebRTC and how does it work? Real-time communication with WebRTC

什麼是WebRTC

WebRTC代表網路實時通訊。 它是一種非常令人興奮、強大且具有高度破壞性的尖端技術和流媒體協議。

WebRTC與HTML5相容,您可以使用它直接在瀏覽器和裝置之間新增實時媒體通訊。 最好的部分之一是,您無需在瀏覽器中安裝外掛的任何先決條件即可做到這一點。 Webrtc正逐漸得到所有主要現代瀏覽器供應商的支援,包括Safari、Google Chrome、Firefox、Opera等。

多虧了WebRTC影片流技術,您可以將實時影片直接嵌入到基於瀏覽器的解決方案中,為您的觀眾創造引人入勝的互動式流媒體體驗,而不必擔心延遲。

現在,影片,特別是直播,是我們快速變化的通訊需求不可或缺的一部分。 隨著社交距離的增加,WebRTC幫助我們滿足這些通訊需求,並增加我們與實時通訊的互動。

WebRTC元件

我們將使用客戶端-A和客戶端-B作為示例來解釋WebRTC的以下元件。

SDP(會話描述協議)

SDP是一個簡單的基於字串的協議,它在瀏覽器之間共享支援的程式碼器。

在我們的例子中,

  • 客戶端 A 創建其 SDP(稱為報價)並將其保存為本地 SDP,然後與客戶端 B 共享。
  • Client-B收到Client-A的SDP,保存為遠程SDP。
  • 客戶端 B 創建其 SDP(稱為答案)並將其保存為本地 SDP,然後與客戶端 A 共享。
  • Client-A收到Client-B的SDP,保存為遠程SDP。

信令伺服器(Signaling Server)負責等體之間的這些SDP傳輸。

讓我們假設客戶端A可能支援H264、VP8和VP9編解碼器用於影片、Opus和PCM編解碼器用於音訊。 客戶端-B可能只支援H264用於影片,只支援Opus編碼器用於音訊。

在這種情況下,客戶端-A和客戶端-B將使用H264和Opus作為編解碼器。 如果對等體之間沒有共同的程式碼器,則無法建立對等通訊。

ICE(交互連接建立)

Interactive Connectivity Establishment (ICE) 用於 Internet 上的兩個節點必須盡可能直接通信的問題,但是 NAT 和防火牆的存在使得節點之間難以相互通信。

它是一種網絡技術,利用 STUN(NAT 會話遍歷實用程序)和 TURN(在 NAT 周圍使用中繼遍歷)在兩個節點之間建立盡可能直接的連接。

WebRTC STUN 服務器NAT 的會話遍歷實用程序) 

STUN Server負責獲取一台機器的所有地址。例如,我們的計算機通常在 192.168.0.0 網絡中有一個本地地址,當我們連接到www.whatismyip.com時,我們會看到第二個地址,這個 IP 地址實際上是我們互聯網網關(調製解調器,調製解調器,路由器等),所以讓我們定義 STUN 服務器:STUN 服務器讓對等方知道他們的公共和本地 IP 地址。

順便說一下,Google 還提供了一個免費的 STUN 服務器 (stun.l.google.com:19302)。

 

WebRTC TURN  Server  (繞過NAT使用中繼遍歷)

TURN(Traversal Using Relays around NAT)是一種協議,可幫助 WebRTC 應用程序穿越網絡地址轉換器 (NAT) 或防火牆。TURN Server 允許客戶端通過中間服務器發送和接收數據。

TURN 協議是 STUN 的擴展。 有時,由於 NAT/Firewall,從STUN服務器 獲取的地址不能用於建立對等點之間的對等連接。在這種情況下,數據通過TURN服務器中繼

在我們的例子中,

  • Client-A通過STUN服務器找到自己的本地地址和公網地址,並通過Signaling Server將這些地址發送給Client-B。從 STUN 服務器收到的每個地址都是 ICE 候選地址。
  • Client-B 做同樣的事情,從 STUN 服務器獲取本地和公共 IP 地址,並將這些地址通過 Signaling Server 發送給 Client-A。
  • Client-A 收到 Client-B 的地址並通過發送特殊的 ping 來嘗試每個 IP 地址以創建與 Client-B 的連接。如果客戶端 A 收到來自任何 IP 地址的響應,它會將該地址及其響應時間和其他性能憑證放入列表中。最後,Client-A 根據其性能選擇最佳地址。
  • Client-B 做同樣的事情以連接到 Client-A

RTP(實時協議)

RTP 是在UDP之上傳輸實時數據的成熟協議。在 WebRTC 中,音頻和視頻通過 RTP 傳輸。RTP 有一個姊妹協議,名為 RTCP(實時控制協議),它在 RTP 通信中提供 QoS。RTSP  (實時流協議)在數據通信中也使用 RTP 協議。

WebRTC 信令服務器

最後一部分是Signaling Server,WebRTC 中沒有定義。如上所述,Signaling Server 用於在 Client-A 和 Client-B 之間發送 SDP 字符串和 ICE Candidates。信令服務器還決定哪些對等點相互連接。WebSocket 技術是與信令服務器進行通信的首選方式。