旁观者 - 郑昀

软件开发这些年来,不断地遇到新领域新知识点,屡屡感受到新进入者的迷惑和彷徨,所以对遇到的每一个问题都详细记录问题现象、解决思路以及解决方案,并在blog中留下印迹,以备他日有心人google之而知之。你们的新手之痛,你们的新业务发展之初的思路混沌,我都感同身受,所以欢迎和我一起探讨这些话题,诸如文本挖掘/自然语言处理/Web3.0/J2ME/Web2.0/IVR/SMS/MMS/WAP/SIP/等等,知无不言言无不尽。

郑昀ID:zhengyun_ustc
1258825次访问,排名14好友5人,关注者75
.
zhengyun_ustc的文章
原创 564 篇
翻译 2 篇
转载 17 篇
评论 1520 篇
郑昀的公告
查看我的简历

google reader
订阅郑昀到鲜果
订阅郑昀到抓虾
联系我:





我的J2ME创意
{8.手机流媒体之实作}

{7.2.增强型二级菜单[SaltedFish]}

{7.1.二级菜单绘制演示-OperaMini风格}

{6.Bloglines手机伴侣-Online Rss Service Reader}
{5.手机玩转点对点MSN传情动漫}
{4.手机玩Podcasting, 无线播客新玩法!}
{3.手机看交通监视器实时录像}
{2.VideoCoolala-- [MobileWebCam]}
{ 1.RSSOwlMidlet (RSS无线阅读器)}

最近评论
微型化:如果说这位i预言家正确的预言过911等事件的话,那应该911之后,就应该看到如“911事件曾被***预言家曾被准确预言过等评论”,但实际未看到过呀!请问那位?在哪里?见到过?
微型化:预言一点不可信
kathy:不管他说的是真的还是假的,我们中国人就应该挺起胸膛,众志成城,一起去面对!!!
中国人是坚强的!!!
welco:@@ 这个sd有够乱的
welco:有点像Q币和rmb的关系 现在网上支付这么方便 为什么不直接用rmb买钻呢 非得费一步事rmb换成qb 再买钻呢 仅仅是历史遗留因素么
文章分类
收藏
相册
BlogPics
GrowGame
j2meStreaming
j2me二级菜单
我爱我车
我爱我家
我的玩聚
IT英才
Geek's Social Dialogue
OneJoo(RSS)
宝聚-股市风向标-中国第一家股市市场信心计算引擎
方军商业日记(RSS)
玩聚-智能语义聚合应用框架
存档
订阅我的博客
XML聚合  FeedSky

原创 [J2ME]手机流媒体之实作[附源码][与RTSP/MMS协议无关]收藏

新一篇: 用脑营销自己 | 旧一篇: [J2ME]增强型二级菜单(增加了三级菜单以及悬浮菜单)

郑昀@ultrapower

产品名称

产品版本

Keyword: JavaME Streaming Audio MMAPI

StreamingDemo

1.0.13

 [J2ME]现行环境下手机

实现网络媒体的流畅实时播放

之简单演示

(StreamingDemo)

说明

 

我的资源:

http://www.cnblogs.com/Files/zhengyun_ustc/StreamingDemo-src-1.0.13.rar

这个1.0.13版本是j2me流媒体播放思路的简单演示软件,并不是对现有的RTSP/MMS流媒体服务器的客户端实现,而是自定义算法下载来保证实时播放,可以在Nokia 7610手机上真实运行。在手机上使用,请在选择连接点时选择“移动梦网”连接点。

如果修改源代码中CommandResources.java中的m_bCMWAPProxy标志使之走CMNET通道,那么能够在Nokia S60的模拟器上运行。

本源代码的大致思路来自于我上次写的三篇讨论稿

J2me流媒体技术实现讨论[1]

J2me流媒体技术实现讨论[2]

J2me流媒体技术实现讨论[3] StreamingDemo的代码你可以借鉴,但不得用于商业用途,除非得到我的授权。

手机jar安装包下载:
http://www.cnblogs.com/Files/zhengyun_ustc/StreamingDemo-deployed.rar
可以将这个包中的StreamingDemo.jar传到您的手机上进行安装。
使用时,请选择移动梦网连接点。

如果你想使用劈分好的媒体文件,请从

http://www.cnblogs.com/Files/zhengyun_ustc/changjin.split.rar下载。

 

1背景、功能

摘要:本章 简单描述StreamingDemo的背景、功能。

 

1.1. 手机上的流媒体

很多人都在j2medev.com上讨论过流媒体的实现方式。国外有一个人提出一种思路,并且号称在Nokia6260[相关数据:诺基亚 6260 Nokia62602.0 (3.0436.0) SymbianOS7.0s Series602.1 ProfileMIDP-2.0 ConfigurationCLDC-1.0]运行了。

当然我们这里说的不是对RTSP/MMS这种主流的流媒体服务器的客户端实现,因为现在中国市场的很多很多手机的Java环境都不支持这两个协议,只有新出的某些手机才内置支持这一功能。

我们这次讲的是,在现有GPRS环境下,在现有的一两千块钱的手机条件下,如何做到流媒体实时播放呢,而且还能做到较为流畅呢?

20061月份,我恰巧看到了

就此思路和诸位高手讨论了一下,并且写了三篇讨论稿,有了大致的思路。但一直都没有时间去测试这个思路是否可行。

今天索性抽出了一两个小时,把这个思路写出来放在真实手机/GPRS网络上测试,不敢独享,遂开放代码,希望借此抛砖引玉。

这里给出StreamingDemo的界面,很简单,主要的线程操作和消息处理都在后台:

Streaming.HttpConnection

1.2. 我所谓流媒体的功能

以前我们谈过:

第一步:
声明两个Player,分别由两个独立的线程掌控着;

第二步:
HttpConnection
开始向服务器请求该audio文件的第一部分字节,我们定这次读取的字节数为18KB

第三步:
等第一部分数据到位后,Player A开始realizeprefetch,并开始播放;

第四步:
Player A播放同时,(18KBamr数据可以播放10秒钟)HttpConnection继续请求第二部分数据(假设GPRS每秒钟传输3KB,那么18KB需要传输6秒,算上前后通讯损失的时间,应该不会超过10秒钟)

第五步:
第二部分数据到位后,假设Player A还没有播放完(这需要调整你的每一部份数据字节数来使得假设成立),那么将数据喂给Player B让它realizeprefetch

第六步:
Player A
播放完后,得到事件通知,于是让Player B开始播放。

如此往复。

      大致的思路就是这样。

这次,我们起了两个线程,一个叫做“Main() ”,一个叫做“Secondary(从属)”,他们都掌握着一个Player,同样一个是Main Player,一个是Secondary Player。这两个Player的操作实际上都被Audio.java类完全封装好了。线程里面仅仅是调用

Audio.prefetchSound(m_form,

                                             m_isInputMusic,

                                             m_Sequence);

啦,

Audio.playSound(m_Sequence);

啦,这样就可以把媒体资源预先运算以及播放了。

 

同时,还必须用到PlayerListener接口,来得到播放器的各种事件通知,我们需要得知每一个播放器的播放结束消息,以便作出下一步选择:是让从属线程开始播放呢,还是让主线程开始播放呢。

PlayerListener的播放结束消息(PlayerListener.END_OF_MEDIA)的处理中,我们还必须用到MVC模式中的Controller,它是代码中的GUIController.java,它负责处理几个消息:

l         EventID.EVENT_MAIN_DownloadCompleted

l         EventID.EVENT_Main_BeginToPlay

l         EventID.EVENT_SECONDARY_BeginToPlay

 

怎么综合使用这些消息和事件呢?

比如说,当主线程的媒体文件下载完毕后,就应该通知GUIController让从属线程也开始下载并加载媒体文件。

当主线程的媒体文件播放完毕了,这时候照理说从属线程的Player也已经预先加载好了下一个要播放的媒体文件(如果不行的话就应该调整媒体文件的大小了以使得下载时间和播放时间差不多),就应该在

public void playerUpdate(Player player, String event, Object data)

的函数处理中,让Secondary Player播放了。

 

这次我们直接将媒体文件用讨论稿中谈及的ffmpeg自动切分的办法,已经辟成11小段的AMR文件了,每一个AMR文件都可以独立播放,连起来就是一首完整的《大长今》乐曲。

PlayerAPlayerB只是周而复始的下载、预运算、播放他们罢了。只不过掌控着Player的两个线程和主控制器,会选择时机来让这些操作次第展开。

 

上面所说的逻辑,可以用下图表示:

2 使用感受

摘要:本章 简单描述StreamingDemo在真实GPRS环境下的使用感受。

 

2.1. Nokia7610手机上的设置

如果你真的要在手机上用到这种功能,那么请申请开通你的GPRS包月套餐,那样20块钱就可以使用50MB流量的GPRS了。

如果你的手机是NokiaS60系列手机,建议用Nokia程序管理器设置这个应用配置一个参数:在连接网络时第一次询问。否则你会屡屡被网络连接警告框打断的。

2.2. Nokia7610手机上的使用感受

这种流媒体的播放,还是取决于使用时GPRS网络的好坏。

我在晚上19点使用了一下,感觉比较流畅,甚至超乎我的预期,不认真听,甚至感觉不到在哪里停顿的。

但是在晚上20点又用了一下,就有点拖拖拉拉的,延迟较为明显。

可见现行的GPRS网络环境还是容易出现拥挤的。

开源版权声明

由于这个手机流媒体简单演示思路和代码来自于郑昀以前的讨论稿,今为了促进J2ME多媒体应用发展,决定遵照GPL协议的大意开放源代码,您可以自由传播和修改,在遵照下面的约束条件的前提下:

 

条件1

只要你在 手机流媒体简单演示 每一副本上明显和恰当地出版版权声明,保持此许可证的声明和没有担保的声明完整无损,并和程序一起给每个其他的程序接受者一份许可证的副本,你就可以用任何媒体复制和发布你收到的原始的程序的源代码。你可以为转让副本的实际行动收取一定费用,但必须事先得到郑昀的同意。

 

条件2

你可以修改 手机流媒体简单演示 程序的一个或几个副本或程序的任何部分,以此形成基于程序的作品。只要你同时满足下面的所有条件,你就可以按前面第一款的要求复制和发布这一经过修改的程序或作品。

 

a

你必须在修改的文件中附有明确的说明:你修改了这一文件及具体的修改日期。

 

b

你必须使你发布或出版的作品(它包含程序的全部或一部分,或包含由程序的全部或部分衍生的作品)允许第三方作为整体按许可证条款免费使用。

 

c

如果修改的程序在运行时以交互方式读取命令,你必须使它在开始进入常规的交互使用方式时打印或显示声明:包括适当的版权声明和没有担保的声明(或者你提供担保的声明);用户可以按此许可证条款重新发布程序的说明;并告诉用户如何看到这一许可证的副本。(例外的情况:如果原始程序以交互方式工作,它并不打印这样的声明,你的基于程序的作品也就不用打印声明)。

 

这样,您就可以自由使用并传播本源代码,当然请您原封不动地保留创建者zhengyun_ustc(郑昀)的作者信息

 

 

发表于 @ 2006年03月28日 19:18:00|评论(loading...)|编辑

新一篇: 用脑营销自己 | 旧一篇: [J2ME]增强型二级菜单(增加了三级菜单以及悬浮菜单)

评论

#zhengyun 发表于2006-03-28 22:51:00  IP: 61.149.199.*
3.1. Nokia7610手机上的设置
如果你真的要在手机上用到这种功能,那么请申请开通你的GPRS包月套餐,那样20块钱就可以使用50MB流量的GPRS了。
如果你的手机是Nokia的S60系列手机,建议用Nokia程序管理器设置这个应用配置一个参数:在连接网络时第一次询问。否则你会屡屡被网络连接警告框打断的。
3.2. Nokia7610手机上的使用感受
这种流媒体的播放,还是取决于使用时GPRS网络的好坏。
我在晚上19点使用了一下,感觉比较流畅,甚至超乎我的预期,不认真听,甚至感觉不到在哪里停顿的。
但是在晚上20点又用了一下,就有点拖拖拉拉的,延迟较为明显。
可见现行的GPRS网络环境还是容易出现拥挤的。
#zhengyun 发表于2006-03-29 09:59:00  IP: 218.249.90.*
手机jar安装包下载:

http://www.cnblogs.com/Files/zhengyun_ustc/StreamingDemo-deployed.rar

可以将这个包中的StreamingDemo.jar传到您的手机上进行安装。

使用时,请选择移动梦网连接点。
#qinjiwy 发表于2006-04-02 19:11:00  IP: 220.192.226.*
好思路,如果想解决NOKIA频繁提示的问题,可以利用
文件合并命令把几个文件再拼起来,然后再连接,通过判断
每个固定文件的大小来播放.
#萱萱 发表于2006-04-08 22:48:00  IP: 222.173.60.*
郑哥哥好,
我想问的是,这个东西是不是播放的《希望》的MID??
#zhengyun 发表于2006-04-09 22:36:00  IP: 61.149.87.*
yes
# Gary  发表于2006-04-15 22:02:00  IP: 61.171.200.*
你去这个网址看看,做的东西和你相比怎么样?目前仍然需要许多开发的内容,但已经初步成型
#zhengyun 发表于2006-04-16 13:01:00  IP: 61.149.86.*
wapmd.com是你做的吗?确实很雏形。连http://wapmd.com/intro.htm的客户端演示都看不了。所以也无从理解你的原理是什么。只能从http://wapmd.com/discuz4/viewthread.php?tid=127&extra=page%3D1看到“WAPMD播放器是一款基于GPRS网络的低速流媒体J2ME应用”。我这篇文章是在论坛中讨论j2ME流媒体原理所用的,并不用于商业应用,我本人也从不进行J2ME的商业开发。所以,你PK恐怕找错对象了吧?你应该去找富年公司PK吧?
#drhu00 发表于2006-07-10 00:58:00  IP: 68.77.2.*
whould you please give the reference for "国外有一个人提出一种思路"?
#zhengyun 发表于2006-07-10 11:09:00  IP: 218.249.90.*
http://forum.java.sun.com/thread.jspa?threadID=439626&start=75&tstart=0,"Streaming with j2me"
#drhu00 发表于2006-07-17 03:36:00  IP: 68.252.220.*
对于你的方法我提几点不足:<br>
1) 最大的缺陷就是服务器要预先分割一个大的流体文件。<br>
2)如果手机不支持多个播放器就无法用了。要考虑单个播放器的情形。<br>
3)无法重新播放一个好不容易下载到的流体文件。<br>
4)没有考虑数据不到位和数据下载快于播放的情形。<br>
我制作了一个程序克服以上不足,请指教和帮忙在你的手机上测试。我只有Motorola手机v188, 它运行的很好<br>
http://www.getjar.net/products/5763/J2MEStreaming
#zhengyun 发表于2006-07-17 11:58:00  IP: 124.42.60.*
你放在getjar的程序已经不在了。
#drhu00 发表于2006-07-17 12:23:00  IP: 68.252.220.*
I just put there today. need 24 hours to active.
请记住,在现有的MIDP2.0环境下,单个播放器绝对做不到流媒体播放,因为从MMAPI底层的实现上就不允许。
What do you mean by that?
See my notes there on http://www.getjar.net/products/5763/J2MEStreaming
tomorrow.
#zhengyun 发表于2006-07-17 11:44:00  IP: 124.42.60.*
我在最开始已经说明了:“这个1.0.13版本是j2me流媒体播放思路的简单演示软件”。
所以请不要吹毛求疵,好吗?
也就是说,这个代码仅仅是演示可以这么做,绝不代表实际商业化的时候也要这么做。好吗?

请记住,在现有的MIDP2.0环境下,单个播放器绝对做不到流媒体播放,因为从MMAPI底层的实现上就不允许。
#zhengyun 发表于2006-07-17 22:38:00  IP: 61.49.113.*
仔细阅读MMAPI的prefetch/start/stop的文档,以及《Working with the Mobile Media API.pdf》和《CH_BriefIntroductiontoMMAPIv1_0.pdf》,你就会明白我为什么这么说。设计MMAPI的时候他们就没有考虑要播放流媒体。
#drhu00 发表于2006-07-19 12:08:00  IP: 68.252.220.*
看到我放在的程序了吗?不知道能否在你的手机上运行?
另外想请你帮忙测试一下我的CNewsRead的SMS功能
http://www.getjar.com/products/5501/CNewsRead
or
http://www.getjar.net/products/5501/CNewsRead
#zhengyun 发表于2006-07-19 21:38:00  IP: 221.216.216.*
我觉得既然我们都是技术人,最好能够以代码讨论的方式互相促进,而不要单纯把我当成一个测试机器,好吗?其实你可以更open一点。
#zhengyun 发表于2006-07-19 21:44:00  IP: 221.216.216.*
还有几点,如果你的程序是基于我的代码之上,请遵守GPL协议;如果你的程序仅仅借鉴了我的思路,对我的程序的缺点作了哪些改进,也请明示。我们既然走到一起来讨论问题,肯定希望互相之间都有所提高,也对J2ME世界有所贡献,对吗?
#drhu00 发表于2006-07-19 22:36:00  IP: 68.252.220.*
我自己重新写的程序没有基于你的代码。
在GETJAR上我已经说明了我实现的方法。
用两个THREAD。一个用于下载数据。一个用于播放。不是像你的程序把播放和下载
放在一起。下载的数据存在一个数据组内,因此下载完后可以重播。播放线程是从
数据组内取数据的。这是最大的不同。
还有就是不需要预先分割媒体数据。当然所有这些都基于媒体是可以部份数据播放
的。
思路有了我想就不难实现了。
#zhengyun 发表于2006-07-20 10:21:00  IP: 124.42.60.*
0:感谢你的说明。我想J2ME世界需要交流需要碰撞,我们不需要保守秘密,描述技术思路对于你我对于大家都有好处。
1:“下载的数据存在一个数据组内”,那你有没有想过对于流媒体,收听十分钟或者二十分钟的节目,这些数据都存储在一个数据组中,对手机内存要求是不是太高了呢?
2:“播放线程是从数据组内取数据的”以及“一个线程用于播放”,那么请问,MMAPI的player加载数据之后还需要prefetch,这个时间在真实手机上往往需要一个卡机的过程,比如稍微低一点的手机处理起来,要么对整个应用有一个卡的作用,要么时间稍微有点长。而你这个播放线程又只有一个,那么请问如何做到流畅播放呢?你在真机上联网读取远端服务器上的音频文件时,试验的效果能够达到流畅吗?
#zhengyun 发表于2006-07-20 11:25:00  IP: 124.42.60.*
我想你可能没有理解我们用两个Player的深意。

之所以费尽周折用两个player,就是因为在目前的MIDP2.0手机上,播放amr/3gp等媒体流,势必prefetch(预处理)需要一点时间甚至于较长时间,所以为了不影响流媒体播放的流畅性,就必须在前台播放一个player时后台预先就让一个player进入prefetch阶段,从而一旦前台播放完,后台就立刻放,不再需要prefetch,从而给用户一种很流畅的感觉。

如果仅仅是一个player,我想那真的会给用户很大的卡卡的感觉的。
#zhengyun 发表于2006-07-20 11:58:00  IP: 124.42.60.*
我个人认为,一个player,切换之间必然会卡。
为首先你要先停掉上一次播放的,调用stop,然后MMAPI会自己deallocate来释放上次的数据。
然后,他还要再来预处理这次的媒体数据流。
这样,在真实机器上,必然很慢。
所以,为了解决这个问题,我们提出两个player。要不然,一个player就够了的话,呵呵,我也不会专门写文章讨论了。
一个就够了的话,无非就是调用MMAPI罢了,有什么难的。就是因为大家都觉得咔咔的,所以才想尽办法。
#zhengyun 发表于2006-07-21 10:44:00  IP: 124.42.60.*
1:
请不要老是盯着“事先分割媒体文件”这个问题,这只是演示的权宜之计,已经有网友基于我的代码作出不需要事先分割即可正常读取流媒体了。这个问题大可不必担心。真正的流媒体服务器也是不需要这么做的。

2:
“如果媒体数据流已到位,预处理是比较快的”,这仅仅是你的假设。请多试验几种不同档次的手机,尤其是不同厂商的手机,你就会知道预处理到底会对播放效果有多么大的影响了。一般来说,单个player每一次切换都会有以下过程,这必定将导致半秒到1秒的停顿,这可不是一个可以接受的用户体验:
A.close()
B.deallocate()
C.realize()
D.prefetch()
E.start()
你测试过不同手机(比如Nokia S60系列、SE等)这5个步骤的时间是多长吗?

3:
我自然读了你的说明,而且下载了。不过我还是觉得一个player在现有MIDP2.0机器下有很大的挑战,而且我觉得完全没有利用现有技术解决什么,那不就是普普通通的播放吗?
#zhengyun 发表于2006-07-21 11:13:00  IP: 124.42.60.*
我昨天就下载并在nokia s60模拟器测试了你的J2MEStreaming.jad,但非常遗憾的是,你并没有输出打印什么时候关闭上一次player,什么时候加载新数据,所以从日志上我没有领会到你的流媒体播放效果。而且就第一次播放了一次音乐,之后不管我如何重启jar,都只是打印出一行“singlePlayer: true”就再也不动了。我使用“PlayAudio”菜单。

再次,你的代码其实也不是太复杂,为何不共享出来,我在我这边也可以调试。
#zhengyun 发表于2006-07-21 11:23:00  IP: 124.42.60.*
如果你不愿意共享的话,不妨把每一次把数据喂给player以及player的start/stop/close/prefetch/realize的函数前后加上日志输出,这样,我一方面从模拟器角度就可以看出如何运行的,一方面我也可以到手机上测试,毕竟你的程序肯定不支持我们国内的CMWAP接入点,只能用CMNET接入点,那资费可是很贵的。

其实你把模型代码共享出来,便利于很多人一起讨论,而不是只是让别人测试测试的。
#drhu00 发表于2006-07-21 09:34:00  IP: 68.79.195.*
看来你并没有读我在GETJAR上的说明。
如果手机支持多两个播放器当然用两个了。
这样播放就会流畅些。当一个播放时另一个从已有的数据中PREFETCH准备。
如果手机不支持也就只好用一个了。
用户可以跟据他的手机来设置呀。
建议你读一下我在GETJAR上的说明。
#drhu00 发表于2006-07-21 09:34:00  IP: 68.79.195.*
如果媒体数据流已到位,预处理是比较快的。
我的Motorola V188手机就不支持两个播放器。可是我仍然能够播放,效果还不错。
还有就是数据不需要预先分割好。因此用户可以从任何HTTP网站上播放。
你为什么不下载来在你的手机上试试。
#路人 发表于2006-07-31 10:30:00  IP: 218.242.190.*
zhengyun说得很对,即然大家一起讨论,为什么不共享呢?这样大家都可以对技术细节有更加清楚的了解。
#chenling 发表于2006-08-06 17:16:00  IP: 222.191.84.*
持续关注中.....
#maomao 发表于2006-09-27 22:54:00  IP: 203.94.167.*
你好, 能不能用RTP来做这个,你试过吗?HttpConnection不能说是目前的一个问题。这个早就可以实现的。
RTP才是不能实现的部分。

请指教,谢谢。
#zhengyun 发表于2006-09-28 12:04:00  IP: 222.131.110.*
这篇文章所做的实验并不是针对HttpConnection,你这么说,说明你并没有看懂这篇文章以及后面的这么多评论。
RTP暂时实现不了。
#JBossVin 发表于2007-01-25 15:09:18  IP: 192.168.12.*
希望继续做出评论。关注中。。。
#JBossVin 发表于2007-01-25 15:12:59  IP: 192.168.12.*
大家都知道GGTV吧,它不是用java做的,可能它底层的API就没有限制(也可能一样有限制),不过它确实实现了实时播放,原理肯定也是一个播一个下,具体怎么实现就不知道了,谁能讲讲呢。
#JBossVin 发表于2007-01-25 15:21:16  IP: 192.168.12.*
还有我一直在怀疑MMAPI到底能不能支持Live,我发现它的API中有一句话:
Get the duration of the media. The value returned is the media's duration when played at the default rate.
If the duration cannot be determined (for example, the Player is presenting live media) getDuration returns TIME_UNKNOWN.

“for example, the Playe