`
阿尔萨斯
  • 浏览: 4165412 次
社区版块
存档分类
最新评论

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

 
阅读更多
<iframe align="center" marginwidth="0" marginheight="0" src="http://www.zealware.com/csdnblog336280.html" frameborder="0" width="336" scrolling="no" height="280"></iframe>

看到很多很多人持续在问这个问题。

以前我也听说,好像kvm底层实现不太支持j2me来做streaming video/audio,但我不知道那人为什么这么说。

那么现在国外有一个人提出下面这种思路,并且号称在Nokia6260[相关数据:诺基亚 6260 Nokia62602.0 (3.0436.0) SymbianOS7.0s Series602.1 ProfileMIDP-2.0 ConfigurationCLDC-1.0]

上真实实现了(两种网络方式:蓝牙和GPRS都试验过),但我怀疑他的前提条件是你的手机必须允许同时实现player的多个实例进入prefetched状态(预读取声音流)

第一步:
声明两个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开始播放。

如此往复。

大家看看此种理论可否。

我自己在nokia 7610上测试了一下,我上面说的前提被证明是可行的:你的手机必须允许同时实现player的多个实例进入prefetched状态(预读取声音流)。真实Nokia手机确实可以如此:
两个线程中各自有一个Player,都开始做m_player.realize();m_player.prefetch();,然后等候。

先播放线程1Player,等她播放完后,
通过

/**//*
*本类实现了PlayerListener接口。通过这个事件来告知媒体已经播放完毕
*/

publicvoidplayerUpdate(Playerplayer,Stringevent,Objectdata){
if(event==PlayerListener.END_OF_MEDIA){
try{
System.out.println(
"playerUpdate>>PlayerListener.END_OF_MEDIA");
stopGauge();
playForeground();
}
catch(Exceptione){
e.printStackTrace();
}

}

}


来通知第二个线程的Player播放。

这样是可以的。

qinjiwy可以,不过前提是该音频文件允许分段播放,有些音频文件就是不允许的.”,你说得对。确实有很多格式的媒体文件不支持分段播放。我所知道的是wav可以,mp3也可以。

服务端每次只读取这两种媒体文件的某一部分,如果是mp3文件的话,我暂时不知道是否每次需要加上特殊的头信息。

但是如果是WAV文件,那么肯定每次都要加上WAV特定的头,要不然Player也无法播放。

这种形式肯定是可行的。因为以前我在VC++上写Text To Speech程序时,就是这么做的:WAV文件的前若干个字节肯定是头信息,这是一定的,随后跟的全是RAW DATA;我每一次读取WAVRAW DATA若干字节后,传给我的播放线程,他需要给这段RAW DATA前加上一个WAV HEADER,然后就可以正常播放了。

20060115增补:

Huang的Mobcast,确实非常著名,几个月以前,在我写toodouPodcastMidlet时就看过许多人介绍过他,但是就是连不上http://www.geocities.com/tvhuangsg/mobcast/这个地址,所以一直未睹真容。

转换各种格式的video为3gp,转换各种格式的audio为amr,这些在开源软件mplayer手下是随手拈来,只需要看懂mplayer的各种参数即可做到了。所以拜mplayer所赐,我也能够制作手机看交通实况录像,都要感谢那些mplayer的开发人员!

"移动收听必须对中断事件进行管理",这个确实需要考虑。当进入Paused状态时,需要通知播放线程暂停,同时连接线程暂时就不要去抓取服务器的媒体数据了;等界面切换回来后,播放线程继续replay,连接线程继续下载音乐。

cleverpig说“可以通过人工(或者用程序)将文件分割后部署放到服务器上来解决”,我想也是,简单的文件分割是不够的,或者说仅仅适合于wav这种原始数据格式。应该事先将音乐文件用mencoder分解成一段一段的音乐文件放在服务器上,mencoder将处理每一段的格式问题保证能独立播放,这样手机下载起来只需要按照编号一段一段地下载即可,服务器不再需要运算和添加头信息。

美中不足,如果两个player切换播放,中间会有一个卡啪声。



Server side java code:

publicvoidtransfer(DataOutputStreamoutput){
try{
inti=0;
intauglis=50058;//chunksize

//ifitiswavfile,weneedtoeditheader:

//audio[4]=(byte)0x8A;
//audio[5]=(byte)0xC3;
//audio[6]=(byte)0x00;
//audio[7]=(byte)0x00;

//audio[54]=(byte)0x50;
//audio[55]=(byte)0xC3;
//audio[56]=(byte)0x00;
//audio[57]=(byte)0x00;


byte[]tmp=newbyte[50058];
intcountBytes=0;
intheaderup=32;//mp3headeris32bytes.

while(i50058){
tmp[i]
=audio[i];//bytearrayaudioisbytearrayfrommp3file
i++;
countBytes
++;
}

output.writeInt(
50058);//writetomidlet,thatchunksizewillbe50058
output.write(tmp);//writechunkitself

booleanvaram=true;//booleandthatwillbecomefalse,whenfileends
while(varam){

inttmplen=garums-countBytes;//checkifitisnotlastchunk

into=50058;
if(tmplen>50058){//ifitisnotlastchunk
o=50058;
}

else{
o
=tmplen+headerup;//ifitislastchunk
tmp=newbyte[o];
varam
=false;//outwhileloopwillend
}


intz=0;
while(z32){//write32byteheadertochunk
tmp[z]=audio[z];
z
++;
countBytes
++;
}


while(zo){//whitechunkitself
tmp[z]=audio[i];
z
++;
i
++;
countBytes
++;
}


headerup
=headerup+32;
output.writeInt(o);
//whitesizeofchunk(typically50058)
output.write(tmp);//whitechunkitself

}



}

catch(Exceptione){}
}




分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics