Frameworks/base/libmediaplayerservice/mediaplayerservice. cpp
Because MX51 is the working platform, MX51 10.3 code is analyzed. This article mainly analyzes the code of the video play part and ignores the recorder and audio parts.
Mediaplayer service is a system service that allows Android video playback, recording and recording, metadata retrieval, and other client applications to interact with mediaplayer service. mediaplayer service enables video playback, video recording, and metadata retrieval.
251 MediaPlayerService::MediaPlayerService() 252 { 253 LOGV("MediaPlayerService created"); 254 mNextConnId = 1; 255 }
Mediaplayerservice Constructor
Mnextconnid records the available connect IDs of the client. Each time a client is created, mnextconnid increments by 1. The used connect IDs cannot be reused.
sp<IMediaMetadataRetriever> MediaPlayerService::createMetadataRetriever(pid_t pid){ sp<MetadataRetrieverClient> retriever = new MetadataRetrieverClient(pid); LOGV("Create new media retriever from pid %d", pid); return retriever;}Create a metadata retriever client. We can guess from the class name that this function is used to obtain the metadata of the media file. View the definition file libmediaplayerservice/metadataretrieverclient. cpp of metadataretrieverclient. You can see that this class provides the following methods:
- Getframeattime obtains the frame content of the video file at the specified time. It can be used to obtain the thumbnail of the media file.
- Extractalbumart gets the albumart of the media file. albumart is the preview cover of the media file. Generally, if this is not extracted, use getframeattime to get the first frame instead.
- Extractmetadata: Get the metadata of the media file: album, artist, author, date, genre, video_format, video_height, etc.
286 sp<IMediaPlayer> MediaPlayerService::create( 287 pid_t pid, const sp<IMediaPlayerClient>& client, const char* url, 288 const KeyedVector<String8, String8> *headers, int audioSessionId) 289 { 290 int32_t connId = android_atomic_inc(&mNextConnId); 291 sp<Client> c = new Client(this, pid, connId, client, audioSessionId); 292 LOGV("Create new client(%d) from pid %d, url=%s, connId=%d, audioSessionId=%d", 293 connId, pid, url, connId, audioSessionId); 294 if (NO_ERROR != c->setDataSource(url, headers)) 295 { 296 c.clear(); 297 return c; 298 } 299 wp<Client> w = c; 300 Mutex::Autolock lock(mLock); 301 mClients.add(w); 302 return c; 303 }Create an object for the mediaplayer Client
@ PID: ID of the process where the client is located
@ Client: mediaplayer Client
@ URL: Media File URL
@ Headers: Unknown
@ Audiosessionid:
301 mclients is an array of client objects. Each newly created client is added to this array.
305 sp<IMediaPlayer> MediaPlayerService::create(pid_t pid, const sp<IMediaPlayerClient>& client, 306 int fd, int64_t offset, int64_t length, int audioSessionId) 307 { 308 int32_t connId = android_atomic_inc(&mNextConnId); 309 sp<Client> c = new Client(this, pid, connId, client, audioSessionId); 310 LOGV("Create new client(%d) from pid %d, fd=%d, offset=%lld, length=%lld, audioSessionId=%d", 311 connId, pid, fd, offset, length, audioSessionId); 312 if (NO_ERROR != c->setDataSource(fd, offset, length)) { 313 c.clear(); 314 } else { 315 wp<Client> w = c; 316 Mutex::Autolock lock(mLock); 317 mClients.add(w); 318 } 319 ::close(fd); 320 return c; 321 }Another reload form of create is
305 sp<IMediaPlayer> MediaPlayerService::create(pid_t pid, const sp<IMediaPlayerClient>& client, 306 int fd, int64_t offset, int64_t length, int audioSessionId) 307 { 308 int32_t connId = android_atomic_inc(&mNextConnId); 309 sp<Client> c = new Client(this, pid, connId, client, audioSessionId); 310 LOGV("Create new client(%d) from pid %d, fd=%d, offset=%lld, length=%lld, audioSessionId=%d", 311 connId, pid, fd, offset, length, audioSessionId); 312 if (NO_ERROR != c->setDataSource(fd, offset, length)) { 313 c.clear(); 314 } else { 315 wp<Client> w = c; 316 Mutex::Autolock lock(mLock); 317 mClients.add(w); 318 } 319 ::close(fd); 320 return c; 321 }@ FD: open media file descriptor
@ Offset: it is confusing to introduce the offset and length parameters to Android. Isn't the operation on the media file started from the start position of FD? It may be true that the media content is in another file container, so that the offset and length are used to define the location of the media content.
@ Length:
MediaPlayerService::Client::Client(const sp<MediaPlayerService>& service, pid_t pid, int32_t connId, const sp<IMediaPlayerClient>& client, int audioSessionId){ LOGV("Client(%d) constructor", connId); mPid = pid; mConnId = connId; mService = service; mClient = client; mLoop = false; mStatus = NO_INIT; mAudioSessionId = audioSessionId;#if CALLBACK_ANTAGONIZER LOGD("create Antagonizer"); mAntagonizer = new Antagonizer(notify, this);#endif}For a video to be played, two clients are created, one in the user space mediaplayer instance (this client is responsible for communicating with mediaplayerservice), and the other in the mediaplayer service space mediaplayerservice: Client :: client instance, used to maintain the status of the client on the mediaplayer Service side.
The server client is created in mediaplayerservice: Create. The newly created client object is added to the mclients array.
player_type getPlayerType(int fd, int64_t offset, int64_t length)........
This function first reads some bytes from the file header, and then returns the corresponding player type based on the file type identified by the header.
player_type getPlayerType(const char* url)............
Determine the player type based on the URL
static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie, notify_callback_f notifyFunc){ sp<MediaPlayerBase> p; switch (playerType & 0xff) {#ifndef NO_OPENCORE case PV_PLAYER: LOGV(" create PVPlayer"); p = new PVPlayer(); break; #endif case SONIVOX_PLAYER: LOGV(" create MidiFile"); p = new MidiFile(); break; case STAGEFRIGHT_PLAYER: LOGV(" create StagefrightPlayer"); p = new StagefrightPlayer; break;#ifdef PREBUILT_FSL_IMX_OMX case OMX_PLAYER: LOGV(" Create OMXPlayer.\n"); p = new OMXPlayer(playerType >> 8); break;#endif case TEST_PLAYER: LOGV("Create Test Player stub"); p = new TestPlayerStub(); break; } if (p != NULL) { if (p->initCheck() == NO_ERROR) { p->setNotifyCallback(cookie, notifyFunc); } else { p.clear(); } } if (p == NULL) { LOGE("Failed to create player object"); } return p;}Create a corresponding Player Based on the specified player type and return it. You can see that pvplayer, midifile, stagefrightplayer, and omxplayer are currently supported.
Omxplayer is a dedicated Freescale player.
status_t MediaPlayerService::Client::setDataSource( const char *url, const KeyedVector<String8, String8> *headers){ LOGV("setDataSource(%s)", url); if (url == NULL) return UNKNOWN_ERROR; if (strncmp(url, "content://", 10) == 0) { // get a filedescriptor for the content Uri and // pass it to the setDataSource(fd) method String16 url16(url); int fd = android::openContentProviderFile(url16); if (fd < 0) { LOGE("Couldn't open fd for %s", url); return UNKNOWN_ERROR; } setDataSource(fd, 0, 0x7fffffffffLL); // this sets mStatus close(fd); return mStatus; } else { player_type playerType = getPlayerType(url); LOGV("player type = %d", playerType); // create the right type of player sp<MediaPlayerBase> p = createPlayer(playerType); if (p == NULL) return NO_INIT; if (!p->hardwareOutput()) { mAudioOutput = new AudioOutput(mAudioSessionId); static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput); } // now set data source LOGV(" setDataSource"); mStatus = p->setDataSource(url, headers); if (mStatus == NO_ERROR) { mPlayer = p; } else { LOGE(" error: %d", mStatus); } return mStatus; }}As the name suggests, setdatasource sets data-related content to the player. If stagefright player is used, the setdatasource member function of awesome player is called. Awesomeplayer: setdatasource has two overload functions: one Stores @ headers directly, and the other calls the corresponding extractor to extract the required information such as mflags and mbitrate from the file.
status_t MediaPlayerService::Client::setVideoSurface(const sp<ISurface>& surface){ LOGV("[%d] setVideoSurface(%p)", mConnId, surface.get()); sp<MediaPlayerBase> p = getPlayer(); if (p == 0) return UNKNOWN_ERROR; return p->setVideoSurface(surface);} Set the surface object for the player
sp<IMemory> MediaPlayerService::Client::captureCurrentFrame(){ LOGV("captureCurrentFrame"); sp<MediaPlayerBase> p = getPlayer(); if (p == NULL) { LOGE("media player is not initialized"); return NULL; } Mutex::Autolock lock(mLock); mVideoFrame.clear(); mVideoFrameDealer.clear(); VideoFrame *frame = NULL; p->captureCurrentFrame(&frame); if (frame == NULL) { LOGE("failed to capture a video frame"); return NULL; } size_t size = sizeof(VideoFrame) + frame->mSize; mVideoFrameDealer = new MemoryDealer(size); if (mVideoFrameDealer == NULL) { LOGE("failed to create MemoryDealer"); return NULL; } mVideoFrame = mVideoFrameDealer->allocate(size); if (mVideoFrame == NULL) { LOGE("not enough memory for VideoFrame size=%u", size); mVideoFrameDealer.clear(); return NULL; } VideoFrame *frameCopy = static_cast<VideoFrame *>(mVideoFrame->pointer()); frameCopy->mWidth = frame->mWidth; frameCopy->mHeight = frame->mHeight; frameCopy->mDisplayWidth = frame->mDisplayWidth; frameCopy->mDisplayHeight = frame->mDisplayHeight; frameCopy->mSize = frame->mSize; frameCopy->mData = (uint8_t *)frameCopy + sizeof(VideoFrame); memcpy(frameCopy->mData, frame->mData, frame->mSize); return mVideoFrame;}Get the data of the current frame and return a piece of memory space. The first part of the memory is the basic information of the frame: width, height, displaywidth, displayheight, size, followed by the frame data.
The video-related code in mediaplayerservice. cpp is analyzed.
The main task of mediaplayerservice is to create a corresponding client proxy in the service when the client application requests playback. The service processes the requests sent by the client application based on the opened file or Uri type, select the Player Plug-in.