博客
关于我
【三】Android MediaPlayer整体架构源码分析 -【设置数据源】【Part 2】
阅读量:670 次
发布时间:2019-03-15

本文共 28950 字,大约阅读时间需要 96 分钟。

承接上一章节分析:

本系列文章分析的安卓源码版本:【Android 10.0 版本】

setDataSource(fd, offset, length)实现分析:

// [frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp]status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length){       ALOGV("setDataSource fd=%d, offset=%" PRId64 ", length=%" PRId64 "", fd, offset, length);    // 该结构对象为文件状态信息    struct stat sb;    // 根据文件访问标识符读取文件状态信息    int ret = fstat(fd, &sb);    if (ret != 0) {       	// 读取失败,则可以通过strerror方法获取失败状态原因        ALOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno));        return UNKNOWN_ERROR;    }    // 文件设备、访问模式、uid用户ID、gid组id、文件大小    ALOGV("st_dev  = %" PRIu64 "", static_cast
(sb.st_dev)); ALOGV("st_mode = %u", sb.st_mode); ALOGV("st_uid = %lu", static_cast
(sb.st_uid)); ALOGV("st_gid = %lu", static_cast
(sb.st_gid)); ALOGV("st_size = %" PRId64 "", sb.st_size); // 文件读取偏移量即文件开始读取位置,若大于等于文件大小则错误, // 由前面相关章节中分析可知,offset默认为0从头开始读取数据 if (offset >= sb.st_size) { ALOGE("offset error"); return UNKNOWN_ERROR; } // 由前面相关章节中分析可知,length默认为long最大值【LONG_MAX】,该值表示的是应该读取的数据大小 // 因此此处若有设置offset大小,且【offset + length】的值大于文件大小时需要纠正应该读取的数据量, // 即不要超出文件最大值范围 if (offset + length > sb.st_size) { length = sb.st_size - offset; ALOGV("calculated length = %" PRId64 "\n", length); } // 播放器创建工厂模块功能获取播放器类型枚举值,根据该值创建对应类型的播放器, // 目前只提供两种s实际使用的播放器即【STAGEFRIGHT_PLAYER】和【NU_PLAYER】, // 其创建规则是给每个播放器打分,分高者将被创建。 // 关于该内容的分析请见我的另一章节分析:[MediaPlayer多种类型播放器注册和获取流程] // 此处默认(推荐)获取到的是NU_PLAYER类型 player_type playerType = MediaPlayerFactory::getPlayerType(this, fd, offset, length); // 见第1小节分析 sp
p = setDataSource_pre(playerType); if (p == NULL) { return NO_INIT; } // 见第2小节分析 // now set data source return mStatus = setDataSource_post(p, p->setDataSource(fd, offset, length));}

另一章节分析:

1、setDataSource_pre(playerType)实现分析:

// [frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp]sp
MediaPlayerService::Client::setDataSource_pre( player_type playerType){ ALOGV("player type = %d", playerType); // 创建对应播放器类型的播放器对象,见1.1小节分析 // create the right type of player sp
p = createPlayer(playerType); if (p == NULL) { return p; } // 收集Binder对端进程(如相关Service服务进程)异常关闭通知事件集合 std::vector
deathNotifiers; // 此处为监听媒体数据提取(即数据解析)解复用模块服务进程的异常关闭断开通知 // Listen to death of media.extractor service // 从前面的类似代码处理分析可知, // 此处功能即为:从服务注册管理中心获取名为【media.extractor】服务的Binder通信服务 sp
sm = defaultServiceManager(); sp
binder = sm->getService(String16("media.extractor")); if (binder == NULL) { ALOGE("extractor service not available"); return NULL; } // 向该集合对象中添加监听的Binder进程 // 注意:此处是创建了DeathNotifier类的匿名对象加入到该集合中的处理, // 调用的构造函数为:DeathNotifier(sp
const& service, Notify const& notify), // 第一个参数为binder,binder后面的全部是第二个参数,其实际上就是一个匿名方法的实现, // 因为Notify就是一个方法引用【using Notify = std::function
;】, // 并且该匿名方法带有一个参数为【l = wp
(p)】即指针弱引用 // 【弱引用的原因是,不能影响其强引用对象指针的回收】 // 因此在监听到对端进程异常关闭后将会执行该匿名方法。 // 其具体实现原理,见1.2小节分析 deathNotifiers.emplace_back( binder, [l = wp
(p)]() { // 被监听的进程异常关闭时,执行此方法 // 将弱引用对象尝试进行提升为强引用对象 sp
listener = l.promote(); if (listener) { // 若不为空则执行该对象p即播放器对象的sendEevent发送事件回调通知处理流程, // 该方法实现即为NuPlayerDriver实现的,见1.3小节分析 ALOGI("media.extractor died. Sending death notification."); listener->sendEvent(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, MEDIAEXTRACTOR_PROCESS_DEATH); } else { // 为空即该播放器p分配的内存已被释放 ALOGW("media.extractor died without a death handler."); } }); { using ::android::hidl::base::V1_0::IBase; // 监听OpenMAX模块的OMX服务进程的死亡通知的处理 // 类似于上面的处理,但注意此处调用的构造函数是另一个: // DeathNotifier(sp
const& service, Notify const& notify) // 其第一个参数定义类型为:using HBase = hidl::base::V1_0::IBase // 其是使用HIDL技术实现的,更多相关内容请参考Google官方网站: // 【https://source.android.google.cn/devices/architecture/hidl-cpp】 // Listen to death of OMX service { sp
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
(p)]() { // 同上处理,也是发送异常通知给到上层APP sp
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."); } }); } } // 同上处理,监听Codec2服务进程死亡通知事件 // Listen to death of Codec2 services { // 这个是获取创建访问编解码器Codec2.0组件的所有服务对应的客户端代理访问对象, // 然后进行监听其服务进程的死亡通知事件 // 备注:一般只会创建一个名叫"software"的服务对象来访问Codec2.0组件相关功能接口 for (std::shared_ptr
const& client : Codec2Client::CreateFromAllServices()) { sp
base = client->getBase(); deathNotifiers.emplace_back( base, [l = wp
(p), name = std::string(client->getServiceName())]() { // 同上处理,也是发送异常通知给到上层APP sp
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); // 创建了一个Audio设备更新监听对象,并传入了新创建的播放器对象 // 主要作用就是收到Audio设备更新通知事件【MEDIA_AUDIO_ROUTING_CHANGED】给到上层APP mAudioDeviceUpdatedListener = new AudioDeviceUpdatedNotifier(p); // 该返回值若为true表示直接输出音频数据给audio硬件端, // 而不使用android的AudioFlinger混音器mixer来输出。 // (该方法在NuPlayerDriver实现中始终返回false【父类中实现】) if (!p->hardwareOutput()) { // 因此创建NuPlayerDriver播放器时进入此处 // 创建Audio Output输出(音频播放)端对象, // AudioOutput是MediaPlayerService的内部类,其父类为AudioSink // 见1.4小节分析 mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid(), mPid, mAudioAttributes, mAudioDeviceUpdatedListener); // 设置创建完成的AudioOutput对象给NuPlayerDriver播放器持有 // 见1.5小节分析 static_cast
(p.get())->setAudioSink(mAudioOutput); } return p;}

1.1、createPlayer(playerType)实现分析:

// [frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp]sp
MediaPlayerService::Client::createPlayer(player_type playerType){ // 获取缓存的该类型播放器对象NuPlayerDriver,见下面的分析 // 此处判断当前Client对象中是否有缓存的该类型播放器对象 // determine if we have the right player type sp
p = getPlayer(); if ((p != NULL) && (p->playerType() != playerType)) { // 若已创建有旧类型播放器并且该播放器类型不相同时, // 则删除/释放该播放器实例,由前面智能指针clear()实现原理分析可知,其会释放p的实际指针对象内存,导致该对象NuPlayerDriver的析构函数被执行 // 可见本系列文章中reset处理流程章节的具体分析 ALOGV("delete player"); p.clear(); } if (p == NULL) { // 创建新的该类型播放器对象 // 见下面的分析 // 此处的mListener是前面分析的Client初始化时创建的回调监听对象, // 主要用于接收事件回调通知事件 p = MediaPlayerFactory::createPlayer(playerType, mListener, mPid); } // 设置调用者UID即调用者用户ID if (p != NULL) { // 见下面分析【此处分析NuPlayerDriver对象】 p->setUID(mUid); } return p;}

getPlayer()实现分析:

直接返回Client类中mPlayer缓存对象值

// [frameworks/av/media/libmediaplayerservice/MediaPlayerService.h]sp
getPlayer() const { Mutex::Autolock lock(mLock); return mPlayer; }

MediaPlayerFactory::createPlayer实现分析:

MediaPlayerFactory类所有相关实现见另一章节分析:

// [frameworks/av/media/libmediaplayerservice/MediaPlayerFactory.cpp]sp
MediaPlayerFactory::createPlayer( player_type playerType, const sp
&listener, pid_t pid) { // 待返回的播放器对象 sp
p; IFactory* factory; // 播放器初始化结果状态 status_t init_result; Mutex::Autolock lock_(&sLock); // 判断当前播放器创建工厂类型是否存在 if (sFactoryMap.indexOfKey(playerType) < 0) { ALOGE("Failed to create player object of type %d, no registered" " factory", playerType); return p; } // 获取其创建工厂 factory = sFactoryMap.valueFor(playerType); CHECK(NULL != factory); // 创建新的播放器,由第四章节分析可知,文件流类型是创建的是NuPlayerDriver对象 // 该对象的类声明和构造函数,见1.1.1小节分析 p = factory->createPlayer(pid); if (p == NULL) { ALOGE("Failed to create player object of type %d, create failed", playerType); return p; } // 初始化播放器 // 见1.1.2小节分析 init_result = p->initCheck(); // 若初始化成功,则设置接收事件通知回调监听,否则失败直接释放播放器对象 if (init_result == NO_ERROR) { // 见1.1.3小节分析 p->setNotifyCallback(listener); } else { // 初始化检查失败则删除/释放该播放器实例,其会导致播放器对象的析构函数被执行 ALOGE("Failed to create player object of type %d, initCheck failed" " (res = %d)", playerType, init_result); p.clear(); } return p;}

1.1.1、NuPlayerDriver类声明和构造函数初始化

NuPlayerDriver类声明及其父类关系(省略其他代码)

// [frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h]struct NuPlayerDriver : public MediaPlayerInterface {   }// [frameworks/av/media/libmediaplayerservice/include/MediaPlayerInterface.h]// Implement this class for media players that use the AudioFlinger software mixerclass MediaPlayerInterface : public MediaPlayerBase {   }// [frameworks/av/media/libmediaplayerservice/include/MediaPlayerInterface.h]// abstract base class - use MediaPlayerInterfaceclass MediaPlayerBase : public RefBase {   }

NuPlayerDriver构造函数初始化:

关于此处分析涉及到的ALooper即是native层Handler机制实现原理可见另一系列章节分析:

// [frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp]NuPlayerDriver::NuPlayerDriver(pid_t pid)	// 初始化播放器状态 STATE_IDLE    : mState(STATE_IDLE),       // 是否正在异步prepare流程执行中      mIsAsyncPrepare(false),      mAsyncResult(UNKNOWN_ERROR),      // 是否正在setSurface处理过程中      mSetSurfaceInProgress(false),       // 音视频时长      mDurationUs(-1),       // 当前已播放位置      mPositionUs(-1),       // 是否正在seek过程中      mSeekInProgress(false),       mPlayingTimeUs(0),      mRebufferingTimeUs(0),      mRebufferingEvents(0),      mRebufferingAtExit(false),      // 初始化一个ALooper用于创建native层Handler机制实现,      // 类似于java层的Handler      mLooper(new ALooper),       // 音视频同步时钟用于同步音视频播放处理      // MediaClock类声明和构造函数初始化,      // 见1.1.1.1小节分析      mMediaClock(new MediaClock),      // 创建工厂创建一个NuPlayer对象      // 见1.1.1.2小节分析      mPlayer(AVNuFactory::get()->createNuPlayer(pid, mMediaClock)),      mPlayerFlags(0),      // 媒体数据统计分析信息收集对象      mAnalyticsItem(NULL),      mClientUid(-1),      // 是否已播放结束即此状态标记是否收到了MEDIA_ERROR状态事件      // 【注意此状态不是EOS状态(end of stream)】      mAtEOS(false),      // 是否上层APP设置了循环播放功能,即在播放完成时不发送播放完成事件,直接进行从头开始播放      mLooping(false),      // 是否支持自动循环播放【注意:该字段和上面这个字段有区别,      // 其默认是若Ogg音频文件媒体信息携带有支持自动循环播放,则在播放完毕后会从头再播放】      // 其主要处理流程,      // 见1.1.1.3小节分析       mAutoLoop(false) {       // 此处的 pid 值从此前的分析过程中可知,此值其实就是调用者进程号即上传APP进程号    // (当前上层APP可能有多个进程号,谁调用就是谁)     ALOGD("NuPlayerDriver(%p) created, clientPid(%d)", this, pid);    // 设置Loop线程名    mLooper->setName("NuPlayerDriver Looper");    // 媒体播放同步时钟初始化    // 见1.1.1.4小节分析     mMediaClock->init();    // set up an analytics record    mAnalyticsItem = MediaAnalyticsItem::create(kKeyPlayer);    // 启动Looper消息循环    mLooper->start(            false, /* runOnCallingThread */            true,  /* canCallJava */            PRIORITY_AUDIO);    // 设置AHandler处理消息对象    mLooper->registerHandler(mPlayer);    // 见1.1.1.5小节分析     mPlayer->init(this);}

1.1.1.1、MediaClock类声明和构造函数初始化

音视频同步时钟用于同步音视频播放处理
MediaClock类声明:(省略其他代码)其实际是AHandler的子类

// [frameworks/av/media/libstagefright/include/media/stagefright/MediaClock.h]struct MediaClock : public AHandler {   }

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);}

1.1.1.2、mPlayer(AVNuFactory::get()->createNuPlayer(pid, mMediaClock))实现分析

【创建工厂创建一个NuPlayer对象,并赋值给mPlayer对象】
AVNuFactory类声明:
主要用于扩展NuPlayer对象功能,并提供了四个方法,后续会都用上

// [frameworks/av/media/libavextentions/mediaplayerservice/AVNuExtensions.h]/* * Factory to create extended NuPlayer objects */struct AVNuFactory {       virtual sp
createNuPlayer(pid_t pid, const sp
&mediaClock); virtual sp
createPassThruDecoder( const sp
&notify, const sp
&source, const sp
&renderer); virtual sp
createDecoder( const sp
&notify, const sp
&source, pid_t pid, uid_t uid, const sp
&renderer); virtual sp
createRenderer( const sp
&sink, const sp
&mediaClock, const sp
&notify, uint32_t flags); // ----- NO TRESSPASSING BEYOND THIS LINE ------ DECLARE_LOADABLE_SINGLETON(AVNuFactory);};

从上面没看到get()方法,但我们首先可以确定【AVNuFactory::get()】肯定是一个静态方法,因此再看【DECLARE_LOADABLE_SINGLETON(AVNuFactory)】的声明和定义(是一个宏定义代码块):

// [frameworks/av/media/libavextensions/common/AVExtensionsCommon.h]/* * Boiler-plate to declare the class as a singleton (with a static getter) * which can be loaded (dlopen'd) via ExtensionsLoader */#define DECLARE_LOADABLE_SINGLETON(className)   \protected:                                      \    className();                                \    virtual ~className();                       \    static className *sInst;                    \private:                                        \    className(const className&);                \    className &operator=(className &);          \public:                                         \    static className *get() {                   \        return sInst;                           \    }                                           \    friend struct ExtensionsLoader
;} //namespace android

将宏定义中的【className】替换为【AVNuFactory】后,即可得到get()方法,根据注释可知,该宏定义作用就是用于提供一个AVNuFactory的单列实例对象,而该对象加载通过如下代码加载的,其是一个so库提供的方法名为【createExtendedNuFactory】类方法实现:

// [frameworks/av/media/libavextensions/common/AVNuFactory.cpp]/staticAVNuFactory *AVNuFactory::sInst =        ExtensionsLoader
::createInstance("createExtendedNuFactory");

ExtensionsLoader类声明:

// [frameworks/av/media/libavextensions/common/AVExtensionsCommon.h]static const char * CUSTOMIZATION_LIB_NAME = "libavenhancements.so";template 
struct ExtensionsLoader { static T *createInstance(const char *createFunctionName);private: static void loadLib(); static void *mLibHandle;};

ExtensionsLoader实现相关如下:

从下面实现可以看出,其实ExtensionsLoader的主要功能正如它的类名一样,即是扩展类加载器,就是我们也可以提供自己的一套对应接口的实现so库,然后让ExtensionsLoader模块来加载我们自己的实现,这里是使用了高通qcom预置的私有库实现来完成的。
对应的qcom高通模块声明为:
./vendor/qcom/proprietary/prebuilt_HY11/target/product/qssi/Android.mk:1231:LOCAL_MODULE := libavenhancements
./vendor/qcom/proprietary/prebuilt_HY11/target/product/qssi/Android.mk:1784:LOCAL_MODULE := libavenhancements

// [frameworks/av/media/libavextensions/common/ExtensionsLoader.hpp]/* * Create strongly-typed objects of type T * If the customization library exists and does contain a "named" constructor, *  invoke and create an instance * Else create the object of type T itself * * Contains a static instance to dlopen'd library, But may end up * opening the library mutiple times. Following snip from dlopen man page is * reassuring "...Only a single copy of an object file is brought into the * address space, even if dlopen() is invoked multiple times in reference to * the file, and even if different pathnames are used to reference the file.." */template 
T *ExtensionsLoader
::createInstance(const char *createFunctionName) { ALOGV("createInstance(%lubit) : %s", (unsigned long)sizeof(intptr_t)*8, createFunctionName); // create extended object if extensions-lib is available using CreateFunc_t = T*(*)(void); CreateFunc_t createFunc = nullptr; // 先加载自定义实现私有库,若未提供私有实现,那么将创建默认的实现,即android自身的两个默认实现文件 loadLib(); if (mLibHandle) { createFunc = (CreateFunc_t)::dlsym(mLibHandle, createFunctionName); if (!createFunc) { ALOGW("symbol %s not found: %s",createFunctionName, dlerror()); } } if (createFunc) { return (*createFunc)(); } // Else, create the default object return new T;}template
void ExtensionsLoader
::loadLib() { if (!mLibHandle) { // 先加载预置指定的自定义实现私有库,该库懒加载方式 mLibHandle = ::dlopen(CUSTOMIZATION_LIB_NAME, RTLD_LAZY); if (!mLibHandle) { ALOGV("%s", dlerror()); return; } ALOGV("Opened %s", CUSTOMIZATION_LIB_NAME); }}//statictemplate
void *ExtensionsLoader
::mLibHandle = NULL;

因此通过上面的分析,我们可以直接参考android自身的默认实现文件。

再看【createNuPlayer(pid, mMediaClock)】实现:【默认实现】
创建了NuPlayer对象,并传入这两个参数

// [frameworks/av/media/libavextensions/common/AVNuFactory.cpp]sp
AVNuFactory::createNuPlayer(pid_t pid, const sp
&mediaClock) { return new NuPlayer(pid, mediaClock);}

NuPlayer类声明:其实际是AHandler的子类即接收Looper线程循环消息处理

// [frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayer.h]struct NuPlayer : public AHandler {   }

NuPlayer类构造函数初始化

// [frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayer.cpp]NuPlayer::NuPlayer(pid_t pid, const sp
&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();}

clearFlushComplete()实现分析:

// [frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayer.h]    inline void clearFlushComplete() {       	// 该变量定义为一个二维数组,来标识音视频解码器和渲染器的flush操作响应处理结果标志位,初始化为false        mFlushComplete[0][0] = false;        mFlushComplete[0][1] = false;        mFlushComplete[1][0] = false;        mFlushComplete[1][1] = false;    }

1.1.1.3、mAutoLoop实现分析:

一个标志位,是否支持自动循环播放【注意:该字段和上面这个字段有区别,其默认是若Ogg音频文件媒体信息携带有支持自动循环播放,则在播放完毕后会从头再播放】

// [frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp]void NuPlayerDriver::notifyPrepareCompleted(status_t err) {       ALOGV("notifyPrepareCompleted %d", err);        // 其从文件解析的元数据中获取【kKeyAutoLoop】字段设置的值,    // 若携带了该字段值不为0,则设置mAutoLoop为true    // kKeyAutoLoop 定义见下面的分析    sp
meta = mPlayer->getFileMeta(); int32_t loop; if (meta != NULL && meta->findInt32(kKeyAutoLoop, &loop) && loop != 0) { mAutoLoop = true; }}

kKeyAutoLoop 定义:是一个枚举定义

注译:Ogg文件将会被标记支持自动循环播放功能

// [frameworks/av/media/libstagefright/include/media/stagefright/MetaDataBase.h]    // Ogg files can be tagged to be automatically looping...    kKeyAutoLoop          = 'autL',  // bool (int32_t)

1.1.1.4、mMediaClock->init()实现分析:

主要就是将当前MediaClock自身(为AHandler子类)注册Looper线程消息循环功能中,用于接收Looper线程的消息事件处理

// [frameworks/av/media/libstagefright/MediaClock.cpp]void MediaClock::init() {       mLooper->registerHandler(this);}

1.1.1.5、mPlayer->init(this)实现分析:

// [frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayer.cpp]void NuPlayer::init(const wp
&driver) { // 缓存NuPlayerDriver对象的弱引用对象(弱指针对象),用于和Driver进行通信 mDriver = driver; // 创建一个能够发送【kWhatMediaClockNotify】事件给NuPlayer自身去接收处理的消息对象 // 备注:该消息对象能够发送一个【kWhatMediaClockNotify】事件通知给 // 当前NuPlayer自身的Looper消息Hander机制去接收处理, // 即因为NuPlayer自身就是AHandler子类,因此自身实现了接收消息事件处理的 // 方法【NuPlayer::onMessageReceived(const sp
&msg)】 sp
notify = new AMessage(kWhatMediaClockNotify, this); // 将其设置给MediaClock音视频同步时钟去缓存,用于和NuPlayer进行该事件的通信处理 // 见下面的分析 mMediaClock->setNotificationMessage(notify);}

mMediaClock->setNotificationMessage(notify)实现分析:

void MediaClock::setNotificationMessage(const sp
&msg) { Mutex::Autolock autoLock(mLock); mNotify = msg;}

1.1.2、p->initCheck()实现分析:

具体实现播放器的初始化检查【此处分析NuPlayerDriver实现】,如下,该播放器默认直接返回成功,不处理任何流程。

// [frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp]status_t NuPlayerDriver::initCheck() {       return OK;}

1.1.3、p->setNotifyCallback(listener)实现分析:

主要就是将Client中的事件回调监听对象赋值给具体实现播放器【此处分析NuPlayerDriver实现】,然后接受播放器的事件回调通知,也就会触发Client的notify方法,即如第二章节分析,将会通知java层相关事件回调。
首先寻找NuPlayerDriver.cpp中该方法的实现,然而并未发现该实现,那么此时我们肯定能确定该方法是在父类中实现的,因此分析过程如下:
查看NuPlayerDriver类声明

// [/frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp]struct NuPlayerDriver : public MediaPlayerInterface {   // 省略其他代码}// [/frameworks/av/include/media/MediaPlayerInterface.h]    void        setNotifyCallback(            const sp
&listener) { Mutex::Autolock autoLock(mNotifyLock); // 缓存该事件回调监听,用于后续事件通知 mListener = listener; }

1.2、DeathNotifier,对对端进程(如相关Service服务进程)异常关闭通知事件的监听实现处理:

该处理功能有必要单独作为一个小章节进行分析,请查看如下章节

1.3、NuPlayerDriver的sendEvent方法实现实现:

从调用可知,该方法为父类实现方法,如下

// [frameworks/av/media/libmediaplayerservice/include/MediaPlayerInterface.h]// 该方法是NuPlayerDriver的父类MediaPlayerBase类中的默认实现    void        sendEvent(int msg, int ext1=0, int ext2=0,                          const Parcel *obj=NULL) {           sp
listener; { // 先加锁获取该对象 Mutex::Autolock autoLock(mNotifyLock); listener = mListener; } if (listener != NULL) { // 不为空则调用其notify方法 // 由前面的分析可知,此处是通知前面分析过的Client播放器对象的notify方法, // 也即会通知上传APP listener->notify(msg, ext1, ext2, obj); } }

1.4、AudioOutput的类声明和初始化创建

代码如下

// [frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp]        mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid(),                mPid, mAudioAttributes, mAudioDeviceUpdatedListener);

创建AudioOutput输出(音频播放)端对象,AudioOutput是MediaPlayerService的内部类,其父类为AudioSink,如下:

AudioOutput的类声明:省略其他代码

// [frameworks/av/media/libmediaplayerservice/MediaPlayerService.h]class AudioOutput : public MediaPlayerBase::AudioSink {   }// [frameworks/av/media/libmediaplayerservice/include/MediaPlayerInterface.cpp]// AudioSink: abstraction layer for audio outputclass AudioSink : public RefBase {   }

AudioOutput构造函数初始化创建:

// [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
& 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();}

setMinBufferCount()实现分析:

//staticvoid MediaPlayerService::AudioOutput::setMinBufferCount(){       char value[PROPERTY_VALUE_MAX];    if (property_get("ro.kernel.qemu", value, 0)) {       	// 标记是模拟器运行的程序        mIsOnEmulator = true;        // 设置初始化最小的缓冲区buffer数为12        // 注译:防止模拟器的系统缓冲区不足        mMinBufferCount = 12;  // to prevent systematic buffer underrun for emulator    }}

1.4.1、mPlaybackRate(AUDIO_PLAYBACK_RATE_DEFAULT)实现分析:

该变量结构声明:

// [frameworks/av/media/libaudioprogressing/include/media/AudioResamplerPublic.h]struct AudioPlaybackRate {   	// 音频播放速度    float mSpeed;    // 音高    float mPitch;    // 音频时间伸缩的伸缩模式,主要用于音频时间伸缩运算的伸缩量    enum AudioTimestretchStretchMode  mStretchMode;    // 音频时间伸缩的回退模式,即上面这个模式不支持的话,就用下面这个    enum AudioTimestretchFallbackMode mFallbackMode;};

AUDIO_PLAYBACK_RATE_DEFAULT默认结构声明定义:

// 关于这些值的具体定义可参考其常量定义的英文说明,后续有时间补上

// [frameworks/av/media/libaudioprogressing/include/media/AudioResamplerPublic.h]static const AudioPlaybackRate AUDIO_PLAYBACK_RATE_DEFAULT = {   		// 宏定义值为 1        AUDIO_TIMESTRETCH_SPEED_NORMAL,        // 宏定义值为 1        AUDIO_TIMESTRETCH_PITCH_NORMAL,        // 枚举,其值为0        AUDIO_TIMESTRETCH_STRETCH_DEFAULT,        // 枚举,其值为0        AUDIO_TIMESTRETCH_FALLBACK_DEFAULT};

1.5、NuPlayerDriver的setAudioSink()方法实现分析:

是在其父类中实现的,如下

// Implement this class for media players that use the AudioFlinger software mixerclass MediaPlayerInterface : public MediaPlayerBase{   public:    virtual             ~MediaPlayerInterface() {    }    virtual bool        hardwareOutput() {    return false; }    // 直接缓存到类全局变量mAudioSink中    virtual void        setAudioSink(const sp
& audioSink) { mAudioSink = audioSink; }protected: sp
mAudioSink;};

2、setDataSource_post(p, p->setDataSource(fd, offset, length))实现分析:

由于篇幅较长,因此请查看下一章续集分析

转载地址:http://popmz.baihongyu.com/

你可能感兴趣的文章
mysql5.7示例数据库_Linux MySQL5.7多实例数据库配置
查看>>
Mysql8 数据库安装及主从配置 | Spring Cloud 2
查看>>
mysql8 配置文件配置group 问题 sql语句group不能使用报错解决 mysql8.X版本的my.cnf配置文件 my.cnf文件 能够使用的my.cnf配置文件
查看>>
MySQL8.0.29启动报错Different lower_case_table_names settings for server (‘0‘) and data dictionary (‘1‘)
查看>>
MYSQL8.0以上忘记root密码
查看>>
Mysql8.0以上重置初始密码的方法
查看>>
mysql8.0新特性-自增变量的持久化
查看>>
Mysql8.0注意url变更写法
查看>>
Mysql8.0的特性
查看>>
MySQL8修改密码报错ERROR 1819 (HY000): Your password does not satisfy the current policy requirements
查看>>
MySQL8修改密码的方法
查看>>
Mysql8在Centos上安装后忘记root密码如何重新设置
查看>>
Mysql8在Windows上离线安装时忘记root密码
查看>>
MySQL8找不到my.ini配置文件以及报sql_mode=only_full_group_by解决方案
查看>>
mysql8的安装与卸载
查看>>
MySQL8,体验不一样的安装方式!
查看>>
MySQL: Host '127.0.0.1' is not allowed to connect to this MySQL server
查看>>
Mysql: 对换(替换)两条记录的同一个字段值
查看>>
mysql:Can‘t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock‘解决方法
查看>>
MYSQL:基础——3N范式的表结构设计
查看>>