MediaPlayer视频播放流程

news2024/12/23 14:20:20

MediaPlayer视频播放流程(基于Android8.0)

  • 1. MediaPlayer源码分析

    • 1.0

      public class MediaPlayer extends PlayerBase implements 
                  SubtitleController.Listener, VolumeAutomation, AudioRouting
      

      MediaPayer继承自PlayerBase类,分别实现了SubtitleController VolumeAutomation AudioRouting接口

      • frameworks/base/media/java/android/media/PlayerBase.java

        PlayeBase是一个抽象类,封装了常规的播放器操作,如start pause stop release

        baseRegisterPlayer(),获取AppOpsService对象,并通过startWatchingMode对播放音乐的权限OP_PLAY_AUDIO进行监听

        protected void baseRegisterPlayer() {
            int newPiid = AudioPlaybackConfiguration.PLAYER_PIID_INVALID;
            //获取AppOpsService对象
            IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE);
            mAppOps = IAppOpsService.Stub.asInterface(b);
            // initialize mHasAppOpsPlayAudio
            //检查权限
            updateAppOpsPlayAudio();
            // register a callback to monitor whether the OP_PLAY_AUDIO is still allowed
            mAppOpsCallback = new IAppOpsCallbackWrapper(this);
            try {
                //注册了权限的监听
                mAppOps.startWatchingMode(AppOpsManager.OP_PLAY_AUDIO,
                        ActivityThread.currentPackageName(), mAppOpsCallback);
            } catch (RemoteException e) {
                Log.e(TAG, "Error registering appOps callback", e);
                mHasAppOpsPlayAudio = false;
            }
            try {
                //调用了AudioService的 trackPlayer,主要将mediaplayer统一管理起来,已方便提供 duck,mediaplayer的状态监听啊,以及外部对mediaplayer控制等功能
                newPiid = getService().trackPlayer(
                        new PlayerIdCard(mImplType, mAttributes, new IPlayerWrapper(this)));
            } catch (RemoteException e) {
                Log.e(TAG, "Error talking to audio service, player will not be tracked", e);
            }
            mPlayerIId = newPiid;
        }
        

        在MediaPlayer()构造函数中调用

        public MediaPlayer() {
            //通过super在playerBase创建一个默认的AudioAttributes,以及player类             
                 //PLAYER_TYPE_JAM_MEDIAPLAYER 表示MediaPlayer 
            super(new AudioAttributes.Builder().build(),
                    AudioPlaybackConfiguration.PLAYER_TYPE_JAM_MEDIAPLAYER);
        
            //获取当前线程的looper,如果当前线程没有lopper那么就获取主线程的looper
            Looper looper;
            if ((looper = Looper.myLooper()) != null) {
                //创建一个handler主要用于控制mediaplayer的播放 
                mEventHandler = new EventHandler(this, looper);
            } else if ((looper = Looper.getMainLooper()) != null) {
                mEventHandler = new EventHandler(this, looper);
            } else {
                mEventHandler = null;
            }
        
            //控制播放时间和播放进度的相关
            mTimeProvider = new TimeProvider(this);
            //创建了一个InputStream向量集合 
            mOpenSubtitleSources = new Vector<InputStream>();
        
            //通过jni向下调用,初始化
            native_setup(new WeakReference<MediaPlayer>(this));
        
            baseRegisterPlayer();
         }
        
      • frameworks/base/media/java/android/media/SubtitleController.java

        frameworks/base/media/java/android/media/SubtitleTrack.java
        frameworks/base/media/java/android/media/SubtitleData.java

        用于为用户显示字幕,允许指定要显示的轨迹、定位点,还允许添加外部带外字幕曲目

      • frameworks/base/media/java/android/media/VolumeAutomation.java

        frameworks/base/media/java/android/media/VolumeShaper.java
        frameworks/base/media/jni/android_media_VolumeShaper.h等

        主要用于音频应用的淡入,淡出,淡入淡出,淡入淡出以及其他短暂的自动音量转换,音量控制通过VolumeShaper.Configuration实现,必须要在8.0及以后才能使用。

    • 2.0

      加载so库

      static {
          System.loadLibrary("media_jni");
          native_init();
      }
      
    • 3.0

      初始化

      public MediaPlayer() {
          ......
      
          //通过jni向下调用,初始化
          native_setup(new WeakReference<MediaPlayer>(this));
      
          ......
      }
      
      • frameworks/base/media/jni/android_media_MediaPlayer.cpp
        static void
        android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
        {
            ALOGV("native_setup");
            // 创建一个MediaPlayer对象(frameworks/av/media/libmedia/mediaplayer.cpp)
            sp<MediaPlayer> mp = new MediaPlayer();
            if (mp == NULL) {
                jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
                return;
            }
        
            // 为MediaPlayer设置listener,目的就是通过callback的方式将player的事件上传至   java层,以便用户做出对应的处理
            // create new listener and give it to MediaPlayer
            sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);
            mp->setListener(listener);
        
            // Stow our new C++ MediaPlayer in an opaque field in the Java object.
            setMediaPlayer(env, thiz, mp);
        }
        
        //JNIMediaPlayerListener类
        class JNIMediaPlayerListener: public MediaPlayerListener
        {
        public:
            JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
            ~JNIMediaPlayerListener();
            virtual void notify(int msg, int ext1, int ext2, const Parcel *obj = NULL);
        private:
            JNIMediaPlayerListener();
            jclass      mClass;     // Reference to MediaPlayer class
            jobject     mObject;    // Weak ref to MediaPlayer Java object to call on
        };
        
        ......
        
        //callback事件的传递
        void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2, const Parcel *obj)
        {
            JNIEnv *env = AndroidRuntime::getJNIEnv();
            if (obj && obj->dataSize() > 0) {
                // 创建java层Parcel对象对应的JNI类型对象(JNI本地引用对象)
                jobject jParcel = createJavaParcelObject(env);
                if (jParcel != NULL) {
                    // 然后获取该Java层Parcel对象对应的native层Parcel对象指针(值)
                    // 然后缓存当前obj额外参数值及其大小
                    Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
                    nativeParcel->setData(obj->data(), obj->dataSize());
                    // 最后调用java层事件回调静态方法【fields.post_event】通知java层
                    // fields.post_event对应于MediaPlayer的java方法 postEventFromNative
                    env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
                            msg, ext1, ext2, jParcel);
                    // 释放创建的java层Parcel对象的JNI本地引用对象
                    env->DeleteLocalRef(jParcel);
                }
            } else {
                // 若无额外参数,则直接调用通知java层
                env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
                        msg, ext1, ext2, NULL);
            }
            // 检查【post_event】方法调用是否有异常,若异常则需要清空该异常等处理
            // 备注:当一个JNI函数返回一个明确的错误码时,仍可用ExceptionCheck来检查是否有异常发生。
            // 但是,用返回的错误码来判断比较高效。一旦JNI函数的返回值是一个错误码,
            // 那么接下来调用ExceptionCheck肯定会返回JNI_TRUE。
            if (env->ExceptionCheck()) {
                ALOGW("An exception occurred while notifying an event.");
                LOGW_EX(env);
                env->ExceptionClear();
            }
        }
        
        ......
        
        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");
            if (fields.post_event == NULL) {
                return;
            }
        
            ......
        }
        
        .....
        
        static sp<MediaPlayer> setMediaPlayer(JNIEnv* env, jobject thiz, const sp<MediaPlayer>& player)
        {
            Mutex::Autolock l(sLock);
            sp<MediaPlayer> old = (MediaPlayer*)env->GetLongField(thiz, fields.context);
            if (player.get()) {
                player->incStrong((void*)setMediaPlayer);
            }
            if (old != 0) {
                old->decStrong((void*)setMediaPlayer);
            }
            // 将mediaplayer对象指针给与了java层的mediaplayer的mNativeContext字段
            env->SetLongField(thiz, fields.context, (jlong)player.get());
            return old;
        }
        
      • frameworks/av/media/libmedia/include/media/mediaplayer.h
        // ref-counted object for callbacks
        class MediaPlayerListener: virtual public RefBase
        {
        public:
            virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) = 0;
        };
        
      • framework/av/media/libmedia/mediaplayer.cpp
        status_t MediaPlayer::setListener(const sp<MediaPlayerListener>& listener)
        {
            ALOGV("setListener");
            Mutex::Autolock _l(mLock);
            mListener = listener;
            return NO_ERROR;
        }
        
        ......
        
        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;
            
            ......
            
            case MEDIA_ERROR:
                // Always log errors.
                // ext1: Media framework error code.
                // ext2: Implementation dependant error code.
                ALOGE("error (%d, %d)", ext1, ext2);
                mCurrentState = MEDIA_PLAYER_STATE_ERROR;
                // 错误发生时,【mPrepareSync】该标识为true时,
                // 表示当前执行的是同步prepare准备流程,非异步执行prepareAsync流程
                if (mPrepareSync)
                {
                    ALOGV("signal application thread");
                    mPrepareSync = false;
                    mPrepareStatus = ext1;
                    mSignal.signal();
                    // prepare同步执行功能失败时,置为false
                    send = false;
                }
                
            ......
                
            ALOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
            sp<MediaPlayerListener> listener = mListener;
            if (locked) mLock.unlock();
        
            // this prevents re-entrant calls into client code
            if ((listener != 0) && send) {
                // 此处根据上面的分析可知,listener不为空并且send为true(即当prepare同步执行过程中无错误发生)时,
                // 进行加锁调用通知java层该事件
                Mutex::Autolock _l(mNotifyLock);
                ALOGV("callback application");
                listener->notify(msg, ext1, ext2, obj);
                ALOGV("back from callback");
            }
        }
        
        
    • 4.0

      setDataSource(文件类型)

      public void setDataSource(FileDescriptor fd, long offset, long length)
          throws IOException, IllegalArgumentException, IllegalStateException {
          _setDataSource(fd, offset, length);
      }
      
      private native void _setDataSource(FileDescriptor fd, long offset, long length)
              throws IOException, IllegalArgumentException, IllegalStateException;
      
      • frameworks/base/media/jni/android_media_MediaPlayer.cpp
        {"_setDataSource",      "(Ljava/io/FileDescriptor;JJ)V",    (void *)
                android_media_MediaPlayer_setDataSourceFD},
        
        ......
        
        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;
            }
            // 在jni中获取文件描述符
            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." );
        }
        
        ......
        
        // 获取java层MediaPlayer对象的mNativeContext字段,转为native层mediaplayer对象
        static sp<MediaPlayer> getMediaPlayer(JNIEnv* env, jobject thiz)
        {
            Mutex::Autolock l(sLock);
            MediaPlayer* const p = (MediaPlayer*)env->GetLongField(thiz, fields.context);
            return sp<MediaPlayer>(p);
        }
        
        ......
        
        // 对setDataSource的结果进行处理
        static void process_media_player_call(JNIEnv *env, jobject thiz, status_t opStatus, const char* exception, const char *message)
        {   
            // 不抛出异常,直接向上层反馈错误事件
            if (exception == NULL) {  // Don't throw exception. Instead, send an event.
                if (opStatus != (status_t) OK) {
                    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
                    if (mp != 0) mp->notify(MEDIA_ERROR, opStatus, 0);
                }
            } else {  // Throw exception!
                if ( opStatus == (status_t) INVALID_OPERATION ) {
                    jniThrowException(env, "java/lang/IllegalStateException", NULL);
                } else if ( opStatus == (status_t) BAD_VALUE ) {
                    jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
                } else if ( opStatus == (status_t) PERMISSION_DENIED ) {
                    jniThrowException(env, "java/lang/SecurityException", NULL);
                } else if ( opStatus != (status_t) OK ) {
                    if (strlen(message) > 230) {
                        // if the message is too long, don't bother displaying the status code
                        jniThrowException( env, exception, message);
                    } else {
                        char msg[256];
                        // append the status code to the message
                        sprintf(msg, "%s: status=0x%X", message, opStatus);
                        jniThrowException( env, exception, msg);
                    }
                }
            }
        }
        
      • frameworks/av/media/libmedia/mediaplayer.cpp
        status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
        {
            // //用于记录framework APIs返回成功与否
            ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
            status_t err = UNKNOWN_ERROR;
            //getMediaPlayerService()函数定义域framework/av/media/libmedia/ IMediaDeathNotifier.cpp中
            //getMediaPlayerService()返回的是MediaPlayerService服务在客户端的代理对象BpMediaPlayerService
            const sp<IMediaPlayerService> service(getMediaPlayerService());
            if (service != 0) {
                //调用IMediaPlayerService中的create()函数查询服务
                //并返回一个调用IMediaPlayer对象
                sp<IMediaPlayer> player(service->create(this, mAudioSessionId));
                //调用服务端的setDataSource(int fd, int64_t offset, int64_t length)方法
                if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
                    (NO_ERROR != player->setDataSource(fd, offset, length))) {
                    player.clear();
                }
                //重置一些变量,更新MediaPlayer对象
                err = attachNewPlayer(player);
            }
            return err;
        }
        
      • frameworks/av/media/libmedia/IMediaDeathNotifier.cpp
        /*static*/const sp<IMediaPlayerService>
        IMediaDeathNotifier::getMediaPlayerService()
        {
            ALOGV("getMediaPlayerService");
            Mutex::Autolock _l(sServiceLock);
            if (sMediaPlayerService == 0) {
                //获取ServiceManager
                sp<IServiceManager> sm = defaultServiceManager();
                sp<IBinder> binder;
                do {
                    //获取MediaPlayer服务的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);
                //将binder对象转换为MediaPlayerService
                sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
            }
            ALOGE_IF(sMediaPlayerService == 0, "no media player service!?");
            return sMediaPlayerService;
        }
        
      • frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp
        //存储各种参数到client对象中,方便client通过IPC调用
        sp<IMediaPlayer> MediaPlayerService::create(const sp<IMediaPlayerClient>& client,
        audio_session_t audioSessionId)
        {
            pid_t pid = IPCThreadState::self()->getCallingPid();
            int32_t connId = android_atomic_inc(&mNextConnId);
        
            sp<Client> c = new Client(
                    this, pid, connId, client, audioSessionId,
                    IPCThreadState::self()->getCallingUid());
        
            ALOGV("Create new client(%d) from pid %d, uid %d, ", connId, pid,
                IPCThreadState::self()->getCallingUid());
        
            wp<Client> w = c;
            {
                Mutex::Autolock lock(mLock);
                mClients.add(w);
            }
            return c;
        }
        
        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);
            //stat结构体主要用来描述系统文件中文件的属性结构,如, 修改时间,文件用户标识等
            struct stat sb;
            //fstat获取文件相关信息保持在stat结构体中,为0表示返回成功
            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);
            }
        
            //调用getPlayerType函数,通过评分机制,获取最优播放器类型
            player_type playerType = MediaPlayerFactory::getPlayerType(this,
                                                                    fd,
                                                                    offset,
                                                                    length);
            //创建播放器
            sp<MediaPlayerBase> p = setDataSource_pre(playerType);
            if (p == NULL) {
                return NO_INIT;
            }
        
            // now set data source
            //在创建的播放器中,设置播放器的数据源
            return mStatus = setDataSource_post(p, p->setDataSource(fd, offset, length));
        }
        
        ......
        
        sp<MediaPlayerBase> MediaPlayerService::Client::setDataSource_pre(
         player_type playerType)
        {
            ALOGV("player type = %d", playerType);
        
            // Mediatek Android Patch Begin
            if (playerType == MST_PLAYER) {
                mIsMstplayer = true;
            }
            // Mediatek Android Patch End
            // create the right type of player
            //根据播放器类型创建播放器
            sp<MediaPlayerBase> p = createPlayer(playerType);
            if (p == NULL) {
                return p;
            }
        
            sp<IServiceManager> sm = defaultServiceManager();
            //获取MediaExtractor服务的binder对象
            sp<IBinder> binder = sm->getService(String16("media.extractor"));
            if (binder == NULL) {
                ALOGE("extractor service not available");
                return NULL;
            }
            //绑定提取器extractor死亡通知
            sp<ServiceDeathNotifier> extractorDeathListener =
                    new ServiceDeathNotifier(binder, p, MEDIAEXTRACTOR_PROCESS_DEATH);
            binder->linkToDeath(extractorDeathListener);
        
            //获取解码器IOmx服务
            sp<IOmx> omx = IOmx::getService();
            if (omx == nullptr) {
                ALOGE("IOmx service is not available");
                return NULL;
            }
            //绑定解码器死亡通知
            sp<ServiceDeathNotifier> codecDeathListener =
                    new ServiceDeathNotifier(omx, p, MEDIACODEC_PROCESS_DEATH);
            omx->linkToDeath(codecDeathListener, 0);
        
            Mutex::Autolock lock(mLock);
        
            clearDeathNotifiers_l();
            mExtractorDeathListener = extractorDeathListener;
            mCodecDeathListener = codecDeathListener;
            mAudioDeviceUpdatedListener = new AudioDeviceUpdatedNotifier(p);
        
            if (!p->hardwareOutput()) {
                //初始化AudioOutput,并且将其设置给player
                //AudioOutput继承自AudioSink,其头文件中的注释:音频输出的抽象层
                //NU_PLAYER播放器的实现在Nuplayer.cpp中 setAudioSink
                mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid(),
                        mPid, mAudioAttributes, mAudioDeviceUpdatedListener);
                static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
            }
        
            return p;
        }
        
        ......
        
        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();
            }
            //根据播放器类型创建播放器,并设置监听和pid号
            if (p == NULL) {
                p = MediaPlayerFactory::createPlayer(playerType, mListener, mPid);
            }
        
            //设置uid
            if (p != NULL) {
                p->setUID(mUid);
            }
        
            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 = sFactoryMap.valueFor(playerType);
            CHECK(NULL != factory);
            //各个工厂类去创建对应的Player
            //如:
            //playervirtual sp<MediaPlayerBase> createPlayer(pid_t pid) {
                //ALOGV(" create NuPlayer");
                //return new NuPlayerDriver(pid);
            //}
            p = factory->createPlayer(pid);
        
            if (p == NULL) {
                ALOGE("Failed to create player object of type %d, create failed",
                    playerType);
                return p;
            }
        
            init_result = p->initCheck();
            if (init_result == NO_ERROR) {
                p->setNotifyCallback(listener);
            } else {
                ALOGE("Failed to create player object of type %d, initCheck failed"
                    " (res = %d)", playerType, init_result);
                p.clear();
            }
        
            return p;
        }
        

      setDataSource(网络视频类型)

      public void setDataSource(String path)
              throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
          setDataSource(path, null, null);
      }
      
      /**
      * Sets the data source (file-path or http/rtsp URL) to use.
      */
      public void setDataSource(String path, Map<String, String> headers)
              throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
          setDataSource(path, headers, null);
      }
      
      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);
      }
      
      private void setDataSource(String path, String[] keys, String[] values,
              List<HttpCookie> cookies)
              throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
          //使用Uri解析文件路径
          final Uri uri = Uri.parse(path);
          //如果本地路径,函数返回值为file,如果是网络地址,返回值为"http"
          final String scheme = uri.getScheme();
          if ("file".equals(scheme)) {
              //本地路径,直接赋值给path
              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);
          if (file.exists()) {
              FileInputStream is = new FileInputStream(file);
              FileDescriptor fd = is.getFD();
              setDataSource(fd);
              is.close();
          } else {
              throw new IOException("setDataSource failed.");
          }
      }
      
      private native void nativeSetDataSource(
          IBinder httpServiceBinder, String path, String[] keys, String[] values)
          throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;
      
      • frameworks/base/media/jni/android_media_MediaPlayer.cpp
        {
            "nativeSetDataSource",
            "(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;"
            "[Ljava/lang/String;)V",
            (void *)android_media_MediaPlayer_setDataSourceAndHeaders
        },
        
        ......
        
        static void
        android_media_MediaPlayer_setDataSourceAndHeaders(
                JNIEnv *env, jobject thiz, jobject httpServiceBinderObj, jstring path,
                jobjectArray keys, jobjectArray values) {
        
            // 同播放本地视频一样,获取java层的mNativeContext,即mediaplayer指针对象
            sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
            if (mp == NULL ) {//对象为空,抛出异常
                jniThrowException(env, "java/lang/IllegalStateException", NULL);
                return;
            }
        
            if (path == NULL) {//地址为空,抛出异常
                jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
                return;
            }
        
            const char *tmp = env->GetStringUTFChars(path, NULL);
            if (tmp == NULL) {  // Out of memory
                return;
            }
            ALOGV("setDataSource: path %s", tmp);
        
            String8 pathStr(tmp);//将地址添加到pathStr中
            env->ReleaseStringUTFChars(path, tmp);
            tmp = NULL;
        
            // We build a KeyedVector out of the key and val arrays
            // 转换播放请求头
            KeyedVector<String8, String8> headersVector;
            if (!ConvertKeyValueArraysToKeyedVector(
                    env, keys, values, &headersVector)) {
                return;
            }
        
            sp<IMediaHTTPService> httpService;
            if (httpServiceBinderObj != NULL) {
                sp<IBinder> binder = ibinderForJavaObject(env, httpServiceBinderObj);
                //获取MediaHttpService对象
                httpService = interface_cast<IMediaHTTPService>(binder);
            }
        
            // Mediatek Android Patch Begin
            bool bNWayPlayback = false;
            int keyValue;
            for (size_t i = 0; i < headersVector.size(); ++i) {
                //如果请求头中不包含set_multiple_player字段,需要回放???
                if (!strncmp(headersVector.keyAt(i), "set_multiple_player", strlen("set_multiple_player"))) {
                    bNWayPlayback = true;
                    keyValue = atoi(headersVector.valueAt(i));
                    headersVector.removeItemsAt(i, 1);
                    break;
                }
            }
            // Mediatek Android Patch End
        
            // 调用mp对象setDataSource
            status_t opStatus =
                mp->setDataSource(
                        httpService,
                        pathStr,
                        headersVector.size() > 0? &headersVector : NULL);
        
            // 处理setDataSource结果
            process_media_player_call(
                    env, thiz, opStatus, "java/io/IOException",
                    "setDataSource failed." );
        
            // Mediatek Android Patch Begin
            // 回放这段视频
            if (bNWayPlayback) {
                Parcel data;
                data.writeInt32(keyValue);
                opStatus = mp->setParameter(KEY_PARAMETER_SET_MULTIPLE_PLAYER, data);
                process_media_player_call(env, thiz, opStatus, "java/io/IOException", "setParameter failed." );
            }
            // Mediatek Android Patch End
        }
        
      • frameworks/av/media/libmedia/mediaplayer.cpp
        status_t MediaPlayer::setDataSource(
                const sp<IMediaHTTPService> &httpService,
                const char *url, const KeyedVector<String8, String8> *headers)
        {
            ALOGV("setDataSource(%s)", url);
            status_t err = BAD_VALUE;
            if (url != NULL) {
                //getMediaPlayerService()函数定义域framework/av/media/libmedia/IMediaDeathNotifier.cpp中
                //getMediaPlayerService()返回的是MediaPlayerService服务在客户端的代理对象BpMediaPlayerService
                const sp<IMediaPlayerService> service(getMediaPlayerService());
                if (service != 0) {
                    //调用IMediaPlayerService中的create()函数查询服务
                    //并返回一个调用IMediaPlayer对象
                    sp<IMediaPlayer> player(service->create(this, mAudioSessionId));
                    if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
                        (NO_ERROR != player->setDataSource(httpService, url, headers))) {
                        player.clear();
                    }
                    //重置一些变量,更新MediaPlayer对象
                    err = attachNewPlayer(player);
                }
            }
            return err;
        }
        
      • frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp
        status_t MediaPlayerService::Client::setDataSource(
                const sp<IMediaHTTPService> &httpService,
                const char *url,
                const KeyedVector<String8, String8> *headers)
        {
            ALOGV("setDataSource(%s)", url);
            if (url == NULL)
                return UNKNOWN_ERROR;
        
            //如果播放的视频是网络视频,需要检查网络权限
            if ((strncmp(url, "http://", 7) == 0) ||
                (strncmp(url, "https://", 8) == 0) ||
                (strncmp(url, "rtsp://", 7) == 0)) {
                if (!checkPermission("android.permission.INTERNET")) {
                    return PERMISSION_DENIED;
                }
            }
        
            //如果播放的是本地视频
            if (strncmp(url, "content://", 10) == 0) {
                // get a filedescriptor for the content Uri and
                // pass it to the setDataSource(fd) method
        
                String16 url16(url);
                //通过provider获取到fd对象,然后走本地播放的流程
                int fd = android::openContentProviderFile(url16);
                if (fd < 0)
                {
                    ALOGE("Couldn't open fd for %s", url);
                    return UNKNOWN_ERROR;
                }
                status_t status = setDataSource(fd, 0, 0x7fffffffffLL); // this sets mStatus
                close(fd);
                return mStatus = status;
            } else {
                // Mediatek Android Patch Begin
                const char *DLNA_FEATURE = "DLNA.FEATURE";
                const char *IMAGE_FEATURE = "IMAGE.FEATURE";
                const char *CHINADRM_FEATURE = "CHINADRM.FEATURE";
                player_type playerType;
                size_t idx;
                //如果播放请求头中指定了对应播放器,则使用对应的播放器类型
                if (headers != NULL) {
                    for (idx = 0; idx < headers->size(); idx++) {
                        if (!strncmp(headers->keyAt(idx), DLNA_FEATURE, strlen(DLNA_FEATURE)) && atoi(headers->valueAt(idx)) > 0) {
                            playerType = MST_PLAYER;
                            break;
                        }
                        if (!strncmp(headers->keyAt(idx), IMAGE_FEATURE, strlen(IMAGE_FEATURE)) && atoi(headers->valueAt(idx)) > 0) {
                            playerType = IMG_PLAYER;
                            break;
                        }
                        if (!strncmp(headers->keyAt(idx), CHINADRM_FEATURE, strlen(CHINADRM_FEATURE)) && atoi(headers->valueAt(idx)) > 0) {
                            ALOGW("CHINADRM.FEATURE is enable for %s, switch to NuPlayer", url);
                            playerType = NU_PLAYER;
                            break;
                        }
                    }
                }
        
                if (headers == NULL || idx == headers->size()) {
                    //如果没有指定播放器,调用getPlayerType函数,通过评分机制,获取最优播放器类型
                    playerType = MediaPlayerFactory::getPlayerType(this, url, httpService);
                }
                // Mediatek Android Patch End
        
                //创建播放器
                sp<MediaPlayerBase> p = setDataSource_pre(playerType);
                if (p == NULL) {
                    return NO_INIT;
                }
        
                //在创建的播放器中,设置播放器的数据源
                return mStatus =
                        setDataSource_post(
                        p, p->setDataSource(httpService, url, headers));
        
        }
        
      • 播放器评分机制

        • mediaplayer和mediacodec最终的调用关系
          在这里插入图片描述

        不管是上层的MediaPlayer还是framework层的MediaPlayer都不是不能说是真正的播放器。真正播放器是底层的NuPlayer和TestPlayer。当应用层的MediaPlayer通过JNI调用了framework层的MediaPlayer,最终调用到MediaPlayerService。MediaPlayerService根据评分机制,比较NuPlayer和TestPlayer的得分,实例化得分最高的。这便是最终使用的底层播放器。

        • 考虑到扩展性,google工程师们使用了工厂模式,来管理播放器的创建和评分机制。这样,出了Android自己的内置播放器,各大Rom厂商也可以实现自己的播放器。我们来看看播放器相关工厂类的类图。
          在这里插入图片描述

        播放器的创建,会使用MediaPlayerFactory的createPlayer函数。MediaPlayerFactory的createPlayer函数中,会根据片源情况,调用注册在tFactoryMap中的各个IFactory实现,获取对应的分值,获得最大分值的工厂类,调用该工厂类的createPlayer函数,最终创建出指定的播放器。

        • 注册播放器工厂的目的,是初始化tFactoryMap,以便通过打分机制比较出最优的播放器,最终创建出对应的播放器。
          初次调用注册播放器工厂的函数是在MediaPlayerService的构造器中,MediaPlayerService作为基础服务,在Android世界启动的时候,便会调用。
          frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp
          MediaPlayerService::MediaPlayerService()
          {
              ALOGV("MediaPlayerService created");
              mNextConnId = 1;
          
              // Mediatek Android Patch Begin
              #ifdef BUILD_WITH_TEE
              MDrv_SYS_GlobalInit();
              TEEC_Initialize();
              #endif
              if (IS_VR360_SUPPORTED)
                  Mdrv_SYS_VR360_Restore_BW_Setting();
              // Mediatek Android Patch End
              // 注册播放器工厂
              MediaPlayerFactory::registerBuiltinFactories();
          }
          
          frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp
          void MediaPlayerFactory::registerBuiltinFactories() {
              Mutex::Autolock lock_(&sLock);
          
              if (sInitComplete)
                  return;
          
              IFactory* factory = new NuPlayerFactory();
              if (registerFactory_l(factory, NU_PLAYER) != OK)
                  delete factory;
              factory = new TestPlayerFactory();
              if (registerFactory_l(factory, TEST_PLAYER) != OK)
                  delete factory;
          
              // Mediatek Android Patch Begin
          #ifdef BUILD_WITH_MSTAR_MM
              registerFactory_l(new MstPlayerFactory(), MST_PLAYER);
          #ifdef SUPPORT_IMAGEPLAYER
              registerFactory_l(new ImagePlayerFactory(), IMG_PLAYER);
          #endif
          #ifdef SUPPORT_MSTARPLAYER
              registerFactory_l(new MstarPlayerFactory(), MSTAR_PLAYER);
          #endif
          #endif
          
              registerVendorFactories();
              // Mediatek Android Patch End
          
              sInitComplete = true;
          }
          
          ......
          
          //将播放器类型作为key,具体的播放器工厂作为值存储在tFactoryMap中
          status_t MediaPlayerFactory::registerFactory_l(IFactory* factory,
                                         player_type type) {
              if (NULL == factory) {
                  ALOGE("Failed to register MediaPlayerFactory of type %d, factory is"
                      " NULL.", type);
                  return BAD_VALUE;
              }
          
              if (sFactoryMap.indexOfKey(type) >= 0) {
                  ALOGE("Failed to register MediaPlayerFactory of type %d, type is"
                      " already registered.", type);
                  return ALREADY_EXISTS;
              }
          
              if (sFactoryMap.add(type, factory) < 0) {
                  ALOGE("Failed to register MediaPlayerFactory of type %d, failed to add"
                      " to map.", type);
                  return UNKNOWN_ERROR;
              }
          
              return OK;
          }
          
        • frameworks/av/media/libmediaplayerservice/MediaPlayerFactory.cpp
          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);
                  // 这里的a是一个参数数组,包含所有getPlayerType的入参                               
                  thisScore = v->scoreFactory(a, bestScore);
                  // 如果当前分数比最高得分大,则替换掉最高得分       
                  if (thisScore > bestScore) { 
                      // 同时将播放器类型交给ret以便返回                    
                      ret = sFactoryMap.keyAt(i);                 \
                      bestScore = thisScore;                      \
                  }                                               \
              }                                                   \
              
              //分数都为0的时候,选择默认播器                                                    
              if (0.0 == bestScore) {                             \
                  ret = getDefaultPlayerType();                   \
              }                                                   \
                                                                  \
              return ret;
          
          ......
          
          static player_type getDefaultPlayerType() {
              // Mediatek Android Patch Begin
          //如果是mstar平台,根据属性值选择播放器
          #ifdef BUILD_WITH_MSTAR_MM
              char value[PROPERTY_VALUE_MAX];
              if (property_get("ms.sf", value, NULL)
                      && (!strcmp("1", value) || !strcasecmp("true", value))) {
                  return STAGEFRIGHT_PLAYER;
              }
          
              if (property_get("ms.nu", value, NULL)
                      && (!strcmp("1", value) || !strcasecmp("true", value))) {
                  return NU_PLAYER;
              }
          
              return MST_PLAYER;
          #endif
              // Mediatek Android Patch End
              //如果不是mstar平台,默认NU_PLAYER
              return NU_PLAYER;
          }
          
        • frameworks/av/include/media/MediaPlayerInterface.h
          enum player_type {
              STAGEFRIGHT_PLAYER = 3,//Android7.0之后已被删除
              NU_PLAYER = 4,
              // Test players are available only in the 'test' and 'eng' builds.
              // The shared library with the test player is passed passed as an
              // argument to the 'test:' url in the setDataSource call.
              //测试播放器只能在’test’和’eng’版本中使用。 当setDataSource参数中带有’test:'开头的url将使用带有测试播放器的共享库
              TEST_PLAYER = 5,
              //mstar平台定制播放器
              // Mediatek Android Patch Begin
              MST_PLAYER = 6,
              HDMI_PLAYER = 7,
              MSTAR_PLAYER = 8,
              IMG_PLAYER = 9,
              // Mediatek Android Patch End
          };
          
        • frameworks/av/media/libmediaplayerservice/MediaPlayerFactory.cpp
          scoreFactory函数是抽象类IFactory中的非抽象函数,NuPlayerFactory和TestPlayerFactory等都继承了IFactory
          class NuPlayerFactory : public MediaPlayerFactory::IFactory {
          public:
          
              // Mediatek Android Patch Begin
          #ifdef BUILD_WITH_MSTAR_MM
              virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
                                      int fd,
                                      int64_t offset,
                                      int64_t length,
                                      float /*curScore*/) {
                  char buf[20];
                  lseek(fd, offset, SEEK_SET);
                  read(fd, buf, sizeof(buf));
                  lseek(fd, offset, SEEK_SET);
          
                  uint32_t ident = *((uint32_t*)buf);
          
                  // Ogg vorbis?
                  if (ident == 0x5367674f) // 'OggS': use NuPlayer to play OGG clips
                      return 1.0;
          
                  if (ident == 0xc450fbff && length == 40541) // FIXME: for CTS testGapless1 test work around
                      return 1.0;
          
                  if (!memcmp(buf+3, " ftypM4A ", 9) && (length == 46180 || length == 83892)) // FIXME: for CTS testGapless2&3 test work around
                      return 1.0;
          
                  // FIXME: for AN7 CTS closed caption tests work around
                  // testChangeSubtitleTrack
                  // testDeselectTrackForSubtitleTracks
                  // testGetTrackInfoForVideoWithSubtitleTracks
                  if (length == 210936)
                      return 1.0;
          
                  // FIXME: for AN7 CTS NativeDecoderTest#testMuxerVp8
                  if (length == 2829176)
                      return 1.0;
          
                  // FIXME: for AN8 CTS android.media.cts.MediaPlayerDrmTest
                  if (length == 3012095) {
                      return 1.0;
                  }
          
                  // FIXME: for AN8 GTS MediaPlayerTest
                  if (length == 1481047 || length == 8127587)
                      return 1.0;
          
                  return 0.0;
              }
          #endif
              // Mediatek Android Patch End
          
              // Mediatek Android Patch Begin
              virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
                                      const char* url,
                                      const sp<IMediaHTTPService>& /* httpService */,
                                      float curScore) {
              // Mediatek Android Patch End
                  static const float kOurScore = 0.8;
          
                  if (kOurScore <= curScore)
                      return 0.0;
          
                  // Mediatek Android Patch Begin
          #ifdef BUILD_WITH_MARLIN
                  if (IsWasabiSourceUrl(url)) {
                      char value[PROPERTY_VALUE_MAX];
                      if (property_get("ms.wasabi.nu", value, NULL)
                          && (!strcmp("1", value))) {
                          return 5.0;
                      }
                  }
          #endif
          #ifdef BUILD_WITH_MSTAR_MM
                  if (strcasestr(url, ".ogg") != NULL) { // use NuPlayer to play OGG clips
                      return 2.1; // use make the value larger than mooplayer.. MStar strategy to force native playerto  play OGG files.... kOurScore;
                  }
          
                  if (strcasestr(url, ".flac") != NULL) { // use NuPlayer to play FLAC clips
                      return kOurScore;
                  }
          
                  if (!(strncmp(url, "data:", 5))) { // using NuPlayer when url type is the "data:"
                      return kOurScore;
                  }
          #endif
          
                  // FIXME: for AN8 GTS MediaPlayerTest
                  if (!strcasecmp(url, "https://storage.googleapis.com/wvmedia/cenc/h264/llama/llama_aac_audio.mp4"))
                      return 1.0;
          
                  // Mediatek Android Patch End
          
                  if (!strncasecmp("http://", url, 7)
                          || !strncasecmp("https://", url, 8)
                          || !strncasecmp("file://", url, 7)) {
                      size_t len = strlen(url);
                      if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) {
          // Mediatek Android Patch Begin
          #ifdef SPECIAL_STREAM_USE_NUPLAYER
                          if (strstr(url, "/sample_aes/") || strstr(url, "/audio_only/") || strstr(url, "/unmuxed_1500k/")) {
                              return 1.0;
                          }
          #endif
          // Mediatek Android Patch End
                          return kOurScore;
                      }
          
                      if (strstr(url,"m3u8")) {
          // Mediatek Android Patch Begin
          #ifdef SPECIAL_STREAM_USE_NUPLAYER
                          if (strstr(url, "/sample_aes/") || strstr(url, "/audio_only/") || strstr(url, "/unmuxed_1500k/")) {
                              return 1.0;
                          }
          #endif
          // Mediatek Android Patch End
                          return kOurScore;
                      }
          
                      if (strstr(url, "/videoplayback/")) { // use NuPlayer to play Sonyliv ad
                          return 1.0;
                      }
          
                      if ((len >= 4 && !strcasecmp(".sdp", &url[len - 4])) || strstr(url, ".sdp?")) {
                          return kOurScore;
                      }
                  }
          
                  if (!strncasecmp("rtsp://", url, 7)) {
                      return kOurScore;
                  }
          
                  return 0.0;
              }
          
              virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
                                      const sp<IStreamSource>& /*source*/,
                                      float /*curScore*/) {
                  // Mediatek Android Patch Begin
                  return 0.8; // use Mstplayer to play IStreamSource
                  // Mediatek Android Patch End
              }
          
              virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
                                      const sp<DataSource>& /*source*/,
                                      float /*curScore*/) {
                  // Only NuPlayer supports setting a DataSource source directly.
                  return 1.0;
              }
          
              virtual sp<MediaPlayerBase> createPlayer(pid_t pid) {
                  ALOGV(" create NuPlayer");
                  return new NuPlayerDriver(pid);
              }
          };
          
          在这里插入图片描述
    • 5.0

      prepare() && prepareAsync()

      prepare()
      同步地为播放器的回放做准备。设置数据源和显示表面之后,需要调用prepare()或prepareAsync()。对于文件,可以调用prepare(),它会阻塞,直到MediaPlayer准备好播放为止。

      prepareAsync()
      异步地为播放器的回放做准备。设置数据源和显示表面之后,需要调用prepare()或prepareAsync()。对于流,应该调用prepareAsync(),它会立即返回,而不是阻塞,直到缓冲了足够的数据。

      public void prepare() throws IOException, IllegalStateException {
          _prepare();
          scanInternalSubtitleTracks();
      
          // DrmInfo, if any, has been resolved by now.
          synchronized (mDrmLock) {
              mDrmInfoResolved = true;
          }
      }
      
      private native void _prepare() throws IOException, IllegalStateException;
      
      public native void prepareAsync() throws IllegalStateException;
      
      • frameworks/base/media/jni/android_media_MediaPlayer.cpp
        {"_prepare",            "()V",                              (void *)android_media_MediaPlayer_prepare},
        {"prepareAsync",        "()V",                              (void *)android_media_MediaPlayer_prepareAsync},
        
        ......
        
        static void
        android_media_MediaPlayer_prepare(JNIEnv *env, jobject thiz)
        {
            //获取java层的mNativeContext,即mediaplayer指针对象
            sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
            if (mp == NULL ) {
                jniThrowException(env, "java/lang/IllegalStateException", NULL);
                return;
            }
        
            // Handle the case where the display surface was set before the mp was
            // initialized. We try again to make it stick.
            //在mediaplayer启动之前,获取IGraphicBufferProducer对象,重新设置了display surface,setDisplay接口可以在setDataSource之前被调用
            //MediaPlayer等生产者生产图形数据到Surface,Surface通过IGraphicBufferProducer把GraphicBuffer跨进程传输给消费者SurfaceFlinger,SurfaceFlinger根据WMS提供的窗口信息合成所有的Layer(对应于Surface),具体的合成策略由hwcomposerHAL模块决定并实施,最后也是由该模块送显到Display,而Gralloc模块则负责分配图形缓冲区
            sp<IGraphicBufferProducer> st = getVideoSurfaceTexture(env, thiz);
            mp->setVideoSurfaceTexture(st);
        
            //处理prepare结果
            process_media_player_call( env, thiz, mp->prepare(), "java/io/IOException", "Prepare failed." );
        }
        
        static void
        android_media_MediaPlayer_prepareAsync(JNIEnv *env, jobject thiz)
        {
            //获取java层的mNativeContext,即mediaplayer指针对象
            sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
            if (mp == NULL ) {
                jniThrowException(env, "java/lang/IllegalStateException", NULL);
                return;
            }
        
            // Handle the case where the display surface was set before the mp was
            // initialized. We try again to make it stick.
            sp<IGraphicBufferProducer> st = getVideoSurfaceTexture(env, thiz);
            mp->setVideoSurfaceTexture(st);
        
            //处理prepareAsync结果
            process_media_player_call( env, thiz, mp->prepareAsync(), "java/io/IOException", "Prepare Async failed." );
        }
        
        ......
        
        static sp<IGraphicBufferProducer>
        getVideoSurfaceTexture(JNIEnv* env, jobject thiz) {
            IGraphicBufferProducer * const p = (IGraphicBufferProducer*)env->GetLongField(thiz, fields.surface_texture);
            return sp<IGraphicBufferProducer>(p);
        }
        

        在这里插入图片描述

      • frameworks/av/media/libmedia/mediaplayer.cpp
        status_t MediaPlayer::setVideoSurfaceTexture(
                const sp<IGraphicBufferProducer>& bufferProducer)
        {
            ALOGV("setVideoSurfaceTexture");
            Mutex::Autolock _l(mLock);
            if (mPlayer == 0) return NO_INIT;
            return mPlayer->setVideoSurfaceTexture(bufferProducer);
        }
        
        ......
        
        status_t MediaPlayer::prepare()
        {
            ALOGV("prepare");
            Mutex::Autolock _l(mLock);
            mLockThreadId = getThreadId();
            //状态不对,还没有准备好
            if (mPrepareSync) {
                mLockThreadId = 0;
                return -EALREADY;
            }
            mPrepareSync = true;
            //prepareAsync_l
            status_t ret = prepareAsync_l();
            if (ret != NO_ERROR) {
                mLockThreadId = 0;
                return ret;
            }
        
            if (mPrepareSync) {
                //准备失败,阻塞等待准备完成
                mSignal.wait(mLock);  // wait for prepare done
                mPrepareSync = false;
            }
            ALOGV("prepare complete - status=%d", mPrepareStatus);
            mLockThreadId = 0;
            return mPrepareStatus;
        }
        
        status_t MediaPlayer::prepareAsync()
        {
            ALOGV("prepareAsync");
            Mutex::Autolock _l(mLock);
            return prepareAsync_l();
        }
        
        ......
        
        // must call with lock held
        status_t MediaPlayer::prepareAsync_l()
        {
            // Mediatek Android Patch Begin
            //如果是CTS测试
            if (isFromSpecificProcess(PROCESS_CTS))
            {
                Parcel data;
                data.writeInt32(DISABLE_PLAYER_RESOURCE_MANAGE);
                mPlayer->setParameter(KEY_PARAMETER_SET_USE_RM_WRAPPER_PLAYER, data);
            }
            // Mediatek Android Patch End
        
            if ( (mPlayer != 0) && ( mCurrentState & (MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED) ) ) {
                if (mAudioAttributesParcel != NULL) {
                    //设置audio参数
                    mPlayer->setParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES, *mAudioAttributesParcel);
                } else {
                    //设置audio流类型
                    mPlayer->setAudioStreamType(mStreamType);
                }
                //将播放器的状态置为MEDIA_PLAYER_PREPARING
                mCurrentState = MEDIA_PLAYER_PREPARING;
                //调用服务端的prepareAsync
                return mPlayer->prepareAsync();
            }
            ALOGE("prepareAsync called in state %d, mPlayer(%p)", mCurrentState, mPlayer.get());
            return INVALID_OPERATION;
        }
        
      • frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp
        status_t MediaPlayerService::Client::prepareAsync()
        {
            ALOGV("[%d] prepareAsync", mConnId);
            //获取创建好的播放器
            sp<MediaPlayerBase> p = getPlayer();
            if (p == 0) return UNKNOWN_ERROR;
        
            // Mediatek Android Patch Begin
            //如果播放器是mstar.multiple.player
            if (property_check_multiple_payerback_process("mstar.multiple.player") == true) {
                //支持倍数解码
                mEnableMultiDecode = true;
            }
        
            //如果是mstplayer
            if (mIsMstplayer) {
                bool IsMainPlayer = true;
                int static LastPid;
                if (LastPid == mPid && mMainClientId && mGetkeyvalue != KEY_PARAMETER_SET_DUAL_DECODE_PIP &&
                    mGetkeyvalue != KEY_PARAMETER_SET_SEAMLESS_MODE) {
                    Parcel data;
                    int key, keyValue;
                    IsMainPlayer = false;
                    if (mEnableMultiDecode) {
                        keyValue = 1;
                        data.writeInt32(keyValue);
                        key = KEY_PARAMETER_SET_MULTIPLE_PLAYER;
                        data.setDataPosition(0);
                        p->setParameter(key, data);
                    }
                }
                LastPid = mPid;
                if (IsMainPlayer && mGetkeyvalue != KEY_PARAMETER_SET_DUAL_DECODE_PIP)
                    mMainClientId = mConnId;
            }
            // Mediatek Android Patch End
            //调用播放器的prepareAsync
            status_t ret = p->prepareAsync();
        #if CALLBACK_ANTAGONIZER
            ALOGD("start Antagonizer");
            if (ret == NO_ERROR) mAntagonizer->start();
        #endif
            return ret;
        }
        
    • NuPlayer简单分析

      nuPlayer涉及的相关源代码路径
      在这里插入图片描述

      nuPlayer相关类结构图
      在这里插入图片描述

      nuPlayer流程图
      在这里插入图片描述

      • setDataSource
        • frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
          //控制指令都通过NuPlayerDriver来传达
          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),
              mLooper(new ALooper),
              mMediaClock(new MediaClock),
              //创建NuPlayer对象
              mPlayer(new NuPlayer(pid, mMediaClock)),
              mPlayerFlags(0),
              mAnalyticsItem(NULL),
              mClientUid(-1),
              mAtEOS(false),
              mLooping(false),
              mAutoLoop(false) {
              ALOGD("NuPlayerDriver(%p) created, clientPid(%d)", this, pid);
              mLooper->setName("NuPlayerDriver Looper");
          
              mMediaClock->init();
          
              // set up an analytics record
              mAnalyticsItem = new MediaAnalyticsItem(kKeyPlayer);
          
              /*NuPlayer实现的是AHanlder-ALooper-AMessage机制*/
              mLooper->start(
                      false, /* runOnCallingThread */
                      true,  /* canCallJava */
                      PRIORITY_AUDIO);
          
              mLooper->registerHandler(mPlayer);
          
              mPlayer->init(this);
          }
          
          ......
          
          //播放网络视频
          status_t NuPlayerDriver::setDataSource(
                  const sp<IMediaHTTPService> &httpService,
                  const char *url,
                  const KeyedVector<String8, String8> *headers) {
              ALOGV("setDataSource(%p) url(%s)", this, uriDebugString(url, false).c_str());
              Mutex::Autolock autoLock(mLock);
          
              if (mState != STATE_IDLE) {
                  return INVALID_OPERATION;
              }
          
              mState = STATE_SET_DATASOURCE_PENDING;
          
              //调用NuPlayer对象的setDataSourceAsync方法
              mPlayer->setDataSourceAsync(httpService, url, headers);
          
              //循环等待mPlayer->setDataSourceAsync完成
              while (mState == STATE_SET_DATASOURCE_PENDING) {
                  mCondition.wait(mLock);
              }
          
              return mAsyncResult;
          }
          
          //播放本地视频
          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;
          
              //调用NuPlayer对象的setDataSourceAsync方法
              mPlayer->setDataSourceAsync(fd, offset, length);
          
              //循环等待mPlayer->setDataSourceAsync完成
              while (mState == STATE_SET_DATASOURCE_PENDING) {
                  mCondition.wait(mLock);
              }
          
              return mAsyncResult;
          }
          
          ......
          
          //setDataSource完成,但播放器的状态还是STATE_UNPREPARED
          void NuPlayerDriver::notifySetDataSourceCompleted(status_t err) {
              Mutex::Autolock autoLock(mLock);
          
              CHECK_EQ(mState, STATE_SET_DATASOURCE_PENDING);
          
              mAsyncResult = err;
              mState = (err == OK) ? STATE_UNPREPARED : STATE_IDLE;
              //广播通知NuPlayerDriver::setDataSource设置完成
              mCondition.broadcast();
          }
          
          ......
          
          status_t NuPlayerDriver::prepareAsync() {
              ALOGV("prepareAsync(%p)", this);
              Mutex::Autolock autoLock(mLock);
          
              switch (mState) {
                  case STATE_UNPREPARED:
                      //把播放器状态置为STATE_PREPARING
                      mState = STATE_PREPARING;
                      mIsAsyncPrepare = true;
                      //最终进入到nuplayer的prepareAsync中
                      //用于初始化((比如构造函数、setDriver/setDataSourceAsync/prepareAsync/setVideoSurfaceTextureAsync))
                      mPlayer->prepareAsync();
                      return OK;
                  case STATE_STOPPED:
                      //播放器状态暂停啦
                      // this is really just paused. handle as seek to start
                      mAtEOS = false;
                      //把播放器状态置为STATE_STOPPED_AND_PREPARING
                      mState = STATE_STOPPED_AND_PREPARING;
                      mIsAsyncPrepare = true;
                      //用于播放控制(比如start/pause/seekToAsync)
                      mPlayer->seekToAsync(0, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */,
                              true /* needNotify */);
                      return OK;
                  default:
                      return INVALID_OPERATION;
              };
          }
          
        • frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
          //播放网络视频
          void NuPlayer::setDataSourceAsync(
                  const sp<IMediaHTTPService> &httpService,
                  const char *url,
                  const KeyedVector<String8, String8> *headers) {
          
              //发送消息的形式
              sp<AMessage> msg = new AMessage(kWhatSetDataSource, this);
              size_t len = strlen(url);
          
              sp<AMessage> notify = new AMessage(kWhatSourceNotify, this);
          
              sp<Source> source;
          // Mediatek Android Patch Begin
          #ifdef BUILD_WITH_MARLIN
              if (IsWasabiSourceUrl(url)) {
                  //这是啥?
                  source = WasabiSourceCreate(notify, url, headers, mUIDValid, mUID);
              } else
          #endif
          
              const char *CHINADRM_FEATURE = "CHINADRM.FEATURE";
              size_t idx;
              if (headers != NULL) {
                  for (idx = 0; idx < headers->size(); idx++) {
                      //判断是不是广电内容数字版权加密保护技术
                      if (!strncmp(headers->keyAt(idx), CHINADRM_FEATURE, strlen(CHINADRM_FEATURE)) && atoi(headers->valueAt(idx)) > 0) {
                          ALOGW("CHINADRM.FEATURE is enable for %s", url);
                          mIsChinaDrm = true;
                          break;
                      }
                  }
              }
          
          // Mediatek Android Patch End
              if (IsHTTPLiveURL(url)) {
                  //HLS协议
                  source = new HTTPLiveSource(notify, httpService, url, headers);
                  ALOGV("setDataSourceAsync HTTPLiveSource %s", url);
                  mDataSourceType = DATA_SOURCE_TYPE_HTTP_LIVE;
              } else if (!strncasecmp(url, "rtsp://", 7)) {
                  //rtsp协议
                  source = new RTSPSource(
                          notify, httpService, url, headers, mUIDValid, mUID);
                  ALOGV("setDataSourceAsync RTSPSource %s", url);
                  mDataSourceType = DATA_SOURCE_TYPE_RTSP;
              } else if ((!strncasecmp(url, "http://", 7)
                          || !strncasecmp(url, "https://", 8))
                              && ((len >= 4 && !strcasecmp(".sdp", &url[len - 4]))
                              || strstr(url, ".sdp?"))) {
                  //SDP会话协议
                  source = new RTSPSource(
                          notify, httpService, url, headers, mUIDValid, mUID, true);
                  ALOGV("setDataSourceAsync RTSPSource http/https/.sdp %s", url);
                  mDataSourceType = DATA_SOURCE_TYPE_RTSP;
              } else {
                  //本地播放
                  ALOGV("setDataSourceAsync GenericSource %s", url);
          
                  sp<GenericSource> genericSource =
                          new GenericSource(notify, mUIDValid, mUID, mMediaClock);
          
                  status_t err = genericSource->setDataSource(httpService, url, headers);
          
                  if (err == OK) {
                      source = genericSource;
                  } else {
                      ALOGE("Failed to set data source!");
                  }
          
                  // regardless of success/failure
                  mDataSourceType = DATA_SOURCE_TYPE_GENERIC_URL;
              }
              msg->setObject("source", source);
              msg->post();
          }
          
          //播放本地视频
          void NuPlayer::setDataSourceAsync(int fd, int64_t offset, int64_t length) {
              //发送消息的形式
              sp<AMessage> msg = new AMessage(kWhatSetDataSource, this);
          
              sp<AMessage> notify = new AMessage(kWhatSourceNotify, this);
          
              //重置Source数据
              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());
          
              //调用GenericSource中的setDataSource方法
              status_t err = source->setDataSource(fd, offset, length);
          
              if (err != OK) {
                  ALOGE("Failed to set data source!");
                  source = NULL;
              }
          
              msg->setObject("source", source);
              msg->post();
              mDataSourceType = DATA_SOURCE_TYPE_GENERIC_FD;
          }
          
          ......
          
          //nuPlayer的重要部分,大部分的操作都在此处完成
          void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
          switch (msg->what()) {
              case kWhatSetDataSource:
              {
                  ALOGV("kWhatSetDataSource");
          
                  CHECK(mSource == NULL);
          
                  status_t err = OK;
                  sp<RefBase> obj;
                  CHECK(msg->findObject("source", &obj));
                  if (obj != NULL) {
                      Mutex::Autolock autoLock(mSourceLock);
                      mSource = static_cast<Source *>(obj.get());
                  } else {
                      err = UNKNOWN_ERROR;
                  }
          
                  CHECK(mDriver != NULL);
                  //NuPlayer以mPlayer这个成员变量存在于NuPlayerDriver结构体中,同样的,NuPlayerDriver以 wp<NuPlayerDriver> mDriver; 的形式存在于NuPlayer中,它也是在NuPlayer的构造函数中赋值的。通过mDriver.promote()的方法就可以使弱指针升级成强指针sp<NuPlayerDriver> driver,这时候这个driver就是NuPlayerDriver
                  sp<NuPlayerDriver> driver = mDriver.promote();
                  if (driver != NULL) {
                      //setDataSource完成
                      driver->notifySetDataSourceCompleted(err);
                  }
                  break;
              }
          ......
          
          void NuPlayer::prepareAsync() {
              ALOGV("prepareAsync");
          
              (new AMessage(kWhatPrepare, this))->post();
          }
          
          ......
          
          case kWhatPrepare:
          {
              ALOGV("onMessageReceived kWhatPrepare");
          
              mSource->prepareAsync();
              break;
          }
          
        • frameworks/av/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp

          HLS协议

          HLS 概述

          HTTP Live Streaming(HLS)是苹果公司实现的基于HTTP的流媒体直播和点播协议,主要应用在iOS系统。相对于普通的流媒体,例如RTMP协议、RTSP协议、MMS协议等,HLS最大的优点是可以根据网络状况自动切换到不同码率的视频,如果网络状况较好,则会切换到高码率的视频,若发现网络状况不佳,则会逐渐过渡到低码率的视频。

          HLS框架结构图

          在这里插入图片描述

          我们首先将要直播的视频送到编码器中,编码器分别对视频和音频进行编码,然后输出到一个MPEG-2格式的传输流中,再由分段器将MPEG-2传输流进行分段,产生一系列等间隔的媒体片段,这些媒体片段一般很小并且保存成后缀为.ts的文件,同时生成一个指向这些媒体文件的索引文件,也就是我们很经常听到的.M3U8文件。完成分段之后将这些索引文件以及媒体文件上传到Web服务器上。客户端读取索引文件,然后按顺序请求下载索引文件中列出的媒体文件。下载后是一个ts文件。需要进行解压获得对应的媒体数据并解码后进行播放。由于在直播过程中服务器端会不断地将最新的直播数据生成新的小文件,并上传所以只要客户端不断地按顺序下载并播放从服务器获取到的文件,从整个过程上看就相当于实现了直播。而且由于分段文件的很短,客户端可以根据实际的带宽情况切换到不同码率的直播源,从而实现多码率的适配的目的。

          HLS播放流程

          1.获取不同带宽下对应的网络资源URI及音视频编解码,视频分辨率等信息的文件

          #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=899152,RESOLUTION=480x270,CODECS="avc1.4d4015,mp4a.40.5"
          http://hls.ftdp.com/video1_widld/m3u8/01.m3u8
          

          2.根据上述获取的信息初始化对应的编解码器

          3.获取第一个网络资源对应的分段索引列表(index文件)

          #EXTM3U
          #EXT-X-VERSION:3
          #EXT-X-TARGETDURATION:10
          #EXT-X-MEDIA-SEQUENCE:6532
          #EXT-X-KEY:METHOD=AES-128,URI="18319965201.key"
          #EXTINF:10,
          20125484T125708-01-6533.ts
          #EXT-X-KEY:METHOD=AES-128,URI="14319965205.key"
          #EXTINF:10,
          20125484T125708-01-6534.ts
          ....
          #EXTINF:8,
          20140804T125708-01-6593.ts
          

          4.获取某一个分片的Key

          5.请求下载某一个分片

          6.根据当前的带宽决定是否切换视频资源

          7.将下载的分片资源解密后送到解码器进行解码

          在这里插入图片描述

          //初始化(setDataSource完成)
          NuPlayer::HTTPLiveSource::HTTPLiveSource(
                  const sp<AMessage> &notify,
                  const sp<IMediaHTTPService> &httpService,
                  const char *url,
                  const KeyedVector<String8, String8> *headers)
              : Source(notify),
              mHTTPService(httpService),
              mURL(url),
              mFlags(0),
              mFinalResult(OK),
              mOffset(0),
              mFetchSubtitleDataGeneration(0),
              mFetchMetaDataGeneration(0),
              mHasMetadata(false),
              mMetadataSelected(false) {
              mBufferingSettings.mInitialMarkMs = kPrepareMarkMs;
              mBufferingSettings.mResumePlaybackMarkMs = kReadyMarkMs;
              if (headers) {
                  mExtraHeaders = *headers;
          
                  ssize_t index =
                      mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log"));
          
                  if (index >= 0) {
                      mFlags |= kFlagIncognito;
          
                      mExtraHeaders.removeItemsAt(index);
                  }
              }
          }
          
          ......
          
          void NuPlayer::HTTPLiveSource::prepareAsync() {
              //创建并启动一个Looper
              if (mLiveLooper == NULL) {
                  mLiveLooper = new ALooper;
                  mLiveLooper->setName("http live");
                  mLiveLooper->start();
          
                  mLiveLooper->registerHandler(this);
              }
          
              sp<AMessage> notify = new AMessage(kWhatSessionNotify, this);
          
              //构建LiveSession对象
              mLiveSession = new LiveSession(
                      notify,
                      (mFlags & kFlagIncognito) ? LiveSession::kFlagIncognito : 0,
                      mHTTPService);
          
              mLiveLooper->registerHandler(mLiveSession);
          
              mLiveSession->setBufferingSettings(mBufferingSettings);
              //创建一个异步连接会话
              mLiveSession->connectAsync(
                      mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders);
          }
          
        • frameworks/av/media/libstagefright/httplive/LiveSession.cpp
          void LiveSession::connectAsync(
                  const char *url, const KeyedVector<String8, String8> *headers) {
              //创建一个kWhatConnect并传入url
              sp<AMessage> msg = new AMessage(kWhatConnect, this);
              msg->setString("url", url);
          
              if (headers != NULL) {
                  msg->setPointer(
                          "headers",
                          new KeyedVector<String8, String8>(*headers));
              }
          
              msg->post();
          }
          
          ......
          
          case kWhatConnect:
          {
              onConnect(msg);
              break;
          }
          
          ......
          
          void LiveSession::onConnect(const sp<AMessage> &msg) {
              //获取传过来的Uri
              CHECK(msg->findString("url", &mMasterURL));
          
              // TODO currently we don't know if we are coming here from incognito mode
              ALOGI("onConnect %s", uriDebugString(mMasterURL).c_str());
          
              KeyedVector<String8, String8> *headers = NULL;
              if (!msg->findPointer("headers", (void **)&headers)) {
                  mExtraHeaders.clear();
              } else {
                  mExtraHeaders = *headers;
          
                  delete headers;
                  headers = NULL;
              }
          
              // create looper for fetchers
              //创建一个轮询器
              if (mFetcherLooper == NULL) {
                  mFetcherLooper = new ALooper();
          
                  mFetcherLooper->setName("Fetcher");
                  mFetcherLooper->start(false, /* runOnCallingThread */
                                      true  /* canCallJava */);
              }
          
              // create fetcher to fetch the master playlist
              //获取不同带宽下对应的网络资源URI及音视频编解码信息
              addFetcher(mMasterURL.c_str())->fetchPlaylistAsync();
          }
          
          ......
          
          sp<PlaylistFetcher> LiveSession::addFetcher(const char *uri) {
              ssize_t index = mFetcherInfos.indexOfKey(uri);
          
              if (index >= 0) {
                  return NULL;
              }
          
              sp<AMessage> notify = new AMessage(kWhatFetcherNotify, this);
              notify->setString("uri", uri);
              notify->setInt32("switchGeneration", mSwitchGeneration);
          
              FetcherInfo info;
              //创建一个PlaylistFetcher并返回
              info.mFetcher = new PlaylistFetcher(
                      notify, this, uri, mCurBandwidthIndex, mSubtitleGeneration);
              info.mDurationUs = -1ll;
              info.mToBeRemoved = false;
              info.mToBeResumed = false;
              mFetcherLooper->registerHandler(info.mFetcher);
          
              mFetcherInfos.add(uri, info);
          
              return info.mFetcher;
          }
          
        • frameworks/av/media/libstagefright/httplive/PlaylistFetcher.cpp
          void PlaylistFetcher::fetchPlaylistAsync() {
              (new AMessage(kWhatFetchPlaylist, this))->post();
          }
          
          ......
          
          case kWhatFetchPlaylist:
          {
              bool unchanged;
              //获取一个M3U8Parser
              sp<M3UParser> playlist = mHTTPDownloader->fetchPlaylist(
                      mURI.c_str(), NULL /* curPlaylistHash */, &unchanged);
          
              sp<AMessage> notify = mNotify->dup();
              notify->setInt32("what", kWhatPlaylistFetched);
              //将playlist返回
              notify->setObject("playlist", playlist);
              notify->post();
              break;
          }
          
        • frameworks/av/media/libstagefright/httplive/HTTPDownloader.cpp
          ssize_t HTTPDownloader::fetchBlock(
                  const char *url, sp<ABuffer> *out,
                  int64_t range_offset, int64_t range_length,
                  uint32_t block_size, /* download block size */
                  String8 *actualUrl,
                  bool reconnect /* force connect HTTP when resuing source */) {
              //没有连接
              if (isDisconnecting()) {
                  return ERROR_NOT_CONNECTED;
              }
          
              off64_t size;
          
              if (reconnect) {
                  //恢复播放源需要强制连接HTTP
                  if (!strncasecmp(url, "file://", 7)) {
                      //本地文件类的播放源
                      mDataSource = new FileSource(url + 7);
                  } else if (strncasecmp(url, "http://", 7)
                          && strncasecmp(url, "https://", 8)) {
                      //不是http或https协议,不支持
                      return ERROR_UNSUPPORTED;
                  } else {
                      KeyedVector<String8, String8> headers = mExtraHeaders;
                      if (range_offset > 0 || range_length >= 0) {
                          //添加分段请求的range
                          headers.add(
                                  String8("Range"),
                                  String8(
                                      AStringPrintf(
                                          "bytes=%lld-%s",
                                          range_offset,
                                          range_length < 0
                                              ? "" : AStringPrintf("%lld",
                                                      range_offset + range_length - 1).c_str()).c_str()));
                      }
          
                      status_t err = mHTTPDataSource->connect(url, &headers);
          
                      if (isDisconnecting()) {
                          return ERROR_NOT_CONNECTED;
                      }
          
                      if (err != OK) {
                          return err;
                      }
          
                      mDataSource = mHTTPDataSource;
                  }
              }
          
              status_t getSizeErr = mDataSource->getSize(&size);
          
              if (isDisconnecting()) {
                  return ERROR_NOT_CONNECTED;
              }
          
              if (getSizeErr != OK) {
                  //获取size大小错误时,赋予最大值65536
                  size = 65536;
              }
          
              //初始化一个缓冲队列buffer
              sp<ABuffer> buffer = *out != NULL ? *out : new ABuffer(size);
              if (*out == NULL) {
                  //下载的数据为空时,设置buffer从头开始
                  buffer->setRange(0, 0);
              }
          
              ssize_t bytesRead = 0;
              // adjust range_length if only reading partial block
              // 如果仅读取部分块,则调整范围长度
              if (block_size > 0 && (range_length == -1 || (int64_t)(buffer->size() + block_size) < range_length)) {
                  range_length = buffer->size() + block_size;
              }
              //循环下载
              for (;;) {
                  // Only resize when we don't know the size.
                  //只有当我们不知道大小时才调整大小
                  size_t bufferRemaining = buffer->capacity() - buffer->size();
                  if (bufferRemaining == 0 && getSizeErr != OK) {
                      //当buffer剩余的容量为0或者获取buffer大小错误时
                      size_t bufferIncrement = buffer->size() / 2;
                      if (bufferIncrement < 32768) {
                          bufferIncrement = 32768;
                      }
                      //增加的下载缓冲区
                      bufferRemaining = bufferIncrement;
          
                      ALOGV("increasing download buffer to %zu bytes",
                          buffer->size() + bufferRemaining);
          
                      sp<ABuffer> copy = new ABuffer(buffer->size() + bufferRemaining);
                      if (copy->data() == NULL) {
                          android_errorWriteLog(0x534e4554, "68399439");
                          ALOGE("not enough memory to download: requesting %zu + %zu",
                                  buffer->size(), bufferRemaining);
                          return NO_MEMORY;
                      }
                      memcpy(copy->data(), buffer->data(), buffer->size());
                      copy->setRange(0, buffer->size());
          
                      buffer = copy;
                  }
          
                  size_t maxBytesToRead = bufferRemaining;
                  if (range_length >= 0) {
                      int64_t bytesLeftInRange = range_length - buffer->size();
                      if (bytesLeftInRange < 0) {
                          ALOGE("range_length %" PRId64 " wrapped around", range_length);
                          return ERROR_OUT_OF_RANGE;
                      } else if (bytesLeftInRange < (int64_t)maxBytesToRead) {
                          maxBytesToRead = bytesLeftInRange;
          
                          if (bytesLeftInRange == 0) {
                              break;
                          }
                      }
                  }
          
                  // The DataSource is responsible for informing us of error (n < 0) or eof (n == 0)
                  // to help us break out of the loop.
                  ssize_t n = mDataSource->readAt(
                          buffer->size(), buffer->data() + buffer->size(),
                          maxBytesToRead);
          
                  if (isDisconnecting()) {
                      return ERROR_NOT_CONNECTED;
                  }
          
                  if (n < 0) {
                      return n;
                  }
          
                  if (n == 0) {
                      break;
                  }
          
                  buffer->setRange(0, buffer->size() + (size_t)n);
                  bytesRead += n;
              }
          
              *out = buffer;
              if (actualUrl != NULL) {
                  *actualUrl = mDataSource->getUri();
                  if (actualUrl->isEmpty()) {
                      *actualUrl = url;
                  }
              }
          
              return bytesRead;
          }
          
          ssize_t HTTPDownloader::fetchFile(
                  const char *url, sp<ABuffer> *out, String8 *actualUrl) {
              ssize_t err = fetchBlock(url, out, 0, -1, 0, actualUrl, true /* reconnect */);
          
              // close off the connection after use
              mHTTPDataSource->disconnect();
          
              return err;
          }
          
          //从服务器端获取到m3u8 playlist内容并存放到buffer缓存区
          sp<M3UParser> HTTPDownloader::fetchPlaylist(
                  const char *url, uint8_t *curPlaylistHash, bool *unchanged) {
              ALOGV("fetchPlaylist '%s'", url);
          
              *unchanged = false;
          
              sp<ABuffer> buffer;
              String8 actualUrl;
              //调用fetchFile
              ssize_t err = fetchFile(url, &buffer, &actualUrl);
          
              // close off the connection after use
              //使用后关闭连接
              mHTTPDataSource->disconnect();
          
              if (err <= 0) {
                  return NULL;
              }
          
              // MD5 functionality is not available on the simulator, treat all
              // playlists as changed.
              // MD5功能在模拟器上不可用,请将所有播放列表视为已更改
          
          #if defined(__ANDROID__)
              uint8_t hash[16];
          
              MD5_CTX m;
              MD5_Init(&m);
              MD5_Update(&m, buffer->data(), buffer->size());
          
              MD5_Final(hash, &m);
          
              //通过hash值判断播放的文件是否有改变
              if (curPlaylistHash != NULL && !memcmp(hash, curPlaylistHash, 16)) {
                  // playlist unchanged
                  *unchanged = true;
          
                  return NULL;
              }
          #endif
          
              //将获取到的缓存数据包装成M3UParser
              sp<M3UParser> playlist =
                  new M3UParser(actualUrl.string(), buffer->data(), buffer->size());
          
              if (playlist->initCheck() != OK) {
                  ALOGE("failed to parse .m3u8 playlist");
          
                  return NULL;
              }
          
          #if defined(__ANDROID__)
              if (curPlaylistHash != NULL) {
          
                  memcpy(curPlaylistHash, hash, sizeof(hash));
              }
          #endif
          
              return playlist;
          }
          
        • frameworks/av/media/libstagefright/httplive/M3UParser.cpp
          M3UParser::M3UParser(
                  const char *baseURI, const void *data, size_t size)
              : mInitCheck(NO_INIT),
              mBaseURI(baseURI),
              mIsExtM3U(false),
              mIsVariantPlaylist(false),
              mIsComplete(false),
              mIsEvent(false),
              mFirstSeqNumber(-1),
              mLastSeqNumber(-1),
              mTargetDurationUs(-1ll),
              mDiscontinuitySeq(0),
              mDiscontinuityCount(0),
              mSelectedIndex(-1) {
              //解析下载的缓存数据
              mInitCheck = parse(data, size);
          }
          
          ......
          
          //解析下载的缓存数据
          status_t M3UParser::parse(const void *_data, size_t size) {
              int32_t lineNo = 0;
          
              sp<AMessage> itemMeta;
          
              const char *data = (const char *)_data;
              size_t offset = 0;
              uint64_t segmentRangeOffset = 0;
              while (offset < size) {
                  size_t offsetLF = offset;
                  //寻找第一个换行符
                  while (offsetLF < size && data[offsetLF] != '\n') {
                      ++offsetLF;
                  }
          
                  AString line;
                  if (offsetLF > offset && data[offsetLF - 1] == '\r') {
                      line.setTo(&data[offset], offsetLF - offset - 1);
                  } else {
                      line.setTo(&data[offset], offsetLF - offset);
                  }
          
                  // ALOGI("#%s#", line.c_str());
          
                  if (line.empty()) {
                      offset = offsetLF + 1;
                      continue;
                  }
          
                  if (lineNo == 0 && line == "#EXTM3U") {
                      mIsExtM3U = true;
                  }
          
                  if (mIsExtM3U) {
                      status_t err = OK;
          
                      if (line.startsWith("#EXT-X-TARGETDURATION")) {
                          if (mIsVariantPlaylist) {
                              return ERROR_MALFORMED;
                          }
                          err = parseMetaData(line, &mMeta, "target-duration");
                      } else if (line.startsWith("#EXT-X-MEDIA-SEQUENCE")) {
                          if (mIsVariantPlaylist) {
                              return ERROR_MALFORMED;
                          }
                          err = parseMetaData(line, &mMeta, "media-sequence");
                      } else if (line.startsWith("#EXT-X-KEY")) {
                          if (mIsVariantPlaylist) {
                              return ERROR_MALFORMED;
                          }
                          err = parseCipherInfo(line, &itemMeta, mBaseURI);
                      } else if (line.startsWith("#EXT-X-ENDLIST")) {
                          mIsComplete = true;
                      } else if (line.startsWith("#EXT-X-PLAYLIST-TYPE:EVENT")) {
                          mIsEvent = true;
                      } else if (line.startsWith("#EXTINF")) {
                          if (mIsVariantPlaylist) {
                              return ERROR_MALFORMED;
                          }
                          err = parseMetaDataDuration(line, &itemMeta, "durationUs");
                      } else if (line.startsWith("#EXT-X-DISCONTINUITY-SEQUENCE")) {
                          if (mIsVariantPlaylist) {
                              return ERROR_MALFORMED;
                          }
                          size_t seq;
                          err = parseDiscontinuitySequence(line, &seq);
                          if (err == OK) {
                              mDiscontinuitySeq = seq;
                              ALOGI("mDiscontinuitySeq %zu", mDiscontinuitySeq);
                          } else {
                              ALOGI("Failed to parseDiscontinuitySequence %d", err);
                          }
                      } else if (line.startsWith("#EXT-X-DISCONTINUITY")) {
                          if (mIsVariantPlaylist) {
                              return ERROR_MALFORMED;
                          }
                          if (itemMeta == NULL) {
                              itemMeta = new AMessage;
                          }
                          itemMeta->setInt32("discontinuity", true);
                          ++mDiscontinuityCount;
                      } else if (line.startsWith("#EXT-X-STREAM-INF")) {
                          if (mMeta != NULL) {
                              return ERROR_MALFORMED;
                          }
                          mIsVariantPlaylist = true;
                          err = parseStreamInf(line, &itemMeta);
                      } else if (line.startsWith("#EXT-X-BYTERANGE")) {
                          if (mIsVariantPlaylist) {
                              return ERROR_MALFORMED;
                          }
          
                          uint64_t length, offset;
                          err = parseByteRange(line, segmentRangeOffset, &length, &offset);
          
                          if (err == OK) {
                              if (itemMeta == NULL) {
                                  itemMeta = new AMessage;
                              }
          
                              itemMeta->setInt64("range-offset", offset);
                              itemMeta->setInt64("range-length", length);
          
                              segmentRangeOffset = offset + length;
                          }
                      } else if (line.startsWith("#EXT-X-MEDIA")) {
                          err = parseMedia(line);
                      }
          
                      if (err != OK) {
                          return err;
                      }
                  }
          
                  if (!line.startsWith("#")) {
                      if (itemMeta == NULL) {
                          ALOGV("itemMeta == NULL");
                          return ERROR_MALFORMED;
                      }
                      if (!mIsVariantPlaylist) {
                          int64_t durationUs;
                          if (!itemMeta->findInt64("durationUs", &durationUs)) {
                              return ERROR_MALFORMED;
                          }
                          itemMeta->setInt32("discontinuity-sequence",
                                  mDiscontinuitySeq + mDiscontinuityCount);
                      }
          
                      mItems.push();
                      Item *item = &mItems.editItemAt(mItems.size() - 1);
          
                      CHECK(MakeURL(mBaseURI.c_str(), line.c_str(), &item->mURI));
          
                      item->mMeta = itemMeta;
          
                      itemMeta.clear();
                  }
          
                  offset = offsetLF + 1;
                  ++lineNo;
              }
          
              // error checking of all fields that's required to appear once
              // (currently only checking "target-duration"), and
              // initialization of playlist properties (eg. mTargetDurationUs)
              if (!mIsVariantPlaylist) {
                  int32_t targetDurationSecs;
                  if (mMeta == NULL || !mMeta->findInt32(
                          "target-duration", &targetDurationSecs)) {
                      ALOGE("Media playlist missing #EXT-X-TARGETDURATION");
                      return ERROR_MALFORMED;
                  }
                  mTargetDurationUs = targetDurationSecs * 1000000ll;
          
                  mFirstSeqNumber = 0;
                  if (mMeta != NULL) {
                      mMeta->findInt32("media-sequence", &mFirstSeqNumber);
                  }
                  mLastSeqNumber = mFirstSeqNumber + mItems.size() - 1;
              }
          
              for (size_t i = 0; i < mItems.size(); ++i) {
                  sp<AMessage> meta = mItems.itemAt(i).mMeta;
                  const char *keys[] = {"audio", "video", "subtitles"};
                  for (size_t j = 0; j < sizeof(keys) / sizeof(const char *); ++j) {
                      AString groupID;
                      if (meta->findString(keys[j], &groupID)) {
                          ssize_t groupIndex = mMediaGroups.indexOfKey(groupID);
                          if (groupIndex < 0) {
                              ALOGE("Undefined media group '%s' referenced in stream info.",
                                  groupID.c_str());
                              return ERROR_MALFORMED;
                          }
                      }
                  }
              }
          
              return OK;
          }
          
        • frameworks/av/media/libmediaplayerservice/nuplayer/GenericSource.cpp
          status_t NuPlayer::GenericSource::setDataSource(
                  int fd, int64_t offset, int64_t length) {
              Mutex::Autolock _l(mLock);
              ALOGV("setDataSource %d/%lld/%lld", fd, (long long)offset, (long long)length);
          
              //重置相关变量
              resetDataSource();
          
              //dup函数是返回一个指向同一个文件的文件描述符
              mFd = dup(fd);
              mOffset = offset;
              mLength = length;
          
              // delay data source creation to prepareAsync() to avoid blocking
              // the calling thread in setDataSource for any significant time.
              return OK;
          }
          
          ......
          
          void NuPlayer::GenericSource::prepareAsync() {
              Mutex::Autolock _l(mLock);
              ALOGV("prepareAsync: (looper: %d)", (mLooper != NULL));
          
              if (mLooper == NULL) {
                  mLooper = new ALooper;
                  mLooper->setName("generic");
                  mLooper->start();
          
                  mLooper->registerHandler(this);
              }
          
              sp<AMessage> msg = new AMessage(kWhatPrepareAsync, this);
              msg->post();
          }
          
          ......
          
          case kWhatPrepareAsync:
          {
              onPrepareAsync();
              break;
          }
          
          ......
          
          void NuPlayer::GenericSource::onPrepareAsync() {
              ALOGV("onPrepareAsync: mDataSource: %d", (mDataSource != NULL));
          
              // delayed data source creation
              //延迟数据源创建
              if (mDataSource == NULL) {
                  // set to false first, if the extractor
                  // comes back as secure, set it to true then.
                  //等待提取器extractor返回是安全的,再设置为true
                  mIsSecure = false;
          
                  if (!mUri.empty()) {
                      //流媒体服务器创建dataSource
                      const char* uri = mUri.c_str();
                      String8 contentType;
          
                      if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
                          mHttpSource = DataSourceFactory::CreateMediaHTTP(mHTTPService);
                          if (mHttpSource == NULL) {
                              ALOGE("Failed to create http source!");
                              notifyPreparedAndCleanup(UNKNOWN_ERROR);
                              return;
                          }
                      }
          
                      mLock.unlock();
                      // This might take long time if connection has some issue.
                      //如果连接出现问题,这可能需要很长时间
                      sp<DataSource> dataSource = DataSourceFactory::CreateFromURI(
                          mHTTPService, uri, &mUriHeaders, &contentType,
                          static_cast<HTTPBase *>(mHttpSource.get()));
                      mLock.lock();
                      if (!mDisconnected) {
                          mDataSource = dataSource;
                      }
                  } else {
                      //"media.stagefright.extractremote"是否为true,若是,就会用binder获取"media.extractor"服务,然后创建extractor,否则用本地的extractor。
                      if (property_get_bool("media.stagefright.extractremote", true) &&
                              !FileSource::requiresDrm(mFd, mOffset, mLength, nullptr /* mime */)) {
                          sp<IBinder> binder =
                                  defaultServiceManager()->getService(String16("media.extractor"));
                          if (binder != nullptr) {
                              ALOGD("FileSource remote");
                              sp<IMediaExtractorService> mediaExService(
                                      interface_cast<IMediaExtractorService>(binder));
                              sp<IDataSource> source =
                                      mediaExService->makeIDataSource(mFd, mOffset, mLength);
                              ALOGV("IDataSource(FileSource): %p %d %lld %lld",
                                      source.get(), mFd, (long long)mOffset, (long long)mLength);
                              if (source.get() != nullptr) {
                                  mDataSource = CreateDataSourceFromIDataSource(source);
                                  if (mDataSource != nullptr) {
                                      // Close the local file descriptor as it is not needed anymore.
                                      close(mFd);
                                      mFd = -1;
                                  }
                              } else {
                                  ALOGW("extractor service cannot make data source");
                              }
                          } else {
                              ALOGW("extractor service not running");
                          }
                      }
                      if (mDataSource == nullptr) {
                          ALOGD("FileSource local");
                          mDataSource = new FileSource(mFd, mOffset, mLength);
                      }
                      // TODO: close should always be done on mFd, see the lines following
                      // CreateDataSourceFromIDataSource above,
                      // and the FileSource constructor should dup the mFd argument as needed.
                      mFd = -1;
                  }
          
                  if (mDataSource == NULL) {
                      ALOGE("Failed to create data source!");
                      notifyPreparedAndCleanup(UNKNOWN_ERROR);
                      return;
                  }
              }
          
              if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
                  //当uri以"http://"为开头,创建NuCachedSource2
                  mCachedSource = static_cast<NuCachedSource2 *>(mDataSource.get());
              }
          
              // For cached streaming cases, we need to wait for enough
              // buffering before reporting prepared.
              mIsStreaming = (mCachedSource != NULL);
          
              // init extractor from data source
              // 初始化extractor
              status_t err = initFromDataSource();
          
              if (err != OK) {
                  ALOGE("Failed to init from data source!");
                  //上报prepare结果
                  notifyPreparedAndCleanup(err);
                  return;
              }
          
              if (mVideoTrack.mSource != NULL) {
                  sp<MetaData> meta = getFormatMeta_l(false /* audio */);
                  sp<AMessage> msg = new AMessage;
                  err = convertMetaDataToMessage(meta, &msg);
                  if(err != OK) {
                      notifyPreparedAndCleanup(err);
                      return;
                  }
                  // 上报视频分辨率
                  notifyVideoSizeChanged(msg);
              }
          
              // 上报函数调用正常结束
              notifyFlagsChanged(
                      // FLAG_SECURE will be known if/when prepareDrm is called by the app
                      // FLAG_PROTECTED will be known if/when prepareDrm is called by the app
                      FLAG_CAN_PAUSE |
                      FLAG_CAN_SEEK_BACKWARD |
                      FLAG_CAN_SEEK_FORWARD |
                      FLAG_CAN_SEEK);
          
              finishPrepareAsync();
          
              ALOGV("onPrepareAsync: Done");
          }
          
          ......
          
          status_t NuPlayer::GenericSource::initFromDataSource() {
              sp<IMediaExtractor> extractor;
              CHECK(mDataSource != NULL);
              sp<DataSource> dataSource = mDataSource;
          
              mLock.unlock();
              // This might take long time if data source is not reliable.
              //在此函数中会判断"media.stagefright.extractremote"是否为true,若是,就会用binder获取"media.extractor"服务, 然后创建extractor,否则用本地的extractor,可能会耗时一段时间。
              extractor = MediaExtractorFactory::Create(dataSource, NULL);
          
              if (extractor == NULL) {
                  ALOGE("initFromDataSource, cannot create extractor!");
                  return UNKNOWN_ERROR;
              }
          
              /**metadata包含如下数据
                  持续时间:(数字)FLV的长度(以秒为单位)。FLVMDI计算此值。
                  lasttimestamp:(数字)FLV文件中最后一个标记的时间戳。
                  lastkeyframetimestamp:(数字)最后一个视频标记的时间戳,它是关键帧。可能需要此信息,因为在此时间之后搜索帧通常不起作用。
                  宽度:(数字)视频的宽度(以像素为单位)(Flash exporter 1.1将其设置为0)。
                  高度:(数字)视频的高度(以像素为单位)(Flash exporter 1.1将其设置为0)。
                  videodatarate:(数字)FLVMDI不计算此值,如果存在,则将其导入(默认值为0)。
                  audiodatarate:(数字)FLVMDI不计算此值,如果存在,则将其导入(默认值为0)。
                  帧率:(数字)FLVMDI计算此值,但如果不是0,则使用导入的值。
                  creationdate:(字符串)FLVMDI无法计算此值并导入它(如果存在)(默认为“未知”)。
                  filesize:(Number)文件大小(以字节为单位)(包括注入的数据)。
                  videosize:(数字)文件中视频标记的总大小(字节)。
                  audiosize:(数字)文件中音频标记的总大小(字节)。
                  datasize:(Number)文件中数据标记的总大小(以字节为单位)。
                  metadatacreator:(字符串)将设置为“Manitu组FLV元数据注入器2”。
                  metadatadate:(日期)添加了日期和时间元数据(请注意,这不是类似于
                  “creationdate”的字符串类型。
                  xtradata:(字符串)如果指定,则附加字符串数据。
                  VideoCodeId:(编号)FLV中使用的视频编解码器ID编号(Sorenson H.263=2,屏幕视频=3,On2 VP6=4和5,屏幕视频V2=6)。
                  audiocodecid:(编号)FLV中使用的音频编解码器ID编号(未压缩=0,ADPCM=1,MP3=2,Nellymore=5和6)。
                  音频延迟:(数字)以秒为单位的音频延迟。Flash 8编码器延迟视频预编器与音频同步(音频和视频不会在时间0同时启动,视频启动稍晚)。该值对于Flash 8Video编码器注入的提示点也很重要,因为提示点的逻辑时间和它们插入LF的物理时间不一致(在编码之前注入提示点,当视频被“音频延迟”秒移位时,提示点也被移位,并且它们在FLV中的物理时间发生变化)。
                  canSeekToEnd:(布尔)如果最后一个视频标记是关键帧,因此可以进行“搜索”,则为True。
                  关键帧:(对象)
              */
              sp<MetaData> fileMeta = extractor->getMetaData();// 获取metadata
          
              size_t numtracks = extractor->countTracks();// 获取track数
              if (numtracks == 0) {
                  ALOGE("initFromDataSource, source has no track!");
                  return UNKNOWN_ERROR;
              }
          
              mLock.lock();
              mFileMeta = fileMeta;
              if (mFileMeta != NULL) {
                  int64_t duration;
                  if (mFileMeta->findInt64(kKeyDuration, &duration)) {
                      //赋值音视频时长
                      mDurationUs = duration;
                  }
              }
          
              //总码率
              int32_t totalBitrate = 0;
          
              //流媒体类型数组
              mMimes.clear();
          
              //遍历track通道,获取每个track的信息
              for (size_t i = 0; i < numtracks; ++i) {
                  sp<IMediaSource> track = extractor->getTrack(i);
                  if (track == NULL) {
                      continue;
                  }
          
                  sp<MetaData> meta = extractor->getTrackMetaData(i);//获取当前通道的metadata
                  if (meta == NULL) {
                      ALOGE("no metadata for track %zu", i);
                      return UNKNOWN_ERROR;
                  }
          
                  const char *mime;
                  CHECK(meta->findCString(kKeyMIMEType, &mime));//获取当前流类型
          
                  ALOGV("initFromDataSource track[%zu]: %s", i, mime);
          
                  // Do the string compare immediately with "mime",
                  // we can't assume "mime" would stay valid after another
                  // extractor operation, some extractors might modify meta
                  // during getTrack() and make it invalid.
                  if (!strncasecmp(mime, "audio/", 6)) {
                      //如果是音频类的流
                      if (mAudioTrack.mSource == NULL) {
                          mAudioTrack.mIndex = i;
                          mAudioTrack.mSource = track;
                          //创建一个音频获取器
                          mAudioTrack.mPackets =
                              new AnotherPacketSource(mAudioTrack.mSource->getFormat());
                          
                          /**  常用的音频类型
                               static const MimeToRole kMimeToRole[] = {
                                  { MEDIA_MIMETYPE_AUDIO_MPEG,
                                      "audio_decoder.mp3", "audio_encoder.mp3" },
                                  { MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I,
                                      "audio_decoder.mp1", "audio_encoder.mp1" },
                                  { MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II,
                                      "audio_decoder.mp2", "audio_encoder.mp2" },
                                  { MEDIA_MIMETYPE_AUDIO_AMR_NB,
                                      "audio_decoder.amrnb", "audio_encoder.amrnb" },
                                  { MEDIA_MIMETYPE_AUDIO_AMR_WB,
                                      "audio_decoder.amrwb", "audio_encoder.amrwb" },
                                  { MEDIA_MIMETYPE_AUDIO_AAC,
                                      "audio_decoder.aac", "audio_encoder.aac" },
                                  { MEDIA_MIMETYPE_AUDIO_VORBIS,
                                      "audio_decoder.vorbis", "audio_encoder.vorbis" },
                                  { MEDIA_MIMETYPE_AUDIO_OPUS,
                                      "audio_decoder.opus", "audio_encoder.opus" },
                                  { MEDIA_MIMETYPE_AUDIO_G711_MLAW,
                                      "audio_decoder.g711mlaw", "audio_encoder.g711mlaw" },
                                  { MEDIA_MIMETYPE_AUDIO_G711_ALAW,
                                      "audio_decoder.g711alaw", "audio_encoder.g711alaw" },
                                  { MEDIA_MIMETYPE_VIDEO_AVC,
                                      "video_decoder.avc", "video_encoder.avc" },
                                  { MEDIA_MIMETYPE_VIDEO_HEVC,
                                      "video_decoder.hevc", "video_encoder.hevc" },
                                  { MEDIA_MIMETYPE_VIDEO_MPEG4,
                                      "video_decoder.mpeg4", "video_encoder.mpeg4" },
                                  { MEDIA_MIMETYPE_VIDEO_H263,
                                      "video_decoder.h263", "video_encoder.h263" },
                                  { MEDIA_MIMETYPE_VIDEO_VP8,
                                      "video_decoder.vp8", "video_encoder.vp8" },
                                  { MEDIA_MIMETYPE_VIDEO_VP9,
                                      "video_decoder.vp9", "video_encoder.vp9" },
                                  { MEDIA_MIMETYPE_AUDIO_RAW,
                                      "audio_decoder.raw", "audio_encoder.raw" },
                                  { MEDIA_MIMETYPE_VIDEO_DOLBY_VISION,
                                      "video_decoder.dolby-vision", "video_encoder.dolby-vision" },
                                  { MEDIA_MIMETYPE_AUDIO_FLAC,
                                      "audio_decoder.flac", "audio_encoder.flac" },
                                  { MEDIA_MIMETYPE_AUDIO_MSGSM,
                                      "audio_decoder.gsm", "audio_encoder.gsm" },
                                  { MEDIA_MIMETYPE_VIDEO_MPEG2,
                                      "video_decoder.mpeg2", "video_encoder.mpeg2" },
                                  { MEDIA_MIMETYPE_AUDIO_AC3,
                                      "audio_decoder.ac3", "audio_encoder.ac3" },
                                  { MEDIA_MIMETYPE_AUDIO_EAC3,
                                      "audio_decoder.eac3", "audio_encoder.eac3" },
                                  { MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC,
                                      "image_decoder.heic", "image_encoder.heic" },
                                  // Medaitek Android Patch Begin
                                  { MEDIA_MIMETYPE_AUDIO_HW_AAC,
                                      "audio_decoder.hwaac", "audio_encoder.hwaac" },
                                  { MEDIA_MIMETYPE_AUDIO_DTS,
                                      "audio_decoder.dts", "audio_encoder.dts" },
                                  { MEDIA_MIMETYPE_AUDIO_DTS_HD,
                                      "audio_decoder.dtshd", "audio_encoder.dtshd" },
                                  { MEDIA_MIMETYPE_AUDIO_DTS_EXPRESS,
                                      "audio_decoder.dtse", "audio_encoder.dtse" },
                                  { MEDIA_MIMETYPE_AUDIO_APE,
                                      "audio_decoder.ape", "audio_encoder.ape" },
                                  { MEDIA_MIMETYPE_AUDIO_WMA,
                                      "audio_decoder.wma", "audio_encoder.wma" },
                                  { MEDIA_MIMETYPE_AUDIO_ADPCM_MS,
                                      "audio_decoder.adpcmms", "audio_encoder.adpcmms" },
                                  { MEDIA_MIMETYPE_AUDIO_ADPCM_IMA,
                                      "audio_decoder.adpcmima", "audio_encoder.adpcmima" },
                                  { MEDIA_MIMETYPE_AUDIO_WMAPRO,
                                      "audio_decoder.wmapro", "audio_encoder.wmapro" },
                                  { MEDIA_MIMETYPE_VIDEO_MJPEG,
                                      "video_decoder.mjpeg", "video_encoder.mjpeg" },
                                  { MEDIA_MIMETYPE_VIDEO_WMV,
                                      "video_decoder.wmv", "video_encoder.wmv" },
                                  { MEDIA_MIMETYPE_VIDEO_VP6,
                                      "video_decoder.vp6", "video_encoder.vp6" },
                                  { MEDIA_MIMETYPE_VIDEO_AVS,
                                      "video_decoder.avs", "video_encoder.avs" },
                                  { MEDIA_MIMETYPE_VIDEO_REAL_VIDEO,
                                      "video_decoder.rv", "video_encoder.rv" },
                                  { MEDIA_MIMETYPE_AUDIO_REAL_AUDIO,
                                      "audio_decoder.ra", "audio_encoder.ra" },
                                  { MEDIA_MIMETYPE_VIDEO_AVS2,
                                      "video_decoder.avs2", "video_encoder.avs2" },
                                  { MEDIA_MIMETYPE_VIDEO_VC1,
                                      "video_decoder.vc1", "video_encoder.vc1" },
                                  { MEDIA_MIMETYPE_VIDEO_FLV,
                                      "video_decoder.flv", "video_encoder.flv" },
                                  { MEDIA_MIMETYPE_VIDEO_DIVX3,
                                      "video_decoder.divx311", "video_encoder.divx311" },
                                  { MEDIA_MIMETYPE_VIDEO_DIVX4,
                                      "video_decoder.divx412", "video_encoder.divx412" },
                                  { MEDIA_MIMETYPE_VIDEO_RV,
                                      "video_decoder.rv", "video_encoder.rv" },
                                  { MEDIA_MIMETYPE_VIDEO_WVC1,
                                      "video_decoder.vc1", "video_encoder.vc1" },
                                  { MEDIA_MIMETYPE_VIDEO_WMV3,
                                      "video_decoder.wmv3", "video_encoder.wmv3" },
                                  { MEDIA_MIMETYPE_VIDEO_MJPG,
                                      "video_decoder.mjpg", "video_encoder.mjpg" },
                                  { MEDIA_MIMETYPE_AUDIO_AC3P,
                                      "audio_decoder.ac3p", "audio_encoder.ac3p" },
                                  { MEDIA_MIMETYPE_AUDIO_DTS_HD,
                                      "audio_decoder.dts", "audio_encoder.dts" },
                                  { MEDIA_MIMETYPE_AUDIO_DTS_LBR,
                                      "audio_decoder.dts", "audio_encoder.dts" },
                                  { MEDIA_MIMETYPE_AUDIO_COOK,
                                      "audio_decoder.ra", "audio_encoder.ra" },
                                  { MEDIA_MIMETYPE_AUDIO_WMA,
                                      "audio_decoder.wma", "audio_encoder.wma" },
                                  { MEDIA_MIMETYPE_AUDIO_AC4,
                                      "audio_decoder.ac4", "audio_encoder.ac4" },
                                  { MEDIA_MIMETYPE_AUDIO_MPEG_H,
                                      "audio_decoder.mpegh", "audio_encoder.mpegh" },
                                  { MEDIA_MIMETYPE_VIDEO_MVC,
                                      "video_decoder.mvc", "video_encoder.mvc" },
                                  { MEDIA_MIMETYPE_VIDEO_HEVCDV,
                                      "video_decoder.hevcdv", "video_encoder.hevcdv" },
                                  { MEDIA_MIMETYPE_AUDIO_DRA,
                                      "audio_decoder.dra", "audio_encoder.dra" },
                                  { MEDIA_MIMETYPE_AUDIO_DSP_AAC,
                                      "audio_decoder.dspaac", "audio_encoder.dspaac" },
                                  { MEDIA_MIMETYPE_AUDIO_PASSTHROUGH,
                                      "audio_decoder.passthrough", "audio_encoder.passthrough"},
                                  // Mediatek Android Patch End
                                  { MEDIA_MIMETYPE_VIDEO_DIVX5,
                                      "video_decoder.divx5", "video_encoder.divx5" },
                                  { MEDIA_MIMETYPE_VIDEO_DIVX_AVC,
                                      "video_decoder.divx-avc", "video_encoder.divx-avc" },
                                  { MEDIA_MIMETYPE_VIDEO_DIVX_HEVC,
                                      "video_decoder.divx-hevc", "video_encoder.divx-hevc" },
                                  { MEDIA_MIMETYPE_VIDEO_AV1,
                                      "video_decoder.av1", "video_encoder.av1" },
                              };
                          */
                          //如果是vorbis(一个很老的音频)音频数据
                          if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
                              mAudioIsVorbis = true;
                          } else {
                              mAudioIsVorbis = false;
                          }
          
                          mMimes.add(String8(mime));
                      }
                  } else if (!strncasecmp(mime, "video/", 6)) {
                      if (mVideoTrack.mSource == NULL) {
                          mVideoTrack.mIndex = i;
                          mVideoTrack.mSource = track;
                          //创建一个视频获取器
                          mVideoTrack.mPackets =
                              new AnotherPacketSource(mVideoTrack.mSource->getFormat());
          
                          // video always at the beginning
                          //视频总是在开头
                          mMimes.insertAt(String8(mime), 0);
                      }
                  }
          
                  //保存每一个Track
                  mSources.push(track);
                   //时间同步
                  int64_t durationUs;
                  if (meta->findInt64(kKeyDuration, &durationUs)) {
                      if (durationUs > mDurationUs) {
                          mDurationUs = durationUs;
                      }
                  }
          
                  int32_t bitrate;
                  if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) {
                      //统计码率
                      totalBitrate += bitrate;
                  } else {
                      totalBitrate = -1;
                  }
              }
          
              ALOGV("initFromDataSource mSources.size(): %zu  mIsSecure: %d  mime[0]: %s", mSources.size(),
                      mIsSecure, (mMimes.isEmpty() ? "NONE" : mMimes[0].string()));
          
              if (mSources.size() == 0) {
                  ALOGE("b/23705695");
                  return UNKNOWN_ERROR;
              }
          
              // Modular DRM: The return value doesn't affect source initialization.
              //返回值不影响source初始化
              (void)checkDrmInfo();
          
              mBitrate = totalBitrate;
          
              return OK;
          }
          
        • frameworks/av/media/libstagefright/MediaExtractorFactory.cpp

          sp<IMediaExtractor> MediaExtractorFactory::Create(
                  const sp<DataSource> &source, const char *mime) {
              ALOGV("MediaExtractorFactory::Create %s", mime);
          
              if (!property_get_bool("media.stagefright.extractremote", true)) {
                  // local extractor
                  //存在本地提取服务
                  ALOGW("creating media extractor in calling process");
                  return CreateFromService(source, mime);
              } else {
                  // remote extractor
                  ALOGV("get service manager");
                  //获取多媒体提取器服务
                  sp<IBinder> binder = defaultServiceManager()->getService(String16("media.extractor"));
          
                  if (binder != 0) {
                      sp<IMediaExtractorService> mediaExService(interface_cast<IMediaExtractorService>(binder));
                      //根据source返回具体的数据提取器
                      sp<IMediaExtractor> ex = mediaExService->makeExtractor(
                              CreateIDataSourceFromDataSource(source), mime);
                      return ex;
                  } else {
                      ALOGE("extractor service not running");
                      return NULL;
                  }
              }
              return NULL;
          }
          
          sp<IMediaExtractor> MediaExtractorFactory::CreateFromService(
                  const sp<DataSource> &source, const char *mime) {
          
              ALOGV("MediaExtractorFactory::CreateFromService %s", mime);
          
              UpdateExtractors(nullptr);
          
              // initialize source decryption if needed
              source->DrmInitialization(nullptr /* mime */);
          
              void *meta = nullptr;
              MediaExtractor::CreatorFunc creator = NULL;
              MediaExtractor::FreeMetaFunc freeMeta = nullptr;
              float confidence;
              sp<ExtractorPlugin> plugin;
              creator = sniff(source.get(), &confidence, &meta, &freeMeta, plugin);
              if (!creator) {
                  ALOGV("FAILED to autodetect media content.");
                  return NULL;
              }
          
              MediaExtractor *ret = creator(source.get(), meta);
              if (meta != nullptr && freeMeta != nullptr) {
                  //释放元数据
                  freeMeta(meta);
              }
          
              ALOGV("Created an extractor '%s' with confidence %.2f",
                  ret != nullptr ? ret->name() : "<null>", confidence);
          
              return CreateIMediaExtractorFromMediaExtractor(ret, source, plugin);
          }
          
          ......
          
          MediaExtractor::CreatorFunc MediaExtractorFactory::sniff(
                  DataSourceBase *source, float *confidence, void **meta,
                  MediaExtractor::FreeMetaFunc *freeMeta, sp<ExtractorPlugin> &plugin) {
              *confidence = 0.0f;
              *meta = nullptr;
          
              std::shared_ptr<List<sp<ExtractorPlugin>>> plugins;
              {
                  Mutex::Autolock autoLock(gPluginMutex);
                  if (!gPluginsRegistered) {
                      return NULL;
                  }
                  plugins = gPlugins;
              }
          
              // Mediatek Android Patch Begin
              MediaExtractor::CreatorFunc creator = NULL;
              //Sniff函数是创建解析器最重要的一个环节,以上代码可以看这里遍历了plugins迭代器,自从mediaExtractor服务从mediaserver中分离出来之后,所有的Extractor(如MPEG4Extractor、MP3Extractor等等)都在开机的时候就加载起来了,这里plugins就是开机时候将所有extractor都存进来了,所以这里的遍历plugins,同时调用每一个extractor的sniff,每一个Extractor中sniff函数都会根据datasource的头部来确定播放文件的类型,根据confidence选择最合适的extractor
              for (auto it = plugins->begin(); it != plugins->end(); ++it) {
                  if ((creator = (*it)->def.sniff(source, confidence, meta, freeMeta))) {
                      plugin = *it;
                      return creator;
                  }
              }
          
              return NULL;
              // Mediatek Android Patch End
          }
          
          
        • frameworks/av/services/mediaextractor/MediaExtractorService.cpp

          sp<IMediaExtractor> MediaExtractorService::makeExtractor(
                  const sp<IDataSource> &remoteSource, const char *mime) {
              ALOGV("@@@ MediaExtractorService::makeExtractor for %s", mime);
          
              //获取本地服务
              sp<DataSource> localSource = CreateDataSourceFromIDataSource(remoteSource);
          
              //创建服务
              sp<IMediaExtractor> extractor = MediaExtractorFactory::CreateFromService(localSource, mime);
          
              ALOGV("extractor service created %p (%s)",
                      extractor.get(),
                      extractor == nullptr ? "" : extractor->name());
          
              if (extractor != nullptr) {
                  registerMediaExtractor(extractor, localSource, mime);
                  return extractor;
              }
              return nullptr;
          }
          

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2203585.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

运筹说 第126期 | 存储论经典例题讲解——随机存储模型

通过上一期&#xff0c;我们已经学习了确定型存储论模型在经济管理中的应用&#xff0c;但其忽略了现实中的随机性和不确定性因素&#xff0c;本期小编选择了一些考虑不确定因素的随机存储模型的典型例题&#xff0c;进行详细讲解。 单周期的随机型存储模型 单周期的随机型存储…

基于springboot模式花店网站的设计与实现(源码+定制+开发)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

《Linux从小白到高手》进阶实操篇:详解Linux系统调优之服务器硬件优化

List item 本篇介绍Linux服务器硬件调优。硬件调优主要包括CPU、内存、磁盘、网络等关键硬件组。 1. CPU优化 选择适合的CPU&#xff1a; –根据应用需求选择多核、高频的CPU&#xff0c;以满足高并发和计算密集型任务的需求。CPU缓存优化&#xff1a; –确保CPU缓存&#x…

【onnx模型转kmodel】记录和踩坑——nncase-v1.9使用

最近几天一直在找相关资料&#xff0c;坑太多&#xff0c;也可能我菜的成分更多一点吧&#xff01;记录下来&#xff0c;以观后用&#xff1b; 背景 我手里有一个正点原子的K210的开发板&#xff1b; 刚刚安装了wsl2下的ubuntu22.04 我手里有正点原子的源码&#xff0c;但是…

【Redis入门到精通十一】Redis集群

目录 集群 1.三种分片算法 1.哈希求余算法 2.一致性哈希算法 3.哈希槽分区算法 2.搭建集群环境 3.集群故障处理 4.集群扩容 集群 上篇文章我们了解Redis哨兵的相关操作&#xff0c;使用哨兵只是解决了主节点瘫痪&#xff0c;从节点不能自动变为主节点的问题&#xff0c;…

[ComfyUI]太赞了!阿里妈妈发布升级版 Flux 图像修复模型,更强细节生成,更高融合度以及更大分辨率支持

小伙伴们还记得我们之前介绍的阿里妈妈发布的 Flux 的 ControlNet 图像修复模型不&#xff0c;之前发布的是 Alpha 早期测试版本&#xff0c;说实话和 Flux 原生的重绘其实差距不大&#xff0c;有些方面甚至还是原生的效果更好。 但是现在&#xff0c;Alpha 的升级版本 Beta 版…

基于java的零食销售系统(源码+定制+开发)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

qt小练习

制作简易闹钟 头文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTimer> //定时器类 #include <QDebug> //信息调试类 #include <QMessageBox> //消息对话框类 #include <QTime> //时间类 #include…

【C语言复习】常见概念(零基础)

【C语言复习】常见概念 1、C语言是什么&#xff1f;2、C语言的历史和辉煌3、 编译器的选择VS20223.1编译和链接3.2编译器的对比3.3 VS2022 的优缺点 4、VS项⽬ 和 源⽂件、头⽂件介绍5、第一个C语言程序6、main函数&#xff08;主函数&#xff09;7、printf和库函数8、关键字介…

基于springboot的大学生体质测试管理系统(含源码+sql+视频导入教程)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1 、功能描述 基于springboot的大学生体质测试管理系统1拥有三种角色 管理员&#xff1a;学生管理、教师管理、日常运行管理、运动分析管理、成绩管理、论坛管理、轮播图管理等 教师&#xff1a;登录…

如何在RuoYi-Vue项目中去除`/dev-api`前缀

前言 在使用RuoYi-Vue框架进行Web应用开发时&#xff0c;有时会遇到API路径需要特定前缀的问题。例如&#xff0c;在某些情况下&#xff0c;开发者可能希望移除或更改默认的/dev-api前缀。 问题描述 当使用YApi直接请求后台接口时&#xff0c;无需添加/dev-api前缀。在生成和…

C++第十六节课 万字详细手动实现string类!

std::basic_string std::basic_string 是 C 标准库中定义的一个模板类&#xff0c;它用于表示字符串。C 中的 std::string 实际上是 std::basic_string<char> 的一个特化版本。也就是说&#xff0c;std::string 是 std::basic_string 这个模板类的一个具体实现&#xff0…

DAY29|| 93.复原ip地址 |78.子集 |90.子集Ⅱ

93.复原ip地址 题目&#xff1a;93. 复原 IP 地址 - 力扣&#xff08;LeetCode&#xff09; 有效 IP 地址 正好由四个整数&#xff08;每个整数位于 0 到 255 之间组成&#xff0c;且不能含有前导 0&#xff09;&#xff0c;整数之间用 . 分隔。 例如&#xff1a;"0.1.2.…

国外电商系统开发-运维系统上传脚本

创建脚本的方式有两种&#xff1a;第一种脚本文件&#xff0c;第二种在线写脚本。并且友好的支持中文的显示和脚本的中文名。 第一种是从您的PC电脑上传一个脚本文件&#xff0c;当然了&#xff0c;还是以老用法&#xff0c;直接拖动就行&#xff1a; 第二种上传方式&#xff0…

『网络游戏』服务器日志工具类优化【18】

创建脚本&#xff1a;PECommon.cs 编写脚本&#xff1a;PECommon.cs 修改脚本&#xff1a;LoginSys 替换 替换完成 修改客户端脚本&#xff1a;ResSvc.cs 本章结束

仓储物流行业--仓储服务升级经典案例

在当今内外贸竞争激烈的仓储物流行业&#xff0c;高效的数据处理和管理是企业提升竞争力的关键。杭州某供应链公司作为一家专注为中小卖家提供定制仓储服务方案的第三方云仓&#xff0c;在业务发展过程中面临着数据处理方面的诸多挑战。本文将详细介绍云仓项目如何通过轻易云数…

上海交通大学震撼发布:首个OpenAI O1项目复现报告,揭秘独家经验!

来源 | 机器之心 团队介绍&#xff1a;本项目的核心开发团队主要由上海交通大学 GAIR 研究组的本科三年级、四年级学生以及直博一年级研究生组成。项目得到了来自 NYU 等一线大型语言模型领域顶尖研究科学家的指导。 详细作者介绍见&#xff1a;https://github.com/GAIR-NLP/…

FireFox简单设置设置

文章目录 一 设置不显示标签页1原来的样子2新的样子3操作方法 二 设置竖直标签页栏1 效果图2 设置方法 三 设置firefox不提醒更新 一 设置不显示标签页 1原来的样子 2新的样子 3操作方法 地址栏输入 about:config搜索icon,双击选项列表中browserchrome.site icons的值&#…

HWS赛题 入门 MIPS Pwn-Mplogin(MIPS_shellcode)

解题所涉知识点&#xff1a; 泄露或修改内存数据&#xff1a; 堆地址&#xff1a;栈地址&#xff1a;栈上数据的连带输出(Stack Leak) && Stack溢出覆盖内存libc地址&#xff1a;BSS段地址&#xff1a; 劫持程序执行流程&#xff1a;[[MIPS_ROP]] 获得shell或flag&am…

关于css文字下划线动画实现

直接上代码 html部分 <div><span class"txt">文字下滑动画</span></div>css部分 .txt {background: linear-gradient(270deg, #4f95fd 0%, #1059df 100%) no-repeat left bottom;background-size: 0px 2px;background-position-x: right;tr…