最近在搞一個視頻截圖的功能,本身在探索過程當中,看到不少各類各樣的解法,走了不少彎路,爲了不作相同功能的朋友們走不少彎路,我把本身解決方案,及探索過程遇到的Bug記錄下來java
screenVideo是一個通用的視頻截圖工具,目前已經適配大部分機型,對於個別機型不能使用的歡迎issuses,Demo中的視頻的url不可用,視頻的url能夠從任意視頻網站找一個能夠播放的視頻地址,用火狐獲取一下播放的URL,替換demo中的url便可 Github下載android
最開始想的是直接用View截圖的方式截取當前的視頻,結果截取的來的圖片是黑屏,附上View截圖代碼git
public Bitmap convertViewToBitmap(View view){
view.destroyDrawingCache();//銷燬舊的cache銷燬,獲取cache一般會佔用必定的內存,因此一般不須要的時候有必要對其進行清理
view.setDrawingCacheEnabled(true);//cache開啓
view.buildDrawingCache();//建立新的緩存,獲取cache一般會佔用必定的內存,因此一般不須要的時候有必要對其進行清理,在每次獲取新的,先銷燬舊的緩存
view.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));//測量view
Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache());//將緩存的view轉換爲圖片
return bitmap;
}
複製代碼
上面的方式只能對靜態的View進行截圖,可是動態的好比說視頻,那麼截出來的圖片就是黑屏。 用SurfaceView顯示在線視頻,而後經過上面截圖方式,獲得圖片是黑屏,(關於黑屏的緣由你們能夠去網上搜索,能夠獲得你想要的答案,這裏就不在說了)因而我就去谷歌,各大博客上尋求解決方案,發現Android提供了MediaMetadataRetriever這個類來獲取縮放圖,因而按照這個思路去搜索,發現能夠經過獲取可以獲取當前播放的幀數,來進行截圖,如下是個人最終解決方案github
/**
* 視頻截圖代碼
* @param url 播放的url
* @param width 生成圖片的寬度
* @param height 生成圖片的高度
* @param currentVideoTime 當前播放的播放的秒數
* @return
*/
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
private Bitmap createVideoThumbnail(String url, int width, int height,String currentVideoTime) {
Bitmap bitmap = null;
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
int kind = MediaStore.Video.Thumbnails.MINI_KIND;
try {
if (Build.VERSION.SDK_INT >= 14) {//Android4.0以上的設備,必須使用這種方式來設置源播放視頻的路徑
retriever.setDataSource(url, new HashMap<String, String>());
} else {
retriever.setDataSource(url);
}
int millis = mMdeiaPlayer.getDuration();
Log.e(TAG, "-----millis----" + millis);
int pro = mMdeiaPlayer.getCurrentPosition();
Log.e(TAG,"-----pro----"+pro);
String timeString = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
long time = Long.parseLong(timeString) * 1000; //獲取總長度,這一句也是必須的
long d = time*pro/millis;//計算當前播放的幀數,來截取當前的視頻
Log.e(TAG,"---------"+d);
bitmap = retriever.getFrameAtTime(d, MediaMetadataRetriever.OPTION_CLOSEST_SYNC);
if (kind == MediaStore.Images.Thumbnails.MICRO_KIND && bitmap != null) {
bitmap = ThumbnailUtils.extractThumbnail(bitmap, width, height,
ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
}
} catch (IllegalArgumentException ex) {
// Assume this is a corrupt video file
} catch (RuntimeException ex) {
// Assume this is a corrupt video file.
} finally {
try {
retriever.release();
mMdeiaPlayer.start();
} catch (RuntimeException ex) {
// Ignore failures while cleaning up.
}
}
return bitmap;
}
複製代碼
Github下載地址 : https://github.com/hi-dhl/screenVideo瀏覽器
04-05 10:58:14.169 2237-2237/demo.dhl.con.onlinevideo E/MediaPlayer: start called in state 4
04-05 10:58:14.169 2237-2237/demo.dhl.con.onlinevideo E/MediaPlayer: error (-38, 0)
04-05 10:58:14.169 2237-2237/demo.dhl.con.onlinevideo E/MediaPlayer: Error (-38,0)
04-05 10:58:14.176 2237-2250/demo.dhl.con.onlinevideo E/MediaPlayer: error (261, -1003)
04-05 10:58:14.176 2237-2237/demo.dhl.con.onlinevideo E/MediaPlayer: Error (261,-1003)
複製代碼
可能因爲的播放的文件錯誤,或者給的url地址不能播放,能夠在瀏覽器中試一下。緩存
04-05 11:50:27.346 2038-2038/demo.dhl.con.onlinevideo E/MediaPlayer: start called in state 1
04-05 11:50:27.347 2038-2038/demo.dhl.con.onlinevideo E/MediaPlayer: error (-38, 0)
04-05 11:50:27.367 2038-2050/demo.dhl.con.onlinevideo E/MediaPlayer: error (261, -1003)
04-05 11:50:27.367 2038-2038/demo.dhl.con.onlinevideo E/MediaPlayer: Error (261,-1003)
複製代碼
緣由:bash
Streaming is Not supported before Android 3.0
Please test in device having above 3.0 version
複製代碼
解決方案:網絡
![](http://upload-images.jianshu.io/upload_images/1479838-d821c0b136e94734.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
這是Android官網關於,Android所支持的網絡協議網絡協議
>音頻和視頻播放支持如下網絡協議:
>RTSP協議(RTP,SDP的)
>HTTP / HTTPS的進步流
>HTTP / HTTPS的現場直播議定書草案:
>MPEG-2 TS流媒體文件只
>協議版本3(的Android 4.0及以上)
>議定書「第2版(Android的3.x版)
>不支持以前的Android 3.0
>注: HTTPS不支持以前的Android 3.1。
更換一臺Android3.0以上的設備就行了
複製代碼
java.io.IOException: setDataSource failed.: status=0x80000000
複製代碼
InputStream in = getResources().getAssets().open("GPSResp.dat");
複製代碼
將播放的視頻或者音樂由於轉換成Android所支持的格式 下面是Android所支持的格式ide
static const char* kNoCompressExt[] = {
".jpg", ".jpeg", ".png", ".gif",
".wav", ".mp2", ".mp3", ".ogg", ".aac",
".mpg", ".mpeg", ".mid", ".midi", ".smf", ".jet",
".rtttl", ".imy", ".xmf", ".mp4", ".m4a",
".m4v", ".3gp", ".3gpp", ".3g2", ".3gpp2",
".amr", ".awb", ".wma", ".wmv"
};
複製代碼
MediaPlay播放視頻的時候報下面的錯工具
java.io.IOException: Prepare failed.: status=0x1
複製代碼
解決方案:把mediaPlayer.prepare;改爲 mediaPlayer.prepareAsync();
播放視頻的時候包下面的錯誤
getFrameAtTime: videoFrame is a NULL pointer
複製代碼
解決方案:視頻地址錯誤,或者 視頻損壞不能播放,檢查視頻是否正常
當咱們使用SurfaceView的來顯示播放的視頻的時候,須要截取視頻的時候,直接使用普通View獲取截圖的方式,會是黑屏,網上不少博客提到了解決方案mHolder.lockCanvas() 獲取Canva來獲取畫布,實現截取視頻,實際上是錯誤的,我照着網上的貼子作了,報了下面的錯,不知道是否是個人使用方法有錯,請網友指正
12:58:24.690: E/BaseSurfaceHolder(719): Exception locking surface
12:58:24.690: E/BaseSurfaceHolder(719): java.lang.IllegalArgumentException
12:58:24.690: E/BaseSurfaceHolder(719): at android.view.Surface.nativeLockCanvas(Native Method)
12:58:24.690: E/BaseSurfaceHolder(719): at android.view.Surface.lockCanvas(Surface.java:447)
12:58:24.690: E/BaseSurfaceHolder(719): at com.android.internal.view.BaseSurfaceHolder.internalLockCanvas(BaseSurfaceHolder.java:184)
複製代碼
緣由: SurfaceView 主要用來兩種用法:
可是不能這兩種方法一塊兒使用或者就會報上面的錯。
解決方案:若是想要作視頻截取的話,可使用MediaMetadataRetriever這個類截取當前播放的幀畫面,來是現實視頻截圖功能,項目貼上,代碼中有註釋