最近項目有用到音視訊的錄制,那麼自然也是有擷取錄制的音視訊資訊的需求,同時也會有擷取網絡視訊資訊的需求了。
其實說來擷取錄制時長的話,完全可以不從檔案本身入手了。可以放個計時器。不過這樣子也是大動幹戈,也太不靈活了。然後就遇到了今天的主角了:MediaMetadataRetriever。看google對于這個類的描述MediaMetadataRetriever class provides a unified interface for retrieving frame and meta data from an input media file.大意為MediaMetadataRetriever提供了一個統一的接口用于擷取輸入的媒體檔案的架構和中繼資料(英文不好,多多包涵)。可能大意就是這個類可以用于擷取輸入媒體檔案的一些資訊吧。
其實我主要是用到了該類的兩個功能了,一個是擷取音視訊的時長,另外一個就是擷取視訊某一幀的縮略圖。具體看下如下代碼:
以下的NETWORK和LOCAL隻是我自己定義的常量而已啦。
//根據url擷取音視訊時長,傳回毫秒
public long getDurationLong(String url,int type){
String duration = null;
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
try {
//如果是網絡路徑
if(type == NETWORK){
retriever.setDataSource(url,new HashMap<String, String>());
}else if(type == LOCAL){//如果是本地路徑
retriever.setDataSource(url);
}
duration = retriever.extractMetadata(android.media.MediaMetadataRetriever.METADATA_KEY_DURATION);
} catch (Exception ex) {
LogUtils.e(ex);
LogUtils.d("nihao", "擷取音頻時長失敗");
} finally {
try {
retriever.release();
} catch (RuntimeException ex) {
LogUtils.e(ex);
LogUtils.d("nihao", "釋放MediaMetadataRetriever資源失敗");
}
}
if(!TextUtils.isEmpty(duration)){
return Long.parseLong(duration);
}else{
return 0;
}
}
//擷取視訊縮略圖
private Bitmap createVideoThumbnail(String url, int type) {
Bitmap bitmap = null;
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
try {
//将網絡檔案以及本地檔案區分開來設定
if (type == NETWORK) {
retriever.setDataSource(url, new HashMap<String, String>());
} else if(type == LOCAL){
retriever.setDataSource(url);
}
bitmap = retriever.getFrameAtTime(0, MediaMetadataRetriever.OPTION_NEXT_SYNC);
} catch (IllegalArgumentException ex) {
LogUtils.e(ex);
LogUtils.d("nihao", "擷取視訊縮略圖失敗");
} finally {
try {
retriever.release();
} catch (RuntimeException ex) {
LogUtils.e(ex);
LogUtils.d("nihao", "釋放MediaMetadataRetriever資源失敗");
}
}
return bitmap;
}
其實他倆基本一緻隻是擷取音頻用的是extractMetadata,而擷取視訊縮略圖用的是getFrameAtTime;其實重點在于兩個方法都對于傳入的url進行了是否是網絡的判斷,那麼接下來我們看看傳入不同參數的setDataSource有什麼不同吧,官方解釋如下:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIyVGduV2QvwVe0lmdhJ3ZvwFM38CXlZHbvN3cpR2Lc1TPB10QGtWUCpEMJ9CXsxWam9CXwADNvwVZ6l2c052bm9CXUJDT1wkNhVzLcRnbvZ2Lc1TWq5EMsdlYpZ1MjZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39TO4EzNyQTM2ETOwITM2EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
這個是我用于擷取本地檔案資訊的方法,可以看下我标紅的地方,path的定義是你傳入的媒體問題的路徑,是以就應該是對應的本地檔案路徑了。但是如果路徑無效是會抛出異常的。
這個是我用于擷取網絡視訊資訊的方法,也可以看下我标紅的部分,這個方法是從android 4.0才開始有的。另外那個第二個參數是請求資料時候攜帶的頭資訊。但是我這裡沒有做特殊的設定了。就傳遞了一個map對象;
上面是我最終的方法。但是一開始其實不是這個樣子的,一開始我是沒有區分網絡路徑和本地路徑的。我隻是加了sdk版本的區分而已,就是如果是4.0及其以上我用了第二個方法。在很多手機上面也沒有事兒,包括本地以及網絡的。可是後來用了小米4的6.0系統,以及華為mate7的6.0系統後,發現用兩個參數的方法是無法擷取到本地視訊的資訊的,會抛出illegalState的異常。因為我的apk的最低安裝版本就是4.0是以其實我的判斷就永遠會走進兩個參數的方法裡面的。
總結一下就是兩個參數的方法大多數情況下既可以擷取網絡音視訊資訊,也可以擷取本地音視訊資訊。但是在有的手機上無法擷取本地視訊資訊。是以就要用到一個參數的方法擷取本地音視訊資訊,且一個參數是不支援擷取網絡音視訊資訊的。是以最終就有了上面的代碼。
以上如有不對之處,歡迎批評指正。