MediaPlayer 播放本地视频源码流程-setDataSource
Posted 蜘蛛侠不会飞
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MediaPlayer 播放本地视频源码流程-setDataSource相关的知识,希望对你有一定的参考价值。
1. MediaPlayer 结合 textureView 播放本地视频
xml 文件
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextureView
android:id="@+id/textureView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<Button
android:id="@+id/btn_opt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="开始"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Activity 类
package com.enjoy.mediademo;
import android.hardware.Camera;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.widget.Button;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import java.io.File;
import java.io.IOException;
public class VideoActivity extends AppCompatActivity implements View.OnClickListener, MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener
private TextureView textureView;
private Button btn_opt;
private MediaPlayer mediaPlayer;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_record);
textureView = findViewById(R.id.textureView);
btn_opt = findViewById(R.id.btn_opt);
btn_opt.setOnClickListener(this);
@Override
public void onClick(View v)
CharSequence text = btn_opt.getText();
if (TextUtils.equals(text, "开始"))
btn_opt.setText("结束");
mediaPlayer = new MediaPlayer();
//设置准备监听
mediaPlayer.setOnPreparedListener(this);
//播放完成监听
mediaPlayer.setOnCompletionListener(this);
try
//指定视频源
mediaPlayer.setDataSource(new File(getExternalFilesDir(""), "a.mp4").getAbsolutePath());
catch (IOException e)
e.printStackTrace();
//设置画布进行展示
mediaPlayer.setSurface(new Surface(textureView.getSurfaceTexture()));
mediaPlayer.prepareAsync();
else
btn_opt.setText("开始");
mediaPlayer.stop();
mediaPlayer.release();
@Override
public void onPrepared(MediaPlayer mp)
mediaPlayer.start();
@Override
public void onCompletion(MediaPlayer mp)
btn_opt.setText("开始");
//释放
mediaPlayer.release();
主要涉及到 MediaPlayer 的方法:
mediaPlayer = new MediaPlayer();
mediaPlayer.setOnPreparedListener(this);
//播放完成回调
mediaPlayer.setOnCompletionListener(this);
mediaPlayer.setDataSource(new File。。。
//设置画布进行展示
mediaPlayer.setSurface(new Surface(textureView.getSurfaceTexture()));
mediaPlayer.prepareAsync();
mediaPlayer.start();
按照实际需求还会调用pause、isPlaying、getDuration、getCurrentPosition、setLooping、seekTo等方法。
2. MediaPlayer 源码分析:
MediaPlayer 的状态图:
音视频相关的编解码,解封装,渲染等操作需要大量的运算,所以谷歌将这些方法通过底层C/C++代码来实现
MediaPlayer框架的层次架构图:
1)创建 MediaPlayer 对象
mediaPlayer = new MediaPlayer();
/frameworks/base/media/java/android/media/MediaPlayer.java
public MediaPlayer()
super(new AudioAttributes.Builder().build(),
AudioPlaybackConfiguration.PLAYER_TYPE_JAM_MEDIAPLAYER);
// EventHandler 是用于native 层发消息给应用层的,作为回调
Looper looper;
// 如果有创建子线程
if ((looper = Looper.myLooper()) != null)
mEventHandler = new EventHandler(this, looper);
// 如果线程是主线程的话
else if ((looper = Looper.getMainLooper()) != null)
mEventHandler = new EventHandler(this, looper);
else
mEventHandler = null;
mTimeProvider = new TimeProvider(this);
mOpenSubtitleSources = new Vector<InputStream>();
/* Native setup requires a weak reference to our object.
* It's easier to create it here than in C++.
*/
// 1. 调用native 层方法
native_setup(new WeakReference<MediaPlayer>(this),
getCurrentOpPackageName());
// 2. 父类方法:用于AudioFlinger跟踪当前播放器的状态信息
baseRegisterPlayer();
// 1. 调用native 层方法 native_setup
private static native final void native_init();
/frameworks/base/media/jni/android_media_MediaPlayer.cpp
static const JNINativeMethod gMethods[] =
"native_setup", "(Ljava/lang/Object;Ljava/lang/String;)V",(void *)android_media_MediaPlayer_native_setup,
static void
android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
jstring opPackageName)
ALOGV("native_setup");
ScopedUtfChars opPackageNameStr(env, opPackageName);
// native层创建 MediaPlayer对象
sp<MediaPlayer> mp = new MediaPlayer(opPackageNameStr.c_str());
if (mp == NULL)
jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
return;
// create new listener and give it to MediaPlayer
sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);
// 通过 MediaPlayer设置观察者然后可以通过 JNIMediaPlayerListener 回调给应用层
mp->setListener(listener);
// Stow our new C++ MediaPlayer in an opaque field in the Java object.
setMediaPlayer(env, thiz, mp);
native层创建 MediaPlayer对象
/frameworks/av/media/libmedia/mediaplayer.cpp
MediaPlayer::MediaPlayer(const std::string opPackageName) : mOpPackageName(opPackageName)
ALOGV("constructor");
mListener = NULL;
mCookie = NULL;
// 设置默认的type 是音乐的
mStreamType = AUDIO_STREAM_MUSIC;
mAudioAttributesParcel = NULL;
mCurrentPosition = -1;
// 默认当前seek模式为seek位置前SYNC同步,默认寻找seek位置前的关键帧数据进行播放
mCurrentSeekMode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC;
mSeekPosition = -1;
mSeekMode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC;
mCurrentState = MEDIA_PLAYER_IDLE;
mPrepareSync = false;
mPrepareStatus = NO_ERROR;
mLoop = false;
mLeftVolume = mRightVolume = 1.0;
mVideoWidth = mVideoHeight = 0;
mLockThreadId = 0;
// 获取 AudiosessionId
mAudioSessionId = (audio_session_t) AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
AudioSystem::acquireAudioSessionId(mAudioSessionId, (pid_t)-1, (uid_t)-1); // always in client.
mSendLevel = 0;
mRetransmitEndpointValid = false;
看一下 EventHandler 的回调事件处理
/frameworks/av/media/libmedia/mediaplayer.cpp
在MediaPlayer 中有去设置 setListener
status_t MediaPlayer::setListener(const sp<MediaPlayerListener>& listener)
ALOGV("setListener");
Mutex::Autolock _l(mLock);
mListener = listener;
return NO_ERROR;
-------
// 有个 notify 方法可以通知到 对应的观察者
void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj)
ALOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
bool send = true;
bool locked = false;
switch (msg)
case MEDIA_NOP: // interface test message
break;
// 比如消息为:MEDIA_PREPARED
case MEDIA_PREPARED:
ALOGV("MediaPlayer::notify() prepared");
mCurrentState = MEDIA_PLAYER_PREPARED;
if (mPrepareSync)
ALOGV("signal application thread");
mPrepareSync = false;
mPrepareStatus = NO_ERROR;
mSignal.signal();
break;
// 将观察者赋值给:listener
sp<MediaPlayerListener> listener = mListener;
if (locked) mLock.unlock();
// this prevents re-entrant calls into client code
if ((listener != 0) && send)
Mutex::Autolock _l(mNotifyLock);
ALOGV("callback application");
// 调用 notify 函数通知,ext1, ext2 分别是宽和高
listener->notify(msg, ext1, ext2, obj);
ALOGV("back from callback");
/frameworks/base/media/jni/android_media_MediaPlayer.cpp
void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2, const Parcel *obj)
JNIEnv *env = AndroidRuntime::getJNIEnv();
if (obj && obj->dataSize() > 0)
jobject jParcel = createJavaParcelObject(env);
if (jParcel != NULL)
Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
nativeParcel->setData(obj->data(), obj->dataSize());
// 其中,post_event就是ap 层的方法
env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
msg, ext1, ext2, jParcel);
env->DeleteLocalRef(jParcel);
else
env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
msg, ext1, ext2, NULL);
if (env->ExceptionCheck())
ALOGW("An exception occurred while notifying an event.");
LOGW_EX(env);
env->ExceptionClear();
-------------------
fields.post_event 在初始化的时候有赋值
static void
android_media_MediaPlayer_native_init(JNIEnv *env)
jclass clazz;
clazz = env->FindClass("android/media/MediaPlayer");
if (clazz == NULL)
return;
fields.context = env->GetFieldID(clazz, "mNativeContext", "J");
if (fields.context == NULL)
return;
// 对应的方法是 postEventFromNative
fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
"(Ljava/lang/Object;IIILjava/lang/Object;)V");
/frameworks/base/media/java/android/media/MediaPlayer.java
private static void postEventFromNative(Object mediaplayer_ref,
int what, int arg1, int arg2, Object obj)
final MediaPlayer mp = (MediaPlayer)((WeakReference)mediaplayer_ref).get();
if (mp == null)
return;
switch (what)
case MEDIA_PREPARED:
// By this time, we've learned about DrmInfo's presence or absence. This is meant
// mainly for prepareAsync() use case. For prepare(), this still can run to a race
// condition b/c MediaPlayerNative releases the prepare() lock before calling notify
// so we also set mDrmInfoResolved in prepare().
synchronized (mp.mDrmLock)
mp.mDrmInfoResolved = true;
break;
if (mp.mEventHandler != null)
Message m = mp.mEventHandler.obtainMessage(what, arg1, arg2, obj);
// EventHandler handler 去处理消息
mp.mEventHandler.sendMessage(m);
---------------
private class EventHandler extends Handler
private MediaPlayer mMediaPlayer;
public EventHandler(MediaPlayer mp, Looper looper)
super(looper);
mMediaPlayer = mp;
@Override
public void handleMessage(Message msg)
if (mMediaPlayer.mNativeContext == 0)
Log.w(TAG, "mediaplayer went away with unhandled events");
return;
switch(msg.what)
// 通知到ap 层媒体已经准备好了,可以显示了
case MEDIA_PREPARED:
try
scanInternalSubtitleTracks();
catch (RuntimeException e)
// send error message instead of crashing;
// send error message instead of inlining a call to onError
// to avoid code duplication.
Message msg2 = obtainMessage(
MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED, null);
sendMessage(msg2);
// mOnPreparedListener为ap 层设置的回调:
// public void setOnPreparedListener(OnPreparedListener listener)
OnPreparedListener onPreparedListener = mOnPreparedListener;
if (onPreparedListener != null)
// 回调 onPrepared方法
onPreparedListener.onPrepared(mMediaPlayer);
return;
---- 还有会回调视频大小的方法---
case MEDIA_SET_VIDEO_SIZE:
OnVideoSizeChangedListener onVideoSizeChangedListener = mOnVideoSizeChangedListener;
if (onVideoSizeChangedListener != null)
onVideoSizeChangedListener.onVideoSizeChanged(
mMediaPlayer, msg.arg1, msg.arg2);
return;
//播放完成回调为如下: mediaPlayer.setOnCompletionListener(this);
case MEDIA_PLAYBACK_COMPLETE:
mOnCompletionInternalListener.onCompletion(mMediaPlayer);
OnCompletionListener onCompletionListener = mOnCompletionListener;
// 回调播放完成
if (onCompletionListener != null)
onCompletionListener.onCompletion(mMediaPlayer);
stayAwake(false);
return;
-------
// stayAwake方法是去设置屏幕不常亮,释放锁
private void stayAwake(boolean awake)
if (mWakeLock != null)
if (awake && !mWakeLock.isHeld())
mWakeLock.acquire();
else if (!awake && mWakeLock.isHeld())
mWakeLock.release();
mStayAwake = awake;
updateSurfaceScreenOn();
具体的话可以参考:MediaPlayer 的消息回调机制
2. 设置播放的源数据:mediaPlayer.setDataSource(new File。。。
MediaPlayer框架采用C/S架构,分别处在两个进程上,采用Bindler机制进行进程间通信。我们发现native层的大部分类都是采用IXXX,BpXXX,BnXXX形式的。在MediaPlayer框架层,由IMediaPlayer,IMediaPlayerService,IMediaPlayerClient三大元老组成了基本框架,由IBinder,BBinder(准确来说叫BnBinder比较合适),BpBinder将其粘合。此外,IXXX类里总是一些虚抽象函数,不存在定义,由BpXXX和BnXXX继承它,BpXXX作为Client端的代理类,发起服务的请求,服务的实现则统一放在BnXXX类里。
/frameworks/base/media/java/android/media/MediaPlayer.java
public void setDataSource(String path)
throws IOException, IllegalArgumentException, SecurityException, IllegalStateException
setDataSource(path, null, null);
-----------
@UnsupportedAppUsage
private void setDataSource(String path, Map<String, String> headers, List<HttpCookie> cookies)
throws IOException, IllegalArgumentException, SecurityException, IllegalStateException
String[] keys = null;
String[] values = null;
if (headers != null)
keys = new String[headers.size()];
values = new String[headers.size()];
int i = 0;
for (Map.Entry<String, String> entry: headers.entrySet())
keys[i] = entry.getKey();
values[i] = entry.getValue();
++i;
setDataSource(path, keys, values, cookies);
@UnsupportedAppUsage
private void setDataSource(String path, String[] keys, String[] values,
List<HttpCookie> cookies)
throws IOException, IllegalArgumentException, SecurityException, IllegalStateException
final Uri uri = Uri.parse(path);
final String scheme = uri.getScheme();
if ("file".equals(scheme))
path = uri.getPath();
else if (scheme != null)
// handle non-file sources
nativeSetDataSource(
MediaHTTPService.createHttpServiceBinderIfNecessary(path, cookies),
path,
keys,
values);
return;
// 如果不是播放网络源的视频,则执行下列的方法
final File file = new File(path);
try (FileInputStream is = new FileInputStream(file))
setDataSource(is.getFD());
--------------
public void setDataSource(@NonNull AssetFileDescriptor afd)
throws IOException, IllegalArgumentException, IllegalStateException
Preconditions.checkNotNull(afd);
// Note: using getDeclaredLength so that our behavior is the same
// as previous versions when the content provider is returning
// a full file.
if (afd.getDeclaredLength() < 0)
setDataSource(afd.getFileDescriptor());
else
setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getDeclaredLength());
--------------------
public void setDataSource(FileDescriptor fd, long offset, long length)
throws IOException, IllegalArgumentException, IllegalStateException
_setDataSource(fd, offset, length);
// 调用native 层的代码
private native void _setDataSource(FileDescriptor fd, long offset, long length)
throws IOException, IllegalArgumentException, IllegalStateException;
/frameworks/base/media/jni/android_media_MediaPlayer.cpp
static const JNINativeMethod gMethods[] =
"nativeSetDataSource",
"(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;"
"[Ljava/lang/String;)V",
(void *)android_media_MediaPlayer_setDataSourceAndHeaders
,
// 调用 如下的方法
"_setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaPlayer_setDataSourceFD,
"_setDataSource", "(Landroid/media/MediaDataSource;)V",(void *)android_media_MediaPlayer_setDataSourceCallback ,
static void
android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
// 获取到 MediaPlayer对象
sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
if (mp == NULL )
jniThrowException(env, "java/lang/IllegalStateException", NULL);
return;
if (fileDescriptor == NULL)
jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
return;
int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
ALOGV("setDataSourceFD: fd %d", fd);
// 处理是否有异常
// MediaPlayer的 setDataSource 方法
process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." );
/frameworks/av/media/libmedia/mediaplayer.cpp
status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
status_t err = UNKNOWN_ERROR;
// 1. 获取 MediaPlayerService:getMediaPlayerService()
const sp<IMediaPlayerService> service(getMediaPlayerService());
if (service != 0)
// 2. 调用 MediaPlayerService的create 方法返回 IMediaPlayer对象
sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mOpPackageName));
// 3. player 去设置 setDataSource
if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
(NO_ERROR != player->setDataSource(fd, offset, length)))
player.clear();
err = attachNewPlayer(player);
return err;
// 1. 获取 MediaPlayerService:getMediaPlayerService()
const sp<IMediaPlayerService> service(getMediaPlayerService())
获取的对应的 getMediaPlayerService 是 BpMediaplayerService,;创建对象的时候会传入Binder对象,传入的是 MediaPlayerService
先看一下mediaplayer 的头文件:
frameworks/av/media/libmedia/include/media/mediaplayer.h
// 包含了如下的文件
#include <media/IMediaPlayerClient.h>
#include <media/IMediaPlayer.h>
#include <media/IMediaDeathNotifier.h>
// MediaPlayer 继承于 BnMediaPlayerClient 和 IMediaDeathNotifier
class MediaPlayer : public BnMediaPlayerClient,
public virtual IMediaDeathNotifier
public:
explicit MediaPlayer(const android::content::AttributionSourceState& mAttributionSource =
android::content::AttributionSourceState());
frameworks/av/media/libmedia/IMediaDeathNotifier.cpp
IMediaDeathNotifier 有实现对应的方法
// establish binder interface to MediaPlayerService
/*static*/const sp<IMediaPlayerService>
IMediaDeathNotifier::getMediaPlayerService()
ALOGV("getMediaPlayerService");
Mutex::Autolock _l(sServiceLock);
if (sMediaPlayerService == 0)
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do
// 获取对应的binder 对象
binder = sm->getService(String16("media.player"));
if (binder != 0)
break;
ALOGW("Media player service not published, waiting...");
usleep(500000); // 0.5 s
while (true);
if (sDeathNotifier == NULL)
sDeathNotifier = new DeathNotifier();
binder->linkToDeath(sDeathNotifier);
// 获取对应的 sMediaPlayerService对象,传入的参数是 binder
sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
ALOGE_IF(sMediaPlayerService == 0, "no media player service!?");
return sMediaPlayerService;
// 获取对应的binder 对象
binder = sm->getService(String16("media.player"));
frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp
其实在 MediaplayerService 初始化的时候,有创建对应的binder 的对象:new MediaPlayerService()
void MediaPlayerService::instantiate()
defaultServiceManager()->addService(
String16("media.player"), new MediaPlayerService());
// 获取对应的 sMediaPlayerService对象,传入的参数是 binder 为:new MediaPlayerService()
sMediaPlayerService = interface_cast<IMediaPlayerService>(binder)
frameworks/av/media/libmedia/IMediaDeathNotifier.cpp
frameworks/av/media/libmedia/include/media/IMediaDeathNotifier.h
#include <utils/threads.h>
// 头文件中有包含 IMediaPlayerService
#include <media/IMediaPlayerService.h>
#include <utils/SortedVector.h>
namespace android
class IMediaDeathNotifier: virtual public RefBase
--------------
frameworks/av/media/libmedia/include/media/IMediaPlayerService.h
#include <utils/RefBase.h>
#include <utils/String8.h>
// 这里有包含 IInterface
#include <binder/IInterface.h>
class IMediaPlayerService: public IInterface
public:
// 这里还去使用了 DECLARE_META_INTERFACE
DECLARE_META_INTERFACE(MediaPlayerService);
frameworks/native/libs/binder/include/binder/IInterface.h
其实是 IMediaPlayerService 的类的一些实现
// INTERFACE 为 IMediaPlayerService
template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
return INTERFACE::asInterface(obj);
------------
如上分析有:DECLARE_META_INTERFACE(MediaPlayerService);
// 传入的参数是:MediaPlayerService
#define DECLARE_META_INTERFACE(INTERFACE) \\
public: \\
static const ::android::String16 descriptor; \\
static ::android::sp<I##INTERFACE> asInterface(const ::android::sp<::android::IBinder>& obj); \\
virtual const ::android::String16& getInterfaceDescriptor() const; \\
// 定义的是 IMediaPlayerService 构造函数
I##INTERFACE(); \\
virtual ~I##INTERFACE(); \\
static bool setDefaultImpl(::android::sp<I##INTERFACE> impl); \\
static const ::android::sp<I##INTERFACE>& getDefaultImpl(); \\
\\
private: \\
static ::android::sp<I##INTERFACE> default_impl; \\
\\
IMPLEMENT_META_INTERFACE 的实现的定义在如下:
frameworks/av/media/libmedia/IMediaPlayerService.cpp
IMPLEMENT_META_INTERFACE(MediaPlayerService, "android.media.IMediaPlayerService");
回到 IIterface
// INTERFACE 是 MediaPlayerService
#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \\
DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \\
#endif
----------------------
#define DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \\
const ::android::StaticString16 I##INTERFACE##_descriptor_static_str16( \\
__IINTF_CONCAT(u, NAME)); \\
const ::android::String16 I##INTERFACE::descriptor(I##INTERFACE##_descriptor_static_str16); \\
// 这里有去设置 BpMediaPlayerService
DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE0(I##INTERFACE, I##INTERFACE, Bp##INTERFACE)
-------------------------------
// 传入的BPTYPE 为:BpMediaPlayerService
#define DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE0(ITYPE, INAME, BPTYPE) \\
const ::android::String16& ITYPE::getInterfaceDescriptor() const return ITYPE::descriptor; \\
::android::sp<ITYPE> ITYPE::asInterface(const ::android::sp<::android::IBinder>& obj) \\
::android::sp<ITYPE> intr; \\
if (obj != nullptr) \\
intr = ::android::sp<ITYPE>::cast(obj->queryLocalInterface(ITYPE::descriptor)); \\
if (intr == nullptr) \\
// 创建对象为 BpMediaPlayerService
intr = ::android::sp<BPTYPE>::make(obj); \\
\\
\\
return intr; \\
\\
::android::sp<ITYPE> ITYPE::default_impl; \\
bool ITYPE::setDefaultImpl(::android::sp<ITYPE> impl) \\
/* Only one user of this interface can use this function */ \\
/* at a time. This is a heuristic to detect if two different */ \\
/* users in the same process use this function. */ \\
assert(!ITYPE::default_impl); \\
if (impl) \\
ITYPE::default_impl = std::move(impl); \\
return true; \\
\\
return false; \\
\\
const ::android::sp<ITYPE>& ITYPE::getDefaultImpl() return ITYPE::default_impl; \\
// 构造函数 IMediaPlayerService 的空实现
ITYPE::INAME() \\
ITYPE::~INAME()
obj 就是传入的对象为:MediaPlayerService
----------------看下BpMediaplayerService------------------
frameworks/av/media/libmedia/IMediaPlayerService.cpp
// 继承了 BpInterface
class BpMediaPlayerService: public BpInterface<IMediaPlayerService>
public:
// 传入的参数是:MediaPlayerService
explicit BpMediaPlayerService(const sp<IBinder>& impl)
: BpInterface<IMediaPlayerService>(impl)
virtual sp<IMediaMetadataRetriever> createMetadataRetriever()
Parcel data, reply;
// 获取 IMediaPlayerService类的 getInterfaceDescriptor
// 对应的实现在:DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
remote()->transact(CREATE_METADATA_RETRIEVER, data, &reply);
return interface_cast<IMediaMetadataRetriever>(reply.readStrongBinder());
看下 BpInterface
frameworks/native/libs/binder/include/binder/IInterface.h
// BpInterface 是多继承的,有继承 IMediaPlayerService和 BpRefBase
// BpInterface 是作为客户端去调用服务器端的方法的
// 其实 remote 也是 MediaPlayerService
// BpInterface 是多继承的,有继承 IMediaPlayerService和 BpRefBase
// BpInterface 是作为客户端去调用服务器端的方法的
// 其实 remote 也是 MediaPlayerService
template<typename INTERFACE>
class BpInterface : public INTERFACE, public BpRefBase
public:
explicit BpInterface(const sp<IBinder>& remote);
protected:
typedef INTERFACE BaseInterface;
virtual IBinder* onAsBinder();
;
下列类就是 服务器端的
template<typename INTERFACE>
class BnInterface : public INTERFACE, public BBinder
public:
virtual sp<IInterface> queryLocalInterface(const String16& _descriptor);
virtual const String16& getInterfaceDescriptor() const;
protected:
typedef INTERFACE BaseInterface;
virtual IBinder* onAsBinder();
;
// 2. 调用 BpMediaPlayerService的create 方法返回 IMediaPlayer对象
sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mOpPackageName));
frameworks/av/media/libmedia/IMediaPlayerService.cpp
class BpMediaPlayerService: public BpInterface<IMediaPlayerService>
public:
explicit BpMediaPlayerService(const sp<IBinder>& impl)
: BpInterface<IMediaPlayerService>(impl)
virtual sp<IMediaPlayer> create(
const sp<IMediaPlayerClient>& client, audio_session_t audioSessionId,
const AttributionSourceState& attributionSource)
Parcel data, reply;
// 写入数据到驱动中
// 通过Binder机制分析可知,getInterfaceDescriptor()该方法为宏定义中实现的,
// 其获取的值其实是如下宏定义赋值的字符串即接口描述符【"android.media.IMediaPlayerService"】
// IMPLEMENT_META_INTERFACE(MediaPlayerService, "android.media.IMediaPlayerService");
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
data.writeStrongBinder(IInterface::asBinder(client));
data.writeInt32(audioSessionId);
data.writeParcelable(attributionSource);
// 传输调用服务器端方法
// 即服务端在Bn实现端的onTransact()需要根据该请求类型标识,
// 来执行对应的任务,此处为创建MediaPlayer的事务请求事件
remote()->transact(CREATE, data, &reply);
// 然后返回BpMediaPlayer
return interface_cast<IMediaPlayer>(reply.readStrongBinder());
remote()->transact(CREATE, data, &reply); 的调用过程
status_t BnMediaPlayerService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
switch (code)
case CREATE:
CHECK_INTERFACE(IMediaPlayerService, data, reply);
// 创建对象 BpMediaPlayerClient
sp<IMediaPlayerClient> client =
interface_cast<IMediaPlayerClient>(data.readStrongBinder());
audio_session_t audioSessionId = (audio_session_t) data.readInt32();
AttributionSourceState attributionSource;
status_t status = data.readParcelable(&attributionSource);
if (status != NO_ERROR)
return status;
// 这里去创建 IMediaPlayer对象,调用的是 create方法,BnMediaPlayerService 的子类的方法
// 有传入对象 BpMediaPlayerClient
sp<IMediaPlayer> player = create(client, audioSessionId, attributionSource);
reply->writeStrongBinder(IInterface::asBinder(player));
return NO_ERROR;
break;
frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp
sp<IMediaPlayer> MediaPlayerService::create(const sp<IMediaPlayerClient>& client,
audio_session_t audioSessionId, const AttributionSourceState& attributionSource)
int32_t connId = android_atomic_inc(&mNextConnId);
// TODO b/182392769: use attribution source util
AttributionSourceState verifiedAttributionSource = attributionSource;
verifiedAttributionSource.pid = VALUE_OR_FATAL(
legacy2aidl_pid_t_int32_t(IPCThreadState::self()->getCallingPid()));
verifiedAttributionSource.uid = VALUE_OR_FATAL(
legacy2aidl_uid_t_int32_t(IPCThreadState::self()->getCallingUid()));
sp<Client> c = new Client(
this, verifiedAttributionSource, connId, client, audioSessionId);
ALOGV("Create new client(%d) from %s, ", connId,
verifiedAttributionSource.toString().c_str());
// Client为内部的类
wp<Client> w = c;
Mutex::Autolock lock(mLock);
mClients.add(w);
return c;
// 3. player【MediaPlayerService的Client内部类】 去设置 setDataSource
首先看下 Client 为什么是 IMediaPlayer
frameworks/av/media/libmediaplayerservice/MediaPlayerService.h
其实具体的实现都是在:Client 内部类去实现的
// 可以看出是继承于 BnMediaPlayer
class Client : public BnMediaPlayer
// IMediaPlayer interface
virtual void disconnect();
virtual status_t setVideoSurfaceTexture(
const sp<IGraphicBufferProducer>& bufferProducer);
virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
virtual status_t getBufferingSettings(
BufferingSettings* buffering /* nonnull */) override;
virtual status_t prepareAsync();
virtual status_t start();
virtual status_t stop();
virtual status_t pause();
virtual status_t isPlaying(bool* state);
virtual status_t setPlaybackSettings(const AudioPlaybackRate& rate);
virtual status_t getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */);
virtual status_t setSyncSettings(const AVSyncSettings& rate, float videoFpsHint);
virtual status_t getSyncSettings(AVSyncSettings* rate /* nonnull */,
float* videoFps /* nonnull */);
virtual status_t seekTo(
int msec,
MediaPlayerSeekMode mode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC);
frameworks/av/media/libmedia/include/media/IMediaPlayer.h
BnMediaPlayer 又是继承于 BnInterface
// BnMediaPlayer 又是继承于 BnInterface
class BnMediaPlayer: public BnInterface<IMediaPlayer>
public:
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);
;
; // namespace android
frameworks/native/libs/binder/include/binder/IInterface.h
// 传入的 INTERFACE 就是 IMediaPlayer
// 并且 BnInterface 多重继承了 IMediaPlayer 和 BBinder所以Client 内部类可以是 IMediaPlayer 类型的
// 传入的 INTERFACE 就是 IMediaPlayer
// 并且 BnInterface 多重继承了 IMediaPlayer 和 BBinder
template<typename INTERFACE>
class BnInterface : public INTERFACE, public BBinder
public:
virtual sp<IInterface> queryLocalInterface(const String16& _descriptor);
virtual const String16& getInterfaceDescriptor() const;
protected:
typedef INTERFACE BaseInterface;
virtual IBinder* onAsBinder();
;
------------------------
setDataSource
frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp
status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length)
ALOGV("setDataSource fd=%d (%s), offset=%lld, length=%lld",
fd, nameForFd(fd).c_str(), (long long) offset, (long long) length);
struct stat sb;
int ret = fstat(fd, &sb);
if (ret != 0)
ALOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
return UNKNOWN_ERROR;
ALOGV("st_dev = %llu", static_cast<unsigned long long>(sb.st_dev));
ALOGV("st_mode = %u", sb.st_mode);
ALOGV("st_uid = %lu", static_cast<unsigned long>(sb.st_uid));
ALOGV("st_gid = %lu", static_cast<unsigned long>(sb.st_gid));
ALOGV("st_size = %llu", static_cast<unsigned long long>(sb.st_size));
if (offset >= sb.st_size)
ALOGE("offset error");
return UNKNOWN_ERROR;
if (offset + length > sb.st_size)
length = sb.st_size - offset;
ALOGV("calculated length = %lld", (long long)length);
// 1. 通过MediaPlayerFactory::getPlayerType获取播放器类型
player_type playerType = MediaPlayerFactory::getPlayerType(this,
fd,
offset,
length);
// 2. 调用setDataSource_pre创建播放器
sp<MediaPlayerBase> p = setDataSource_pre(playerType);
if (p == NULL)
return NO_INIT;
// 3. 调用setDataSource_post通过创建的播放器设置setDataSource
// now set data source
return mStatus = setDataSource_post(p, p->setDataSource(fd, offset, length));
- 通过MediaPlayerFactory::getPlayerType获取播放器类型
- 调用setDataSource_pre创建播放器
- 调用setDataSource_post通过创建的播放器设置setDataSource
1. 通过MediaPlayerFactory::getPlayerType获取播放器类型
frameworks/av/media/libmediaplayerservice/MediaPlayerFactory.cpp
获取到的播放器类型为:NU_PLAYER
player_type MediaPlayerFactory::getPlayerType(const sp<IMediaPlayer>& client,
int fd,
int64_t offset,
int64_t length)
GET_PLAYER_TYPE_IMPL(client, fd, offset, length);
-------------
#define GET_PLAYER_TYPE_IMPL(a...) \\
Mutex::Autolock lock_(&sLock); \\
\\
player_type ret = STAGEFRIGHT_PLAYER; \\
float bestScore = 0.0; \\
\\
for (size_t i = 0; i < sFactoryMap.size(); ++i) \\
\\
IFactory* v = sFactoryMap.valueAt(i); \\
float thisScore; \\
CHECK(v != NULL); \\
thisScore = v->scoreFactory(a, bestScore); \\
if (thisScore > bestScore) \\
ret = sFactoryMap.keyAt(i); \\
bestScore = thisScore; \\
\\
\\
\\
if (0.0 == bestScore) //这里取获取默认的播放器类型 \\
ret = getDefaultPlayerType(); \\
\\
\\
return ret;
--------------------
static player_type getDefaultPlayerType()
/ return NU_PLAYER;
2. 调用setDataSource_pre创建播放器
sp<MediaPlayerBase> MediaPlayerService::Client::setDataSource_pre(
player_type playerType)
ALOGV("player type = %d", playerType);
// create the right type of player
// 1. 创建播放器为:NuPlayerDriver
sp<MediaPlayerBase> p = createPlayer(playerType);
if (p == NULL)
return p;
std::vector<DeathNotifier> deathNotifiers;
// Listen to death of media.extractor service
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("media.extractor"));
if (binder == NULL)
ALOGE("extractor service not available");
return NULL;
deathNotifiers.emplace_back(
binder, [l = wp<MediaPlayerBase>(p)]()
sp<MediaPlayerBase> l以上是关于MediaPlayer 播放本地视频源码流程-setDataSource的主要内容,如果未能解决你的问题,请参考以下文章
如何在实际完全加载视频之前开始在 MediaPlayer 中播放视频