最近在搞一個(gè)視頻截圖的功能,自己在探索過(guò)程中,看到很多各種各樣的解法,走了很多彎路,為了避免做相同功能的朋友們走很多彎路,我把自己解決方案,及探索過(guò)程遇到的Bug記錄下來(lái),目前已經(jīng)適配大部分機(jī)型,對(duì)于個(gè)別機(jī)型不能使用的歡迎issuses Github下載
最開(kāi)始想的是直接用View截圖的方式截取當(dāng)前的視頻,結(jié)果截取的來(lái)的圖片是黑屏,附上View截圖代碼
public Bitmap convertViewToBitmap(View view){
view.destroyDrawingCache();//銷(xiāo)毀舊的cache銷(xiāo)毀,獲取cache通常會(huì)占用一定的內(nèi)存,所以通常不需要的時(shí)候有必要對(duì)其進(jìn)行清理
view.setDrawingCacheEnabled(true);//cache開(kāi)啟
view.buildDrawingCache();//創(chuàng)建新的緩存,獲取cache通常會(huì)占用一定的內(nèi)存,所以通常不需要的時(shí)候有必要對(duì)其進(jìn)行清理,在每次獲取新的,先銷(xiāo)毀舊的緩存
view.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));//測(cè)量view
Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache());//將緩存的view轉(zhuǎn)換為圖片
return bitmap;
}
上面的方式只能對(duì)靜態(tài)的View進(jìn)行截圖,但是動(dòng)態(tài)的比如說(shuō)視頻,那么截出來(lái)的圖片就是黑屏。
用SurfaceView顯示在線(xiàn)視頻,然后通過(guò)上面截圖方式,得到圖片是黑屏,(關(guān)于黑屏的原因大家可以去網(wǎng)上搜索,可以得到你想要的答案,這里就不在說(shuō)了)于是我就去谷歌,各大博客上尋求解決方案,發(fā)現(xiàn)Android提供了MediaMetadataRetriever這個(gè)類(lèi)來(lái)獲取縮放圖,于是按照這個(gè)思路去搜索,發(fā)現(xiàn)可以通過(guò)獲取能夠獲取當(dāng)前播放的幀數(shù),來(lái)進(jìn)行截圖,以下是我的最終解決方案
/**
* 視頻截圖代碼
* @param url 播放的url
* @param width 生成圖片的寬度
* @param height 生成圖片的高度
* @param currentVideoTime 當(dāng)前播放的播放的秒數(shù)
* @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以上的設(shè)備,必須使用這種方式來(lái)設(shè)置源播放視頻的路徑
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; //獲取總長(zhǎng)度,這一句也是必須的
long d = time*pro/millis;//計(jì)算當(dāng)前播放的幀數(shù),來(lái)截取當(dāng)前的視頻
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)
可能由于的播放的文件錯(cuò)誤,或者給的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官網(wǎng)關(guān)于,Android所支持的網(wǎng)絡(luò)協(xié)議網(wǎng)絡(luò)協(xié)議
>音頻和視頻播放支持以下網(wǎng)絡(luò)協(xié)議:
>RTSP協(xié)議(RTP,SDP的)
>HTTP / HTTPS的進(jìn)步流
>HTTP / HTTPS的現(xiàn)場(chǎng)直播議定書(shū)草案:
>MPEG-2 TS流媒體文件只
>協(xié)議版本3(的Andr??oid 4.0及以上)
>議定書(shū)“第2版(Android的3.x版)
>不支持之前的Andr??oid 3.0
>注: HTTPS不支持之前的Android 3.1。
更換一臺(tái)Android3.0以上的設(shè)備就好了
status=0x80000000
java.io.IOException: setDataSource failed.: status=0x80000000
1、 第一種解決方法
InputStream in = getResources().getAssets().open("GPSResp.dat");
2、 第二種解決方案
將播放的視頻或者音樂(lè)因?yàn)檗D(zhuǎn)換成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播放視頻的時(shí)候報(bào)下面的錯(cuò)
java.io.IOException: Prepare failed.: status=0x1
解決方案
把mediaPlayer.prepare;改成
mediaPlayer.prepareAsync();
getFrameAtTime: videoFrame is a NULL pointer
播放視頻的時(shí)候包下面的錯(cuò)誤
getFrameAtTime: videoFrame is a NULL pointer
解決方案:
視頻地址錯(cuò)誤,或者 視頻損壞不能播放,檢查視頻是否正常
怎么樣對(duì)播放的視頻進(jìn)行截圖
當(dāng)我們使用SurfaceView的來(lái)顯示播放的視頻的時(shí)候,需要截取視頻的時(shí)候,直接使用普通View獲取截圖的方式,會(huì)是黑屏,網(wǎng)上很多博客提到了解決方案mHolder.lockCanvas() 獲取Canva來(lái)獲取畫(huà)布,實(shí)現(xiàn)截取視頻,其實(shí)是錯(cuò)誤的,我照著網(wǎng)上的貼子做了,報(bào)了下面的錯(cuò),不知道是不是我的使用方法有錯(cuò),請(qǐng)網(wǎng)友指正
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 主要用來(lái)兩種用法:
1、和MediaPlay配合使用播放視頻,
2、或者和Canvas配合使用實(shí)現(xiàn)一些動(dòng)畫(huà)
但是不能這兩種方法一起使用或者就會(huì)報(bào)上面的錯(cuò)。
解決方案:
如果想要做視頻截取的話(huà),可以使用MediaMetadataRetriever這個(gè)類(lèi)截取當(dāng)前播放的幀畫(huà)面,來(lái)是現(xiàn)實(shí)視頻截圖功能,項(xiàng)目貼上,代碼中有注釋