OSDN Git Service

RIO-8970: Fixing media scanner inappropriate removal of media files (https://review...
[android-x86/external-opencore.git] / android / mediascanner.cpp
index 86f597a..735b0c9 100644 (file)
@@ -16,7 +16,9 @@
  * -------------------------------------------------------------------
  */
 
+
 #include <media/mediascanner.h>
+#include <private/media/VideoFrame.h>
 #include <stdio.h>
 
 
@@ -47,7 +49,7 @@
 #include "media/mediametadataretriever.h"
 
 #include <media/thread_init.h>
-#include <utils/string_array.h>
+#include <utils/StringArray.h>
 
 #define MAX_BUFF_SIZE   1024
 
@@ -80,8 +82,9 @@ MediaScanner::~MediaScanner()
     free(mLocale);
 }
 
-static PVMFStatus parseMP3(const char *filename, MediaScannerClient& client)
+static PVMFStatus parseID3Tag(const char *filename, MediaScannerClient& client)
 {
+    // This method parses the ID3 tags in a source file.
     PVID3ParCom pvId3Param;
     PVFile fileHandle;
     Oscl_FileServer iFs;
@@ -102,8 +105,8 @@ static PVMFStatus parseMP3(const char *filename, MediaScannerClient& client)
     }
 
     fileHandle.Seek(0, Oscl_File::SEEKSET);
-       pvId3Param.ParseID3Tag(&fileHandle);
-       fileHandle.Close();
+    pvId3Param.ParseID3Tag(&fileHandle);
+    fileHandle.Close();
     iFs.Close();
 
     //Get the frames information from ID3 library
@@ -119,9 +122,17 @@ static PVMFStatus parseMP3(const char *filename, MediaScannerClient& client)
         bool isIso88591 = false;
 
         // type should follow first semicolon
-        const char* type = strchr(key, ';') + 1;
-        if (type == 0) continue;
-
+        const char* type = strchr(key, ';');
+        if (type == NULL) continue;
+        type++;
+
+        char tracknumkeybuf[MAX_BUFF_SIZE];
+        if (oscl_strncmp(key, "track-info/track-number;", 24) == 0) {
+            // Java expects the track number key to be called "tracknumber", so
+            // construct a temporary one here.
+            snprintf(tracknumkeybuf, sizeof(tracknumkeybuf),"tracknumber;%s", type);
+            key = tracknumkeybuf;
+        }
         
         const char* value = framevector[i]->value.pChar_value;
 
@@ -199,8 +210,8 @@ static PVMFStatus parseMP3(const char *filename, MediaScannerClient& client)
             LOGE("IMpeg3File constructor returned %d.\n", err);
             return err;
         }
-               err = mp3File.ParseMp3File();
-               if (err != MP3_SUCCESS) {
+        err = mp3File.ParseMp3File();
+        if (err != MP3_SUCCESS) {
             LOGE("IMpeg3File::ParseMp3File returned %d.\n", err);
             return err;
         }
@@ -290,7 +301,7 @@ static PVMFStatus reportM4ATags(IMpeg4File *mp4Input, MediaScannerClient& client
     trackNum = mp4Input->getITunesThisTrackNo();
     totalTracks = mp4Input->getITunesTotalTracks();
     sprintf(buffer, "%d/%d", trackNum, totalTracks);
-    if (!client.addStringTag("tracknumber", buffer)) goto failure;
+    if (!client.addStringTag("track-info/track-number", buffer)) goto failure;
 
     // Duration
     duration = mp4Input->getMovieDuration();
@@ -354,19 +365,15 @@ static PVMFStatus parseMP4(const char *filename, MediaScannerClient& client)
                 uint32 trackType = mp4Input->getTrackMediaType(tracks[i]);
                 OSCL_HeapString<OsclMemAllocator> streamtype;
                 mp4Input->getTrackMIMEType(tracks[i], streamtype);
-                char streamtypeutf8[128];
-        strncpy (streamtypeutf8, streamtype.get_str(), streamtype.get_size());
-                if (streamtypeutf8[0])
-        {                                                                           
-                    if (strcmp(streamtypeutf8,"FORMATUNKNOWN") != 0) {
-                            if (trackType ==  MEDIA_TYPE_AUDIO) {
-                                hasAudio = true;
-                            } else if (trackType ==  MEDIA_TYPE_VISUAL) {
-                                hasVideo = true;
-                            }
-                    } else {
-                        //LOGI("@@@@@@@@ %100s: %s\n", filename, streamtypeutf8);
+
+                if (!(streamtype == "FORMATUNKNOWN")) {
+                    if (trackType ==  MEDIA_TYPE_AUDIO) {
+                        hasAudio = true;
+                    } else if (trackType ==  MEDIA_TYPE_VISUAL) {
+                        hasVideo = true;
                     }
+                } else {
+                    //LOGI("@@@@@@@@ %100s: %s\n", filename, streamtypeutf8);
                 }
             }
 
@@ -482,9 +489,9 @@ static PVMFStatus parseMidi(const char *filename, MediaScannerClient& client) {
 static PVMFStatus parseASF(const char *filename, MediaScannerClient& client)
 {
     sp<MediaMetadataRetriever> retriever = new MediaMetadataRetriever();
-       if(retriever == NULL) {
-               return PVMFErrNoMemory;
-       }
+    if(retriever == NULL) {
+        return PVMFErrNoMemory;
+    }
     retriever->setMode( 1 /*MediaMetadataRetriever.MODE_GET_METADATA_ONLY*/);
     status_t status = retriever->setDataSource(filename);
     if (status != NO_ERROR) {
@@ -534,49 +541,57 @@ static PVMFStatus parseASF(const char *filename, MediaScannerClient& client)
         client.addStringTag("year", value);
     value = retriever->extractMetadata(METADATA_KEY_CD_TRACK_NUMBER);
     if (value)
-        client.addStringTag("tracknumber", value);
-
+        client.addStringTag("track-info/track-number", value);
+    value = retriever->extractMetadata(METADATA_KEY_DURATION);
+    if (value) {
+        client.addStringTag("duration",value);
+        LOGE("Duration Value %s for \n",value);
+    }
     retriever->disconnect();
     return PVMFSuccess;
 }
 
 status_t MediaScanner::processFile(const char *path, const char* mimeType, MediaScannerClient& client)
 {
-    status_t result;
-       int error = 0;
+    status_t result = PVMFSuccess;
+    int error = 0;
     InitializeForThread();
-       
-       OSCL_TRY(error,
-                       client.setLocale(mLocale);
-                       client.beginFile();
-                       
-                       //LOGD("processFile %s mimeType: %s\n", path, mimeType);
-                       const char* extension = strrchr(path, '.');
-
-                       if (extension && strcasecmp(extension, ".mp3") == 0) {
-                               result = parseMP3(path, client);
-                       } else if (extension &&
-                               (strcasecmp(extension, ".mp4") == 0 || strcasecmp(extension, ".m4a") == 0 ||
-                                strcasecmp(extension, ".3gp") == 0 || strcasecmp(extension, ".3gpp") == 0 ||
-                                strcasecmp(extension, ".3g2") == 0 || strcasecmp(extension, ".3gpp2") == 0)) {
-                               result = parseMP4(path, client);
-                       } else if (extension && strcasecmp(extension, ".ogg") == 0) {
-                               result = parseOgg(path, client);
-                       } else if (extension &&
-                               ( strcasecmp(extension, ".mid") == 0 || strcasecmp(extension, ".smf") == 0
-                               || strcasecmp(extension, ".imy") == 0)) {
-                               result = parseMidi(path, client);
-                       } else if (extension &&
-                               (strcasecmp(extension, ".wma") == 0 || strcasecmp(extension, ".wmv") == 0 ||
-                                        strcasecmp(extension, ".asf") == 0 )) { 
-                               result = parseASF(path, client);   
-                       } else {
-                               result = PVMFFailure;
-                       }
-                       client.endFile();
-                       );
-       
-       OSCL_FIRST_CATCH_ANY( error,LOGV("OSCL_LEAVE happened in processFile Exit with failure");return PVMFFailure);
+
+    OSCL_TRY(error,
+        client.setLocale(mLocale);
+        client.beginFile();
+
+        //LOGD("processFile %s mimeType: %s\n", path, mimeType);
+        const char* extension = strrchr(path, '.');
+
+        if (extension &&
+           (strcasecmp(extension, ".mp3") == 0 || strcasecmp(extension, ".aac") == 0)) {
+            // Both mp3 and aac files use ID3 tags to hold metadata
+            result = parseID3Tag(path, client);
+        } else if (extension &&
+            (strcasecmp(extension, ".mp4") == 0 || strcasecmp(extension, ".m4a") == 0 ||
+             strcasecmp(extension, ".3gp") == 0 || strcasecmp(extension, ".3gpp") == 0 ||
+             strcasecmp(extension, ".3g2") == 0 || strcasecmp(extension, ".m4b") == 0 || 
+               strcasecmp(extension, ".3gpp2") == 0)) {
+            result = parseMP4(path, client);
+        } else if (extension && strcasecmp(extension, ".ogg") == 0) {
+            result = parseOgg(path, client);
+        } else if (extension &&
+            (strcasecmp(extension, ".mid") == 0 || strcasecmp(extension, ".smf") == 0 || 
+             strcasecmp(extension, ".imy") == 0)) {
+            result = parseMidi(path, client);
+        } else if (extension &&
+            (strcasecmp(extension, ".wma") == 0 || strcasecmp(extension, ".wmv") == 0 ||
+             strcasecmp(extension, ".asf") == 0 || strcasecmp(extension, ".amr") == 0 || 
+             strcasecmp(extension, ".wav") == 0 || strcasecmp(extension, ".awb") == 0)) {
+            result = parseASF(path, client);   
+        } else {
+            result = PVMFFailure;
+        }
+            client.endFile();
+        );
+
+    OSCL_FIRST_CATCH_ANY( error,LOGV("OSCL_LEAVE happened in processFile Exit with failure");return PVMFFailure);
     return result;
 }
 
@@ -609,6 +624,10 @@ status_t MediaScanner::doProcessDirectory(char *path, int pathRemaining, const c
         strcpy(fileSpot, ".nomedia");
         if (access(path, F_OK) == 0) {
             LOGD("found .nomedia, skipping directory\n");
+            // restore path
+            fileSpot[0] = 0;
+            // notify client
+            client.addNoMediaFolder(path);
             return OK;
         }
 
@@ -674,34 +693,34 @@ status_t MediaScanner::processDirectory(const char *path, const char* extensions
         MediaScannerClient& client, ExceptionCheck exceptionCheck, void* exceptionEnv)
 {
     InitializeForThread();
-       int error = 0;
-       status_t result = PVMFSuccess;
-
-       OSCL_TRY(error, 
-                       int pathLength = strlen(path);
-                       if (pathLength >= PATH_MAX) {
-                               return PVMFFailure;
-                       }
-                       char* pathBuffer = (char *)malloc(PATH_MAX + 1);
-                       if (!pathBuffer) {
-                               return PVMFFailure;
-                       }
-
-                       int pathRemaining = PATH_MAX - pathLength;
-                       strcpy(pathBuffer, path);
-                       if (pathBuffer[pathLength - 1] != '/') {
-                               pathBuffer[pathLength] = '/';
-                               pathBuffer[pathLength + 1] = 0;
-                               --pathRemaining;
-                       }
-
-                       client.setLocale(mLocale);
-                       result = doProcessDirectory(pathBuffer, pathRemaining, extensions, client, exceptionCheck, exceptionEnv);
-
-                       free(pathBuffer);
-                       );
-
-       OSCL_FIRST_CATCH_ANY(error,LOGV("OSCL_LEAVE happened in processDirectory Exit with failure"); return PVMFFailure);      
+    int error = 0;
+    status_t result = PVMFSuccess;
+
+    OSCL_TRY(error,    
+            int pathLength = strlen(path);
+            if (pathLength >= PATH_MAX) {
+                return PVMFFailure;
+            }
+            char* pathBuffer = (char *)malloc(PATH_MAX + 1);
+            if (!pathBuffer) {
+                return PVMFFailure;
+            }
+
+            int pathRemaining = PATH_MAX - pathLength;
+            strcpy(pathBuffer, path);
+            if (pathBuffer[pathLength - 1] != '/') {
+                pathBuffer[pathLength] = '/';
+                pathBuffer[pathLength + 1] = 0;
+                --pathRemaining;
+            }
+
+            client.setLocale(mLocale);
+            result = doProcessDirectory(pathBuffer, pathRemaining, extensions, client, exceptionCheck, exceptionEnv);
+
+            free(pathBuffer);
+            );
+
+    OSCL_FIRST_CATCH_ANY(error,LOGV("OSCL_LEAVE happened in processDirectory Exit with failure"); return PVMFFailure);    
     return result;
 }
 
@@ -742,9 +761,9 @@ static char* extractMP3AlbumArt(int fd)
 
     FILE *f = fdopen(fd, "r");
     filehandle = new OsclFileHandle(f);
-       if(filehandle == NULL) {
-               return NULL;
-       }
+    if(filehandle == NULL) {
+        return NULL;
+    }
     file.SetFileHandle(filehandle);
 
     if( 0 != file.Open(NULL, Oscl_File::MODE_READ | Oscl_File::MODE_BINARY, iFs) )
@@ -762,7 +781,7 @@ static char* extractMP3AlbumArt(int fd)
     PvmiKvpSharedPtrVector framevector;
     pvId3Param.GetID3Frames(framevector);
 
-       uint32 num_frames = framevector.size();
+    uint32 num_frames = framevector.size();
     for (uint32 i = 0; i < num_frames; i++)
     {
         const char* key = framevector[i]->key;
@@ -826,31 +845,60 @@ static char* extractM4AAlbumArt(int fd)
     return result;
 }
 
+static char* extractASFAlbumArt(int fd)
+{
+    struct stat asfbuf;
+    char *data = NULL;
+    sp<MediaMetadataRetriever> retriever = new MediaMetadataRetriever();
+    if ((retriever == NULL) && (0 != (fstat(fd,&asfbuf)))) {
+        return data;
+    }
+    retriever->setMode( 1 /*MediaMetadataRetriever.MODE_GET_METADATA_ONLY*/);
+    status_t status = retriever->setDataSource(fd,0,asfbuf.st_size);
+    if (status == NO_ERROR) {
+        sp<IMemory> bitmap = retriever->extractAlbumArt();
+        if (bitmap != NULL) {
+            MediaAlbumArt *albumArtCopy = static_cast<MediaAlbumArt *>(bitmap->pointer());
+            data = (char*)malloc(albumArtCopy->mSize + 4);
+            if (data && albumArtCopy->mData) {
+                long *len = (long*)data;
+                *len = albumArtCopy->mSize;
+                albumArtCopy->mData = (uint8_t *)albumArtCopy + sizeof(MediaAlbumArt);
+                memcpy(data + 4, (const char*)albumArtCopy->mData, *len);
+            }
+        }
+    }
+    retriever->disconnect();
+    return data;
+}
 
 char* MediaScanner::extractAlbumArt(int fd)
 {
     InitializeForThread();
-       
-       char *  albumArtData = NULL;
-       int error = 0;
+    
+    char *    albumArtData = NULL;
+    int error = 0;
     int32 ident;
     lseek(fd, 4, SEEK_SET);
     read(fd, &ident, sizeof(ident));
-       
-       OSCL_TRY(error, 
-                       if (ident == 0x70797466) {
-                               // some kind of mpeg 4 stream
-                               lseek(fd, 0, SEEK_SET);
-                               albumArtData = extractM4AAlbumArt(fd);
-                       } else {
-                               // might be mp3
-                               albumArtData = extractMP3AlbumArt(fd);
-                       }
-                       );
-
-       OSCL_FIRST_CATCH_ANY(error,LOGV("OSCL_LEAVE happened in extractAlbumArt retrun null");return NULL);     
-       return albumArtData;
-       
+    
+    OSCL_TRY(error,    
+            if (ident == 0x70797466) {
+                // some kind of mpeg 4 stream
+                lseek(fd, 0, SEEK_SET);
+                albumArtData = extractM4AAlbumArt(fd);
+            }else if (ident == 0x11CF668E) {
+                lseek(fd, 0, SEEK_SET);
+                albumArtData = extractASFAlbumArt(fd);
+            }else {
+                // might be mp3
+                albumArtData = extractMP3AlbumArt(fd);
+            }
+            );
+
+    OSCL_FIRST_CATCH_ANY(error,LOGV("OSCL_LEAVE happened in extractAlbumArt retrun null");return NULL);    
+    return albumArtData;
+    
 }
 
 MediaScannerClient::MediaScannerClient()