android多媒体本地播放流程video playback--base on jellybean (三)
上一篇我们讲了多媒体的总体框架,本章我们先来讨论媒体文件的本地播放,也是手机的基本功能。现在市面上的手机配置越来越高,支持高清视频(1920x1080P)已不在话下。那现在android主流播放器都支持哪些媒体格式呢?一般来说mp3,mp4,m4a,m4v,amr等大众格式都是支持的,具体支持成什么样这得看手机厂商和芯片厂商了。具体格式大全可以看framework/base/media/java/android/media/MediaFile.java。
我们下面进入正题研究多媒体文件的本地播放(video playback),具体用到的工具有source insight,astah(免费的画流程图工具),android 4.1代码。代码如何获取可以到google source下下载:http://source.android.com/source/downloading.html。
一般上层应用要本地播放播放一个媒体文件,需要经过如下过程:
MediaPlayer mMediaPlayer = new MediaPlayer( );
mMediaPlayer.setDataSource(mContext, mUri);-
mMediaPlayer.setDisplay(mSu易做图ceHolder);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.prepareAsync();
mMediaPlayer.start();
首先我们先来分析setDataSource方法,这个方法有两个功能:一个是根据文件类型获得相应的player,一个是创建相应文件类型的mediaExtractor,解析媒体文件,记录metadata的主要信息。
代码如下:
framework/av/media/libmedia/ MediaPlayer.cpp
status_t MediaPlayer::setDataSource(
const char *url, const KeyedVector<String8, String8> *headers)
{
ALOGV("setDataSource(%s)", url);
status_t err = BAD_VALUE;
if (url != NULL) {
const sp<IMediaPlayerService>& service(getMediaPlayerService());
if (service != 0) {
sp<IMediaPlayer> player(service->create(getpid(), this, mAudioSessionId));
if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
(NO_ERROR != player->setDataSource(url, headers))) {
player.clear();
}
err = attachNewPlayer(player);
}
}
return err;
}
我们先来看下setDataSource方法中如何获取player。大体的流程图如下图:
我们知道MediaplayerService是负责外部请求,针对每个APP player ,mediaplayerservice都会开辟一个client端来专门处理。
client 定义如下:
framework/av/media/libmediaplayerservice/ MediaPlayerService.h
class Client : public BnMediaPlayer {...
private:
friend class MediaPlayerService;
Client( const sp<MediaPlayerService>& service,
pid_t pid,
int32_t connId,
const sp<IMediaPlayerClient>& client,
int audioSessionId,
uid_t uid);
}
}
从代码看就是一个BnMediaplayer的子类(即local binder)。既然有了BnMediaplayer,客户端也应该有相应的BpMediaplayer。获取这个BpMediaplayer要分两步骤走:第一,获取BpMediaplayerService;第二就是在setDataSource方法中的:
sp<IMediaPlayer> player(service->create(getpid(), this, mAudioSessionId)); 这个函数会返回一个BpMediaplayer。
获取BpMediaplayerService,首先要去ServiceManager获取相应的服务Mediaplayer,里面的流程是这样检查是否存在要找的service,没有就创建,有就返回BpXX。
有了BpMediaplayerService,我们就可以跟MediaplayerService通信了,自然就可以创建对应的client端来服务对应的BpMediaplayer(客户端):
framework/av/media/libmediaplayerservice/ MediaPlayerService.cpp
sp<IMediaPlayer> MediaPlayerService::create(pid_t pid, const sp<IMediaPlayerClient>& client,
int audioSessionId)
{
int32_t connId = android_atomic_inc(&mNextConnId);
sp<Client> c = new Client(
this, pid, connId, client, audioSessionId,
IPCThreadState::self()->getCallingUid());
ALOGV("Create new client(%d) from pid %d, uid %d, ", connId, pid,
IPCThreadState::self()->getCallingUid());
wp<Client> w = c;
{
Mutex::Autolock lock(mLock);
mClients.add(w);
}
return c;
}
到此我们的sp<IMediaPlayer> player(service->create(getpid(), this, mAudioSessionId));
变成了:sp<IMediaPlayer> player(Client); 那它是如何变成我们需要的BpMediaplayer呢,请看下面的定义原型,INTERFACE就是mediaplayer,大伙把宏取代下就知道了:
frameworks/av/media/include/IMediapalyer.h
class IMediaPlayer: public IInte易做图ce
{
public:
DECLARE_META_INTERFACE(MediaPlayer);
DECLARE_META_INTERFACE宏定义如下:
#define DECLARE_META_INTERFACE(INTERFACE) \
static const android::String16 descriptor; \
static android::sp<I##INTERFACE> asInte易做图ce( \
const android::sp<android::IBinder>& obj); &n
补充:移动开发 , Android ,