http://blog.csdn.net/u010499721/article/details/50338623
前些天有个师弟(在做一个仿LinkInEyes行车记录仪的app)问我怎么获取视频缩略图,起初以为很简单,就找了个常用的解决方案(用户获取正常的视频文件的缩略图):
- 方案1:
private void initView() {
imgPic = (ImageView) findViewById(R.id.img_pic); seekbar = (SeekBar) findViewById(R.id.seekbar); mmr = new MediaMetadataRetriever(); mmr.setDataSource("/sdcard/3.mp4"); // 取得视频的长度(单位为毫秒) String time = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION); seekbar.setMax(Integer.parseInt(time) * 1000); bt = (Button) findViewById(R.id.bt); bt.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MainActivity.this, " " + seekbar.getProgress(), 1).show(); Bitmap bitmap = mmr.getFrameAtTime(seekbar.getProgress(), MediaMetadataRetriever.OPTION_CLOSEST_SYNC); // Bitmap bitmap = mmr.getFrameAtTime(seekbar.getProgress()); imgPic.setImageBitmap(bitmap); System.out.println(mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DATE)+ ""); System.out.println(mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_MIMETYPE)+ ""); // mmr.release(); } }); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
要求Android api>=10
- 方案2:
ThumbnailUtils.createVideoThumbnail(filePath, kind);方法获取
public static Bitmap createVideoThumbnail(String filePath, int kind) { Bitmap bitmap = null; MediaMetadataRetriever retriever = new MediaMetadataRetriever(); try { retriever.setDataSource(filePath); bitmap = retriever.getFrameAtTime(-1); } catch (IllegalArgumentException ex) { // Assume this is a corrupt video file } catch (RuntimeException ex) { // Assume this is a corrupt video file. } finally { try { retriever.release(); } catch (RuntimeException ex) { // Ignore failures while cleaning up. } } if (bitmap == null) return null; if (kind == Images.Thumbnails.MINI_KIND) { // Scale down the bitmap if it's too large. int width = bitmap.getWidth(); int height = bitmap.getHeight(); int max = Math.max(width, height); if (max > 512) { float scale = 512f / max; int w = Math.round(scale * width); int h = Math.round(scale * height); bitmap = Bitmap.createScaledBitmap(bitmap, w, h, true); } } else if (kind == Images.Thumbnails.MICRO_KIND) { bitmap = extractThumbnail(bitmap, TARGET_SIZE_MICRO_THUMBNAIL, TARGET_SIZE_MICRO_THUMBNAIL, OPTIONS_RECYCLE_INPUT); } return bitmap; }
- 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
- 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
该方法在2.x系统下可用,API LEVEL > 14时却只能返回null
http://my.oschina.net/kylinhuang/blog/472757?fromerr=vASTONAf
- 方案3
使用开源代码:MediaMetadataRetriever
private Bitmap getBitMap() { Bitmap b = null; // Retrieve all metadata. List<Metadata> metadata = new ArrayList<Metadata>(); if (mUri == null) return null; FFmpegMediaMetadataRetriever fmmr = new FFmpegMediaMetadataRetriever(); try { fmmr.setDataSource(mUri); for (int i = 0; i < Constants.METADATA_KEYS.length; i++) { //注意 String key = Constants.METADATA_KEYS[i]; String value = fmmr.extractMetadata(key); if (value != null) { metadata.add(new Metadata(key, value)); Log.i(MetadataLoader.class.getName(), "Key: " + key + " Value: " + value); } } b = fmmr.getFrameAtTime(); if (b != null) { Bitmap b2 = fmmr.getFrameAtTime(seekbar.getProgress(), FFmpegMediaMetadataRetriever.OPTION_CLOSEST_SYNC); if (b2 != null) { b = b2; } } if (b != null) { metadata.add(new Metadata("image", b)); Log.i(MetadataLoader.class.getName(), "Extracted frame"); } else { Log.e(MetadataLoader.class.getName(), "Failed to extract frame"); } } catch (IllegalArgumentException ex) { ex.printStackTrace(); } finally { fmmr.release(); } return b; }
- 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
- 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
fmmr.setDataSource(mUri);中uri支持的文件类型 file, http, https, mms and mmsh 支持的编码格式(音频&视频): aac, acc+, avi, flac, mp2, mp3, mp4, ogg, 3gp and more! 扩展支持:
开源地址:https://github.com/wseemann/FFmpegMediaMetadataRetriever
備份地址:https://github.com/qq179157977/FFmpegMediaMetadataRetriever
理论上,进过测试以上三个方案,基本的可以获取网络或本地的map4,avi等视频的缩略图了。
但是师弟说还是获取不了,因为他获取到的是一个thm文件(idr流返回),这种文件不是视频文件,是是MP4或者MPG视频文件的索引文件,用以上三种方法根本获取不到缩略图,我就觉得奇怪,想起强大的ffmpeg也可以获取缩略图,于是下载了一个命令行的ffmpeg开始尝试获取缩略图:
先将文件放到c盘,切换到c盘(ffmpeg也在c盘),运行:
ffmpeg -i C:\fengkai.htm -y -f image2 -t 0.001 -s 352x240 a.jpg
运行完毕,出现了a.jpg,还真的可以获取htm文件的缩略图
但是,ffmpeg命令要在android上运行,需要将ffmpeg(Linux版)文件放到一个目录,然后用root权限给予ffmpeg执行权,才可以调用上述获取缩略图命令,原因是系统没有ffmpeg命令~
这是只能继续找到不需要权限又能通过ffmpeg获取缩略图的demo了,找了一段时间,找到一个外国人写的牛逼开源项目:
https://github.com/WritingMinds/ffmpeg-android-java
运行app,输入框输入:-
i /sdcard/test.asf -y -f image2 -t 0.001 -s 352x240 /sdcard/a.jpg
执行完毕,sdcard生成缩略图,棒!成功了!
附录
thm测试文件参考:
http://my.oschina.net/kylinhuang/blog/472757?fromerr=vASTONAf
http://www.tuicool.com/articles/uqmUFfY
http://helloandroid.iteye.com/blog/1753355