MediaPlayer
通常MediaPlayer的調用邏輯是,構造函數-> setDataSource -> SetVideoSurfaceTexture-> prepare/prepareAsync -> start-> stop-> reset-> 析構函數,按照實際需求還會調用pause、isPlaying、getDuration、getCurrentPosition、setLooping、seekTo等方法。
1、 MediaPlayer的狀态圖
Idle狀态
調用new或reset()方法建立MediaPlayer後進入空閑
End狀态
調用release()後就結束
Error狀态
播放控制操作出錯或無效狀态下調用播放控制操作
Initialized狀态
調用setDataSource之後完成初始化
Prepared狀态
同步prepare()或異步prepareAsync()完成準備
Preparing狀态
是一種瞬時狀态,調用prepareAsync()時會先進入此狀态
Started 狀态
要開始播放必須調用start()
Paused 狀态
調用pause()并成功傳回後播放可以被暫停
Stopped狀态
調用stop()會停止播放
PlaybackCompleted狀态
當播放到達流末端時,播放完成
2、 MediaPlayer執行個體的擷取
用new直接建立
MediaPlayer mp = new MediaPlayer();
用create建立,這種方法不用再調用setDataSource
MediaPlayer mp = MediaPlayer.create(this, R.raw.test);
3、 MediaPlayer和MediaPlayerService
3.1、MediaPlayerService服務
mediaserver 啟動後會把media相關一些服務添加到servicemanager中,其中就有mediaPlayerService。這樣應用啟動前,系統就有了mediaPlayerService這個服務程式。【Main_mediaserver.cpp】

3.2、建立MediaPlayer
Java應用程式中建立MediaPlayer對象 MediaPlayer mediaPlayer = new MediaPlayer();
MediaPlayer的構造函數中比較重要的就是本地的native函數:native_setup ,其對應的函數為
android_media_MediaPlayer_native_setup
構造Native層的MediaPlayer對象的時候【MediaPlayer.cpp】,也會構造其父類的對象。在MediaPlayer的父類IMediaDeathNotifier中有個很重要的方法getMediaPlayerService()來擷取MediaPlayerService,其關系到MediaPlayer和MediaPlayerService之間的通信。
3.3、setDataSource設定播放資源
在整個應用程式的程序中,Mediaplayer.cpp 中 setDataSource會從service manager中獲得mediaPlayerService 服務,然後通過服務來建立player,這個player就是播放器的真實執行個體,同時也使MediaPlayer和MediaPlayerService建立了聯系。
在java層MediaPlayer.java中的setDataSource最終會調用_setDataSource方法,對應native層MediaPlayer.cpp中的setDataSource方法。
通過 getMediaPlayerService 得到的BpMediaPlayerService類型的service,和mediaPlayerService程序中的BnMediaPlayerService 相對應負責binder通訊。
在create函數中建立了一個MediaPlayerService::Client的執行個體,是MediaPlayerService的内部類,也就是說MediaPlayerService會為每個client應用程序建立一個相應的MediaPlayerService::Client的執行個體,來實作播放以及播放過程的控制,向MediaPlayer發事件通知。到這裡,在Server端的對象就建立完成了。
然後在MediaPlayer.cpp中就得到了一個sever端的player執行個體,它和本地其他類的執行個體沒什麼用法上的差別,而實際上則是通過binder機制運作在另外一個程序中的。獲得此執行個體後繼續player->setDataSource操作。
總結:Java應用程式中使用MediaPlayer.java的setDataSource()會傳遞到Native層中MediaPlayer.cpp的setDataSource()去執行,而MediaPlayer.cpp又會把這個方法交給MediaPlayerservice去執行。MediaPlayerService則是使用NuPlayer實作的,最後, setDataSource還是交給了NuPlayer去執行了。這個過程把MediaPlayer和MediaPlayerService之間的聯系建立起來,同時又把MediaPlayerService和NuPlayer的關系建立了起來。
NuPlayer
NuPlayer由NuPlayerDriver封裝,利用了底層的ALooper/AHandler機制來異步地處理請求,ALooper儲存消息請求,然後在AHandler中處理。另外,NuPlayer中利用到了Acodec。
1、整體架構圖
其中的幾個部分:
NuPlayer::Source 解析子產品(parser,功能類似FFmpeg的avformat)。其接口與MediaExtractor和
MediaSource組合的接口差不多,同時提供了用于快速定位的seekTo接口。
NuPlayer::Decoder 解碼子產品(decoder,功能類似FFmpeg的avcodec),封裝了用于AVC、AAC解碼的接口,
通過ACodec實作解碼(包含OMX硬解碼和軟解碼)。
NuPlayer::Render 渲染子產品(render,功能類似聲霸卡驅動和顯示卡驅動),主要用于音視訊渲染和同步,與
NativeWindow有關。
NuPlayer 是播放架構中連接配接Source、Decoder、Renderer的紐帶
NuPlayerDriver 作為NuPlayer類的封裝,直接調用NuPlayer。
2、ALooper/AHandler機制
NuPlayer本身繼承自AHandler類,而ALooper對象儲存在NuPlayerDriver中。ALooper/AHandler機制是一種消息循環處理方式,通常有三個主要部分:消息(message,通常包含Handler)、消息隊列(queue)、消息處理線程(looperthread)。此機制會将變量封裝到一個消息AMessage結構體中,然後放到隊列中去,背景專門有一個線程會從這個隊列中取出消息然後通過函數onMessageReceived執行。
2.1、AHandler
是消息處理類的父類,基本上隻有一個onMessageReceived用于子類繼承,deliverMessage用于給類AMessage使用,setID用于給友元類ALooperRoster使用(消息的發送和取出都是調用輔助類ALooperRoster完成的)。
2.2、AMessage
其是消息的載體,在使用AMessage時隻需要指定消息類别和要處理該消息的AHandler即可,可以通過構造函數建立,也可以單獨調用setWhat和setTarget接口來設定。AMessage構造完成之後,可以調用setXXX設定對應的參數,通過findXXX擷取傳遞的參數。最後通過post即可将消息投遞到AHandler的消息隊列中。
2.3、ALooper及背景線程
是消息處理循環,其調用邏輯是先建立一個ALooper對象,然後調用setName和start接口,之後調用registerHandler設定一個AHandler,這樣就完成了初始化。在析構之前需要調用stop接口。
2.4、例子
2.5、總結
總的來說整個消息的處理過程就是:在ALoop中的ALooper::start接口會啟動一個線程LooperThread,并調用ALooper::loop函數來完成消息的實際執行。而消息是由AMessage通過調用ALooper::post接口,将AMessage添加到消息隊列中的。ALooper中存在的背景線程線程LooperThread維護着這個消息隊列,線程函數不斷從這個隊列中取出消息執行。其流程如下圖所示:
frameworks/av/media/libmediaplayerservice/MediaPlayerService.h
MediaPlayerService 類的繼承關系如下:
Client 和 AudioOutput 是 MediaPlayerService的内部類
IMediaPlayerService是對為提供的接口類, 定義如下:
frameworks/av/include/media/IMediaPlayerService.h
class IMediaPlayerService: public IInterface
44{
public:
DECLARE_META_INTERFACE(MediaPlayerService);
virtual sp<IMediaRecorder> createMediaRecorder(const String16 &opPackageName) = ;
virtual sp<IMediaMetadataRetriever> createMetadataRetriever() = ;
virtual sp<IMediaPlayer> create(const sp<IMediaPlayerClient>& client,
audio_session_t audioSessionId = AUDIO_SESSION_ALLOCATE) = ;
virtual sp<IOMX> getOMX() = ;
virtual sp<IHDCP> makeHDCP(bool createEncryptionModule) = ;
virtual sp<IMediaCodecList> getCodecList() const = ;
// Connects to a remote display.
// 'iface' specifies the address of the local interface on which to listen for
// a connection from the remote display as an ip address and port number
// of the form "x.x.x.x:y". The media server should call back into the provided remote
// display client when display connection, disconnection or errors occur.
// The assumption is that at most one remote display will be connected to the
// provided interface at a time.
virtual sp<IRemoteDisplay> listenForRemoteDisplay(const String16 &opPackageName,
const sp<IRemoteDisplayClient>& client, const String8& iface) = ;
// codecs and audio devices usage tracking for the battery app
enum BatteryDataBits {
// tracking audio codec
kBatteryDataTrackAudio = ,
// tracking video codec
kBatteryDataTrackVideo = ,
// codec is started, otherwise codec is paused
kBatteryDataCodecStarted = ,
// tracking decoder (for media player),
// otherwise tracking encoder (for media recorder)
kBatteryDataTrackDecoder = ,
// start to play an audio on an audio device
kBatteryDataAudioFlingerStart = ,
// stop/pause the audio playback
kBatteryDataAudioFlingerStop = ,
// audio is rounted to speaker
kBatteryDataSpeakerOn = ,
// audio is rounted to devices other than speaker
kBatteryDataOtherAudioDeviceOn = ,
};
virtual void addBatteryData(uint32_t params) = ;
virtual status_t pullBatteryData(Parcel* reply) = ;
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
MediaPlayerService 是native系統服務, 通過ServiceManager注冊到系統中
frameworks/av/media/mediaserver/main_mediaserver.cpp
.....
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm(defaultServiceManager());
ALOGI("ServiceManager: %p", sm.get());
InitializeIcuOrDie();
MediaPlayerService::instantiate();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
instantiate() 建立MediaPlayerService并注冊到系統服務中
frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp
void MediaPlayerService::instantiate() {
defaultServiceManager()->addService(
String16("media.player"), new MediaPlayerService());
}
- 1
- 2
- 3
- 4
- 5
MediaPlayerService構造函數如下:
MediaPlayerService::MediaPlayerService()
{
ALOGV("MediaPlayerService created");
mNextConnId = ;
mBatteryAudio.refCount = ;
for (int i = ; i < NUM_AUDIO_DEVICES; i++) {
mBatteryAudio.deviceOn[i] = ;
mBatteryAudio.lastTime[i] = ;
mBatteryAudio.totalTime[i] = ;
}
// speaker is on by default
mBatteryAudio.deviceOn[SPEAKER] = ;
// reset battery stats
// if the mediaserver has crashed, battery stats could be left
// in bad state, reset the state upon service start.
BatteryNotifier::getInstance().noteResetVideo();
//register built-in player
MediaPlayerFactory::registerBuiltinFactories();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
registerBuiltinFactories() register the NU_PLAYER and TEST_PLAYER
void MediaPlayerFactory::registerBuiltinFactories() {
Mutex::Autolock lock_(&sLock);
if (sInitComplete)
return;
registerFactory_l(new NuPlayerFactory(), NU_PLAYER);
registerFactory_l(new TestPlayerFactory(), TEST_PLAYER);
sInitComplete = true;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
createMediaRecorder() 建立Recorder用于錄音
sp<IMediaRecorder> MediaPlayerService::createMediaRecorder(const String16 &opPackageName)
{
pid_t pid = IPCThreadState::self()->getCallingPid();
sp<MediaRecorderClient> recorder = new MediaRecorderClient(this, pid, opPackageName);
wp<MediaRecorderClient> w = recorder;
Mutex::Autolock lock(mLock);
mMediaRecorderClients.add(w);
ALOGV("Create new media recorder client from pid %d", pid);
return recorder;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
建立Client主要用于播放
sp<IMediaPlayer> MediaPlayerService::create(const sp<IMediaPlayerClient>& client,
audio_session_t audioSessionId)
{
pid_t pid = IPCThreadState::self()->getCallingPid();
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;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
MediaPlayerService::Client::Client(
const sp<MediaPlayerService>& service, pid_t pid,
int32_t connId, const sp<IMediaPlayerClient>& client,
audio_session_t audioSessionId, uid_t uid)
{
ALOGV("Client(%d) constructor", connId);
mPid = pid;
mConnId = connId;
mService = service;
mClient = client;
mLoop = false;
mStatus = NO_INIT;
mAudioSessionId = audioSessionId;
mUID = uid;
mRetransmitEndpointValid = false;
mAudioAttributes = NULL;
#if CALLBACK_ANTAGONIZER
ALOGD("create Antagonizer");
mAntagonizer = new Antagonizer(notify, this);
#endif
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
<link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-258a4616f7.css" target="_blank" rel="external nofollow" rel="stylesheet">
</div>
frameworks/av/media/libmediaplayerservice/MediaPlayerService.h