最近在搞一個視頻截圖的功能,自己在探索過程中,看到很多各種各樣的解法,走了很多彎路,為了避免做相同功能的朋友們走很多彎路,我把自己解決方案,及探索過程遇到的Bug記錄下來,目前已經適配大部分機型,對于個別機型不能使用的歡迎issuses Github下載
最開始想的是直接用View截圖的方式截取當前的視頻,結果截取的來的圖片是黑屏,附上View截圖代碼
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這個類來獲取縮放圖,于是按照這個思路去搜索,發現可以通過獲取能夠獲取當前播放的幀數,來進行截圖,以下是我的最終解決方案
/**
* 視頻截圖代碼
* @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;
}
demo下載:https://github.com/denghuilong/screenVideo/tree/master
bug及解決方案
start called in state 4
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地址不能播放,可以在瀏覽器中試一下。
start called in state 1
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)
原因:
Streaming is Not supported before Android 3.0
Please test in device having above 3.0 version
解決方案:

這是Android官網關于,Android所支持的網絡協議網絡協議
>音頻和視頻播放支持以下網絡協議:
>RTSP協議(RTP,SDP的)
>HTTP / HTTPS的進步流
>HTTP / HTTPS的現場直播議定書草案:
>MPEG-2 TS流媒體文件只
>協議版本3(的Andr??oid 4.0及以上)
>議定書“第2版(Android的3.x版)
>不支持之前的Andr??oid 3.0
>注: HTTPS不支持之前的Android 3.1。
更換一臺Android3.0以上的設備就好了
status=0x80000000
java.io.IOException: setDataSource failed.: status=0x80000000
1、 第一種解決方法
InputStream in = getResources().getAssets().open("GPSResp.dat");
2、 第二種解決方案
將播放的視頻或者音樂因為轉換成Android所支持的格式
下面是Android所支持的格式
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"
};
java.io.IOException: Prepare failed.: status=0x1
MediaPlay播放視頻的時候報下面的錯
java.io.IOException: Prepare failed.: status=0x1
解決方案
把mediaPlayer.prepare;改成
mediaPlayer.prepareAsync();
getFrameAtTime: videoFrame is a NULL pointer
播放視頻的時候包下面的錯誤
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 主要用來兩種用法:
1、和MediaPlay配合使用播放視頻,
2、或者和Canvas配合使用實現一些動畫
但是不能這兩種方法一起使用或者就會報上面的錯。
解決方案:
如果想要做視頻截取的話,可以使用MediaMetadataRetriever這個類截取當前播放的幀畫面,來是現實視頻截圖功能,項目貼上,代碼中有注釋