MediaMetadataRetriever获取网络/本地视频第一帧图片

获取视频第一帧图片,这种需求不多,项目中用到了这个功能踩了点坑,很骚。

获取网络视频

1
2
3
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
//后面这个是传请求Headers,如果有需要可以添加
mmr.setDataSource(url, new HashMap());

获取本地视频(setDataSource中不需要传第二个参数,直接传路径就好)

1
2
3
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
//后面这个是传请求Headers,如果有需要可以添加
mmr.setDataSource(path, new HashMap());

封装的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
public class MediaUtils {
public static final int MEDIA_TYPE_IMAGE = 1;
public static final int MEDIA_TYPE_VIDEO = 2;
public static File file;

/**
* Create a file Uri for saving an image or video
*/
public static Uri getOutputMediaFileUri(Context context, int type) {
Uri uri = null;
//适配Android N
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
return FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".provider", getOutputMediaFile(type));
} else {
return Uri.fromFile(getOutputMediaFile(type));
}
}

/**
* Create a File for saving an image or video
*/
public static File getOutputMediaFile(int type) {
// To be safe, you should check that the SDCard is mounted
// using Environment.getExternalStorageState() before doing this.
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), "image");
// This location works best if you want the created images to be shared
// between applications and persist after your app has been uninstalled.
// Create the storage directory if it does not exist
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
return null;
}
}
// Create a media file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File mediaFile;
if (type == MEDIA_TYPE_IMAGE) {
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"IMG_" + timeStamp + ".jpg");
} else if (type == MEDIA_TYPE_VIDEO) {
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"VID_" + timeStamp + ".mp4");
} else {
return null;
}
file = mediaFile;
return mediaFile;
}

/**
* 获取视频的第一帧图片
*/
public static void getImageForVideo(String videoPath, OnLoadVideoImageListener listener) {
LoadVideoImageTask task = new LoadVideoImageTask(listener);
task.execute(videoPath);
}

public static class LoadVideoImageTask extends AsyncTask<String, Integer, File> {
private OnLoadVideoImageListener listener;

public LoadVideoImageTask(OnLoadVideoImageListener listener) {
this.listener = listener;
}

@Override
protected File doInBackground(String... params) {
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
String path = params[0];
if (path.startsWith("http"))
//获取网络视频第一帧图片
mmr.setDataSource(path, new HashMap());
else
//本地视频
mmr.setDataSource(path);
Bitmap bitmap = mmr.getFrameAtTime();
//保存图片
File f = getOutputMediaFile(MEDIA_TYPE_IMAGE);
if (f.exists()) {
f.delete();
}
try {
FileOutputStream out = new FileOutputStream(f);
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.flush();
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
mmr.release();
return f;
}

@Override
protected void onPostExecute(File file) {
super.onPostExecute(file);
if (listener != null) {
listener.onLoadImage(file);
}
}
}

public interface OnLoadVideoImageListener {
void onLoadImage(File file);
}
}

因为考虑到处理视频比较耗时,上面代码使用了AsycTask+Callback的方式来实现,先保存到本地后在加载本地的图片。

坚持原创技术分享,您的支持将鼓励我继续创作!