阅读:2405回复:7
C++流媒体解码编程技巧讨论现在”3G网络”的概念成为了人们对未来网络最常见的一种说法,不过什么是3g呢,其实它的全称为3rd Generation,即第三代数字通信。它能够处理比以前更多的服务,如图像,音视频等多种多媒体形式提供给用户,而它和前两代的唯一区别就是3G网络最大的速率可以达到2Mbps,远远超过了前两代网络,这使得手机影院等大数据流应用,可以实现,为用户带来更好的移动体验。电信运营商及通信设备制造商都非常关注。 3G网络的到来,为移运运营商提供了商机,目前中国三个运营商纷纷引入自己的3g标准,其中,移动做为3g的先导者,自然不会错失这个机会,在今年08年推出了自己的手机系统OPhone OS平台,OPhone OS平台本身是基于Linux开放系统所设计,并不断的完善,相信不少见过OPhone OS手机的用户都被它的惊人的人性化界面所打动,其实OPhone OS系统所拥有的不单单是这些,为了极大的满足人们日益的需求,OPhone OS平台除保留了Gmail,Gtalk等原有业务外,还内置了中国移动的全部增值服务,为用户提供了更贴心的体验。同时移动还推出了线上软件销售商店Mobile Market,为个人和公司提供了面向移动拥有的5亿手机用户和庞大商业客户的销售机会。这样看来,手机上的个人娱乐软件和商业管理软件,如果中国移动大力推动,会带来很大市场。联通、电信虽然手机用户规模相对小些,但相信也会大力发展。 这也是我为什么要在下面向大家,以OPhone平台为例,介绍移动平台上流媒体编成的技巧。 话说回来,和Linux一样,OPhone OS保留了原有的开发语言C/C++,Java,不过OPhone OS对其进行了极大的优化,C/C++虽然效率高,不过这样并不安全,因为恶意的程序,会使得系统变得不安全,Java虽然很安全,不过效率太低,不利于大的项目开发,而且单纯的Java程序并不能完成一些特定的任务,在这种情况下,OPhone OS平台寻求到了完美的解决方案,JNI(Java Native Interface,Java本地化方法)技术运用而生,JNI简单的说,是让C/C++做完底层开发,并为Java提供接口以为调用,这样,JNI方式即不失低效率,也保证了平台安全性 OPhone OS平台的流媒体支持 OpenCore模块为OPhone OS平台提供了核心的多媒体支持,它处于整个平台的Libraries层,以os的方式为上层语言提供服务,OpenCore主要是用C/C++来实现,开发者可以修改及移植别的编/解码器,然后通过上层软件使用,OpenCore不能直接被用户所使用,必需借住其它的方式调用,如Java的JNI方式,OpenCore模块内置了OpenMAX1L interface接口进行扩展,这种技术分离了具体硬件的依赖,方便了开发者的移植,目前OPhone OS平台提供了3GP,MP4,ACV等媒体格式的支持,如果是在线看的话,还支持http,rtp等协议 OPhone OS媒体源码文件 曾经写过一个关于音频部分的,介绍过如何下载这部分的源码,接着我简单讲一下相关的C代码 Opencore目录包括了所有关于媒体方面的源码,其中最重要的是android,engines和codecs_v2,protocols四个目录,android主要包括了一些纯虚类,为适配器,engines为媒体引擎部分,主要是OPhone OS平台内置的编解码程序,后一个为第三方所提供,为OPhone OS系统的扩展应用,protocols目录里提供了在线流媒体的协议,包括http,rtp,rtsp,我们重点说一下protocols的结构, opencore\protocols\http_parcom\include\http_composer.h头文件中enum HTTPVersion { HTTP_V1_0 = 0, HTTP_V1_1 }; // HTTPMethod enum enum HTTPMethod { HTTP_METHOD_GET = 0, // both HTTP 1.0 and HTTP 1.1 HTTP_METHOD_HEAD, // both HTTP 1.0 and HTTP 1.1 HTTP_METHOD_POST, // both HTTP 1.0 and HTTP 1.1 HTTP_METHOD_DELETE, // both HTTP 1.0 and HTTP 1.1 HTTP_METHOD_LINK, // HTTP 1.0 only HTTP_METHOD_UNLINK, // HTTP 1.0 only HTTP_METHOD_OPTIONS, // HTTP 1.1 only HTTP_METHOD_PUT, // HTTP 1.1 only HTTP_METHOD_TRACE, // HTTP 1.1 only HTTP_METHOD_CONNECT, // HTTP 1.1 only }; 列出来http协议下流媒体的支持的http协议为1.0和1.1,从中我们可以看出来,OPhone OS媒体部分支持Get和Post方式播放数据 下面我们来通过Java的JNI方式去调用,我们以SDK中的MediaPlayerDemo_Video.java说明 package com.example.android.apis.media; import com.example.android.apis.R; import com.example.android.apis.app.AlarmController; import android.app.Activity; import android.graphics.PixelFormat; import android.media.AudioManager; import android.media.MediaPlayer; import android.media.MediaPlayer.OnBufferingUpdateListener; import android.media.MediaPlayer.OnCompletionListener; import android.os.Bundle; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.Toast; public class MediaPlayerDemo_Video extends Activity implements OnBufferingUpdateListener, OnCompletionListener, MediaPlayer.OnPreparedListener, SurfaceHolder.Callback { private static final String TAG = "MediaPlayerDemo"; private int mVideoWidth; private int mVideoHeight; private MediaPlayer mMediaPlayer; private SurfaceView mPreview; private SurfaceHolder holder; private String path; private Bundle extras; private static final String MEDIA = "media"; private static final int LOCAL_AUDIO = 1; private static final int STREAM_AUDIO = 2; private static final int RESOURCES_AUDIO = 3; private static final int LOCAL_VIDEO = 4; private static final int STREAM_VIDEO = 5; /** * * Called when the activity is first created. */ public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.mediaplayer_2); mPreview = (SurfaceView) findViewById(R.id.surface); holder = mPreview.getHolder(); holder.addCallback(this); holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); extras = getIntent().getExtras(); } private void playVideo(Integer Media) { try { switch (Media) { case LOCAL_VIDEO: /* * TODO: Set the path variable to a local media file path. */ path = ""; if (path == "") { // Tell the user to provide a media file URL. Toast .makeText( MediaPlayerDemo_Video.this, "Please edit MediaPlayerDemo_Video Activity, " + "and set the path variable to your media file path." + " Your media file must be stored on sdcard.", Toast.LENGTH_LONG).show(); } break; case STREAM_VIDEO: /* * TODO: Set path variable to progressive streamable mp4 or * 3gpp format URL. Http protocol should be used. * Mediaplayer can only play "progressive streamable * contents" which basically means: 1. the movie atom has to * precede all the media data atoms. 2. The clip has to be * reasonably interleaved. * */ path = "http://xxx.xxx.xxx.xxx/xxx.3gp"; if (path == "") { // Tell the user to provide a media file URL. Toast .makeText( MediaPlayerDemo_Video.this, "Please edit MediaPlayerDemo_Video Activity," + " and set the path variable to your media file URL.", Toast.LENGTH_LONG).show(); } break; } // Create a new media player and set the listeners mMediaPlayer = new MediaPlayer(); mMediaPlayer.setDataSource(path); mMediaPlayer.setDisplay(holder); mMediaPlayer.prepare(); mMediaPlayer.setOnBufferingUpdateListener(this); mMediaPlayer.setOnCompletionListener(this); mMediaPlayer.setOnPreparedListener(this); mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); } catch (Exception e) { Log.e(TAG, "error: " + e.getMessage(), e); } } public void onBufferingUpdate(MediaPlayer arg0, int percent) { Log.d(TAG, "onBufferingUpdate percent:" + percent); } public void onCompletion(MediaPlayer arg0) { Log.d(TAG, "onCompletion called"); } public void onPrepared(MediaPlayer mediaplayer) { Log.d(TAG, "onPrepared called"); mVideoWidth = mMediaPlayer.getVideoWidth(); mVideoHeight = mMediaPlayer.getVideoHeight(); if (mVideoWidth != 0 && mVideoHeight != 0) { holder.setFixedSize(mVideoWidth, mVideoHeight); mMediaPlayer.start(); } } public void surfaceChanged(SurfaceHolder surfaceholder, int i, int j, int k) { Log.d(TAG, "surfaceChanged called"); } public void surfaceDestroyed(SurfaceHolder surfaceholder) { Log.d(TAG, "surfaceDestroyed called"); } public void surfaceCreated(SurfaceHolder holder) { // TODO Auto-generated method stub Log.d(TAG, "surfaceCreated called"); playVideo(extras.getInt(MEDIA)); } @Override protected void onDestroy() { super.onDestroy(); // TODO Auto-generated method stub if (mMediaPlayer != null) { mMediaPlayer.release(); mMediaPlayer = null; } } } case STREAM_VIDEO: path = "http://xxx.xxx.xxx.xxx/xxx.3gp"; 这里大家可以为MediaPlayer指定一个URL,播放器会为这个通过http播放媒体数据OPhone OS平台目前只支持HTTP download方式来播放media文件. 下一个版本会支持streaming流媒体,以前程序的巧妙之处在于,JNI方式将java和C/C++分工来完成一个复杂的任务,目前在流媒体方式,大家可以下载Spb TV(OPhone OS平台下的流媒体电视) 如果对OPhone平台有兴趣,提供一个学习网站 http://www.ophonesdn.com,上面的开发入门资料很丰富,同时还有个发帖赢OPhone手机活动,鼓励大家分享经验,同时也可以获得体验一下OPhone手机如何酷炫的机会。移动最近刚跟一批工程师签约了他们开发的软件,看样子这确实会给大家带来一些更好发展的机会。 |
|
沙发#
发布于:2009-10-15 12:32
谢谢楼主分享,学习啦,不错
|
|
板凳#
发布于:2009-10-16 15:43
我这蹦出个问题:我在打开那个MediaPlayerDemo_Video.java文件的时候,一直报错
|
|
地板#
发布于:2009-10-18 08:27
|
|
地下室#
发布于:2009-10-19 18:41
你要导入整个apiDemo目录,因为.java文件用到一些其它目录的东西,直接打开这个源码,会提示你找不到部分资料的
|
|
5楼#
发布于:2009-10-19 23:10
谢谢楼主分享,学习啦,不错
|
|
6楼#
发布于:2009-10-22 16:13
我觉得ophoneSDN的资料很多,以后可以好好学学了
|
|
7楼#
发布于:2009-10-24 23:13
JNI这个东西值得研究。
|
|