android多媒体数据库框架介绍
这是一篇老文了,原文已经找不到出处,都是互联网上转过去转过来的。介绍了安卓中对图片 视频 音频等多媒体文件的数据库管理框架:
Android平台上的媒体文件管理和桌面系统不同。在桌面系统上,不同目录下的媒体文件呈树状结构显示给用户,用户需要进入不同目录寻找该目录下的文件。而在Android平台上,不同目录下的媒体文件则以一层列表方式显示给用户,用户不需进入子目录就可以列出(某种类型的)所有媒体文件。
在Android上,为了实现这种模式的媒体文件管理,对所有管理的媒体文件抽取其元数据,也就是ID3(mp3文件包含的元数据可参考http://en.wikipedia.org/wiki/ID3),存储在数据库中,并作为一个content provider提供给其他应用使用。用户的每一次显示媒体文件的操作,就是对这个数据库的一次查询操作。在多媒体管理模块中,主要分成三个模块:
多媒体数据库
MediaStore这个类是android系统提供的一个多媒体数据库,android中多媒体信息都可以从这里提取。这个MediaStore包括了多媒体数据库的所有信息,包括音频,视频和图像,android把所有的多媒体数据库接口进行了封装,所有的数据库不用自己进行创建,直接调用利用ContentResolver去掉用那些封装好的接口就可以进行数据库的操作,多媒体数据库的使用方法和SQLITE3的方法是一样的。
MediaStore中的数据是在MediaScanner扫描后通过MediaProvider中的一个service进行更新的。框架图如下:
MediaScanner
在Android系统中,多媒体库是通过MediaScanner去扫描磁盘文件,对元信息的处理,并通过MediaProvider保存到MediaStore中。下图为MediaScannerr 框架:
MediaScanner可以通过手动控制,在ANDROID系统中,已经定制了三种事件会触发MediaScanner去扫描磁盘文件:ACTION_BOOT_COMPLETED、ACTION_MEDIA_MOUNTED、 ACTION_MEDIA_SCANNER_SCAN_FILE。其中ACTION_BOOT_COMPLETED是系统启动完后发出这个消息,ACTION_MEDIA_MOUNTED是插卡事件触发的消息,ACTION_MEDIA_SCANNER_SCAN_FILE消息一般是在一些文件操作后,开发人员手动发出的一个重新扫描多媒体文件的消息。发送消息通过sendBroadcast函数完成,比如广播一个ACTION_MEDIA_MOUNTED消息:
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStorageDirectory())));
由上可知是通过发送了一个广播(传递对应的扫描要求)来触发重新扫描磁盘事件,那么可以猜测系统肯定存在一个广播接收器(何时何地注册?),在收到这个广播消息后,通过对应参数启动MediaScannerService。MediaScannerService调用一个公用类
MediaScanner去处理真正的工作。MediaScannerReceiver维持两种扫描目录:一种是内部卷(internal volume)指向$(ANDROID_ROOT)/media. 另一种是外部卷(external volume)指向$(EXTERNAL_STORAGE),扫描的位置可以修改(一般外部不用修改,默认为SDCARD,内部根据驱动命名的INAND路经名做对应的修改),对应图1-1系统源码具体位置:
MediaScannerReceiver:
/mydroid/packages/providers/MediaProvider/src/com/android/providers/media/MediaScannerReceiver.java
Scanner事件接收,继承了BroadcastReceiver类,收到扫描消息后启动MediaScannerService,但有一点要注意的是: Service的onCreate的方法只会被调用一次,就是你无论多少次的startService又 bindService,Service只被创建一次。如果先是bind了,那么start的时候就直接运行Service的 onStart方法,如果先是start,那么bind的时候就直接运行onBind方法。如果你先bind上了,就stop不掉了,对啊,就是stopService不好使了,只能先UnbindService, 再StopService,所以是先start还是先bind行为是有区别的。(关于BINDLE接口请参考其它文档)
MediaScannerService:
/mydroid/packages/providers/MediaProvider/src/com/android/providers/media/MediaScannerService.java
通过此服务,去调用MediaScanner的具体实现方法。
MediaScanner: (方法)
\\frameworks\\base\\media\\java\\android\\media\\ MediaScanner.java
MediaPlayer整体流程:
Thumbnails缩略图概述
缩略图保存位置:/sdcard/DCIM/.thumbnails
缩略图(大):一张张的JPEG文件
所有的都存入同一个二进制文件.thumbdata+version+”-”+hashcode,字节大小均为 10000bytes
详解:
对于每一张图片,都会生成大缩略图和小缩略图,大缩略图保存在(外部设备)
/sdcard/DCIM/.thumbnails/ 目录下,大缩略图大小上限是512 X 384,下限1 X1。小缩略图被统一保存到一个随机访问文件 (外部设备)/sdcard/DCIM/.thumbnails/ +".thumbdata" + version + "-"+ mUri.hashcode()
缩略图存储到数据库里面
扫描一个文件的最后endfile()会mMediaProvider.insert()或者mMediaProvider.update()。在mMediaProvider.insert()时对于IMAGES_MEDIA 和VIDEO_MEDIA类型:
requestMediaThumbnail()--->mCurrentThumbRequest.execute(); 在执行时会首先会去缩略图的数据库中查询,查询到就返回,未查询到会
ThumbnailUtil.createVideoThumbnail(mPath)或者
ThumbnailUtil.createImageThumbnail(mCr, mPath, mUri,
mOrigId,Images.Thumbnails.MICRO_KIND, true/*saveMini*/));
创建图片缩略图:
创建thumbnail时调用ThumbnailUtil.makeBitmap()创建;如果saveMini为真会保存缩略图ThumbnailUtil.storeThumbnail(cr, origId, thumbData, bitmap.getWidth(), bitmap.getHeight());; 保存时会通过origId向数据库查询,查到返回对应的uri,未查找到就插入数据库并返回uri,最终返回bitmap。对于创建视频缩略图:直接在视频文件中取一帧得到bintmap并返回保存大缩略图到文件:
bitmap.compress(Bitmap.CompressFormat.JPEG, 75, miniOutStream);
保存小缩略图到随机访问文件:
data = miniOutStream.toByteArray();
miniThumbFile.saveMiniThumbToFile(data, mOrigId, magic);
在mMediaProvider.update()时,对IMAGES_MEDIA,IMAGES_MEDIA_ID,VIDEO_MEDIA,VIDEO_MEDIA_ID类型会查询magic,如果没查到会执行requestMediaThumbnail(),流程同上。
MediaProvider是对上面整个流程的实现。可参考里面的代码。