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

简介:

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

以前我也听说,好像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(); ,然后等候。

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

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

public   void  playerUpdate(Player player, String event, Object data) {
  
if(event == PlayerListener.END_OF_MEDIA){
   
try{
    System.out.println(
"playerUpdate>>PlayerListener.END_OF_MEDIA");
    stopGauge();
    playForeground();
   }
catch(Exception e){
    e.printStackTrace();
   }

  }

}


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

这样是可以的。  

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

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

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

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

Server side java code:

public   void  transfer(DataOutputStream output)  {
         
try{  
                   
int i = 0;
                   
int auglis = 50058//chunk size
              
                
//if it is wav file, we need to edit header:
                
                   
//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 = new byte[50058];
                   
int countBytes= 0;
                   
int headerup = 32//mp3 header is 32 bytes.
                   
                
while(i<50058){
                 tmp[i] 
= audio[i]; //byte array audio is byte array from mp3 file
                 i++;
                 countBytes
++;
                   }
  
                output.writeInt(
50058);     //write to midlet, that chunk size will be 50058
                output.write(tmp);   //write chunk itself
                     
                   
boolean varam = true//booleand that will become false, when file ends
                   while(varam){
                 
                   
int tmplen = garums - countBytes; //check if it is not last chunk
   
                   
int o=50058;
                   
if(tmplen>50058)//if it is not last chunk
                     o = 50058;  
                   }

                   
else{
                   o 
= tmplen+headerup; // if it is last chunk
                   tmp = new byte[o];
                   varam 
= false//out while loop will end
                   }

                   
                       
int z = 0;
                       
while(z<32)//write 32 byte header to chunk
                       tmp[z] = audio[z];          
                       z
++;
                       countBytes
++;
                       }
   
                             
                       
while(z<o)//white chunk it self
                       tmp[z] = audio[i];
                       z
++;
                       i
++;
                       countBytes
++;
                       }
  
                          
                  headerup 
=  headerup +32;
                  output.writeInt(o);          
//white size of chunk (typically 50058)
                  output.write(tmp);    //white chunk itself
              
                   }

         
         
         }

         
catch (Exception e) {}
    }

 

目录
相关文章
|
11月前
|
Java API Apache
java集成stable diffusion
通过REST API和JNI两种方法,我们可以在Java应用程序中集成Stable Diffusion模型。REST API方法更加简单和易于维护,而JNI方法则提供更高的性能。根据具体应用场景和需求,选择合适的集成方法,可以充分利用Stable Diffusion的强大功能,实现高效的图像生成和处理。
275 15
|
11月前
|
JSON 缓存 API
深度探索淘宝详情API接口:高效获取商品信息的实践指南
淘宝详情API接口是阿里巴巴开放平台的重要组成部分,帮助开发者通过程序化方式获取淘宝商品的详细信息,如标题、价格、销量等。本文介绍其使用方法,涵盖权限申请、请求构造、异常处理及高级应用,助力开发者优化电商体验和业务决策。
|
存储 监控 Linux
docker构建镜像详解!!!
本文回顾了Docker的基本命令和管理技巧,包括容器和镜像的增删改查操作,容器的生命周期管理,以及如何通过端口映射和数据卷实现容器与宿主机之间的网络通信和数据持久化。文章还详细介绍了如何使用Docker部署一个简单的Web应用,并通过数据卷映射实现配置文件和日志的管理。最后,文章总结了如何制作自定义镜像,包括Nginx、Python3和CentOS镜像,以及如何制作私有云盘镜像。
538 2
|
10月前
|
人工智能 自然语言处理 算法
垂直领域大模型必须备案吗?90%企业都搞错的大模型备案真相!
珠宝设计师专用的大模型是否需要备案?本文解析大模型备案与算法备案的区别及法规边界。大模型备案针对公众服务,仅面向专业设计师可暂缓;但算法备案必须完成。涉及深度合成类算法的企业需在30日内备案。合规不仅是义务,更是提升企业竞争力的关键。
|
7月前
|
Docker 容器
在openEuler 22.03 LTS上安装Docker CE和Docker Compose
以上就是在openEuler 22.03 LTS上安装Docker CE和Docker Compose的过程。希望这个指南能帮助你顺利完成安装。
1805 12
|
网络协议 网络性能优化 API
TCP或RDMA
【10月更文挑战第1天】TCP或RDMA
688 2
|
JavaScript 数据可视化 定位技术
漏刻有时数据可视化Echarts组件开发(24):本地离线的地图下钻与散点图
漏刻有时数据可视化Echarts组件开发(24):本地离线的地图下钻与散点图
350 0
漏刻有时数据可视化Echarts组件开发(24):本地离线的地图下钻与散点图
|
Linux API 图形学
深度探索Linux操作系统 —— Linux图形原理探讨2
深度探索Linux操作系统 —— Linux图形原理探讨
239 3
|
SQL 人工智能 API
openai停止中国的api服务,但是性能相当的阿里云免费提供迁移
OpenAI暂停中国API服务,阿里云百炼响应迅速,提供免费tokens(2200万)与迁移服务给受影响开发者。Qwen2-72B与GPT-4同列全球第四(HELM MMLU榜)。Qwen-plus调用成本仅GPT-4的1/50。阿里云百炼以开放性著称,兼容LlamaIndex等,支持多种数据源及自定义组件,加速AI应用集成。官网有丰富资源,助力快速上手大模型开发。
594 0
|
Linux Windows
【Linux】grub命令行引导进入windows系统
【8月更文挑战第20天】在Linux中通过GRUB命令行引导Windows的方法包括:1) 进入GRUB命令行模式,启动时按`c`键;2) 使用`ls`查找含Windows引导文件的分区,如`bootmgr`或`ntldr`;3) 设置根设备`root=(hd0,msdos3)`与链加载器`chainloader +1`;4) 输入`boot`命令启动Windows。请注意实际步骤可能因系统配置而异。
2069 2