首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

JMF RTP 媒體流網路傳輸完整架構:會話管理、格式轉制、傳輸/接收管線深度解析

     編輯:Java 相關知識

Java Media Framework (JMF) 提供完整的 RTP/RTCP 媒體流網路傳輸支援。本文系統解析 JMF RTP 架構核心組件:SessionManager 會話管理、RTPManager 傳輸/接收管線、格式轉制邏輯、事件模型與整體傳輸模型,並提供關鍵代碼片段與圖解說明。

1. RTP 架構核心組件

1.1 SessionManager:會話控制中樞

  • 職責:管理會話參與者、控制 RTP 會話生命週期、收集統計資訊 (發送/接收封包數、丟包率、抖動等)。
  • 兩大子組件:
    • Session Statistics:GlobalReceptionStats, GlobalTransmissionStats, ReceptionStats, TransmissionStats。
    • Session Streams:ReceiveStream (遠端媒體流), SendStream (本地媒體流)。

1.2 RTP 事件模型 (繼承 MediaEvent)

監聽器介面核心事件類別觸發情境
SessionListenerNewParticipantEvent, LocalCollisionEvent新參與者加入、SSRC 衝突
SendStreamListenerNewSendStreamEvent, ActiveSendStreamEvent, InactiveSendStreamEvent, LocalPayloadChangeEvent, StreamClosedEvent本地發送流建立/啟動/停止/格式變更/關閉
ReceiveStreamListenerNewReceiveStreamEvent, ActiveReceiveStreamEvent, InactiveReceiveStreamEvent, TimeoutEvent, RemotePayloadChangeEvent, ApplicationEvent遠端接收流偵測/啟動/停止/超時/格式變更/APP 包
RemoteListenerReceiverReportEvent (RR), SenderReportEvent (SR), RemoteCollisionEvent接收 RTCP RR/SR 報告、遠端 SSRC 衝突

1.3 RTCP 封包類型與 JMF 事件對應

SR  → SenderReportEvent
RR  → ReceiverReportEvent
SDES → (Source Description, 承載於 Sender/Receiver Report)
BYE  → (隱含於 StreamClosedEvent/InactiveEvent)
APP  → ApplicationEvent

1.4 RTP 傳輸支援編碼格式

媒體類別RTP 封裝格式 (JMF 支援)
音訊JAUDIO_G711_ULAW/rtp, DVI/rtp, G723/rtp, GSM/rtp
視訊JPEG/rtp, H261/rtp, H263/rtp

2. 關鍵技術:視訊格式轉制 (滿足 RTP 解析度限制)

限制:JPEG 寬高須為 8 倍數;H.263 僅支援 352×288 (CIF)、176×144 (QCIF)、128×96 (SQCIF)。

// 從 Processor 取得軌道控制器
TrackControl[] tracks = processor.getTrackControls();
for (int i = 0; i < tracks.length; i++) {
    Format original = tracks[i].getFormat();
    Format supported = tracks[i].getSupportedFormats()[0];
    Format chosen = checkForVideoSizes(original, supported);
    if (chosen != null) tracks[i].setFormat(chosen);
}

Format checkForVideoSizes(Format original, Format supported) {
    Dimension size = ((VideoFormat) original).getSize();
    Format jpegFmt = new Format(VideoFormat.JPEG_RTP);
    Format h263Fmt = new Format(VideoFormat.H263_RTP);
    int width, height;

    if (supported.matches(jpegFmt)) {
        width  = (size.width  % 8 == 0) ? size.width  : (size.width  / 8) * 8;
        height = (size.height % 8 == 0) ? size.height : (size.height / 8) * 8;
    } else if (supported.matches(h263Fmt)) {
        if (size.width < 128)      { width = 128; height = 96; }
        else if (size.width < 176) { width = 176; height = 144; }
        else                       { width = 352; height = 288; }
    } else {
        return supported;
    }
    return new VideoFormat(null, new Dimension(width, height),
                           Format.NOT_SPECIFIED, null, Format.NOT_SPECIFIED)
           .intersects(supported);
}

3. RTP 媒體流傳輸管線 (發送端)

// 1. Processor 轉制後取得 DataSource
DataSource dataOutput = processor.getDataOutput();
PushBufferDataSource pbds = (PushBufferDataSource) dataOutput;
PushBufferStream[] pbss = pbds.getStreams(); // 每軌道一個 Stream

// 2. 建立 RTPManager 並初始化會話
RTPManager[] rtpMgrs = new RTPManager[pbss.length];
InetAddress destIP = InetAddress.getByName("192.168.1.100");
int basePort = 5000; // 視訊端口,音訊 = basePort + 2

for (int i = 0; i < pbss.length; i++) {
    rtpMgrs[i] = RTPManager.newInstance();
    SessionAddress localAddr = new SessionAddress(InetAddress.getLocalHost(), basePort + i*2);
    SessionAddress destAddr = new SessionAddress(destIP, basePort + i*2);
    rtpMgrs[i].initialize(localAddr);
    rtpMgrs[i].addTarget(destAddr);

    // 3. 建立發送流並啟動
    SendStream sendStream = rtpMgrs[i].createSendStream(dataOutput, i);
    sendStream.start();
}

4. RTP 媒體流接收管線 (接收端)

// 1. 建立 RTPManager 初始化本地會話
RTPManager rtpMgr = RTPManager.newInstance();
SessionAddress localAddr = new SessionAddress(InetAddress.getLocalHost(), 5000);
rtpMgr.initialize(localAddr);

// 2. 註冊接收流事件監聽器
rtpMgr.addReceiveStreamListener(new ReceiveStreamListener() {
    @Override
    public void update(ReceiveStreamEvent evt) {
        if (evt instanceof NewReceiveStreamEvent) {
            ReceiveStream stream = ((NewReceiveStreamEvent) evt).getReceiveStream();
            DataSource ds = stream.getDataSource(); // 供 Player 播放
            // 建立 Player 播放 ds ...
        } else if (evt instanceof ByeEvent) {
            // 遠端結束傳輸
        }
    }
});

// 3. 等待遠端傳輸 (addTarget 可選,若知遠端 IP)
rtpMgr.addTarget(new SessionAddress(InetAddress.getByName("192.168.1.100"), 5000));

5. 整體傳輸模型圖解

6. 實戰部署建議

  1. 防火牆/NAT 穿透:RTP 使用動態 UDP 端口,需配置 STUN/TURN/ICE 或固定端口範圍並開放防火牆。
  2. 頻寬自適應:監聽 ReceiverReportEvent 計算丟包率/抖動,動態切換編碼碼率/解析度 (需重新 createSendStream)。
  3. 同步與唇音同步:利用 RTP 時間戳記 + RTCP SR/NTP 時間戳記實現跨軌道同步。
  4. 安全性:採用 SRTP (RFC 3711) 加密媒體載荷,JMF 需外掛支援。
  5. 現代替代方案:JMF 早已停止維護,新專案強烈建議使用 WebRTC (Java: Jitsi, Kurento)、FFmpeg + RTMP/SRT、GStreamer Java Binding 等活躍生態。

總結

JMF RTP 架構以 SessionManager 統一管理會話統計與流、RTPManager 負責傳輸/接收管線、事件模型提供精細狀態感知、格式轉制確保符合 RTP 封裝規格。掌握此架構有助於理解即時媒體傳輸核心原理,但實務開發請轉向現代化媒體框架。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved