我正在使用MediaMetadataRetriever
在视频中的特定时间检索缩略图。这就是我实现这个目标的方法:
MediaMetadataRetriever metadataRetriever = new MediaMetadataRetriever();
try {
metadataRetriever.setDataSource(MainActivity.this, Uri.parse("android.resource://packageName/raw/"+"test"));
String duration=metadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
long time = Long.valueOf(duration)/3;
Bitmap bitmap1 = metadataRetriever.getFrameAtTime(time,MediaMetadataRetriever.OPTION_CLOSEST_SYNC);
imgone.setImageBitmap(bitmap1);
}catch (Exception ex) {
Toast.makeText(MainActivity.this, String.valueOf(ex), Toast.LENGTH_SHORT).show();
}
这会返回一个预期的位图/缩略图,问题是如果我想在视频中的不同时间获得多个缩略图,如下所示:
MediaMetadataRetriever metadataRetriever = new MediaMetadataRetriever();
try {
metadataRetriever.setDataSource(MainActivity.this, Uri.parse("android.resource://packageName/raw/"+"test"));
String duration=metadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
long time = Long.valueOf(duration)/3;
long time2 = time+time;
long time3 = time+time+time;
Bitmap bitmap1 = metadataRetriever.getFrameAtTime(time,MediaMetadataRetriever.OPTION_CLOSEST_SYNC);
Bitmap bitmap2 = metadataRetriever.getFrameAtTime(time2,MediaMetadataRetriever.OPTION_CLOSEST_SYNC);
Bitmap bitmap3 = metadataRetriever.getFrameAtTime(time3,MediaMetadataRetriever.OPTION_CLOSEST_SYNC);
imgone.setImageBitmap(bitmap1);
imgtwo.setImageBitmap(bitmap2);
imgthree.setImageBitmap(bitmap3);
}catch (Exception ex) {
Toast.makeText(MainActivity.this, String.valueOf(ex), Toast.LENGTH_SHORT).show();
}
然后它仍然只返回相同的缩略图,我不确定是不是因为只有一个缩略图可用于视频或什么,但我尝试了不同的视频文件,结果相同。
我尝试将MediaMetadataRetriever.OPTION_CLOSEST_SYNC
更改为所有可用选项,但结果仍然相同。
我不确定FFMPEG
是否会是更好的选择?
答案 0 :(得分:4)
正好一年后,我注意到我从未提供答案。
在最初的问题中,我想检索3个缩略图,最终检索到5个。我还提到我不确定FFmpeg是否适合使用,这正是我所使用的。
因此,在OnCreate
中,我确保支持FFmpeg,然后执行以下操作:
if (FFmpeg.getInstance(getApplication()).isSupported()) {
@SuppressLint("SimpleDateFormat")
//ffmpeg expects the time format to be "00:00:00"
Format formatter = new SimpleDateFormat("00:" + "mm:ss.SS");
//Get the duration of the video
long duration = player.getDuration();
//Since I want 5 thumbnails, I divide the duration by 6 to get the first thumbnail position
long img1 = duration / 6;
//I format the first thumbnail time since ffmpeg expects "00:00:00" format
String firstTumbTime = formatter.format(img1);
//Scale the size of the thumbnail output (this can be improved/changed to your liking)
String scaledSize = displayMetrics.widthPixels / 7 + ":" + displayMetrics.heightPixels / 7;
//Set ffmpeg command (notice that I set vframes to one, since I only want 1 thumbnail/image)
String[] a = {"-ss", firstTumbTime, "-i", mStringFilePath, "-vframes", "1", "-s", scaledSize, imageThumbsDirectory + "/" + "thumb1.bmp"};
//start ffmpeg asynctask for the first thumbnail
ExecuteThumbFFMPEG(a);
} else {
Toast.makeText(TestNewPlayer.this, "Your device doesn't support FFMPEG...", Toast.LENGTH_SHORT).show();
}
上面代码中的注释说明了所有内容,现在是我的ExecuteThumbFFMPEG
方法。
public void ExecuteThumbFFMPEG(String[] command) {
ffmpegImages = FFmpeg.getInstance(this).execute(command, new ExecuteBinaryResponseHandler() {
@Override
public void onStart() {
//ffmpeg started
}
@Override
public void onProgress(String message) {
//get ffmpeg progress
}
@Override
public void onFailure(String message) {
//ffmpeg failed
}
@Override
public void onSuccess(String message) {
//first thumbnail saved successfully, now to get the other 4
//Scale the thumbnail output (Same as above)
String scaledSize = displayMetrics.widthPixels / 7 + ":" + displayMetrics.heightPixels / 7;
try {
//I first set the path/name for each thumbnail, this will also be used to check if the thumbnail is available or if we should get it
String imgPath1 = imageThumbsDirectory + "/" + "thumb1.bmp";
String imgPath2 = imageThumbsDirectory + "/" + "thumb2.bmp";
String imgPath3 = imageThumbsDirectory + "/" + "thumb3.bmp";
String imgPath4 = imageThumbsDirectory + "/" + "thumb4.bmp";
String imgPath5 = imageThumbsDirectory + "/" + "thumb5.bmp";
//Set the format again (same as above)
@SuppressLint("SimpleDateFormat")
Format formatter = new SimpleDateFormat("00:" + "mm:ss.SS");
//Get the length of the video
long duration = Player.getDuration();
//Divide the length of the video by 6 (same as above)
long time = duration / 6;
//Since I want 5 thumbnails evenly distributed throughout the video
//I use the video length divided by 6 to accomplish that
long img2 = time + time;
long img3 = time + time + time;
long img4 = time + time + time + time;
long img5 = time + time + time + time + time;
//Format the time (calculated above) for each thumbnail I want to retrieve
String Img2Timeformat = formatter.format(img2);
String Img3Timeformat = formatter.format(img3);
String Img4Timeformat = formatter.format(img4);
String Img5Timeformat = formatter.format(img5);
//Get reference to the thumbnails (to see if they have been created before)
File fileimgPath1 = new File(imgPath1);
File fileimgPath2 = new File(imgPath2);
File fileimgPath3 = new File(imgPath3);
File fileimgPath4 = new File(imgPath4);
File fileimgPath5 = new File(imgPath5);
//If thumbnail 1 exist and thumbnail 2 doesn't then we need to get thumbnail 2
if (fileimgPath1.exists() && !fileimgPath2.exists()) {
//Get/decode bitmap from the first thumbnail path to be able to set it to our ImageView that should hold the first thumbnail
Bitmap bmp1 = BitmapFactory.decodeFile(imgPath1);
//Set the first thumbnail to our first ImageView
imgone.setImageBitmap(bmp1);
//Set the ffmpeg command to retrieve the second thumbnail
String[] ffmpegCommandForThumb2 = {"-ss", Img2Timeformat, "-i", mStringFilePath, "-vframes", "1", "-s", scaledSize, imageThumbsDirectory + "/" + "thumb2.bmp"};
//Start ffmpeg again, this time we will be getting thumbnail 2
ExecuteThumbFFMPEG(ffmpegCommandForThumb2);
}
//If thumbnail 2 exist and thumbnail 3 doesn't then we need to get thumbnail 3
if (fileimgPath2.exists() && !fileimgPath3.exists()) {
//Get/decode bitmap from the second thumbnail path to be able to set it to our ImageView that should hold the second thumbnail
Bitmap bmp2 = BitmapFactory.decodeFile(imgPath2);
//Set the second thumbnail to our second ImageView
imgTwo.setImageBitmap(bmp2);
//Set the ffmpeg command to retrieve the third thumbnail
String[] ffmpegCommandForThumb3 = {"-ss", Img3Timeformat, "-i", mStringFilePath, "-vframes", "1", "-s", scaledSize, imageThumbsDirectory + "/" + "thumb3.bmp"};
//Start ffmpeg again, this time we will be getting thumbnail 3
ExecuteThumbFFMPEG(ffmpegCommandForThumb3);
}
////If thumbnail 3 exist and thumbnail 4 doesn't then we need to get thumbnail 4
if (fileimgPath3.exists() && !fileimgPath4.exists()) {
//Get/decode bitmap from the third thumbnail path to be able to set it to our ImageView that should hold the third thumbnail
Bitmap bmp3 = BitmapFactory.decodeFile(imgPath3);
//Set the third thumbnail to our third ImageView
imgThree.setImageBitmap(bmp3);
//Set the ffmpeg command to retrieve the fourth thumbnail
String[] ffmpegCommandForThumb4 = {"-ss", Img4Timeformat, "-i", mStringFilePath, "-vframes", "1", "-s", scaledSize, imageThumbsDirectory + "/" + "thumb4.bmp"};
//Start ffmpeg again, this time we will be getting thumbnail 4
ExecuteThumbFFMPEG(ffmpegCommandForThumb4);
}
////If thumbnail 4 exist and thumbnail 5 doesn't then we need to get thumbnail 5
if (fileimgPath4.exists() && !fileimgPath5.exists()) {
//Get/decode bitmap from the first fourth path to be able to set it to our ImageView that should hold the fourth thumbnail
Bitmap bmp4 = BitmapFactory.decodeFile(imgPath4);
//Set the fourth thumbnail to our fourth ImageView
imgFour.setImageBitmap(bmp4);
//Set the ffmpeg command to retrieve the last thumbnail
String[] ffmpegCommandForThumb5 = {"-ss", Img5Timeformat, "-i", mStringFilePath, "-vframes", "1", "-s", scaledSize, imageThumbsDirectory + "/" + "thumb5.bmp"};
//Start ffmpeg again, this time we will be getting thumbnail 5
ExecuteThumbFFMPEG(ffmpegCommandForThumb5);
}
//If thumbnail 5 exist, then we are done and we need to set it to our ImageView
if (fileimgPath5.exists()) {
Bitmap bmp5 = BitmapFactory.decodeFile(imgPath5);
imgFive.setImageBitmap(bmp5);
}
} catch (Exception ex) {
Toast.makeText(Player.this, String.valueOf(ex), Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFinish() {
//ffmpeg is done
}
});
}
当调用从Activity
或OnDestroy
中退出的用户时,应删除所有缩略图,我可以通过调用以下方法来做到这一点:
DeleteThumbs.deleteAllThumbnails(getBaseContext());
这里是DeleteThumbs
类,用于删除所有缩略图/图像
class DeleteThumbs {
@SuppressWarnings("unused")
static void deleteAllThumbnails(Context baseContext){
//Directory where all the thumbnails are stored
File imageThumbsDirectory = baseContext.getExternalFilesDir("ThumbTemp");
//Path to each thumbnail
File f1 = new File(imageThumbsDirectory + "/" + "thumb1.bmp");
File f2 = new File(imageThumbsDirectory + "/" + "thumb2.bmp");
File f3 = new File(imageThumbsDirectory + "/" + "thumb3.bmp");
File f4 = new File(imageThumbsDirectory + "/" + "thumb4.bmp");
File f5 = new File(imageThumbsDirectory + "/" + "thumb5.bmp");
boolean d1 = f1.delete();
boolean d2 = f2.delete();
boolean d3 = f3.delete();
boolean d4 = f4.delete();
boolean d5 = f5.delete();
}
}
由于我们知道每个缩略图的名称,因此很容易一次将它们全部删除。
这为我提供了5张缩略图,这些缩略图经过缩放以减少加载到ImageView
的时间。因为我将视频的时长除以6,所以我得到了5张在整个视频中均匀分布的图像。
注意:
这可以通过将图像缓存到内存中或使用像Picasso或glide这样的库来为我们处理图像加载来改善。
答案 1 :(得分:1)
试试这个
buildscript {
ext.kotlin_version = '1.1.51'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}