編輯:關於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 MapmHeaders;
在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, Mapheaders) { 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); spmp = 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); spproc(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 );//根據視頻源獲取要使用的播放器的類型 ........ spp = 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 spcreatePlayer() { 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處理機制在下一文中分享
1.Animation 動畫類型Android的animation由四種類型組成:XML中 alph 漸變透明度動畫效果 scale 漸變尺寸伸縮動畫效果 tr
Android AlertDialog關系圖如下: Android主要提供四種對話框: 1:AlertDialog:功能最豐富,實際應用最廣的對話框。 2:P
一、Android的事件處理 Android事件處理包括兩個部分:Android事件處理機制(基本)和Android消息傳遞機制(進階)。前者包含三種處理方式
轉載請標明出處:http://blog.csdn.net/lmj623565791/article/details/24252901很多的Android入門程序猿來說對於