程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 基於JMF RTP的網絡傳輸媒體流

基於JMF RTP的網絡傳輸媒體流

編輯:關於JAVA

JMF中可以實現RTP媒體流的回放(playback)和傳輸(transmission),主要由javax.media.rtp, javax.media.rtp.event,和javax.media.rtp.rtcp包中定義的API完成。JMF可以通過標准的JMF plug-in機制來實現支持特定的RTP格式和動態負載。

你可以在本地播放RTP數據流,或將其存儲到本地文件。

同樣,你可以通過JMF中RTP API實現傳輸捕獲的或存儲的媒體流到網上。RTP媒體流可以創建自一個本地文件或捕獲自媒體采集設備。這些RTP媒體流同樣可以在本地播放或存儲。

整體流程圖示:

1.RTP結構

1.1 SessionManager

在JMF架構中Session Manager對程序之間的會話進程進行控制和管理。Session Manager主要作用:

①明確每一個會話(session)中的所有參與者(participants)。

②管理每一個RTP會話。

③保存來自每一個發送或接收到的RTP和RTCP包中的統計信息。

JMF RTP Session結構圖:

SessionManagr包含2個部分:Session Statistics和Session Streams。

1.1.1Session Statistics

統計量(Statistics)是記錄基於每一條媒體流上的整個會話的統計信息。它包含:

①GobalReceptionStats:包含此會話的全局接收統計信息。

②GobalTransmissionStats:包含此會話的全局傳輸統計信息。

③RecetionStats:包含每一個參與者接收統計信息。

④TransmissionStats:包含每一個參與者的傳輸統計信息。

1.1.2Session Streams

①ReceiveStream:表示一個接收到的來自遠端參與者的媒體流。

②SendStream:表示一個來自本地的媒體流。

1.2 RTP事件

如下圖所示,通過繼承JMF中MediaEvent的類,可以創建響應的RTP事件。

⑴SessionListener:通過它得到一個會話狀態的改變。

①NewParticipantEvent:表示一個新的參與者加入會話。

②LocalCollisionEvent:表示參與者請求的同步資源正在使用。

⑵SendStreamListener:通過它得到一個正在傳送的RTP數據流狀態的改變。

①NewSendStreamEvent:表示本地參與者已經創建一個新的發送數據流。

②ActiveSendStreamEvent:表示從DataSource創建的數據流已經開始發送。

③InactiveSendStreamEvent:表示從本地DataSource創建的數據流已經停止。

④LocalPayloadChangeEvent:表示數據流格式已經開始改變。

⑤StreamClosedEvent:表示數據流已經停止。

⑶ReceiveStreamListener:通過它得到一個正在接收的RTP數據流狀態的改變。

①NewReceiveStreamEvent:表示SessionManager已經創建了一個從新的偵測到的地址傳來的接收數據流。

②ActiveReceiveStreamEvent: 表示數據的傳送已經開始。

③InactiveReceiveStreamEvent:表示數據的傳送已經停止。

④TimeoutEvent:表示數據傳送超時。

⑤RemotePayloadChangeEvent:表示接收到的數據流格式已經改變。

⑥ApplicationEvent:表示收到了一個RTCP App數據包。

⑷RemoteListener:通過它得到遠端會話參與者的時間或RTP控制信息。

①ReceiverReportEvent:表示接收到一個RTCP的RR包。

②SenderReportEvent:表示收到一個RTCP的SR包。

③RemoteCollisionEvent:表示兩個遠端的參與者使用了相同的SSRC 出錯。

1.3與RTP事件相對應的RTCP類型表

RTCP的控制類型和JMF事件類的一致性

RTCP類型 JMF中的事件類 SR SendStreamEvent RR ReceiveStreamEvent SDES SenderReportEvent BYE ByeEvent APP ApplicationEvent:

1.4數據傳輸格式

在RTP傳輸中,如果還是用傳統的AVI,MOV格式的話,將會增加服務器負荷,而且對網絡要求特別高,因此需要將傳統格式轉化至易於傳送,網絡適應性好,抗丟包性能和抗誤碼性能好的編碼格式。下表是JMF項目支持的視音頻在RTP傳送的壓縮格式,也就是說經過定制後的輸出視頻流,還得進行一次轉換,以便網絡發送。

表 JMF支持的視音頻在RTP傳送中的格式

多媒體類別 RTP傳輸格式 音頻 JAUDIO_G711_ULAW/rtp,dvi/rtp ,g723/rtp ,gsm/rtp 視頻 jpeg/rtp,h261/rtp,h263/rtp

轉化格式的關鍵代碼及其分析(視頻):

//從processor獲得軌道控制器
TrackControl [] tracks = processor.getTrackControls();
//為每個軌道的格式進行轉制
for (int i = 0; i < tracks.length; i++)
{
 //此處省略獲得軌道信息格式和支持格式代碼
  //下面一行為轉制函數,需要參數為:軌道格式和軌道支持的格式
  chosen = checkForVideoSizes(tracks[i].getFormat(), supported[0]);
  //此處省略如果不能對軌道格式轉變代碼
}
//轉制函數
/* 在傳輸視頻信息時,對於JPEG編碼格式,視頻圖像的寬和高是8像素的整數倍,對於
*H263編碼格式,只支持三種圖像的大小,即352X288,176X144,128X96像素,只要滿
*足了這些條件,才可以正常傳輸視頻信息,所以,需要對視頻格式進行轉制,                                                                                                                                                                                                                                                               
*不負荷條件的都需要轉化,以滿足正常傳輸。
*/
  Format checkForVideoSizes(Format original, Format supported) {
  int width, height;
  Dimension size = ((VideoFormat)original).getSize();//獲取視頻圖像的尺寸
  Format jpegFmt = new Format(VideoFormat.JPEG_RTP);
  Format h263Fmt = new Format(VideoFormat.H263_RTP);
  if (supported.matches(jpegFmt)) {//如果是JPEG格式
  //調整寬  
width = (size.width % 8 == 0 ? size.width :(int)(size.width / 8) * 8);
//調整高
height = (size.height % 8 == 0 ? size.height :(int)(size.height / 8) * 8);
  } else if (supported.matches(h263Fmt)) {//如果是H263格式
    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);

2.RTP媒體數據流的傳輸與接收2.1 RTP媒體數據流的傳輸過程

上圖為Transmit的整個設計架構,Processor處理來自Capture Device的數據後,輸入對方IP和Port,將數據傳送到網絡上等待接收端接收,其中音頻的端口為視頻的端口加2。

部分代碼及分析:

①將轉換格式後的數據放入一個DataSource

//獲得轉制後的DataSource
dataOutput = processor.getDataOutput();
//將DataSource轉化為Push數據流
PushBufferDataSource pbds = (PushBufferDataSource)dataOutput;
//獲取Push數據流
PushBufferStream pbss[] = pbds.getStreams();

數據源決定了軌道數的多少,如果數據源中包括視頻和音頻內容,則有兩個軌道,一個軌道分給視頻,一個軌道分給音頻,在數據源的格式轉制完成以後,每個軌道對應著一個RTP會話,這些RTP會話由會話管理器(RTPManager)統一管理。

②以下是建立RTP Session中發送的關鍵代碼和分析:

rtpMgrs[i] = RTPManager.newInstance();//RTP管理器實例化
ipAddr = InetAddress.getByName("59.64.84.243");//獲得目的地址的IP地址
//獲取本機IP地址
localAddr = new SessionAddress( InetAddress.getLocalHost(),port);
//獲取目的機IP地址
destAddr = new SessionAddress( ipAddr, port);
//分別將本機和目的機IP地址加入至RTP會話管理器
rtpMgrs[i].initialize( localAddr);
rtpMgrs[i].addTarget( destAddr);
//產生第N條軌道的傳輸流
sendStream = rtpMgrs[i].createSendStream(dataOutput, i);
//傳輸流開始
sendStream.start();
2.2 RTP媒體數據流的接收過程

接收方式為經由SessionManager到DataSource到Player,然後播放。上圖即為Receive的整個設計構架,傳送端送出數據後,接收端輸入對方IP然後等待接收數據,其中音頻的端口為視頻的端口加2。

部分代碼及分析:

/*
*目的機建立RTP會話管理器原理和步驟基本與發送端一至,我們主要分析接收多媒體流的事件類。
*/
public synchronized void update( ReceiveStreamEvent evt){
if(evt instanceof NewReceiveStreamEvent) {//接收到一個新的數據流
//根據獲取的數據流獲得一個數據源。這個數據源為播放使用
} else if (evt instanceof StreamMappedEvent) {
//數據流映射事件
//如果當前數據源為NULL,根據這個事件獲得一個Datasource,否則忽略
}else if (evt instanceof ByeEvent) {//數據接收完畢
//播放結束
}
}

2.3基於JMF 的RTP/RTCP 傳輸模型的整體設計

本文出自 “子 孑” 博客,請務必保留此出處http://zhangjunhd.blog.51cto.com/113473/25487

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved