MediaScanner添加对多种音频文件ID3信息的保存支持

平台:Android2.3
场景:Hifi播放器,在原生系统的基础上需要添加对各种类型的音频文件的ID3信息扫描,保存,显示。
时间:2012.3.30

首先android系统已经支持了大部分经常使用的音频文件的ID3信息的解码。在2.2系统以后,其使用的是google提供的stagefright。
在Java层,mediascaaner对应的程序是在packages\providers\MediaProvider下面。其中AndroidManifest.xml文件中的
application android:process=”android.process.media”表明,我们通过ps看到的 android.process.media进程即为MediaScanner。
通过其中的MediaScannerReceiver接受广播,然后调用MediaScannerService的scan()方法进行扫描。scan()方法中又通过
MediaScanner scanner = createMediaScanner();
scanner.scanDirectories(directories, volumeName);
这一句实现的扫描调用。

从Java层开始的MediaScan,需要确保额外的音频格式被扫描到。所以需要在
frameworks\base\media\java\android\media\MediaFile.java中,
对sFileExtensions进行添加。
使用addFileType(“AIFF”, FILE_TYPE_M4A, “audio/mp4”)的方式。因为在后面的扫描的过程中,会调用processDirectory(directories[i], MediaFile.sFileExtensions, mClient)。只有在sFileExtensions中申明的类型才会被MediaScanner扫描到。

MediaScanner 在框架的代码中,其扫描实现代码都在\frameworks\base\media\下面。比较有意思的是, scanDirectories函数会调用到jni函数,经过一次次调用后,还会从jni回调 MediaScanner.java里面的scanFile()函数,继而调用scanFile()里面的doScanFile()函数,此函数可以看做是java层开始进行扫描的真正入口。其中从beginFile()开始确认,是否有新文件进入从而需要扫描。若有新文件则继续调用processFile()进行真正的扫描,并将扫描得到的内容保存到全局变量中,最后通过endFile()函数将全局变量的信息存入到数据库中。
processFile()函数是一个native函数,在android_media_MediaScanner.cpp中根据使用的方法不同,stagefright或者是opencore,从而进入不同的processFile()中。在此处,我们进入的是StagefrightMediaScanner.cpp中的processFile()函数中。

根据自己的需求,可以在processFile()中截断,并调用库里面提供的统一的接口来获取ID3信息的值,然后通过client.addStringTag()进行一次的添加,最后还需要调用client.endFile()。在client.addStringTag()的调用中就会调用到handleStringTag()函数了,这个在java代码里面的函数,然后会去改变mArtist等的全局变量,从而使得java的endFile()的时候将这些全局变量保存到数据库中。
在native层对client.endFile()的调用,其实际的更大价值在于:判断将要保存的ID3信息的编码格式,尽量对其进行最合理的转化后进行保存。

简单说一下在StagefrightMediaScanner.cpp中,系统默认的处理方式。首先,需要支持的音频格式定义在kValidExtensions变量中。然后在processFile()函数中,通过mRetriever->setDataSource(path)来将要扫描的文件的路径传入。跟踪代码会发现,
StagefrightMediaScanner:mRetriever->setDataSource(path)
-MediaMetadataRetriever:mRetriever->setDataSource(srcUrl)
-MediaPlayerService:createMetadataRetriever()
-MetadataRetrieverClient:setDataSource(const char *url)
-StagefrightMetadataRetriever:setDataSource(const char *uri)
-MediaExtractor:Create(const sp &source, const char *mime)
其最终是调用了MediaExtractor.cpp中的Create()函数,会根据不同的文件后缀进行不同的解析代码的调用,比如MP3,使用return new MP3Extractor(source, meta)。而这个返回值是在StagefrightMetadataRetriever.cpp里面的全局变量mExtractor。而后在processFile()中通过value = mRetriever->extractMetadata(kKeyMap[i].key)从mExtractor中获取出解析得到的ID3信息值,进而继续调用 client.addStringTag()进行添加。

总结:
1.在MediaFile.java中添加需要额外扫描的音频文件格式的申明。
2.在StagefrightMediaScanner.cpp中对额外需要支持的音频的格式做截断,然后调用自己定义的函数或者是库提供的接口进行添加。

参考:
http://blog.csdn.net/innost/article/details/6083467

你可能感兴趣的:(MediaScanner添加对多种音频文件ID3信息的保存支持)