- 浏览: 868156 次
- 性别:
- 来自: 上海
最新评论
-
waterflow:
感谢分享
简单的ChartDirector生成图表例子 -
YQuite:
写到最后一种文件才看到这个,洼的一声哭了出来 - - !
java简单解析docx、pptx、xlsx文档 -
q394469902:
Android通过selector改变界面状态 -
db6623919:
直接粘贴别人帖子还是英文的,有意思?
实现RTSP协议的简单例子 -
ykou314:
请问下,这些超级命令,是否需要android root权限,尤 ...
Android系统在超级终端下必会的命令大全(七)
Back to RTPSourceStream and StreamingDataSource
With the protocol handler in place, let's revisit the RTPSourceStream
and StreamingDataSource
classes from earlier, where they contained only place-holder methods. The StreamingDataSource
is simple to code:
import java.io.IOException; import javax.microedition.media.Control; import javax.microedition.media.protocol.DataSource; import javax.microedition.media.protocol.SourceStream; public class StreamingDataSource extends DataSource { // the full URL like locator to the destination private String locator; // the internal streams that connect to the source // in this case, there is only one private SourceStream[] streams; // is this connected to its source? private Boolean connected = false; public StreamingDataSource(String locator) { super(locator); setLocator(locator); } public void setLocator(String locator) { this.locator = locator; } public String getLocator() { return locator; } public void connect() throws IOException { // if already connected, return if (connected) return; // if locator is null, then can't actually connect if (locator == null) throw new IOException("locator is null"); // now populate the sourcestream array streams = new RTPSourceStream[1]; // with a new RTPSourceStream streams[0] = new RTPSourceStream(locator); // set flag connected = true; } public void disconnect() { // if there are any streams if (streams != null) { // close the individual stream try { ((RTPSourceStream)streams[0]).close(); } catch(IOException ioex) {} // silent } // and set the flag connected = false; } public void start() throws IOException { if(!connected) return; // start the underlying stream ((RTPSourceStream)streams[0]).start(); } public void stop() throws IOException { if(!connected) return; // stop the underlying stream ((RTPSourceStream)streams[0])Close(); } public String getContentType() { // for the purposes of this article, it is only video/mpeg return "video/mpeg"; } public Control[] getControls() { return new Control[0]; } public Control getControl(String controlType) { return null; } public SourceStream[] getStreams() { return streams; } }
The main work takes place in the connect()
method. It creates a new RTPSourceStream
with the requested address. Notice that the getContentType()
method returns video/mpeg
as the default content type, but change it to the supported content type for your system. Of course, this should not be hard-coded; it should be based on the actual support for different media types.
The next listing shows the complete RTPSourceStream
class, which, along with RTSPProtocolHandler
, does the bulk of work in connecting getting the RTP packets of the server:
import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import javax.microedition.io.Datagram; import javax.microedition.io.Connector; import javax.microedition.media.Control; import javax.microedition.io.SocketConnection; import javax.microedition.io.DatagramConnection; import javax.microedition.media.protocol.SourceStream; import javax.microedition.media.protocol.ContentDescriptor; public class RTPSourceStream implements SourceStream { private RTSPProtocolHandler handler; private InputStream is; private OutputStream Os; private DatagramConnection socket; public RTPSourceStream(String address) throws IOException { // create the protocol handler and set it up so that the // application is ready to read data // create a socketconnection to the remote host // (in this case I have set it up so that its localhost, you can // change it to wherever your server resides) SocketConnection sc = (SocketConnection)Connector.open("socket://localhost:554"); // open the input and output streams is = sc.openInputStream(); Os = sc.openOutputStream(); // and initialize the handler handler = new RTSPProtocolHandler(address, is, Os); // send the basic signals to get it ready handler.doDescribe(); handler.doSetup(); } public void start() throws IOException { // open a local socket on port 8080 to read data to socket = (DatagramConnection)Connector.open("datagram://:8080"); // and send the PLAY command handler.doPlay(); } public void close() throws IOException { if(handler != null) handler.doTeardown(); is.close(); os.close(); } public int read(byte[] buffer, int offset, int length) throws IOException { // create a byte array which will be used to read the datagram byte[] fullPkt = new byte[length]; // the new Datagram Datagram packet = socket.newDatagram(fullPkt, length); // receive it socket.receive(packet); // extract the actual RTP Packet's media data in the requested buffer RTPPacket rtpPacket = getRTPPacket(packet, packet.getData()); buffer = rtpPacket.getData(); // debug System.err.println(rtpPacket + " with media length: " + buffer.length); // and return its length return buffer.length; } // extracts the RTP packet from each datagram packet received private RTPPacket getRTPPacket(Datagram packet, byte[] buf) { // SSRC long SSRC = 0; // the payload type byte PT = 0; // the time stamp int timeStamp = 0; // the sequence number of this packet short seqNo = 0; // see http://www.networksorcery.com/enp/protocol/rtp.htm // for detailed description of the packet and its data PT = (byte)((buf[1] & 0xff) & 0x7f); seqNo = (short)((buf[2] << 8) | ( buf[3] & 0xff)); timeStamp = (((buf[4] & 0xff) << 24) | ((buf[5] & 0xff) << 16) | ((buf[6] & 0xff) << 8) | (buf[7] & 0xff)) ; SSRC = (((buf[8] & 0xff) << 24) | ((buf[9] & 0xff) << 16) | ((buf[10] & 0xff) << 8) | (buf[11] & 0xff)); // create an RTPPacket based on these values RTPPacket rtpPkt = new RTPPacket(); // the sequence number rtpPkt.setSequenceNumber(seqNo); // the timestamp rtpPkt.setTimeStamp(timeStamp); // the SSRC rtpPkt.setSSRC(SSRC); // the payload type rtpPkt.setPayloadType(PT); // the actual payload (the media data) is after the 12 byte header // which is constant byte payload[] = new byte [packet.getLength() - 12]; for(int i=0; i < payload.length; i++) payload [i] = buf[i+12]; // set the payload on the RTP Packet rtpPkt.setData(payload); // and return the payload return rtpPkt; } public long seek(long where) throws IOException { throw new IOException("cannot seek"); } public long tell() { return -1; } public int getSeekType() { return NOT_SEEKABLE; } public Control[] getControls() { return null; } public Control getControl(String controlType) { return null; } public long getContentLength() { return -1; } public int getTransferSize() { return -1; } public ContentDescriptor getContentDescriptor() { return new ContentDescriptor("audio/rtp"); } }
The constructor for the RTPSourceStream
creates a SocketConnection
to the remote server (hard-coded to the local server and port here, but you can change this to accept any server or port). It then opens the input and output streams, which it uses to create the RTSPProtocolHandler
. Finally, using this handler, it sends the DESCRIBE
and SETUP
commands to the remote server to get the server ready to send the packets. The actual delivery doesn't start until the start()
method is called by the StreamingDataSource
, which opens up a local port (hard-coded to 8081
in this case) for receiving the packets and sends the PLAY
command to start receiving these packets. The actual reading of the packets is done in the read()
method, which receives the individual packets, strips them to create the RTPPacket
instances (with the getRTPPacket()
method), and returns the media data in the buffer supplied while calling the read()
method.
A MIDlet to see if it works
With all the classes in place, let's write a simple MIDlet to first create a Player
instance that will use the StreamingDataSource
to connect to the server and then get media packets from it. The Player
interface is defined by the MMAPI and allows you to control the playback (or recording) of media. Instances of this interface are created by using the Manager
class from the MMAPI javax.microedition.media
package (see the MMAPI tutorial). The following shows this rudimentary MIDlet:
import javax.microedition.media.Player; import javax.microedition.midlet.MIDlet; import javax.microedition.media.Manager; public class StreamingMIDlet extends MIDlet { public void startApp() { try { // create Player instance, realize it and then try to start it Player player = Manager.createPlayer( new StreamingDataSource( "rtsp://localhost:554/sample_100kbit.mp4")); player.realize(); player.start(); } catch(Exception e) { e.printStackTrace(); } } public void pauseApp() {} public void destroyApp(boolean unconditional) {} }
So what should happen when you run this MIDlet in the Wireless toolkit? I have on purpose left out any code to display the resulting video on screen. When I run it in the toolkit, I know that I am receiving the packets because I see the debug statements as shown in Figure 2.
Figure 2. Running StreamingMIDlet output
The RTP packets as sent by the server are being received. The StreamingDataSource
along with the RTSPProtocolHandler
and RTPSourceStream
are doing their job of making the streaming server send these packets. This is confirmed by looking at the streaming server's admin console as shown in Figure 3.
Figure 3. Darwin's admin console shows that the file is being streamed (click for full-size image).
Unfortunately, the player constructed by the Wireless toolkit is trying to read the entire content at one go. Even if I were to make a StreamingVideoControl
, it will not display the video until it has read the whole file, therefore defeating the purpose of the streaming aspect of this whole experiment. So what needs to be done to achieve the full streaming experience?
Ideally, MMAPI should provide the means for developers to register the choice of Player
for the playback of certain media. This is easily achieved by providing a new method in the Manager
class for registering (or overriding) MIME types or protocols with developer-made Player
instances. For example, let's say I create a Player instance that reads streaming data called StreamingMPEGPlayer. With the Manager class, I should be able to say Manager.registerPlayer("video/mpeg", StreamingMPEGPlayer.class)
or Manager.registerPlayer("rtsp", StreamingMPEGPlayer.class)
. MMAPI should then simply load this developer-made Player
instance and use this as the means to read data from the developer-made datasource.
In a nutshell, you need to be able to create an independent media player and register it as the choice of instance for playing the desired content. Unfortunately, this is not possible with the current MMAPI implementation, and this is the data consumption conundrum that I had talked about earlier.
Of course, if you can test this code in a toolkit that does not need to read the complete data before displaying it (or for audio files, playing them), then you have achieved the aim of streaming data using the existing MMAPI implementation.
This experiment should prove that you can stream data with the current MMAPI implementation, but you may not be able to manipulate it in a useful manner until you have better control over the Manager
and Player
instances. I look forward to your comments and experiments using this code.
发表评论
-
j2me to android 例子源码下载
2009-11-11 12:21 1640推荐下载: iWidsets最新版2.0.0下载(J2ME) ... -
J2ME时间例子
2009-11-04 01:51 2101下面是一个时间例子: Calendar.getInst ... -
MP3Dict应用发布了
2009-11-03 18:33 1675iWidsets发布新用MP3Dict了 ... -
一些很特别的J2ME开源项目
2009-11-03 04:35 2201StrutsME 一个轻量级的序列化协议,使J2ME客户端能调 ... -
基于J2ME平台的Log4j
2009-11-03 03:55 2114J2ME平台并没有提供LOG来获取一些有用的信息,如 ... -
iWidsets公告
2009-10-21 15:16 1842由于前段时间忘记备案,国庆前关闭网站,导致软件无法下载,请见谅 ... -
iWidsets 发布1.8.1版本(20090920)
2009-09-20 21:21 19971.1 iWidsets 发布1.8.1版本,此版本主要修正B ... -
iWidsets J2ME客户端首次发布了
2009-09-13 13:40 1115经过九个月的开发,iWidsets J2ME客户端首次发布了, ... -
iWidsets J2ME客户端首次发布了
2009-09-13 12:20 1234经过九个月的开发,iWidsets J2ME客户端首次发布了, ... -
解决java.lang.SecurityException: Access denied
2009-08-13 15:42 11247NOKIA的一些目录不允许创建文件,所以会抛出java.lan ... -
J2ME FileConnection开发
2009-08-07 00:00 2646下面是对开发J2ME FileConnection的一些总结: ... -
Experiments in Streaming Content in Java ME(源码下载)
2009-08-04 09:38 1332Experiments in Streaming Conten ... -
keyRepeated和keyPressed处理
2009-07-26 21:38 3134今天修改了一个很重要的Bug,这个BUG会不断向服务端请求相同 ... -
Experiments in Streaming Content in Java ME(2)
2009-07-14 11:12 2803Creating an RTSP Protocol Handl ... -
Experiments in Streaming Content in Java ME(1)
2009-07-14 11:06 3802Since my book on Mobile Media A ... -
J2ME实现RTSP(只有在支持的手机才能用)
2009-07-12 21:09 2014最近在研究J2ME实现RTSP协议,在索爱开发网站中看到一个类 ... -
少用System.out.println()
2009-07-11 16:13 3510之前就知道System.out.println ... -
读取流最快方式
2009-07-09 11:42 2604读取流最快方式,当你知道流的长度时,如流长度是maxLengt ... -
让你的J2ME安装包跑起来及其优化
2009-07-09 11:21 1286一、无法下载:通过HTTP下载安装包时,可能会出现“未知文件类 ... -
安装Jar提示“jar文件无效”的另一个奇怪原因
2009-06-24 15:29 8766今天在做魔橙推送邮时遇到一个奇怪的问题,在安装jar时总是提示 ...
相关推荐
标题“Experiments in Streaming Content in Java ME(源码下载)”涉及的是在Java ME环境中实现流媒体内容的实验。Java ME(Micro Edition)是Java平台的一个版本,主要用于移动设备和嵌入式系统。这个项目可能专注于...
这本书对反应式机器人和行为式机器人有各种介绍,对智能机器人的爱好者是一个很不错的启发学习。
《车辆:合成心理学的实验》是由Valentino Braitenberg所著的一本经典著作,它深入探讨了人工生命和智能机器人的概念,特别是在心理学视角下的机器行为。这本书的核心是Braitenberg小车,这是一种简单的机器人设计,...
java8流源码java-flow-experiments 在这个存储库中,我正在试验 ,它将成为 Java 8 应用程序java.util.concurrent包中的 Java 9 的一部分。 这个存储库是为我的主题为 java.util.concurrent.Flow 做好准备的演讲准备...
ideally, intermediate-level data analysts and data scientists with experience in Java. Preferably, you will have experience with the fundamentals of machine learning and now have a desire to explore ...
3. **回顾式再评估**:随着时间的推移,新的经验和数据会不断积累,这要求我们不断地回顾和评估原有的假设和结论。这种方法有助于确保理论的持续更新和发展。 通过这样的动态反馈机制,思维实验不仅能够在理论上...
The release of Java 9 has brought many subtle and not-so-subtle changes to the way in which Java programmers approach their code. The most important ones are definitely the availability of a REPL, ...
1 the fruit-fly experiments described in Carl Zimmer’s piece in the Science Times on Tuesday. Fruit flies who were taught to be smarter than the average fruit fly 2 to live shorter lives. This ...
- 《实验设计:理论与应用》(Design and Analysis of Experiments)由Douglas C. Montgomery著。 - 《统计学原理》(Principles of Statistics)等相关教材。 通过以上概述,我们可以看到《实验设计与分析第一门...
Design of Experiments for Engineers and Scientists Second Edition Design of Experiments (DOE) is a powerful technique used for both exploring new processes and gaining increased knowledge of existing ...
3. **全局信息利用**:根据整个图像的统计信息调整合并策略,确保分割结果的一致性和准确性。 4. **区域合并**:根据预设的规则或阈值标准来决定哪些相邻的子区域应该被合并为更大的区域。 5. **迭代优化**:算法...
In conclusion, this Java laboratory report covers fundamental programming structures in Java, including data types, variables, assignments, and operators. The three experiments demonstrate the ...
"gradle_java_experiments"项目是一个专注于探索Gradle与Java结合使用的实验性项目,旨在帮助开发者深入理解这两个工具的协同工作方式。 **Gradle特性与优势** 1. **灵活的构建模型**:Gradle基于Groovy或Kotlin ...
3. **图像恢复与去噪**:Shearlet变换在去除图像噪声方面表现出色,尤其是在处理带有多方向结构的噪声时。通过保留重要的Shearlet系数并去除噪声系数,可以实现有效的图像去噪。 4. **图像增强**:Shearlet变换可以...
1. 书籍的版权归属于John Wiley & Sons, Inc.,表明该书是由知名的学术出版机构出版。 2. 文档中包含版权声明,说明了版权所有、复制、存储、检索、传输等方面的规定,反映了对于知识产权的保护。 3. 提到了可以通过...
Hein,出版于2009年3月,隶属于波特兰州立大学。书籍内容主要围绕离散数学、逻辑和可计算性的理论知识,并通过Prolog编程语言的实验来加强对这些理论知识的理解和应用。在IT领域,Prolog(Programming in Logic)是...
David S. Lee:Randomized Experiments from Non-random Selection in U.S. House Elections._ Journal of Econometrics,
Java8实验 酿什么呢? Java8是! 这个实验项目深入到Java8中,并探讨了其中引入的一些非常酷的功能。 该代码包含以下Java8功能: 内置功能接口 谓词 职能 溪流 map() reduce filter collect 自定义功能界面 ...
Design And Analysis Of Experiments, 5Th Edition (Douglas C Montgomery)-Keep 试验设计与分析 5ed