<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                1. PVMS的processDirectory分析 來看PVMediaScanner(以后簡稱為PVMS,它就是Native層的MS)的processDirectory函數。這個函數是由它的基類MS實現的。注意,源碼中有兩個MediaScanner.cpp,它們的位置分別是: - framework/base/media/libmedia - external/opencore/android/ 看libmedia下的那個MediaScanner.cpp,其中processDirectory函數的代碼如下所示: **MediaScanner.cpp** ~~~ status_t MediaScanner::processDirectory(constchar *path, const char *extensions, MediaScannerClient&client, ExceptionCheckexceptionCheck, void *exceptionEnv) { ......//做一些準備工作 client.setLocale(locale()); //給Native的MyMSC設置locale信息 //調用doProcessDirectory函數掃描文件夾 status_tresult = doProcessDirectory(pathBuffer,pathRemaining, extensions, client,exceptionCheck, exceptionEnv); free(pathBuffer); returnresult; } //下面直接看這個doProcessDirectory函數 status_t MediaScanner::doProcessDirectory(char*path, int pathRemaining, const char *extensions,MediaScannerClient&client, ExceptionCheck exceptionCheck,void *exceptionEnv) { ......//忽略.nomedia文件夾 DIR*dir = opendir(path); ...... while((entry = readdir(dir))) { //枚舉目錄中的文件和子文件夾信息 const char* name = entry->d_name; ...... int type = entry->d_type; ...... if(type == DT_REG || type == DT_DIR) { int nameLength = strlen(name); bool isDirectory = (type == DT_DIR); ...... strcpy(fileSpot, name); if (isDirectory) { ...... //如果是子文件夾,則遞歸調用doProcessDirectory int err = doProcessDirectory(path, pathRemaining - nameLength - 1, extensions, client, exceptionCheck, exceptionEnv); ...... } else if (fileMatchesExtension(path, extensions)) { //如果該文件是MS支持的類型(根據文件的后綴名來判斷) struct stat statbuf; stat(path, &statbuf); //取出文件的修改時間和文件的大小 if (statbuf.st_size > 0) { //如果該文件大小非零,則調用MyMSC的scanFile函數!!? client.scanFile(path,statbuf.st_mtime, statbuf.st_size); } if (exceptionCheck && exceptionCheck(exceptionEnv)) gotofailure; } } } ...... } ~~~ 假設正在掃描的媒體文件的類型是屬于MS支持的,那么,上面代碼中最不可思議的是,它竟然調用了MSC的scanFile來處理這個文件,也就是說,MediaScanner調用MediaScannerClient的scanFile函數。這是為什么呢?還是來看看這個MSC的scanFile吧。 2. MyMSC的scanFile分析 (1)JNI層的scanFile 其實,在調用processDirectory時,所傳入的MSC對象的真實類型是MyMediaScannerClient,下面來看它的scanFile函數,代碼如下所示: **android_media_MediaScanner.cpp** ~~~ virtual bool scanFile(const char* path, longlong lastModified, long long fileSize) { jstring pathStr; if((pathStr = mEnv->NewStringUTF(path)) == NULL) return false; //mClient是Java層的那個MyMSC對象,這里調用它的scanFile函數 mEnv->CallVoidMethod(mClient, mScanFileMethodID, pathStr,lastModified, fileSize); mEnv->DeleteLocalRef(pathStr); return (!mEnv->ExceptionCheck()); } ~~~ 太沒有天理了!Native的MyMSCscanFile主要的工作就是調用Java層MyMSC的scanFile函數。這又是為什么呢? (2)Java層的scanFile 現在只能來看Java層的這個MyMSC對象了,它的scanFile代碼如下所示: **MediaScanner.java** ~~~ public void scanFile(String path, longlastModified, long fileSize) { ...... //調用doScanFile函數 doScanFile(path, null, lastModified, fileSize, false); } //直接來看doScanFile函數 publicUri doScanFile(String path, String mimeType, long lastModified, long fileSize, boolean scanAlways) { /* 上面參數中的scanAlways用于控制是否強制掃描,有時候一些文件在前后兩次掃描過程中沒有 發生變化,這時候MS可以不處理這些文件。如果scanAlways為true,則這些沒有變化 的文件也要掃描。 */ Uriresult = null; long t1 = System.currentTimeMillis(); try{ /* beginFile的主要工作,就是將保存在mFileCache中的對應文件信息的 mSeenInFileSystem設為true。如果這個文件之前沒有在mFileCache中保存, 則會創建一個新項添加到mFileCache中。另外它還會根據傳入的lastModified值 做一些處理,以判斷這個文件是否在前后兩次掃描的這個時間段內被修改,如果有修改,則 需要重新掃描 */ FileCacheEntryentry = beginFile(path, mimeType,lastModified, fileSize); if(entry != null && (entry.mLastModifiedChanged || scanAlways)) { String lowpath = path.toLowerCase(); ...... if (!MediaFile.isImageFileType(mFileType)) { //如果不是圖片,則調用processFile進行掃描,而圖片不需要掃描就可以處理 //注意在調用processFile時把這個Java的MyMSC對象又傳了進去。 processFile(path, mimeType, this); } //掃描完后,需要把新的信息插入數據庫,或者要將原有的信息更新,而endFile就是做這項工作的。 result = endFile(entry, ringtones, notifications,alarms, music, podcasts); } } ...... return result; } ~~~ 下面看這個processFile,這又是一個native的函數。 上面代碼中的beginFile和endFile函數比較簡單,讀者可以自行研究。 (3)JNI層的processFile分析 MediaScanner的代碼有點繞,是不是?總感覺我們像追兵一樣,追著MS在赤水來回地繞,現在應該是二渡赤水了。來看這個processFile函數,代碼如下所示: **android_media_MediaScanner.cpp** ~~~ android_media_MediaScanner_processFile(JNIEnv*env, jobject thiz, jstring path, jstring mimeType, jobject client) { //Native的MS還是那個MS,其真實類型是PVMS。 MediaScanner *mp = (MediaScanner *)env->GetIntField(thiz,fields.context); //又構造了一個新的Native的MyMSC,不過它指向的Java層的MyMSC沒有變化。 MyMediaScannerClient myClient(env, client); //調用PVMS的processFile處理這個文件。 mp->processFile(pathStr,mimeTypeStr, myClient); } ~~~ 看來,現在得去看看PVMS的processFile函數了。 3. PVMS的processFile分析 (1)掃描文件 這是我們第一次進入到PVMS的代碼中進行分析: **PVMediaScanner.cpp** ~~~ status_t PVMediaScanner::processFile(const char*path, const char* mimeType, MediaScannerClient& client) { status_t result; InitializeForThread(); //調用Native MyMSC對象的函數做一些處理 client.setLocale(locale()); /* beginFile由基類MSC實現,這個函數將構造兩個字符串數組,一個叫mNames,另一個叫mValues。 這兩個變量的作用和字符編碼有關,后面會碰到。 */ client.beginFile(); ...... constchar* extension = strrchr(path, '.'); //根據文件后綴名來做不同的掃描處理 if(extension && strcasecmp(extension, ".mp3") == 0) { result = parseMP3(path, client);//client又傳進去了,我們看看對MP3文件的處理 ...... } /* endFile會根據client設置的區域信息來對mValues中的字符串做語言轉換,例如一首MP3 中的媒體信息是韓文,而手機設置的語言為簡體中文,endFile會盡量對這些韓文進行轉換。 不過語言轉換向來是個大難題,不能保證所有語言的文字都能相互轉換。轉換后的每一個value都 會調用handleStringTag做后續處理。 */ client.endFile(); ...... } ~~~ 下面再到parseMP3這個函數中去看看,它的代碼如下所示: **PVMediaScanner.cpp** ~~~ static PVMFStatus parseMP3(const char *filename,MediaScannerClient& client) { //對MP3文件進行解析,得到諸如duration、流派、標題的TAG(標簽)信息。在Windows平臺上 //可通過千千靜聽軟件查看MP3文件的所有TAG信息 ...... //MP3文件已經掃描完了,下面將這些TAG信息添加到MyMSC中,一起看看 if(!client.addStringTag("duration", buffer)) ...... } ~~~ (2)添加TAG信息 文件掃描完了,現在需要把文件中的信息通過addStringTag函數告訴給MyMSC。下面來看addStringTag的工作。這個函數由MyMSC的基類MSC處理。 **MediaScannerClient.cpp** ~~~ bool MediaScannerClient::addStringTag(constchar* name, const char* value) { if(mLocaleEncoding != kEncodingNone) { bool nonAscii = false; const char* chp = value; char ch; while ((ch = *chp++)) { if (ch & 0x80) { nonAscii = true; break; } } /* 判斷name和value的編碼是不是ASCII,如果不是的話則保存到 mNames和mValues中,等到endFile函數的時候再集中做字符集轉換。 */ if(nonAscii) { mNames->push_back(name); mValues->push_back(value); return true; } } //如果字符編碼是ASCII的話,則調用handleStringTag函數,這個函數由子類MyMSC實現。 returnhandleStringTag(name, value); } ~~~ **android_media_MediaScanner.cpp::MyMediaScannerClient類** ~~~ virtual bool handleStringTag(const char* name,const char* value) { ...... //調用Java層MyMSC對象的handleStringTag進行處理 mEnv->CallVoidMethod(mClient, mHandleStringTagMethodID, nameStr,valueStr); } ~~~ **MediaScanner.java** ~~~ publicvoid handleStringTag(String name, String value) { //保存這些TAG信息到MyMSC對應的成員變量中去。 if (name.equalsIgnoreCase("title") ||name.startsWith("title;")) { mTitle = value; } else if (name.equalsIgnoreCase("artist") || name.startsWith("artist;")) { mArtist = value.trim(); } else if (name.equalsIgnoreCase("albumartist") || name.startsWith("albumartist;")) { mAlbumArtist = value.trim(); } ...... } ~~~ 到這里,一個文件的掃描就算做完了。不過,讀者還記得是什么時候把這些信息保存到數據庫的嗎? 是在Java層MyMSC對象的endFile中,這時它會把文件信息組織起來,然后存入媒體數據庫。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看