• Android 多媒体 1.1 获取多媒体信息[原创]


    1  Android多媒体

    通过调用AndroidAPI,可以实现相册,播放器,录音和摄像等功能。这一章需要掌握如下功能:

    q      多媒体的ContentProvider的调用

    q      Camera

    q      AudioRecordAudioTrack

    q      MediaPlayer

      1.1  获取多媒体信息

    多媒体信息?在pc中的音乐播放器总是很容易的显示歌手名、歌曲名、专辑名、年代。在Android中应该如何获取这些信息呢?

    1.1.1  查看多媒体ContentProvider

    前面我们学习了ContentProvider来保存和检索数据,Android为常用的数据类型(如:音视频、图片和联系方式等)提供了大量的ContentProvider,它们被定义在android.provider包下。那么我们如何获取多媒体的ContentProvider呢。

    1       Eclipse中添加Android自带的FileExplorer视图:

    菜单栏->window->show view->other->Android->FileExplorer

    2       开启模拟器,在FileExplorer中查看data/data/com.android.providers.media/databases/(如图1.1

    3       external.db文件 pullpc上,用sqlite工具(可以使用火狐插件SQliteManager)查看:(如图1.2

    4       查看表结构:

    audio_meta:管理sd卡中的音频资源。(如图1.3)

    video:管理sd卡中的视频资源。(如图1.4)

    images:管理sd卡中的图片。(如图1.5)

     

     

    1.1  多媒体数据库所在包

     

    1.2  多媒体数据库表

     

     

    1.3  音频表结构(audio_meta)

     

    1.4  视频表结构(video)

     

    1.5  图片表结构(images)

    可能大家看到这里会不明白为什么讲多媒体先要介绍这些。笔者这里给大家列举一个音乐播放器的需求:

    1)      获得音乐文件列表及路径

    2)      获得音乐文件属性(歌曲名、歌手名、专辑、年代。。)

    3)      手动删除内存卡中音乐文件,如何能同步更新文件列表

    如果是没有Android经验,大家可能会这样分析:

           文件路径嘛,我调用file.listFile()就可以得到音乐文件列表。如果内存卡里有很多文件,那么这个将会特别的耗时,如果让用户等上10秒去扫描存储卡,用户很有可能将你的应用卸载掉。

           音乐文件属性一般保存在音乐文件中,有的放在文件头,有的放在文件尾,必须读出该文件相关字节中的内容才可以获取音乐文件信息。OK,有个开源的项目,可以解析MP3文件中的文件信息。但是它同样也是耗时的操作。而且学会调用这个开源项目还需要一周的时间。做一个项目没那么难吧?

           在文件管理器中手动删除或添加一个音乐文件,这个时候如何把它更新到音乐列表中呢,当你选择一首歌播放的时候,很有可能已经被删掉了。总不能让它时刻去调用file.listFile()去维护吧?

           那么我们到底应该怎么做呢?你要始终相信Android是强大的,它早已为我们提供了这些功能,我们只需要调用Android提供的API,就可以解决上述的需求。

           现在我们先看个图,图1.6为模拟器开机时,在log中打印的日志。

     

    1.6  开机时的log

    大家会看到,系统会调用MediaScanner去扫描InternalExternal Volume。原来,在开机时,系统会在后台扫描内存和外存设备,将多媒体数据更新到数据库中。同时也会扫描文件信息,这样,我们不费吹灰之力就解决了问题。

    小插曲:之前由于笔者还不知道这个方法,在摸索中让同事去研究解析MP3文件信息,花了他一个星期时间,当他做出来了,我花了十分钟找到了这个方法。真是罪过罪过。

    那么我们如何得到多媒体数据呢,请看下面的例子:

    /**

          * 读取sd卡中的音乐文件

          * @return

          * @throws Exception

          */

         public static ArrayList<Song> readDataFromSD(Context context,int component){

    //       Log.i(TAG, "scanFile");

             Cursor cursor = context.getContentResolver().query(

                       MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,

                       new String[] { MediaStore.Audio.Media._ID, MediaStore.Audio.Media.DISPLAY_NAME, MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.DURATION, MediaStore.Audio.Media.ARTIST, MediaStore.Audio.Media.ALBUM, MediaStore.Audio.Media.YEAR, MediaStore.Audio.Media.MIME_TYPE, MediaStore.Audio.Media.SIZE, MediaStore.Audio.Media.DATA}

                       , MediaStore.Audio.Media.MIME_TYPE+"=? or " + MediaStore.Audio.Media.MIME_TYPE+"=?", new String[]{"audio/mpeg","audio/x-ms-wma"},null);

             ArrayList<Song> songs = null;

             if (cursor.moveToFirst()) {

                  songs = SongInfoUtil.getList(cursor, context, component);

             }

             return songs;

         }

     

     

    /**

     * @author stayzhang 封装信息至Song

     */

    public class SongInfoUtil {

    //   private static final String TAG = "ListUtils";

         public static ArrayList<Song> getList(Cursor cursor, Context mContext, int component) {

             Song song = null;

             do {

    //            Log.i(TAG, "getList");

                  song = new Song();

                  song.setFilename(cursor.getString(1));//文件名

                  song.setTitle(cursor.getString(2));//歌曲名

                  song.setDuration(cursor.getInt(3));//时长

                  song.setSinger(cursor.getString(4));//歌手名

                  song.setAlbum(cursor.getString(5));//专辑名

                  if (cursor.getString(6) != null) {//年代

                       song.setYear(cursor.getString(6));

                  } else {

                       song.setYear("未知");

                  }

                  if ("audio/mpeg".equals(cursor.getString(7).trim())) {//歌曲格式

                       song.setType("mp3");

                  } else if ("audio/x-ms-wma".equals(cursor.getString(7).trim())) {

                       song.setType("wma");

                  }

                  if (cursor.getString(8) != null) {//文件大小

                       float temp = cursor.getInt(8) / 1024f / 1024f;

                       String sizeStr = (temp + "").substring(0, 4);

                       song.setSize(sizeStr + "M");

                  } else {

                       song.setSize("未知");

                  }

                  if (cursor.getString(9) != null) {//文件路径

                       song.setFileUrl(cursor.getString(9));

                  }

             } while (cursor.moveToNext());

             cursor.close();

             return dbService.query(component, null, null);

         }

    }

    同理,图片还有视频文件也可以这样获得,不再赘述。

    这样第一个和第二个需求我们已经解决,那第三个需求呢。

    当我们手动的删除或添加多媒体文件到存储卡中时,Android会自动扫描这些文件并将其更新到数据库吗?

    答案是不会,那么我们如何将数据实时更新到数据库中呢。还记得logcat中打印出来的MediaScanner吗?我们也可以调用MediaScanner这个类去扫描存储卡。但是不能直接调用这个类,只能以广播的形式通知系统,让系统去扫描存储卡指定的URI,扫描完后,再通过ContentProvider查询数据库。

    方法如下:

    /**

              * 调用系统api扫描sd

              */

             private void scanSdCard() {

                       IntentFilter intentFilter = new IntentFilter(

                                         Intent.ACTION_MEDIA_SCANNER_STARTED);

                       intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);

                       intentFilter.addDataScheme("file");

                       scanReceiver = new ScanSdFilesReceiver();

                       registerReceiver(scanReceiver, intentFilter);

                       sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,

                                         Uri.parse("file://" + getExternalStorageDirectory().getAbsolutePath)));

             }

     

             /**

              * @author stayzhang 注册扫描开始/完成的广播

              */

             private class ScanSdFilesReceiver extends BroadcastReceiver {

                       public void onReceive(Context context, Intent intent) {

                                String action = intent.getAction();

                                if (Intent.ACTION_MEDIA_SCANNER_STARTED.equals(action)) {

    //当系统开始扫描sd卡时,为了用户体验,可以加上一个等待框

                                         scanHandler.sendEmptyMessage(STARTED);

                                }

                                if (Intent.ACTION_MEDIA_SCANNER_FINISHED.equals(action)) {

                                //当系统扫描完毕时,停止显示等待框,并重新查询ContentProvider

                                         scanHandler.sendEmptyMessage(FINISHED);

                                }

                       }

             }

    OK,关于多媒体的ContentProvider的知识告一段落,下面就是如何调用Android API来使用这些多媒体文件。

    后续内容我会慢慢整理,再发出来。tks

    1.1.2  使用Camera

    1.2  使用视频

    1.2.1  录制视频

    1.2.2  播放视频

    1.3  使用音频

    1.3.1  录制音频

    1.3.2  播放音频

    1.3.3  共享音频

    1.3.4  使用音频

     

     

  • 相关阅读:
    mysql 存储过程实例
    国际会议查询方式和相关会议
    用 WEKA 进行数据挖掘,第 1 部分: 简介和回归(转)
    java实现甘特图的2种方法:SwiftGantt和Jfree (转)
    通过jxl 读取excel 文件中的日期,并计算时间间隔
    R 操作矩阵和计算SVD的基本操作记录
    SVD java 算法实现
    聚类方法简介
    Kolmogorov-Smirnov检验
    Java Thread 多线程 介绍
  • 原文地址:https://www.cnblogs.com/stay/p/2142774.html
Copyright © 2020-2023  润新知