編輯:關於Android編程
Android源碼版本Version:4.2.2; 硬件平台 全志A31
前沿:
回首往事,記得2012年的時候,那時還年少不知,就研究過android的多媒體框架,那時還是2.3的源碼,看過stagefright的源碼,記得當時是特別的痛苦。而今,再次看起這個多媒體模塊的代碼,突然間覺得豁然開朗,模塊間的層次清晰,有據可依,遇到的疑問往往都能迎刃而解。我想,也許這就是2年多來的進步與經驗吧。感謝時間,讓我學會了成才。
鄧凡平老師告訴我:無論何時進入互聯網都不算遲,的確站在巨人的肩膀上再次重新梳理舊的東西,還是能學習的更多更深。
接下去的一段時間,打算主攻android多媒體框架、camera架構、surfaceflinger等FrameWork層,HAL層的模塊以及相關的Android系統定制與類平板的開發,更底層是linux內核中的視頻采集與顯示驅動等來作為接下去尋找工作的重中之重。自我感覺在移動互聯以及嵌入式的世界裡,這幾個方面現在應該還都是不可欠缺的。
Android的多媒體框架熟悉的人很熟悉,像我等菜鳥,就只能慢慢的啃了。這裡以4.2.2的源碼為背景,記錄下我所熟悉的多媒體框架的核心模塊,以便以後使用。
多媒體框架在android中的功能主要體現雜音視頻的播放以及錄制等,前者對應著解碼,後者對應著編碼。Android中以一個MediaPlay類作為音視頻播放的基礎類,圍繞著他開展了一系列的處理。學習一個新的模塊,最簡單的步驟就是找到一個典型的應用程序,通過它的實現,來分析整個模塊的數據流和控制流。如SurfaceFlinger的研究可以以Bootanmation的啟動來學習。典型的MediaPlay在Java處的接口包括視頻播放類VideoView以及音頻專用MediaPlay類。
1.APP閃的VideoView類,其實質是用MediaPlay類來實現的,只是由於其是視頻播放,不得不和surfaceview掛上夠,才將其獨立出來。使得其有如下的結構:
public class VideoView extends SurfaceView implements MediaPlayerControl {
private String TAG = VideoView;
// settable by the client
private Uri mUri;
private Map mHeaders;
在APP中,VideoView的典型簡單使用如下:
video = (VideoView) findViewById(R.id.videoView1);
mediacontroller =new MediaController(this);
video.setVideoPath(Video_fd);
mediacontroller.setAnchorView(video); //控件和視頻綁定
video.setMediaController(mediacontroller); //設置視頻播放的控制器
video.start();
通過setVideoPath的API處理,依次進行如下的調用:
public void setVideoPath(String path) {
setVideoURI(Uri.parse(path));
}
public void setVideoURI(Uri uri) {
setVideoURI(uri, null);
}
/**
* @hide
*/
public void setVideoURI(Uri uri, Map headers) {
mUri = uri;
mHeaders = headers;
mSeekWhenPrepared = 0;
openVideo();
requestLayout();
invalidate();
}
openVideo的處理,讓最終的處理權交給了MediaPlayer。
private void openVideo() {
if (mUri == null || mSurfaceHolder == null) {
// not ready for playback just yet, will try again later
return;
}
// Tell the music playback service to pause
// TODO: these constants need to be published somewhere in the framework.
Intent i = new Intent(com.android.music.musicservicecommand);
i.putExtra(command, pause);
mContext.sendBroadcast(i);
// we shouldn't clear the target state, because somebody might have
// called start() previously
release(false);
try {
mMediaPlayer = new MediaPlayer();
......
*/
mMediaPlayer.setDataSource(mContext, mUri, mHeaders);
.........
}
上述的兩個架構,在音頻播放的APP調用更加緊密,如下所示:
mediaplayer = new MediaPlayer(); mediaplayer.setDataSource(Music_fd); //設置要播放的音頻文件 mediaplayer.prepare(); mediaplayer.seekTo(0);
到這裡基本的音視頻框架在APP中的調用就基本完成了。
2.進入MediaPlay的世界
2.1 首先關注MediaPlay的對象創建過程,這也是分析android源碼的一個基本要求。依次通過java,JNI(libmedia_jni.so)進入Framework(libmedia.so)的處理流程。
new VideoView——> new MediaPlay ——>native_setup:典型的一個對象的建立,並傳統到JNI。native_setup主要用於本地C++層的對象的建立
進入JNI做android_media_MediaPlayer_native_setup處理,使得最終進入C++的世界。
android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
{
ALOGV(native_setup);
sp mp = new MediaPlayer();
if (mp == NULL) {
jniThrowException(env, java/lang/RuntimeException, Out of memory);
return;
}
// create new listener and give it to MediaPlayer
sp listener = new JNIMediaPlayerListener(env, thiz, weak_this);
mp->setListener(listener);
// Stow our new C++ MediaPlayer in an opaque field in the Java object.
setMediaPlayer(env, thiz, mp);
}
好了,到此為止,真正的建立了一個所謂native處的MediaPlayer對象。當然java處也有這個對象類。
2.2 setDataSource
MediaPlay的C++代碼位於/home/A31_Android4.2.2/android/frameworks/av/media/libmedia下形成一個libmedia.so。
下面來看這個API的處理,接下去都只分析FW層的C++的處理流,java的流和上面的分析類似。
status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
{
ALOGV(setDataSource(%d, %lld, %lld), fd, offset, length);
status_t err = UNKNOWN_ERROR;
const sp& service(getMediaPlayerService());
if (service != 0) {
sp player(service->create(getpid(), this, mAudioSessionId));//返回一個Bpmediaplayer
if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
(NO_ERROR != player->setDataSource(fd, offset, length))) {//設置視頻源
player.clear();
}
err = attachNewPlayer(player);
}
return err;
}
典型的Binder C/S架構,獲取MediaPlayerService(MPS)的proxy,提交給MPS處理。
3. MediaPlayerService的工作。
MPS和千萬萬的Service一樣,以一個服務者的身份存在,他是作為分析Binder驅動架構和原理的一個典型代表。在mediaserver中啟動,和其他CameraService和AudioFlinger做為多媒體服務。
int main(int argc, char** argv)
{
signal(SIGPIPE, SIG_IGN);
sp proc(ProcessState::self());
sp sm = defaultServiceManager();
ALOGI(ServiceManager: %p, sm.get());
AudioFlinger::instantiate();//多媒體服務的啟動包括音頻,攝像頭等
MediaPlayerService::instantiate();
CameraService::instantiate();
AudioPolicyService::instantiate();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
3.1 處理create請求:
spMediaPlayerService::create(pid_t pid, const sp & client, int audioSessionId)//創建一個mediaplayer,范范一個Client { ALOGV(MediaPlayerService::create); int32_t connId = android_atomic_inc(&mNextConnId); sp c = new Client( this, pid, connId, client, audioSessionId, IPCThreadState::self()->getCallingUid());//內部類創建,實現BnMediaPlayer ..... }
創建一個MPS的內部客戶端類Client(繼承於Binder本地接口類BnMediaPlay),這個看上去和CameraService很相似。有了這個本地客戶端類,那麼應用端的MediaPlay後續只需要和Client交互即可,而這其中是匿名的Binder在起作用。
3.2 player->setDataSource()
player是調用MPS後返回的一個BpBinder派生類,最終調用MPS的內部類Client的setDataSource()來實現。
status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length)
{
.........
player_type playerType = MediaPlayerFactory::getPlayerType(this,
fd,
offset,
length,
true );//根據視頻源獲取要使用的播放器的類型
........
sp p = setDataSource_pre(playerType); // now set data source
setDataSource_post(p, p->setDataSource(fd, offset, length));
return mStatus;
}
這裡面出現了一個MediaPlayerFactory,姑且理解為播放器廠商類吧。通過它來獲取當前傳入的視頻源的視頻源後綴格式等:如mp4,avi,3gp等。最終假設當前返回的playerType為STAGEFRIGHT_PLAYER。接著分析setDataSource_pre函數:
spMediaPlayerService::Client::setDataSource_pre( player_type playerType) { // create the right type of player sp p = createPlayer(playerType);//創建一個播放器 if (p == NULL) { return p; } if (!p->hardwareOutput()) { mAudioOutput = new AudioOutput(mAudioSessionId); static_cast (p.get())->setAudioSink(mAudioOutput);//強制轉化為MediaPlayerInterface } return p; }
3.3 真正的創建一個適合於當前視頻文件播放需要的Player:createPlayer。
spMediaPlayerService::Client::createPlayer(player_type playerType) { // determine if we have the right player type sp p = mPlayer; if ((p != NULL) && (p->playerType() != playerType)) { ALOGV(delete player); p.clear(); } if (p == NULL) { p = MediaPlayerFactory::createPlayer(playerType, this, notify);//新建一個player } if (p != NULL) { p->setUID(mUID); } return p; }
第一次處理時,mPlayer肯定為空,故可以看到最終還是回到了這個廠商播放器類來實現,因為這個類維護著當前平台支持的播放器類型(說到低就是解碼器的種類).
spMediaPlayerFactory::createPlayer( player_type playerType, void* cookie, notify_callback_f notifyFunc) { sp p; IFactory* factory; status_t init_result; Mutex::Autolock lock_(&sLock); if (sFactoryMap.indexOfKey(playerType) < 0) { ALOGE(Failed to create player object of type %d, no registered factory, playerType); return p; } factory = sFactoryMap.valueFor(playerType);//根據type類型獲取一個StagefrightPlayerFactory CHECK(NULL != factory); p = factory->createPlayer();//調用創建一個真正的palyer StagefrightPlayerPlay if (p == NULL) { ALOGE(Failed to create player object of type %d, create failed, playerType); return p; } init_result = p->initCheck(); if (init_result == NO_ERROR) { p->setNotifyCallback(cookie, notifyFunc); } else { ALOGE(Failed to create player object of type %d, initCheck failed (res = %d), playerType, init_result); p.clear(); } return p; }
這裡出現了一個全局變量SFactoryMap變量:
MediaPlayerFactory::tFactoryMap sFactoryMap;//實際的類型是typedef KeyedVector
3.4 系統支持的播放器類型相關信息的注冊:
MediaPlayerService::MediaPlayerService()
{
ALOGV(MediaPlayerService created);
mNextConnId = 1;
mBatteryAudio.refCount = 0;
for (int i = 0; i < NUM_AUDIO_DEVICES; i++) {
mBatteryAudio.deviceOn[i] = 0;
mBatteryAudio.lastTime[i] = 0;
mBatteryAudio.totalTime[i] = 0;
}
// speaker is on by default
mBatteryAudio.deviceOn[SPEAKER] = 1;
MediaPlayerFactory::registerBuiltinFactories();//注冊建立廠商的play
void MediaPlayerFactory::registerBuiltinFactories() {
Mutex::Autolock lock_(&sLock);
if (sInitComplete)
return;
registerFactory_l(new CedarXPlayerFactory(), CEDARX_PLAYER);
registerFactory_l(new CedarAPlayerFactory(), CEDARA_PLAYER);
registerFactory_l(new TPlayerFactory(), THUMBNAIL_PLAYER);
registerFactory_l(new StagefrightPlayerFactory(), STAGEFRIGHT_PLAYER);
registerFactory_l(new NuPlayerFactory(), NU_PLAYER);
registerFactory_l(new SonivoxPlayerFactory(), SONIVOX_PLAYER);
registerFactory_l(new TestPlayerFactory(), TEST_PLAYER);//不同的播放器注冊
sInitComplete = true;
}
這裡以我們要舉例的STAGEFRIGHT_PLAYER為例,進行分析:
a.new StagefrightPlayerFactory()新建一個播放器類,該類的結構如下:
class StagefrightPlayerFactory :
public MediaPlayerFactory::IFactory {
public:
virtual float scoreFactory(const sp& client,
int fd,
int64_t offset,
int64_t length,
float curScore) {
char buf[20];
lseek(fd, offset, SEEK_SET);
read(fd, buf, sizeof(buf));
lseek(fd, offset, SEEK_SET);
long ident = *((long*)buf);
// Ogg vorbis?
if (ident == 0x5367674f) // 'OggS'
return 1.0;
return 0.0;
}
virtual sp createPlayer() {
ALOGV( create StagefrightPlayer);
return new StagefrightPlayer();//新建一個StagefrightPlayer
}
};
很明顯,該類的特點是繼承並實現了IFactory這個接口類的相關功能。
b. 將新建的這個播放器對象進行注冊,依次添加索引值:播放器類型type,並將其對應的factory保存到sFactorymap這種向量表中。
status_t MediaPlayerFactory::registerFactory_l(IFactory* factory,
player_type type) {
if (NULL == factory) {
ALOGE(Failed to register MediaPlayerFactory of type %d, factory is
NULL., type);
return BAD_VALUE;
}
if (sFactoryMap.indexOfKey(type) >= 0) {
ALOGE(Failed to register MediaPlayerFactory of type %d, type is
already registered., type);
return ALREADY_EXISTS;
}
if (sFactoryMap.add(type, factory) < 0) {
ALOGE(Failed to register MediaPlayerFactory of type %d, failed to add
to map., type);
return UNKNOWN_ERROR;
}
return OK;
}
我們回到3.3的程序中區,通過factory = sFactoryMap.valueFor(playerType);//根據type類型獲取一個StagefrightPlayerFactory,即之前注冊的factory對象。實際是調用他的虛函數create_player()來實現:
virtual sp createPlayer() {
ALOGV( create StagefrightPlayer);
return new StagefrightPlayer();//新建一個StagefrightPlayer
}
接下去我們看到的將是真正進入StageFright的實現流程:
StagefrightPlayer::StagefrightPlayer()
: mPlayer(new AwesomePlayer) {//新建一個AwesomePlayer類,該結構體類屬於Stagefright
ALOGV(StagefrightPlayer);
mPlayer->setListener(this);//注冊StagefrightPlayer到AwesomePlayer類
}
3.4 AwesimePlayer打入stagefright內部
////////////////////////////////////////////////////////////////////////////////
AwesomePlayer::AwesomePlayer()
: mQueueStarted(false),
mUIDValid(false),
mTimeSource(NULL),
mVideoRenderingStarted(false),
mVideoRendererIsPreview(false),
mAudioPlayer(NULL),
mDisplayWidth(0),
mDisplayHeight(0),
mVideoScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW),
mFlags(0),
mExtractorFlags(0),
mVideoBuffer(NULL),
mDecryptHandle(NULL),
mLastVideoTimeUs(-1),
mTextDriver(NULL) {
CHECK_EQ(mClient.connect(), (status_t)OK);//OMXClient,connect後維護一個mOMX:BpOMX
DataSource::RegisterDefaultSniffers();
mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);//注冊onVideoEvent事件
mVideoEventPending = false;
mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone);//注冊onStreamDone事件
mStreamDoneEventPending = false;
mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate);//注冊onBufferingUpdate
mBufferingEventPending = false;
mVideoLagEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoLagUpdate);
mVideoEventPending = false;
mCheckAudioStatusEvent = new AwesomeEvent(
this, &AwesomePlayer::onCheckAudioStatus);
mAudioStatusEventPending = false;
reset();
}
Awesomeplay的構造函數,主要過程是建立了幾個事件處理的注冊,具體的event處理機制在下一文中分享
android 動畫類型
1.Animation 動畫類型Android的animation由四種類型組成:XML中 alph 漸變透明度動畫效果 scale 漸變尺寸伸縮動畫效果 tr
Android AlertDialog對話框詳解及實例
Android AlertDialog關系圖如下: Android主要提供四種對話框: 1:AlertDialog:功能最豐富,實際應用最廣的對話框。 2:P
Android筆記Android基於事件監聽器處理機制
一、Android的事件處理 Android事件處理包括兩個部分:Android事件處理機制(基本)和Android消息傳遞機制(進階)。前者包含三種處理方式
Android自定義View詳解
轉載請標明出處:http://blog.csdn.net/lmj623565791/article/details/24252901很多的Android入門程序猿來說對於