android 獲取視頻縮略圖終極解決方案(ffmpeg)


http://blog.csdn.net/u010499721/article/details/50338623

前些天有個師弟(在做一個仿LinkInEyes行車記錄儀的app)問我怎么獲取視頻縮略圖,起初以為很簡單,就找了個常用的解決方案(用戶獲取正常的視頻文件的縮略圖):

  1. 方案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

  1. 方案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

  1. 方案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

http://i.imgur.com/cP4WhLn.gif

下載測試app

運行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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM