基于rtp_jmf的摄像头视频采集和传输1
- 格式:doc
- 大小:47.50 KB
- 文档页数:9
基于JMF RTP的网络传输媒体流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:表示一个来自本地的媒体流。
基于RTP协议的视频实时采集与传输的研究
赵臣兵;刘立柱
【期刊名称】《微计算机信息》
【年(卷),期】2006(022)016
【摘要】分析了实时通信协议RTP及其控制协议RTCP,构建一个基于RTP协议的采集传输系统,能够实时采集视频数据、编码并通过网络传输.
【总页数】3页(P124-126)
【作者】赵臣兵;刘立柱
【作者单位】450002,郑州解放军信息工程大学信号分析工程系;450002,郑州解放军信息工程大学信号分析工程系
【正文语种】中文
【中图分类】TN919
【相关文献】
1.基于RTP协议的MPEG-4视频传输系统的设计与实现 [J], 刘宝林;胡博;范小安;王行言
2.基于RTP协议的嵌入式网络视频传输系统 [J], 张婉明;李琦
3.基于RTP协议中Translator的实时视频传输性能优化方案 [J], 余胜生;林涛;周敬利
4.基于RTP协议的MPEG-4的视频传输系统应用研究 [J], 王原丽;刘建伟
5.基于RTP协议的视频实时采集与传输的研究 [J], 赵臣兵;刘立柱
因版权原因,仅展示原文概要,查看原文内容请购买。
基于JMF的实时多媒体传输系统的研究与实现XX:1009-3044(20XX)14-3407-03Reserch nd Implementtion of Rel-time Multimedi Communiction System Bsed on JMFQING Xiu-hu(School of Electronic & Electricl Engineering, Wuhn Textile University, Wuhn 430073, Chin)bstrct: The multimedi Frmework nd the running mode of JMF were nlysis. JMF design of Rel-time Multimedi Communi ction System hd n in depth reserch. nd use the JMF frmework for the reliztion of Rel-time Multimedi Communiction Sys tem.Key words: JMF; multimedi communiction system; rel-time communiction1概述目前,微软公司的MSN、腾讯公司的QQ等XX络上流行的很多支持多媒体功能的即时通信软件,虽然都能提供两个用户之间的点对点音视频通信以及多用户之间的文字通信,但是对于多用户之间的音视频等多媒体通信的支持却不够好。
JMF是Jv多媒体框架(Jv Medi FrmeWork)的简称,JMF 不用关怀底层复杂的实现细节就可以编写出功能强大的多媒体程序。
JMF中包含了许多用于处理多媒体的PI。
在JMF中,用来接收和传输多媒体数据的协议是RTP协议(Rel-time Trnsport Pro tocol,实时传输协议)。
RTP是一种针对多媒体数据传输的实时传输协议,RTP会话将音视频等多媒体数据分为一系列的数据报,组成RTP数据流来传输,这种多媒体数据流是一种实时数据流,实时流的最大优点是:当客户端以实时流的形式接收音视频数据时,可以不用等待所有的数据接收完毕,就可以开始播放。
基于Android的实时监控系统的设计与实现作者:骆伟初海英于海燕来源:《软件工程师》2013年第05期摘要:随着移动互联技术的发展,3G、Wi-Fi技术以及智能手机在社会上得到了大量的应用。
本文主要介绍在3G网络或Wi-Fi覆盖范围内,使用基于Android操作系统的智能手机,对特定场所进行远程的实时视频监控和操作。
关键词:JMF;RTP协议;Andriod;视频监控1 引言本文主要研究的是“实时视频系统”的开发,本系统通过服务器端连接的摄像头拍摄画面,经过处理与压缩后通过互联网将视频流传送给便携设备手机,使用户随时随地可以对某些特定场所,如家庭、办公室、实验室等场所的安全、环境等情况进行远程的监控。
本系统采用C/S 构架,服务器端使用JMF技术对捕获的视频进行处理和压缩,通过RSTP协议经由互联网,将视频流传送给以手机为平台的客户端上,使用户可以远程观看某些特定场所的画面。
2 系统分析2.1 功能架构根据需求调研结果确定本系统主要包括以下功能模块,如图1所示。
2.2 模块需求(1)视频流捕获及处理对USB摄像头的拍摄视频流进行实时捕获与处理。
(2)视频流传输与客户端建立连接,开始视频流传输。
(3)接受视频流及播放客户端将接收的视频流进行处理并通过播放器播放出来。
2.3 系统开发环境(1)服务器硬件环境:1GHz/512MB/5G/1Mbps网络接入。
(2)客户端硬件环境:手机。
(3)服务器软件环境:jdk1.6。
(4)客户端软件环境:Android 1.6以上。
3 系统设计3.1 架构设计本系统采用C/S构架,在PC端搭建RED5服务器,手机或PC机客户端通过3G网络、以太网或Wi-Fi网络连接服务器。
服务器端进行视频采集和后台数据处理,客户端为用户呈现实时视频数据信息等。
[1]3.2 功能结构设计本系统主要分为服务端功能和客户端功能。
服务端有采集视频功能,采集后将视频处理并传输给客户端,客户端通过播放器显示接收到的视频流。
import java.io.*;import java.awt.*;import .*;import java.awt.event.*;import java.util.Vector;import javax.media.*;import javax.media.rtp.*;import javax.media.rtp.event.*;import javax.media.rtp.rtcp.*;import javax.media.protocol.*;import javax.media.protocol.DataSource;import javax.media.format.AudioFormat;import javax.media.format.VideoFormat;import javax.media.Format;import javax.media.format.FormatChangeEvent;import javax.media.control.BufferControl;/*** AVReceive3 to receive RTP transmission using the RTPConnector.*/public class AVReceive3 implements ReceiveStreamListener, SessionListener, ControllerListener{String sessions[] = null;RTPManager mgrs[] = null;Vector playerWindows = null;boolean dataReceived = false;Object dataSync = new Object();public AVReceive3(String sessions[]) {this.sessions = sessions;}protected boolean initialize() {try {mgrs = new RTPManager[sessions.length];playerWindows = new Vector();SessionLabel session;// Open the RTP sessions.for (int i = 0; i < sessions.length; i++) {// Parse the session addresses.try {session = new SessionLabel(sessions[i]);} catch (IllegalArgumentException e) {System.err.println("Failed to parse the session address given: " + sess ions[i]);return false;}System.err.println(" - Open RTP session for: addr: " + session.addr + " po rt: " + session.port + " ttl: " + session.ttl);mgrs[i] = (RTPManager) RTPManager.newInstance();mgrs[i].addSessionListener(this);mgrs[i].addReceiveStreamListener(this);// Initialize the RTPManager with the RTPSocketAdaptermgrs[i].initialize(new RTPSocketAdapter(InetAddress.getByName(session.addr),session.port, session.ttl));// You can try out some other buffer size to see// if you can get better smoothness.BufferControl bc = (BufferControl)mgrs[i].getControl("javax.media.control.B ufferControl");if (bc != null)bc.setBufferLength(350);}} catch (Exception e){System.err.println("Cannot create the RTP Session: " + e.getMessage());return false;}// Wait for data to arrive before moving on.long then = System.currentTimeMillis();long waitingPeriod = 30000; // wait for a maximum of 30 secs.try{synchronized (dataSync) {while (!dataReceived &&System.currentTimeMillis() - then < waitingPeriod) {if (!dataReceived)System.err.println(" - Waiting for RTP data to arrive");dataSync.wait(1000);}}} catch (Exception e) {}if (!dataReceived) {System.err.println("No RTP data was received.");close();return false;}return true;}public boolean isDone() {return playerWindows.size() == 0;}/*** Close the players and the session managers.*/protected void close() {for (int i = 0; i < playerWindows.size(); i++) {try {((PlayerWindow)playerWindows.elementAt(i)).close();} catch (Exception e) {}}playerWindows.removeAllElements();// close the RTP session.for (int i = 0; i < mgrs.length; i++) {if (mgrs[i] != null) {mgrs[i].removeTargets( "Closing session from AVReceive3"); mgrs[i].dispose();mgrs[i] = null;}}}PlayerWindow find(Player p) {for (int i = 0; i < playerWindows.size(); i++) {PlayerWindow pw = (PlayerWindow)playerWindows.elementAt(i);if (pw.player == p)return pw;}return null;}PlayerWindow find(ReceiveStream strm) {for (int i = 0; i < playerWindows.size(); i++) {PlayerWindow pw = (PlayerWindow)playerWindows.elementAt(i);if (pw.stream == strm)return pw;}return null;}/*** SessionListener.*/public synchronized void update(SessionEvent evt) {if (evt instanceof NewParticipantEvent) {Participant p = ((NewParticipantEvent)evt).getParticipant();System.err.println(" - A new participant had just joined: " + p.getCNAME() );}}/*** ReceiveStreamListener*/public synchronized void update( ReceiveStreamEvent evt) {RTPManager mgr = (RTPManager)evt.getSource();Participant participant = evt.getParticipant(); // could be null.ReceiveStream stream = evt.getReceiveStream(); // could be null.if (evt instanceof RemotePayloadChangeEvent) {System.err.println(" - Received an RTP PayloadChangeEvent.");System.err.println("Sorry, cannot handle payload change.");System.exit(0);}else if (evt instanceof NewReceiveStreamEvent) {try {stream = ((NewReceiveStreamEvent)evt).getReceiveStream();DataSource ds = stream.getDataSource();// Find out the formats.RTPControl ctl = (RTPControl)ds.getControl("javax.media.rtp.RTPControl");if (ctl != null){System.err.println(" - Recevied new RTP stream: " + ctl.getFormat()); } elseSystem.err.println(" - Recevied new RTP stream");if (participant == null)System.err.println(" The sender of this stream had yet to be ident ified.");else {System.err.println(" The stream comes from: " + participant.getCNA ME());}// create a player by passing datasource to the Media ManagerPlayer p = javax.media.Manager.createPlayer(ds);if (p == null)return;p.addControllerListener(this);p.realize();PlayerWindow pw = new PlayerWindow(p, stream);playerWindows.addElement(pw);// Notify intialize() that a new stream had arrived.synchronized (dataSync) {dataReceived = true;dataSync.notifyAll();}} catch (Exception e) {System.err.println("NewReceiveStreamEvent exception " + e.getMessage());return;}}else if (evt instanceof StreamMappedEvent) {if (stream != null && stream.getDataSource() != null) {DataSource ds = stream.getDataSource();// Find out the formats.RTPControl ctl = (RTPControl)ds.getControl("javax.media.rtp.RTPControl"); System.err.println(" - The previously unidentified stream ");if (ctl != null)System.err.println(" " + ctl.getFormat());System.err.println(" had now been identified as sent by: " + participa nt.getCNAME());}}else if (evt instanceof ByeEvent) {System.err.println(" - Got \"bye\" from: " + participant.getCNAME());PlayerWindow pw = find(stream);if (pw != null) {pw.close();playerWindows.removeElement(pw);}}}/*** ControllerListener for the Players.*/public synchronized void controllerUpdate(ControllerEvent ce) {Player p = (Player)ce.getSourceController();if (p == null)return;// Get this when the internal players are realized.if (ce instanceof RealizeCompleteEvent) {PlayerWindow pw = find(p);if (pw == null) {// Some strange happened.System.err.println("Internal error!");System.exit(-1);}pw.initialize();pw.setVisible(true);p.start();}if (ce instanceof ControllerErrorEvent) {p.removeControllerListener(this);PlayerWindow pw = find(p);if (pw != null) {pw.close();playerWindows.removeElement(pw);}System.err.println("AVReceive3 internal error: " + ce);}}/*** A utility class to parse the session addresses.*/class SessionLabel {public String addr = null;public int port;public int ttl = 1;SessionLabel(String session) throws IllegalArgumentException {int off;String portStr = null, ttlStr = null;if (session != null && session.length() > 0) {while (session.length() > 1 && session.charAt(0) == '/') session = session.substring(1);// Now see if there's a addr specified.off = session.indexOf('/');if (off == -1) {if (!session.equals(""))addr = session;} else {addr = session.substring(0, off);session = session.substring(off + 1);// Now see if there's a port specifiedoff = session.indexOf('/');if (off == -1) {if (!session.equals(""))portStr = session;} else {portStr = session.substring(0, off);session = session.substring(off + 1);// Now see if there's a ttl specifiedoff = session.indexOf('/');if (off == -1) {if (!session.equals(""))ttlStr = session;} else {ttlStr = session.substring(0, off);}}}}if (addr == null)throw new IllegalArgumentException();if (portStr != null) {try {Integer integer = Integer.valueOf(portStr);if (integer != null)port = integer.intValue();} catch (Throwable t) {throw new IllegalArgumentException();}} elsethrow new IllegalArgumentException();if (ttlStr != null) {try {Integer integer = Integer.valueOf(ttlStr);if (integer != null)ttl = integer.intValue();} catch (Throwable t) {throw new IllegalArgumentException();}}}}/*** GUI classes for the Player.*/class PlayerWindow extends Frame {Player player;ReceiveStream stream;PlayerWindow(Player p, ReceiveStream strm) {player = p;stream = strm;}public void initialize() {add(new PlayerPanel(player));}public void close() {player.close();setVisible(false);dispose();}public void addNotify() {super.addNotify();pack();}}/*** GUI classes for the Player.*/class PlayerPanel extends Panel {Component vc, cc;PlayerPanel(Player p) {setLayout(new BorderLayout());if ((vc = p.getVisualComponent()) != null)add("Center", vc);if ((cc = p.getControlPanelComponent()) != null)add("South", cc);}public Dimension getPreferredSize() {int w = 0, h = 0;if (vc != null) {Dimension size = vc.getPreferredSize();w = size.width;h = size.height;}if (cc != null) {Dimension size = cc.getPreferredSize();if (w == 0)w = size.width;h += size.height;}if (w < 160)w = 160;return new Dimension(w, h);}}public static void main(String argv[]) {if (argv.length == 0)prUsage();AVReceive3 avReceive = new AVReceive3(argv);if (!avReceive.initialize()) {System.err.println("Failed to initialize the sessions."); System.exit(-1);}// Check to see if AVReceive3 is done.try {while (!avReceive.isDone())Thread.sleep(1000);} catch (Exception e) {}System.err.println("Exiting AVReceive3");}static void prUsage() {System.err.println("Usage: AVReceive3 <session> <session> "); System.err.println(" <session>: <address>/<port>/<ttl>");System.exit(0);}}// end of AVReceive3发送端代码:import java.awt.*;import java.io.*;import .InetAddress;import javax.media.*;import javax.media.protocol.*;import javax.media.protocol.DataSource;import javax.media.format.*;import javax.media.control.TrackControl;import javax.media.control.QualityControl;import javax.media.rtp.*;import javax.media.rtp.rtcp.*;import com.sun.media.rtp.*;public class AVTransmit3 {// Input MediaLocator// Can be a file or http or capture sourceprivate MediaLocator locator;private String ipAddress;private int portBase;private Processor processor = null;private RTPManager rtpMgrs[];private DataSource dataOutput = null;public AVTransmit3(MediaLocator locator,String ipAddress,String pb,Format format) {this.locator = locator;this.ipAddress = ipAddress;Integer integer = Integer.valueOf(pb);if (integer != null)this.portBase = integer.intValue();}/*** Starts the transmission. Returns null if transmission started ok. * Otherwise it returns a string with the reason why the setup failed. */public synchronized String start() {String result;// Create a processor for the specified media locator// and program it to output JPEG/RTPresult = createProcessor();if (result != null)return result;// Create an RTP session to transmit the output of the// processor to the specified IP address and port no.result = createTransmitter();if (result != null) {processor.close();processor = null;return result;}// Start the transmissionprocessor.start();return null;}/*** Stops the transmission if already started*/public void stop() {synchronized (this) {if (processor != null) {processor.stop();processor.close();processor = null;for (int i = 0; i < rtpMgrs.length; i++) {rtpMgrs[i].removeTargets( "Session ended.");rtpMgrs[i].dispose();}}}}private String createProcessor() {if (locator == null)return "Locator is null";DataSource ds;DataSource clone;try {ds = javax.media.Manager.createDataSource(locator);} catch (Exception e) {return "Couldn't create DataSource";}// Try to create a processor to handle the input media locator try {processor = javax.media.Manager.createProcessor(ds);} catch (NoProcessorException npe) {return "Couldn't create processor";} catch (IOException ioe) {return "IOException creating processor";}// Wait for it to configureboolean result = waitForState(processor, Processor.Configured);if (result == false)return "Couldn't configure processor";// Get the tracks from the processorTrackControl [] tracks = processor.getTrackControls();// Do we have atleast one track?if (tracks == null || tracks.length < 1)return "Couldn't find tracks in processor";// Set the output content descriptor to RAW_RTP// This will limit the supported formats reported from// Track.getSupportedFormats to only valid RTP formats.ContentDescriptor cd = new ContentDescriptor(ContentDescriptor.RAW_RTP); processor.setContentDescriptor(cd);Format supported[];Format chosen;boolean atLeastOneTrack = false;// Program the tracks.for (int i = 0; i < tracks.length; i++) {Format format = tracks[i].getFormat();if (tracks[i].isEnabled()) {supported = tracks[i].getSupportedFormats();// We've set the output content to the RAW_RTP.// So all the supported formats should work with RTP.// We'll just pick the first one.if (supported.length > 0) {if (supported[0] instanceof VideoFormat) {// For video formats, we should double check the// sizes since not all formats work in all sizes.chosen = checkForVideoSizes(tracks[i].getFormat(),supported[0]);} elsechosen = supported[0];tracks[i].setFormat(chosen);System.err.println("Track " + i + " is set to transmit as:");System.err.println(" " + chosen);atLeastOneTrack = true;} elsetracks[i].setEnabled(false);} elsetracks[i].setEnabled(false);}if (!atLeastOneTrack)return "Couldn't set any of the tracks to a valid RTP format";// Realize the processor. This will internally create a flow// graph and attempt to create an output datasource for JPEG/RTP // audio frames.result = waitForState(processor, Controller.Realized);if (result == false)return "Couldn't realize processor";// Set the JPEG quality to .5.setJPEGQuality(processor, 0.5f);// Get the output data source of the processordataOutput = processor.getDataOutput();return null;}/*** Use the RTPManager API to create sessions for each media* track of the processor.*/private String createTransmitter() {// Cheated. Should have checked the type.PushBufferDataSource pbds = (PushBufferDataSource)dataOutput;PushBufferStream pbss[] = pbds.getStreams();rtpMgrs = new RTPManager[pbss.length];SendStream sendStream;int port;SourceDescription srcDesList[];for (int i = 0; i < pbss.length; i++) {try {rtpMgrs[i] = RTPManager.newInstance();port = portBase + 2*i;// Initialize the RTPManager with the RTPSocketAdapterrtpMgrs[i].initialize(new RTPSocketAdapter(InetAddress.getByName(ipAddress),port));System.err.println( "Created RTP session: " + ipAddress + " " + port);sendStream = rtpMgrs[i].createSendStream(dataOutput, i);sendStream.start();} catch (Exception e) {return e.getMessage();}}return null;}/*** For JPEG and H263, we know that they only work for particular* sizes. So we'll perform extra checking here to make sure they* are of the right sizes.*/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)) {// For JPEG, make sure width and height are divisible by 8.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)) {// For H.263, we only support some specific sizes.if (size.width < 128) {width = 128;height = 96;} else if (size.width < 176) {width = 176;height = 144;} else {width = 352;height = 288;}} else {// We don't know this particular format. We'll just// leave it alone then.return supported;}return (new VideoFormat(null,new Dimension(width, height),Format.NOT_SPECIFIED,null,Format.NOT_SPECIFIED)).intersects(supported);}/*** Setting the encoding quality to the specified value on the JPEG encoder. * 0.5 is a good default.*/void setJPEGQuality(Player p, float val) {Control cs[] = p.getControls();QualityControl qc = null;VideoFormat jpegFmt = new VideoFormat(VideoFormat.JPEG);// Loop through the controls to find the Quality control for// the JPEG encoder.for (int i = 0; i < cs.length; i++) {if (cs[i] instanceof QualityControl &&cs[i] instanceof Owned) {Object owner = ((Owned)cs[i]).getOwner();// Check to see if the owner is a Codec.// Then check for the output format.if (owner instanceof Codec) {Format fmts[] = ((Codec)owner).getSupportedOutputFormats(null);for (int j = 0; j < fmts.length; j++) {if (fmts[j].matches(jpegFmt)) {qc = (QualityControl)cs[i];qc.setQuality(val);System.err.println("- Setting quality to " +val + " on " + qc);break;}}}if (qc != null)break;}}}/**************************************************************** * Convenience methods to handle processor's state changes.****************************************************************/private Integer stateLock = new Integer(0);private boolean failed = false;Integer getStateLock() {return stateLock;}void setFailed() {failed = true;}private synchronized boolean waitForState(Processor p, int state) { p.addControllerListener(new StateListener());failed = false;// Call the required method on the processorif (state == Processor.Configured) {p.configure();} else if (state == Processor.Realized) {p.realize();}// Wait until we get an event that confirms the// success of the method, or a failure event.// See StateListener inner classwhile (p.getState() < state && !failed) {synchronized (getStateLock()) {try {getStateLock().wait();} catch (InterruptedException ie) {return false;}}}if (failed)return false;elsereturn true;}/***************************************************************** Inner Classes****************************************************************/ class StateListener implements ControllerListener {public void controllerUpdate(ControllerEvent ce) {// If there was an error during configure or// realize, the processor will be closedif (ce instanceof ControllerClosedEvent)setFailed();// All controller events, send a notification// to the waiting thread in waitForState method.if (ce instanceof ControllerEvent) {synchronized (getStateLock()) {getStateLock().notifyAll();}}}}/***************************************************************** Sample Usage for AVTransmit3 class****************************************************************/public static void main(String [] args) {// We need three parameters to do the transmission// For example,// java AVTransmit3 file:/C:/media/test.mov 129.130.131.132 42050if (args.length < 3) {prUsage();}Format fmt = null;int i = 0;// Create a audio transmit object with the specified params. AVTransmit3 at = new AVTransmit3(new MediaLocator(args[i]), args[i+1], args[i+2], fmt);// Start the transmissionString result = at.start();// result will be non-null if there was an error. The return // value is a String describing the possible error. Print it.if (result != null) {System.err.println("Error : " + result);System.exit(0);}System.err.println("Start transmission for 60 seconds");// Transmit for 60 seconds and then close the processor// This is a safeguard when using a capture data source// so that the capture device will be properly released// before quitting.// The right thing to do would be to have a GUI with a// "Stop" button that would call stop on AVTransmit3 try {Thread.currentThread().sleep(60000);} catch (InterruptedException ie) {}// Stop the transmissionat.stop();System.err.println("transmission ended.");System.exit(0);}static void prUsage() {System.err.println("Usage: AVTransmit3 <sourceURL> <destIP> <destPortBase>"); System.err.println(" <sourceURL>: input URL or file name");System.err.println(" <destIP>: multicast, broadcast or unicast IP address f or the transmission");System.err.println(" <destPortBase>: network port numbers for the transmiss ion.");System.err.println(" The first track will use the destPortB ase.");System.err.println(" The next track will use destPortBase + 2 and so on.\n");System.exit(0);}}底层传输部分代码:import java.io.IOException;import .InetAddress;import .DatagramSocket;import .MulticastSocket;import .DatagramPacket;import .SocketException;import javax.media.protocol.DataSource;import javax.media.protocol.PushSourceStream;import javax.media.protocol.ContentDescriptor;import javax.media.protocol.SourceTransferHandler;import javax.media.rtp.RTPConnector;import javax.media.rtp.OutputDataStream;/*** An implementation of RTPConnector based on UDP sockets.*/public class RTPSocketAdapter implements RTPConnector {DatagramSocket dataSock;DatagramSocket ctrlSock;InetAddress addr;int port;SockInputStream dataInStrm = null, ctrlInStrm = null;SockOutputStream dataOutStrm = null, ctrlOutStrm = null;public RTPSocketAdapter(InetAddress addr, int port) throws IOException {this(addr, port, 1);}public RTPSocketAdapter(InetAddress addr, int port, int ttl) throws IOException {try {if (addr.isMulticastAddress()) {dataSock = new MulticastSocket(port);ctrlSock = new MulticastSocket(port+1);((MulticastSocket)dataSock).joinGroup(addr);((MulticastSocket)dataSock).setTimeToLive(ttl);((MulticastSocket)ctrlSock).joinGroup(addr);((MulticastSocket)ctrlSock).setTimeToLive(ttl);} else {dataSock = new DatagramSocket(port, InetAddress.getLocalHost());ctrlSock = new DatagramSocket(port+1, InetAddress.getLocalHost());}} catch (SocketException e) {throw new IOException(e.getMessage());}this.addr = addr;this.port = port;}/*** Returns an input stream to receive the RTP data.*/public PushSourceStream getDataInputStream() throws IOException {if (dataInStrm == null) {dataInStrm = new SockInputStream(dataSock, addr, port);dataInStrm.start();}return dataInStrm;}/*** Returns an output stream to send the RTP data.*/public OutputDataStream getDataOutputStream() throws IOException {if (dataOutStrm == null)dataOutStrm = new SockOutputStream(dataSock, addr, port);return dataOutStrm;}/*** Returns an input stream to receive the RTCP data.*/public PushSourceStream getControlInputStream() throws IOException {if (ctrlInStrm == null) {ctrlInStrm = new SockInputStream(ctrlSock, addr, port+1);ctrlInStrm.start();}return ctrlInStrm;}/*** Returns an output stream to send the RTCP data.*/public OutputDataStream getControlOutputStream() throws IOException { if (ctrlOutStrm == null)ctrlOutStrm = new SockOutputStream(ctrlSock, addr, port+1);return ctrlOutStrm;}/*** Close all the RTP, RTCP streams.*/public void close() {if (dataInStrm != null)dataInStrm.kill();if (ctrlInStrm != null)ctrlInStrm.kill();dataSock.close();ctrlSock.close();}/*** Set the receive buffer size of the RTP data channel.* This is only a hint to the implementation. The actual implementation* may not be able to do anything to this.*/public void setReceiveBufferSize( int size) throws IOException {dataSock.setReceiveBufferSize(size);}/*** Get the receive buffer size set on the RTP data channel.* Return -1 if the receive buffer size is not applicable for* the implementation.*/public int getReceiveBufferSize() {try {return dataSock.getReceiveBufferSize();} catch (Exception e) {return -1;}}/*** Set the send buffer size of the RTP data channel.* This is only a hint to the implementation. The actual implementation * may not be able to do anything to this.*/public void setSendBufferSize( int size) throws IOException {dataSock.setSendBufferSize(size);}/*** Get the send buffer size set on the RTP data channel.* Return -1 if the send buffer size is not applicable for* the implementation.*/public int getSendBufferSize() {try {return dataSock.getSendBufferSize();} catch (Exception e) {return -1;}}/*** Return the RTCP bandwidth fraction. This value is used to* initialize the RTPManager. Check RTPManager for more detauls.* Return -1 to use the default values.*/public double getRTCPBandwidthFraction() {return -1;}/*** Return the RTCP sender bandwidth fraction. This value is used to* initialize the RTPManager. Check RTPManager for more detauls.* Return -1 to use the default values.*/public double getRTCPSenderBandwidthFraction() {return -1;}/*** An inner class to implement an OutputDataStream based on UDP sockets. */class SockOutputStream implements OutputDataStream {DatagramSocket sock;InetAddress addr;int port;public SockOutputStream(DatagramSocket sock, InetAddress addr, int port) { this.sock = sock;this.addr = addr;this.port = port;}public int write(byte data[], int offset, int len) {try {sock.send(new DatagramPacket(data, offset, len, addr, port));} catch (Exception e) {return -1;}return len;}}/*** An inner class to implement an PushSourceStream based on UDP sockets.。
基于RTP与模板卷积法的视频无线传输技术汪宋良;卓微【摘要】The paper proposes adaptive subcontracting technology using a new RTCP feedback technology and calculation methods of motion vector based on template convolution,based on RTP transport protocol and MPEG-4 stream subcontracting.The technology in a wire transmission can effectively solve the high-resolution video images of the large amount of data packet loss rate problem.By the experimental results show that the technology can guarantee a high quality of real-time wireless video transmission.%速率控制和差错控制是视频传输系统重点研究内容,在RTP实时传输协议和MPEG-4码流分包的基础上,提出了采用一种新的基于RTCP反馈的自适应分包技术和基于模板卷积的计算运动矢量的方法.该技术能有效解决高分辨率、大数据量视频图像在无线视频传输中的丢包率难题.通过实验结果表明,该技术能保证无线视频实时传输质量.【期刊名称】《计算机系统应用》【年(卷),期】2013(022)005【总页数】5页(P198-202)【关键词】RTP;自适应分包法;差错掩盖;无线视频传输;模板卷积【作者】汪宋良;卓微【作者单位】宁波城市职业技术学院信息学院,宁波315100;宁波大学信息学院,宁波315211【正文语种】中文高分辨率无线视频传输需要消耗大量带宽, 同时存在时延严格、无线信道易干扰、差错率高以及时变和不对称传播的特性. 虽然MPEG-4本身带有一定的纠错机制,如变字长码编码和预测编码等技术, 使用改变量化参数进行码率控制的自适应编码、多码率编码、分层编码、多描述编码等技术[1], 但是无线信道传输视频信息仍会造成丢包率较高情况. 本文将讨论无线视频传输中的实时传输技术和差错控制机制. 1.1 传统分包法在无线视频传输系统中, 为保证播放视频流畅, 目前较多采用Real-time Transport Protocol协议(以下简称RTP)解决实时传输问题. RTP是用于Internet上针对多媒体数据流的一种实时应用的传输协议, 可以提供端到端的网络传输服务. 传统的分包技术多数采用RTP硬分包法. 即不管数据的内容, 机械的将固定的值(常常以MTU)作为每个包的大小. 这样, 同一个视频帧可能会被放入两个不同的包内, 每个数据包之间的相关性会非常大, 数据一旦发生丢包, 就无法在接收端采取差错掩盖的技术进行恢复, 因为接收到的数据有可能是不完整的, 也不知道是哪一帧被丢弃. 因此, 这种方法有可能造成接收端画面的黑屏或者不连续, 大大影响播放的质量而无线信道中, 信道的利用率和数据包的长度有直接的关系[2], 如图1所示. 包的长度并不是越长越好, 我们要对视频流采取合理的、动态的RTP分包方法, 把丢包率控制在中低程度. 在设计新的分包方法时候充分考虑两个因素: 1)如何实现自适应. 即根据网络条件(如带宽、拥塞程度等)变化自适应地调整RTP大小, 以此来提供更好的服务质量; 2)如何提高带宽使用率, 不浪费有限的带宽资源.1.2 基于RTCP反馈自适应分包法本文沿用RFC3016中VOP作为封装的基本单元进行软分包技术, 并在此基础上提出基于宏块的自适应调整分包大小的方法. 对于一个超过MTU大小的VOP的分包, 要分成几个不同的RTP包(VGA格式的MPEG-4视频流中几乎每个VOP都会超过MTU的大小). 每个包的数据以宏块为单位存入. 而每个RTP包中的宏块个数根据反馈到的网络状态自动调整. 如图2所示, 系统建立一个反馈机制, 在接收端截取RTCP包, 进行自适应分包控制. 一个包的丢失只是导致几个宏块的损坏. 接收端的解码时采用差错掩盖技术, 使解码时尽可能掩盖和减小由于丢包而出现的差错, 使图像的视觉效果接近于原来的效果.1.3 基于宏块自适应分包规则以VOP为单位打包既提高了效率, 又充分利用MPEG-4的编码特性, 具体分包规则如下:1) MPEG-4码流的头通常携带比较重要的信息, 所以单独一个RTP包;2) 不同的VOP应该分为不同的RTP包, 这样可以保证RTP时间戳能唯一地表示VOP分帧时间. 即使在包空间允许的情况下, 也不能把不同的VOP数据打入同一个RTP包中;3) 对于一个超过MTU大小的VOP的分包, 要以MTU为单位, 分成几个不同的RTP包.自适应调整分包大小的方法具体如下: 发送端通过RTCP反馈过来RR包并计算丢包率信息, 判断当前的网络状况处于轻载、重载或是拥塞. 若确认处于长期拥塞的状态时, 则对它的分包大小进行动态的调整, 减少包的长度. 待恢复正常以后再缓慢增大包的长度. 本方案采用一种类似于网络传输速率控制中的AMD方法(即乘性减少、加性增加), 动态地对宏块进行打包, 公式如下:其中为返回的RTCP包所含的丢包率, 一个VOP中所剩余的宏块个数, 为线性增量因子, 为乘性减少因子, 为丢包率的门限值, 为当前打入一个RTP数据包的宏块个数, 为根据当前网络状态更新后的一个RTP包中的宏块个数, 为取整符号.无线视频传输系统传送VGA格式的高分辨率视频图像信号存在信道易错、时变和带限等特征, 以及因多径现象导致的慢衰落和快衰落现象, 使无线信道的误码率要比有线环境大得多. 在采取RTP自适应分包技术后, 仍有部分发生差错的数据被丢弃. 所以传输系统要有一定的差错控制机制. 差错控制机制主要可以分为时域掩盖和空域掩盖, 本系统的空域差错掩盖技术采用一种基于针对编码具有低复杂度的空域差错掩盖算法[3]实现, 而时域差错掩盖技术采用一种新的模板卷积的算法实现.2.1 空域差错掩盖技术这种算法对连续多行的宏块丢失具有很好的掩盖效果, 非常适合无线网络环境下的视频应用. 由于帧内编码帧的差错掩盖非常重要, 算法核心思想为I帧数据的误码宏块中的每一个象素与同一帧个相邻宏块正确的象素进行加权内插来重构错误宏块. 以16*16的宏块为例, P (i,j)是受损宏块中的某个象素点, 它通过周围的个象素的插值进行估计. Ptop(i,16)、 Pbottom(i,1)、 Pleft(16,j)、Pright(1,j)表示上下左右四个相邻块中最靠近受损宏块的像素点. j、17-j、i、17-i分别为对应的权重值, 如图3所示. 在进行插值时, 只使用可以得到的宏块. 若上下左右四个相邻的宏块数据都是正常的, 则插值处理用公式(2)描述如下:但是, 一般来说, 宏块信息受损时, 其水平方向相邻宏块的信息也会受损, 所以插值计算主要是使用上面和下面接邻宏块的像素点来计算. 计算公式(3)描述如下: 2.2 时域差错掩盖技术本文采用类似于模板卷积算法, 取当前帧的受损宏块的上方接邻宏块(记为A)的部分特征作为匹配模板, 用该模板与前一帧对应位置的宏块(记为A)进行逐列比较, 计算各位置的卷积值, 取卷积最大的点为最佳匹配点, 将该匹配点的位置与该模板在当前帧中的位置相比较, 求得图像运动距离, 即为运动矢量[4,5]. 具体的实现步骤如图4所示.1) 在宏块A中取N列图像作为匹配的模板, 在前一帧的对应的宏块A中也选取n 列图像(一般从第一列开始比较);2) 用(1)选取当前帧的宏块A中N列图像与前一帧的宏块A中的第1~N列图像进行卷积, 对各像素的卷积的结果求和, 作为当前帧宏块A中该位置的卷积和;3) 前一帧的宏块A中的N列图像往右移动一列, 重复步骤2)3);4) 当前帧的宏块A的N列与前一帧的16列(16为宏块的宽度)图像卷积后, 得到16-N+1个卷积和的结果值, 求其中的最大值, 该值对应的前一帧的位置, 即为匹配模块在前一帧的最佳匹配位置, 计算该位置和匹配模块在当前帧的位置之间的差, 从而得到当前帧的宏块A的运动矢量.3.1 自适应分包法实验结果表1是多次实验获得的丢包率数据. 系统在传输分辨率为320*240(QVGA格式)的图像时, 丢包率在1%-3%之间, 对改进RTP自适应分包法效果不明显. 而系统在传输分辨率为640*480(VGA格式)的图像时, 数据量在20M字节至30M字节之间. 由此可得, RTP自适应对MPEG-4流进行分包方法在无线传输的丢包率较传统的硬分包的丢包率小, 均值在5.8%左右, 在无线网络中属于中低丢包率. 从视觉感官角度来说, 图像的连续性较好, 传输延迟小, 效果比较理想. 此外, 当发送频率下调至每秒15帧时, 则丢包率明显下降, 因此丢包率和包的发送频率也是非常有关的.3.2 差错控制机制实验结果在差错掩盖的实验中, 首先对标准视频序的Forman序列进行了空域差错掩盖和时域差错掩盖的实验. 图像质量的客观评价主要用图像的峰值信噪比(PSNR, Peak Signal to Noise Ratio)的大小来衡量. 对空域差错掩盖时, 取forman序列的第1帧. 该帧的某一宏块丢失, 造成黑屏, 如图5(a)所示. 图5(b)是使用空域差错掩盖方法进行恢复后的图像. 由图可见, 帧内编码帧的图像, 若采用空域的方法进行恢复, 效果理想.在使用时域差错掩盖技术时, 取forman序列的0-10帧, 若每一帧的相同宏块的损坏或丢失, 则使用模板卷积的方法重新计算相邻两帧该宏块的运动矢量. 表2是计算得出的受损宏块的运动矢量.图6(c)(d)是F1帧的受损图像根据运动矢量, 运动补偿后的获得的图像. 由此可见, 当F1帧的受损宏块使用前一帧F0的对应的宏块来简单代替时, 即宏块的运动矢量为0时, 图像掩盖效果不是很好, 有明显的方块效应, 且图像的不连续. 这是由于forman序列运动较为剧烈, 且人物和镜头都在晃动, 而且, 该方法实际上并没有使用运动补偿的方法. 所以利用前一帧对应位置的正确数据块来代替当前帧的错误数据块的方法只适用于静止的图像或者运动较小的区域, 不适用于快速运动的区域. 而采用本文提出的模板卷积的方法, 从视觉效果上看, 图像连续, 从实验数据来说, 图像的PSNR值较前者有所提高.为了与系统更好的结合, 在使用时域差错的模板卷积的技术运动矢量的实验中, 采取了系统采集到图片进行恢复. 图7是对实际摄像机系统中接收端的某一帧的截取. 由图可得, 使用模板卷积方法进行时域的差错掩盖, 恢复的图像效果良好.通过实验表明, 文中提出的基于RTCP反馈的自适应分包方法和基于模板卷积的时域差错掩盖计算方法对改善高分辨率图像的无线传输效果具有显著的效果. 采用该技术将实时视频数据传输到接收端, 测试得知, 在空旷的50米内的空间范围内, 在图像分辨率为640×480时, 采集速度稳定在每秒30帧, 视频较为流畅, 丢包现象较少, 基本达到了传输要求. 在实际应用中具有很大的商业开发价值.1 Ding XW, Yang ZX, Guo YC. Temporal Error Concealment Technique for MPEG-4 Video.Transactions of Tianjin University, 2006,12(4):291-296.2 董振亚,张拥军,彭宇行.基于RTP的MPEG-4视频传输.计算机应用研究,2003,20(7):57-59.3 徐银辉,周伟,董育宁.一种基于数据隐藏的H.264空域差错掩盖的改进方法.广东通信技术,2008,28(3):5-7,11.4 马鑫,杨小康,宋利.自适应时域差错掩盖方法.中国图象图形学报,2007,12(10):1782-1785.5 贺贵明,吴元保,蔡朝晖,等.基于内容的视频编码与传输控制技术.武汉:武汉大学出版社,2004.6 Gonzalez RC, Woods RE.数字图像处理.北京:电子工业出版社,2004.。
基于RTP的机载网络视频实时监控系统设计郝朝;王灏【摘要】在飞行试验中,视频实时监控是保障试飞安全和提高试飞效率的重要环节.为了解决某型机机载网络视频的实时监控问题,提出了基于RTP/RTCP协议的机载网络视频实时解析系统设计方案.通过UDP组播协议接收网络电台发送的RTP/RTCP数据包,经过解包,拼成完整的一帧视频图像,采用FFmpeg进行视频解码并利用SDL进行显示.首先介绍了遥测网络视频实时监控系统架构,重点介绍了RTP/RTCP协议及解包方法,然后论述了视频解码与显示流程、YUV图像处理算法.软件采用模块化、多线程并发和多缓冲区设计思路,提高处理效率,保证网络视频监控的实时性和功能的可扩展性.目前该软件已成功应用于某型号任务视频实时监控中.实际应用效果表明,视频播放效果清晰流畅,该软件具有良好的实时性、可靠性和人机交互功能,有效保证了试飞安全.【期刊名称】《计算机技术与发展》【年(卷),期】2019(029)005【总页数】4页(P131-134)【关键词】RTP/RTCP;机载网络视频;FFmpeg;SDL;多线程;实时监控【作者】郝朝;王灏【作者单位】中国飞行试验研究院,陕西西安 710089;中国飞行试验研究院,陕西西安 710089【正文语种】中文【中图分类】TP311.10 引言在飞行试验中,实时监控是保障飞行安全和提高飞行效率的一个关键环节,要求实时查看飞行器的位置姿态信息和设备的工作状态。
机载视频影像能够以最为直观与准确的方式描述飞机当前的工作状态,为地面飞行指挥人员和试飞工程师提供及时、丰富的信息,对于保障飞行安全、提高试飞效率有不可替代的作用[1]。
在某型飞机的实时监控中,既有传统的PCM数据遥测,也有网络电台遥测。
传统的视频遥测是将数字视频信号以PCM流的形式传输至地面进行解析[2]。
在该型机上,由于任务需求,在机上加装网络摄像头,通过网络电台以RTP/RTCP[3-4]网络数据包的形式进行H.264视频网络化遥测传输。
基于rtp_jmf的摄像头视频采集和传输1.txt人永远不知道谁哪次不经意的跟你说了再见之后就真的再也不见了。
一分钟有多长?这要看你是蹲在厕所里面,还是等在厕所外面……JMF 视频传输Rtp与Rtcp协议1.流媒体( Streaming Media)1.1流媒体概念流媒体技术是网络技术和多媒体技术发展到一定阶段的产物。
术语流媒体既可以指在网上传输连续时基媒体的流式技术,也可以指使用流式技术的连续时基媒体本身。
在网上传输音频、视频等多媒体信息目前主要有两种方式:下载和流式传输。
采用下载方式,用户需要先下载整个媒体文件,然后才能进行播放。
由于网络带宽的限制,下载常常要花很长时间,所以这种处理方式延迟很大。
而流媒体实现的关键技术是流式传输。
传输之前首先对多媒体进行预处理(降低质量和高效压缩) ,然后使用缓存系统来保证数据连续正确地进行传输。
使用流式传输方式,用户不必像采用下载方式那样要等到整个文件全部下载完毕,而是只需经过几秒到几十秒的启动延时即可在客户端进行播放和观看。
此时媒体文件的剩余部分将在后台继续下载。
与单纯的下载方式相比,这种对多媒体文件边下载边播放的流式传输方式不仅使启动延时大幅度地缩短,而且对系统缓存容量的需求也大大降低。
使用流式传输的另一个好处是使传输那些事先不知道或无法知道大小的媒体数据(如网上直播、视频会议等) 成为可能。
到目前为止,Internet 上使用较多的流式视频格式主要有以下三种:RealNetworks 公司的RealMedia ,Apple 公司的QuickTime 以及Microsoft 公司的Advanced Streaming Format (ASF) 。
1.2支持流媒体的协议多媒体应用的一个显著特点是数据量大,并且许多应用对实时性要求比较高。
传统的TCP 协议是一个面向连接的协议,它的重传机制和拥塞控制机制都是不适用于实时多媒体传输的。
RTP 是一个应用型的传输层协议,它并不提供任何传输可靠性的保证和流量的拥塞控制机制。
RTP 位于UDP(User Datagram Protocol) 之上。
UDP 虽然没有TCP 那么可靠,并且无法保证实时业务的服务质量,需要RTCP 实时监控数据传输和服务质量。
但是,由于UDP 的传输时延低于TCP ,能与音频和视频很好地配合。
因此,在实际应用中,RTP/ RTCP/ UDP 用于音频/ 视频媒体,而TCP 用于数据和控制信令的传输。
目前,支持流媒体传输的协议主要有实时传输协议RTP( Real-Time Transport Protocol) 、实时传输控制协议RTCP(Real-Time Transport Control Protocol) 和实时流协议RTSP(Real-Time Streaming Protocol) 等2.实时传输协议RTP(Real-Time Transport Protocol):RTP是针对Internet上多媒体数据流的一个传输协议, 由IETF(Internet工程任务组)作为RFC1889发布。
RTP被定义为在一对一或一对多的传输情况下工作,其目的是提供时间信息和实现流同步。
RTP的典型应用建立在UDP上,但也可以在TCP或ATM等其他协议之上工作。
RTP本身只保证实时数据的传输,并不能为按顺序传送数据包提供可靠的传送机制,也不提供流量控制或拥塞控制,它依靠RTCP提供这些服务。
2.1 RTP工作机制威胁多媒体数据传输的一个尖锐的问题就是不可预料数据到达时间。
但是流媒体的传输是需要数据的适时的到达用以播放和回放。
rtp协议就是提供了时间标签,序列号以及其它的结构用于控制适时数据的流放。
在流的概念中”时间标签”是最重要的信息。
发送端依照即时的采样在数据包里隐蔽的设置了时间标签。
在接受端收到数据包后,就依照时间标签按照正确的速率恢复成原始的适时的数据。
不同的媒体格式调时属性是不一样的。
但是rtp本身并不负责同步,rtp只是传输层协议,为了简化运输层处理,提高该层的效率。
将部分运输层协议功能(比如流量控制)上移到应用层完成。
同步就是属于应用层协议完成的。
它没有运输层协议的完整功能,不提供任何机制来保证实时地传输数据,不支持资源预留,也不保证服务质量。
rtp报文甚至不包括长度和报文边界的描述。
同时rtp协议的数据报文和控制报文的使用相邻的不同端口,这样大大提高了协议的灵活性和处理的简单性。
rtp协议和udp二者共同完成运输层协议功能。
udp协议只是传输数据包,不管数据包传输的时间顺序。
rtp的协议数据单元是用udp分组来承载的。
在承载rtp数据包的时候,有时候一帧数据被分割成几个包具有相同的时间标签,则可以知道时间标签并不是必须的。
而udp的多路复用让rtp协议利用支持显式的多点投递,可以满足多媒体会话的需求。
rtp协议虽然是传输层协议但是它没有作为osi体系结构中单独的一层来实现。
rtp协议通常根据一个具体的应用来提供服务,rtp只提供协议框架,开发者可以根据应用的具体要求对协议进行充分的扩展。
3.实时传输控制协议RTCP(Real-Time Transport Control Protocol)RTCP负责管理传输质量在当前应用进程之间交换控制信息。
在RTP会话期间,各参与者周期性地传送RTCP包,包中含有已发送的数据包的数量、丢失的数据包的数量等统计资料。
因此,服务器可以利用这些信息动态地改变传输速率,甚至改变有效载荷类型。
RTP和RTCP 配合使用,能以有效的反馈和最小的开销使传输效率最佳化,故特别适合传送网上的实时数据。
3.1 RTCP工作机制当应用程序开始一个rtp会话时将使用两个端口:一个给rtp,一个给rtcp。
rtp本身并不能为按顺序传送数据包提供可靠的传送机制,也不提供流量控制或拥塞控制,它依靠rtcp提供这些服务。
在rtp的会话之间周期的发放一些rtcp包以用来传监听服务质量和交换会话用户信息等功能。
rtcp包中含有已发送的数据包的数量、丢失的数据包的数量等统计资料。
因此,服务器可以利用这些信息动态地改变传输速率,甚至改变有效载荷类型。
rtp 和rtcp配合使用,它们能以有效的反馈和最小的开销使传输效率最佳化,因而特别适合传送网上的实时数据。
根据用户间的数据传输反馈信息,可以制定流量控制的策略,而会话用户信息的交互,可以制定会话控制的策略。
3.2 RTCP数据报在RTCP通信控制中,RTCP协议的功能是通过不同的RTCP数据报来实现的,主要有如下几种类型:①SR:发送端报告,所谓发送端是指发出RTP数据报的应用程序或者终端,发送端同时也可以是接收端。
②RR:接收端报告,所谓接收端是指仅接收但不发送RTP数据报的应用程序或者终端。
③SDES:源描述,主要功能是作为会话成员有关标识信息的载体,如用户名、邮件地址、电话号码等,此外还具有向会话成员传达会话控制信息的功能。
④BYE:通知离开,主要功能是指示某一个或者几个源不再有效,即通知会话中的其他成员自己将退出会话。
⑤APP:由应用程序自己定义,解决了RTCP的扩展性问题,并且为协议的实现者提供了很大的灵活性。
JMF术语名称:Java媒体框架(JMF)术语解释:该核心框架支持不同媒体(如:音频输出和视频输出)间的时钟同步。
它是一个标准的扩展框架,允许用户制作纯音频流和视频流。
JMF实际上是Java的一个类包。
JMF 2.1.1技术提供了先进的媒体处理能力,从而扩展了Java平台的功能。
这些功能包括:媒体捕获、压缩、流转、回放,以及对各种主要媒体形式和编码的支持,如M-JPEG、H.263、MP3、RTP/RTSP (实时传送协议和实时流转协议)、Macromedias Flash、IBM的HotMedia和Beatniks的Rich Media Format (RMF)等。
JMF 2.1.1还支持广受欢迎的媒体类型,如Quicktime、Microsofts AVI和MPEG-1等。
此外,JMF 2.1.1软件中包括了一个开放的媒体架构,可使开发人员灵活采用各种媒体回放、捕获组件,或采用他们自己的定制的内插组件。
Sun以四种不同的专用版本提供JMF 2.1.1技术,满足专业开发人员的各类需求,第一个是一个轻便型版本,它完全采用Java语言编写,适用于任何Java兼容系统。
此外,开发人员还可选择分别适用于Solaris、Windows或Linux等操作系统的性能最优化软件包,以提高性能和能力。
JMF 2.1.1软件也是Java Media系列软件的一部分。
Java Media系列软件包括Java 3D、Java 2D、Java Sound和Java Advanced Imaging等API。
采用各种Java Media API,软件开发商人员就能容易、快速地为他们已有的各种应用程序和客户端Java小程序增添丰富的媒体功能,如流式视频、3D图像和影像处理等。
就是说,各种Java Media API发挥了Java 平台的固有优势,将"编写一次,到处运行"的能力扩展到了图像、影像和数字媒体等各种应用领域,从而大大缩减了开发时间和降低了开发成本。
JMF系统介绍一.简介1.1JMF 体系结构简介在开发JMF 应用程序之前要完全理解JMF 的体系架构、接口和类。
就拿我们的家用摄像机系统作个例子。
首先用摄像机拍摄内容,拍摄下来的内容录制在DV带中。
DV带可以放在放像机里播放、放像机提供视频信号给电视机,提供音频信号给音箱,这样我们就可以在电视机上看到画面,从音箱里听到声音。
JMF API 提供的也是同样的模型。
JMF 提供的模型可大致分为七类* 数据源(Data source)* 截取设备(Capture Device,包括视频和音频截取设备)* 播放器(Player)* 处理器(Processor)* 数据池(DataSink)* 数据格式(Format)* 管理器(Manager)1.2 如何应用JMF捕获媒体数据可以应用JMF从摄像头和麦克风中采集数据,采集后的数据可以被处理、保存、渲染为以后应用。
捕获媒体数据需要做以下工作。
1.定位所需要用的捕获设备,可以通过查询CaptureDeviceManager来定位。
2.获取这个捕获设备的信息CaptureDeviceInfo对象。
3.从CaptureDeviceInfo对象中获取捕获设备的位置Medialocator。
4.利用MediaLocator创建DataSource。
5.使用DataSource创建Player或是Processor。
6.然后启动Player就开始了媒体的捕获。
如果只是想观看捕获的内容,只需要使用捕获数据源创建播放器Player即可。