Android之流媒体播放

Android之流媒体播放

 

 

最近做一个项目设计到流媒体的播放,因为是实时播放,所以我们不能支持http传输协议;我选择了RTSP传输协议,正好android SDK 自带的VedioPlayer类支持RTSP 的URI;好了,我们可以播放流媒体视频了,但是问题又来了,这里不能支持.flv格式的视频;后来查找资料发现.flv格式的视频只能支持RTMP流;怎么办?

 

 

再解决问题前,先说明下android 下的VedioPlayer是怎样实现流媒体播放的:

通常在Android中播放视频用到的是MediaPlayer类,展示视频使用的是SurfaceView控件;VedioPlayer通过调用MediaPlayer来实现视频播放,继承SurfaceView 来实现布局;

 

    显然,视频播放需要通过:

(1) JAVA Framework(即Android Framework),通过VideoView,经过Surface,

(2) 再到Native Framework

(3) 最后到达Driver.

做个简单的例子:

我们首先在main.xml布局文件中添加用于视频画面绘制的SurfaceView控件:

<SurfaceView android:layout_width="fill_parent"android:layout_height="240dip"android:id="@+id/surfaceView"/>

我们编写一个简单的视频播放器调用的常用方法如下。        

SurfaceView surfaceView = (SurfaceView)this.findViewById(R.id.surfaceView); 

surfaceView.getHolder().setFixedSize(720, 576);  //设置分辨率  

/*下面设置Surface不维护自己的缓冲区,而是等待屏幕的渲染引擎将内容推送到用户面前*/ 

surfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 

/* new 一个播放器 mediaPlayer */

MediaPlayer mediaPlayer = new MediaPlayer(); 

mediaPlayer.reset();      //重置为初始状态  

mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); 

/* 设置Video影片以SurfaceHolder播放 */ 

mediaPlayer.setDisplay(surfaceView.getHolder()); 

mediaPlayer.setDataSource("/mnt/sdcard/test.ts"); 

mediaPlayer.prepare();             //缓冲   

mediaPlayer.start();               //播放 

 mediaPlayer.pause();              //暂停播放  

mediaPlayer.start();               //恢复播放  

mediaPlayer.stop();                         //停止播放  

mediaPlayer.release();             //释放资源

 

接下来着重看MediaPlayer这个类的实现:

publicclassMediaPlayer

我们来看这个static{…},首先会加载libmedia_jni.so库,调用native_init()方法,对应JNI接口为:

MediaPlayer和Surface是怎样通信的?通过JNI层的notify函数建立连接:

 

Java层通过setDisplay()设置播放器显示输出:

 

好了,关键的地方到了,我们如何来识别播放源的格式,又是如何去解码的呢,这里我们通过设置播放源setDataSource()

 

 

setDataSource()设置播放源,对应的JNI函数为:

static voidandroid_media_MediaPlayer_setDataSource(JNIEnv *env, jobject thiz, jstringpath)

{

 android_media_MediaPlayer_setDataSourceAndHeaders(env, thiz, path, NULL,NULL);

}

调用的是mp.setDataSource(path, NULL);

status_t MediaPlayer::setDataSource(const char* url, const KeyedVector<String8, String8>* headers)

{

  const sp<IMediaPlayerService>& service(getMediaPlayerService());

  sp<IMediaPlayer> player(service->create(getpid(), this,mAudioSessionId));

  player->setDataSource(url,headers);

  attachNewPlayer(player);

}

 

这里首先 MediaPlayer的基类IMediaDeathNotifierstatic函数getMediaPlayerService()函数获取MediaPlayerService的代理BpMediaPlayerService,然后通过Binder通信调用IMediaPlayerServicecreate()函数,传入的参数分别为当前线程的PID,当前MediaPlayer对象和前面获取的mAudioSessionId,返回一个IMediaPlayer对象实际类型为MediaPlayerService内部类型Client

 

 这里看下MediaPlayerServicecreate函数: 

sp<IMediaPlayer> create(pid_t pid, cosnt sp<IMediaPlayerClient>& client, int audioSessionId)

{

  int32_t connId =android_atomic_inc(&mNextConnId);

 

  // 穿入参数分别为:当前MediaPlayerService对象、客户端进程pid、客户端MediaPlayer对象的引用、audioSessionId

  sp<Client> c = new Client(this, pid, client,audioSessionId, IPCThreadState::self()->getCallingUid());

 

  wp<Client> w = c; // Client的构造函数就是一些简单的给变量赋值操作了

  mClients.add(w);

  return c;

}


        
分析到这里我们在Java中调用setDataSource()的时候底层MediaPlayer类首先通过Binder获取MediaPlayerService的代理BpMediaPlayerService,然后调用其create函数,由MediaPlayerService来处理,返回一个匿名Binder对象Client,返回类型为IMediaPlayer,保存在MediaPlayer类的sp<IMediaPlayer>mPlayer中。后续我们就可以直接使用这个mPlayer对象了,调用它的setDataSourcepreparestartstop等。

      下面我们可以直接跳到MediaPlayerService内部类Client里面去看setDataSource():

 分析代码我们发现StagefrightPlayer其实就是AwesomePlayer的封装,基本上StagefrightPlayer所有的方法都是调用AwesomePlayer来实现的。AwesomePlayer类比较复杂,涉及到获取音视频流的格式、找到并打开相应的解码器、缓冲音视频数据送到解码器解码都是在这个类里面完成;

好了,现在可以解决我们的问题了,我们在这里只需要修改StagefrigtPlayer类;

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值