android 獲取視訊縮圖終極解決方案(ffmpeg)
阿新 • • 發佈:2018-12-30
前些天有個師弟(在做一個仿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();
}
});
}
要求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;
}
該方法在2.x系統下可用,API LEVEL > 14時卻只能返回null
- 方案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;
}
理論上,進過測試以上三個方案,基本的可以獲取網路或本地的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命令~
執行app,輸入框輸入:-
i /sdcard/test.asf -y -f image2 -t 0.001 -s 352x240 /sdcard/a.jpg
執行完畢,sdcard生成縮圖,棒!成功了!