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> listener = l.promote();
if (listener) {
ALOGI("media.extractor died. Sending death notification.");
listener->sendEvent(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED,
MEDIAEXTRACTOR_PROCESS_DEATH);
} else {
ALOGW("media.extractor died without a death handler.");
}
});
{
using ::android::hidl::base::V1_0::IBase;
// Listen to death of OMX service
{
sp<IBase> base = ::android::hardware::media::omx::V1_0::
IOmx::getService();
if (base == nullptr) {
ALOGD("OMX service is not available");
} else {
deathNotifiers.emplace_back(
base, [l = wp<MediaPlayerBase>(p)]() {
sp<MediaPlayerBase> listener = l.promote();
if (listener) {
ALOGI("OMX service died. "
"Sending death notification.");
listener->sendEvent(
MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED,
MEDIACODEC_PROCESS_DEATH);
} else {
ALOGW("OMX service died without a death handler.");
}
});
}
}
// Listen to death of Codec2 services
{
for (std::shared_ptr<Codec2Client> const& client :
Codec2Client::CreateFromAllServices()) {
sp<IBase> base = client->getBase();
deathNotifiers.emplace_back(
base, [l = wp<MediaPlayerBase>(p),
name = std::string(client->getServiceName())]() {
sp<MediaPlayerBase> listener = l.promote();
if (listener) {
ALOGI("Codec2 service \"%s\" died. "
"Sending death notification.",
name.c_str());
listener->sendEvent(
MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED,
MEDIACODEC_PROCESS_DEATH);
} else {
ALOGW("Codec2 service \"%s\" died "
"without a death handler.",
name.c_str());
}
});
}
}
}
Mutex::Autolock lock(mLock);
mDeathNotifiers.clear();
mDeathNotifiers.swap(deathNotifiers);
mAudioDeviceUpdatedListener = new AudioDeviceUpdatedNotifier(p);
if (!p->hardwareOutput()) {
// 2. 创建 AudioOutput
mAudioOutput = new AudioOutput(mAudioSessionId, mAttributionSource,
mAudioAttributes, mAudioDeviceUpdatedListener);
static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
}
return p;
}
// 1. 创建播放器createPlayer(playerType)为:NuPlayerDriver
sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType)
{
// determine if we have the right player type
sp<MediaPlayerBase> p = getPlayer();
if ((p != NULL) && (p->playerType() != playerType)) {
ALOGV("delete player");
p.clear();
}
if (p == NULL) {
// 通过 MediaPlayerFactory 取创建 播放器,mListener 为其回调的对象
p = MediaPlayerFactory::createPlayer(playerType, mListener,
VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(mAttributionSource.pid)));
}
if (p != NULL) {
p->setUID(VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(mAttributionSource.uid)));
}
return p;
}
frameworks/av/media/libmediaplayerservice/MediaPlayerFactory.cpp
sp<MediaPlayerBase> MediaPlayerFactory::createPlayer(
player_type playerType,
const sp<MediaPlayerBase::Listener> &listener,
pid_t pid) {
sp<MediaPlayerBase> 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 返回的是NuPlayerFactory,去创建播放器
factory = sFactoryMap.valueFor(playerType);
CHECK(NULL != factory);
// 创建了对象 NuPlayerDriver
p = factory->createPlayer(pid);
if (p == NULL) {
ALOGE("Failed to create player object of type %d, create failed",
playerType);
return p;
}
// NuPlayerDriver去初始化
init_result = p->initCheck();
if (init_result == NO_ERROR) {
// NuPlayerDriver这里去设置了观察者,即去回调
p->setNotifyCallback(listener);
} else {
ALOGE("Failed to create player object of type %d, initCheck failed"
" (res = %d)", playerType, init_result);
p.clear();
}
return p;
}
class NuPlayerFactory : public MediaPlayerFactory::IFactory {
public:
virtual sp<MediaPlayerBase> createPlayer(pid_t pid) {
ALOGV(" create NuPlayer");
// 这里去创建了对象 NuPlayerDriver
return new NuPlayerDriver(pid);
}
看下 NuPlayerDriver
frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
// 结构体 NuPlayerDriver 继承于 MediaPlayerInterface
struct NuPlayerDriver : public MediaPlayerInterface {
explicit NuPlayerDriver(pid_t pid);
frameworks/av/media/libmediaplayerservice/include/MediaPlayerInterface.h
// 所以 MediaPlayerBase 是 NuPlayerDriver 的父类
class MediaPlayerInterface : public MediaPlayerBase
{
public:
virtual ~MediaPlayerInterface() { }
看下 NuPlayerDriver构造函数初始化:
frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
MediaClock 用于音视频同步时钟,用于同步音视频播放处理
NuPlayerDriver::NuPlayerDriver(pid_t pid)
: mState(STATE_IDLE),
mIsAsyncPrepare(false),
mAsyncResult(UNKNOWN_ERROR),
mSetSurfaceInProgress(false),
mDurationUs(-1),
mPositionUs(-1),
mSeekInProgress(false),
mPlayingTimeUs(0),
mRebufferingTimeUs(0),
mRebufferingEvents(0),
mRebufferingAtExit(false),
// 这里去创建 looper 对象
mLooper(new ALooper),
// 音视频同步时钟用于同步音视频播放处理
// MediaClock类声明和构造函数初始化,
// 创建 MediaClock
mMediaClock(new MediaClock),
mPlayer(new NuPlayer(pid, mMediaClock)),
mPlayerFlags(0),
mMetricsItem(NULL),
mClientUid(-1),
mAtEOS(false),
mLooping(false),
mAutoLoop(false) {
ALOGD("NuPlayerDriver(%p) created, clientPid(%d)", this, pid);
// 设置这个looper 的名字
mLooper->setName("NuPlayerDriver Looper");
mMediaClock->init();
// set up an analytics record
mMetricsItem = mediametrics::Item::create(kKeyPlayer);
// 启动这里looper,开启线程
mLooper->start(
false, /* runOnCallingThread */
true, /* canCallJava */
PRIORITY_AUDIO);
// 注册handler,为 NuPlayer
mLooper->registerHandler(mPlayer);
// 对 NuPlayer 进行初始化
mPlayer->init(this);
}
MediaClock类声明和构造函数初始化
音视频同步时钟用于同步音视频播放处理
头文件:
frameworks/av/media/libstagefright/include/media/stagefright/MediaClock.h
// MediaClock 继承了 AHandler
struct MediaClock : public AHandler {
enum {
TIMER_REASON_REACHED = 0,
TIMER_REASON_RESET = 1,
};
MediaClock();
构造函数:
// [frameworks/av/media/libstagefright/MediaClock.cpp]
MediaClock::MediaClock()
// 媒体同步锚点时间戳即当次播放的音视频开始时间戳,
// 注意这个值的含义,该值不是随便更新,只有在检测到当前音频播放前后帧不连续时
// (目前默认为10毫秒之内才是连续帧)则会更新或者在每次seek后也会更新的,
// 也就是它记录的是本次播放的媒体开始时间戳,记录的是媒体开始播放时间戳,非系统时间戳噢
: mAnchorTimeMediaUs(-1),
// 音视频同步锚点实际时间戳即当次播放时的系统存活时间戳值,
// 但注意该值不会从1997年那个时间开始计算的,而是当前系统存活时长时间戳,
// 比如若关机后再开机,就会从0开始计数
mAnchorTimeRealUs(-1),
// 默认的媒体最大时间值(64位的Int最大值)
mMaxTimeMediaUs(INT64_MAX),
// 媒体开始播放时间戳
// 注意该值和上面【mAnchorTimeMediaUs】值的区别,该值不会随便更新,最初值和mAnchorTimeMediaUs大致相同,
// 但mAnchorTimeMediaUs会随时更新的,它的更新时机已说明。
mStartingTimeMediaUs(-1),
// 播放速率,默认为1即正常播放速度,该值用于控制音视频的播放速度的处理,如快进快退等
mPlaybackRate(1.0),
// 此标记名为“代数”,其实际作用就是一个操作计数值,并调节视频播放的同步处理,
// 即在每次视频帧需要延迟播放时会创建一个时间倒计时并记录当时的代数值,
// 若时间计时器到期时再次检查当前代数值是否相同,若相同则正常执行渲染流程,
// 若不相同(一般都是计数增大)则会放弃此次时间计时器timer的处理,等待下一次相同时才进行渲染操作
mGeneration(0) {
// 创建一个Looper线程循环消息,设置名称,并启动
mLooper = new ALooper;
mLooper->setName("MediaClock");
mLooper->start(false /* runOnCallingThread */,
false /* canCallJava */,
ANDROID_PRIORITY_AUDIO);
}
NuPlayer类声明:其实际是AHandler的子类即接收Looper线程循环消息处理
// [frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayer.h]
struct NuPlayer : public AHandler {}
NuPlayer类构造函数初始化
frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
// [frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayer.cpp]
NuPlayer::NuPlayer(pid_t pid, const sp<MediaClock> &mediaClock)
// 标识调用者用户ID是否有效
: mUIDValid(false),
// 调用者进程ID即上层APP进程号
mPID(pid),
mMediaClock(mediaClock),
mSourceFlags(0),
// 是否支持audio offload播放模式即使用硬件音频解码器
mOffloadAudio(false),
// 音频解码器代数值,用于判断某些相关操作是否有效
mAudioDecoderGeneration(0),
// 视频解码器代数值,用于判断某些相关操作是否有效
mVideoDecoderGeneration(0),
// Renderer渲染器代数值,用于判断某些相关操作是否有效
mRendererGeneration(0),
// 默认最大输出帧率为每秒60帧
mMaxOutputFrameRate(60),
// 最近已开始播放时间戳
mLastStartedPlayingTimeNs(0),
// 最近已开始渲染时间戳
mLastStartedRebufferingTimeNs(0),
// 上一次seek时间戳
mPreviousSeekTimeUs(0),
// 音频播放完毕即EOS(end of stream)事件消息
mAudioEOS(false),
// 视频播放完毕即EOS(end of stream)事件消息
mVideoEOS(false),
// 标记是否数据源待扫描即还未扫描
mScanSourcesPending(false),
// 数据源扫描代数值,用于判断某些相关操作是否有效
mScanSourcesGeneration(0),
// 数据源周期性拉取事件代数值,用于判断某些相关操作是否有效
mPollDurationGeneration(0),
// 时序(定时)文本事件代数值,用于判断某些相关操作是否有效
mTimedTextGeneration(0),
// 枚举类,audio刷新清空Flushing状态
mFlushingAudio(NONE),
// 枚举类,video刷新清空Flushing状态
mFlushingVideo(NONE),
// 是否等待恢复播放标志
mResumePending(false),
// 视频缩放模式:默认为视频帧buffer匹配native window大小的缩放即以window大小来缩放
mVideoScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW),
// 音频播放设置信息 即同前面分析的AudioOutput中该字段分析一样
mPlaybackSettings(AUDIO_PLAYBACK_RATE_DEFAULT),
// 视频帧率(提示信息)
mVideoFpsHint(-1.f),
// 是否已执行start流程
mStarted(false),
// 是否prepare流程已完成
mPrepared(false),
// 是否正在执行reset流程
mResetting(false),
// 是否已执行数据源source的start流程
mSourceStarted(false),
// 是否音频解码器错误(接收到解码器错误事件通知)
mAudioDecoderError(false),
// 是否视频解码器错误
mVideoDecoderError(false),
// 是否已执行pause暂停流程
mPaused(false),
// 标记是否被Client端如上层APP请求执行暂停流程(默认为true)
// 注意和mPaused的区别,mPaused是控制onPause()方法不会被重复执行,
// 而mPausedByClient会每次都赋值为true,其主要就是记录客户端要求暂停的请求暂停状态(有可能已暂停)
mPausedByClient(true),
// 标记是否是为了缓冲数据而暂停
// 主要就是source数据源获取buffer数据不足,
// 然后通知NuPlayer需要缓冲数据,则此时设置为true,缓冲结束设置为false
mPausedForBuffering(false),
// 媒体源是否需要数字版权管理保护
mIsDrmProtected(false),
// 数据源类型枚举值 (如RTSP/http/文件类型等)
mDataSourceType(DATA_SOURCE_TYPE_NONE) {
CHECK(mediaClock != NULL);
// 清除数据刷新完成处理,即重置初始化一些值
// 见下面的分析
clearFlushComplete();
}
// NuPlayerDriver这里去设置了观察者,即去回调
p->setNotifyCallback(listener)
在父类中去设置了观察者listener
frameworks/av/media/libmediaplayerservice/include/MediaPlayerInterface.h
// abstract base class - use MediaPlayerInterface
class MediaPlayerBase : public RefBase
{
public:
void setNotifyCallback(
const sp<Listener> &listener) {
Mutex::Autolock autoLock(mNotifyLock);
// 保存了 mListener
mListener = listener;
}
// 2. 创建 AudioOutput
mAudioOutput = new AudioOutput(mAudioSessionId, mAttributionSource,
mAudioAttributes, mAudioDeviceUpdatedListener);
frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp
// [frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp]
// 注意此处的LOG_TAG处理非常有意思,因为当前文件最前面已宏定义了LOG_TAG为"MediaPlayerService",因此这里先将其取消定义,然后重新定义它的值为AudioSink,如此从此行代码下面的所有相关LOG打印的TAG就是新值了
#undef LOG_TAG
#define LOG_TAG "AudioSink"
MediaPlayerService::AudioOutput::AudioOutput(audio_session_t sessionId, uid_t uid, int pid,
const audio_attributes_t* attr, const sp<AudioSystem::AudioDeviceCallback>& deviceCallback)
: mCallback(NULL),
mCallbackCookie(NULL),
mCallbackData(NULL),
// 音频流类型,默认设置为MUSIC
mStreamType(AUDIO_STREAM_MUSIC),
// 默认当前程序(播放器)音量比例为1即为系统当前音量
//(系统音量和程序音量是两种调节,系统音量包含背景音量和程序音量)
mLeftVolume(1.0),
mRightVolume(1.0),
// 播放速率参数默认值,这是个结构体
// 见1.4.1小节分析
mPlaybackRate(AUDIO_PLAYBACK_RATE_DEFAULT),
// 音频采样率
mSampleRateHz(0),
// 帧率(但注意单位为毫秒即每毫秒多少帧)
mMsecsPerFrame(0),
// 帧数
mFrameSize(0),
// audio session id信息
mSessionId(sessionId),
// 调用者用户ID
mUid(uid),
// 调用者进程ID即上层APP进程号
mPid(pid),
mSendLevel(0.0),
mAuxEffectId(0),
mFlags(AUDIO_OUTPUT_FLAG_NONE),
// 此对象定义的是缓存音量调节处理相关的信息,目前暂不分析
mVolumeHandler(new media::VolumeHandler()),
// 已选择的设备ID(audio设备端口访问句柄)
mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
// 已路由的设备ID(audio设备端口访问句柄)
mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE),
// 设备回调功能是否可用
mDeviceCallbackEnabled(false),
// 设备回调监听对象,即上面传入的【mAudioDeviceUpdatedListener】
mDeviceCallback(deviceCallback)
{
ALOGV("AudioOutput(%d)", sessionId);
if (attr != NULL) {
// 传入的audio属性值不为空时,分配新内存
mAttributes = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
if (mAttributes != NULL) {
// 缓存attr值到新变量中
memcpy(mAttributes, attr, sizeof(audio_attributes_t));
// 然后从audio参数属性值中获取其音频流类型
// 实现大致原理:主要从audio策略服务端获取audio产品策略列表信息,
// 从中获取对应的当前音频流类型。暂不展开分析
mStreamType = AudioSystem::attributesToStreamType(*attr);
}
} else {
mAttributes = NULL;
}
// 设置初始化最小的缓冲区buffer数
// 默认模拟器设置为12,其他情况设置为4
// 见下面的分析
setMinBufferCount();
}
//static
void MediaPlayerService::AudioOutput::setMinBufferCount()
{
if (property_get_bool("ro.boot.qemu", false)) {
mIsOnEmulator = true;
mMinBufferCount = 12; // to prevent systematic buffer underrun for emulator
}
}
3. 调用setDataSource_post通过创建的播放器设置setDataSource
return mStatus = setDataSource_post(p, p->setDataSource(fd, offset, length))
frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
由上面分析, p 对应的是 NuPlayerDriver 对象
status_t NuPlayerDriver::setDataSource(int fd, int64_t offset, int64_t length) {
ALOGV("setDataSource(%p) file(%d)", this, fd);
Mutex::Autolock autoLock(mLock);
if (mState != STATE_IDLE) {
return INVALID_OPERATION;
}
// 更新播放器状态
mState = STATE_SET_DATASOURCE_PENDING;
// mPlayer其实就是NuPlayer对象
mPlayer->setDataSourceAsync(fd, offset, length);
while (mState == STATE_SET_DATASOURCE_PENDING) {
// C++实现的条件锁,等待上面【setDataSourceAsync】处理流程完成后才唤醒此处
// 注意:每次都会执行此处,因此可以知晓上层APP进行的setDataSource操作其实可能会耗时,
// 当然一般情况下会非常快的,因为NuPlayer中的处理其实很简单不耗时的,
// 除非NuPlayer自身的ALooper消息循环线程本身已阻塞,否则将非常快返回。
mCondition.wait(mLock);
}
return mAsyncResult;
}
frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
void NuPlayer::setDataSourceAsync(int fd, int64_t offset, int64_t length) {
// 创建【kWhatSetDataSource】设置数据源事件消息,NuPlayer自身为AHandler子类接收处理
sp<AMessage> msg = new AMessage(kWhatSetDataSource, this);
sp<AMessage> notify = new AMessage(kWhatSourceNotify, this);
// 创建一个通用(统一)数据源处理对象 GenericSource
sp<GenericSource> source =
new GenericSource(notify, mUIDValid, mUID, mMediaClock);
ALOGV("setDataSourceAsync fd %d/%lld/%lld source: %p",
fd, (long long)offset, (long long)length, source.get());
// 1. 通过 GenericSource对象去设置数据源
status_t err = source->setDataSource(fd, offset, length);
if (err != OK) {
ALOGE("Failed to set data source!");
source = NULL;
}
msg->setObject("source", source);
// 由 AHandler 、AMessage和 ALooper 及其 NuPlayer是继承了 AHandler 分析可知:
// 2. 最终会携带 kWhatSetDataSource消息,执行 NuPlayer的 onMessageReceived 方法
msg->post();
mDataSourceType = DATA_SOURCE_TYPE_GENERIC_FD;
}
AHandler 、AMessage和 ALooper 的分析会另外开 一篇文章为:
// 1. 通过 GenericSource对象去设置数据源
status_t err = source->setDataSource(fd, offset, length);
先看下 GenericSource 的头文件,其实也是个Handler
// [frameworks/av/media/libmediaplayerservice/nuplayer/GenericSource.h]
struct NuPlayer::GenericSource : public NuPlayer::Source,
public MediaBufferObserver // Modular DRM
{}
// [frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerSource.h]
struct NuPlayer::Source : public AHandler {}
// [frameworks/av/media/libstagefright/include/media/stagefright/MediaBufferBase.h]
class MediaBufferObserver {}
frameworks/av/media/libmediaplayerservice/nuplayer/GenericSource.cpp
GenericSource构造函数:
// [frameworks/av/media/libmediaplayerservice/nuplayer/GenericSource.cpp]
NuPlayer::GenericSource::GenericSource(
const sp<AMessage> ¬ify,
bool uidValid,
uid_t uid,
const sp<MediaClock> &mediaClock)
// 父类Source构造方法,见下面的分析
: Source(notify),
mAudioTimeUs(0),
mAudioLastDequeueTimeUs(0),
mVideoTimeUs(0),
mVideoLastDequeueTimeUs(0),
mPrevBufferPercentage(-1),
mPollBufferingGeneration(0),
mSentPauseOnBuffering(false),
mAudioDataGeneration(0),
mVideoDataGeneration(0),
mFetchSubtitleDataGeneration(0),
mFetchTimedTextDataGeneration(0),
mDurationUs(-1LL),
mAudioIsVorbis(false),
mIsSecure(false),
mIsStreaming(false),
mUIDValid(uidValid),
mUID(uid),
mMediaClock(mediaClock),
mFd(-1),
// 码率
mBitrate(-1LL),
mPendingReadBufferTypes(0) {
ALOGV("GenericSource");
CHECK(mediaClock != NULL);
// 数据缓冲设置信息的初始化标记时间【单位为毫秒ms】,初始化值5秒
mBufferingSettings.mInitialMarkMs = kInitialMarkMs;
// 数据缓冲设置信息的底缓冲数据时指定的可恢复播放标记时间【单位为毫秒ms】,
// 初始化值15秒即默认需要缓冲15秒的数据。
// 该参数作用:即若是由于底缓冲数据需要缓冲数据时造成的暂停播放,
// 则会在缓冲数据达到该标记时间值时自动恢复播放。
mBufferingSettings.mResumePlaybackMarkMs = kResumePlaybackMarkMs;
// 重置(初始化)数据源信息
// 见下面的分析
resetDataSource();
}
status_t NuPlayer::GenericSource::setDataSource(
int fd, int64_t offset, int64_t length) {
Mutex::Autolock _l(mLock);
ALOGV("setDataSource %d/%lld/%lld (%s)", fd, (long long)offset, (long long)length, nameForFd(fd).c_str());
resetDataSource();
mFd.reset(dup(fd));
// 缓存文件偏移量即文件开始读取位置
mOffset = offset;
// 缓存文件总大小
mLength = length;
// 返回成功OK状态
// 注意此处英文注释意思:即当前方法只是记录了打开的文件描述符和文件信息,
// 但没有执行文件数据源的读取处理,而将该处理移到prepareSync()方法中执行,
// 原因是避免阻塞方法调用端线程。
// delay data source creation to prepareAsync() to avoid blocking
// the calling thread in setDataSource for any significant time.
return OK;
}
// 2. 最终会携带 kWhatSetDataSource消息,执行 NuPlayer的 onMessageReceived 方法
消息处理
frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
case kWhatSetDataSource:
{
ALOGV("kWhatSetDataSource");
CHECK(mSource == NULL);
status_t err = OK;
sp<RefBase> obj;
// 获取传入的数据源对象source参数
CHECK(msg->findObject("source", &obj));
if (obj != NULL) {
Mutex::Autolock autoLock(mSourceLock);
// 若不为空,则加锁,强转为子类sp<Source>类型数据来缓存
mSource = static_cast<Source *>(obj.get());
} else {
err = UNKNOWN_ERROR;
}
CHECK(mDriver != NULL);
// 尝试提升NuPlayerDriver为强引用指针对象
sp<NuPlayerDriver> driver = mDriver.promote();
if (driver != NULL) {
driver->notifySetDataSourceCompleted(err);
}
break;
}
frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
通知设置 dataSource 设置属于源成功
// [frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp]
void NuPlayerDriver::notifySetDataSourceCompleted(status_t err) {
// 加锁
Mutex::Autolock autoLock(mLock);
// 检查当前状态必须是该状态
CHECK_EQ(mState, STATE_SET_DATASOURCE_PENDING);
// 设置数据源完成状态码【成功或失败】
mAsyncResult = err;
// 成功则扭转状态为 STATE_UNPREPARED 即已设置数据源但未prepare状态,
// 否则设置为空闲状态【STATE_IDLE】
mState = (err == OK) ? STATE_UNPREPARED : STATE_IDLE;
// 然后激活等待在该条件变量上所有线程【基本上只会有一个线程等待,因为做了状态判断】
// 即会激活本文开头NuPlayerDriver.setDataSource()中的等待事件被唤醒继续执行,
// 也就完成了整个设置数据源处理流程
mCondition.broadcast();
}
至此,setDataSource的流程就讲完了。