This is the sixth day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021
Android video image thumbnail get
Now to get straight to the point, for getting a thumbnail of a video, In the android system provides ThumbnailUtils, android. The provider. The MediaStore. Images. The Thumbnails, android. The provider. The MediaStore. Video. Thumbnails, M Several classes are available for ediaMetadataRetriever. In this article, I only analyze ThumbnailsUtils, but I will introduce the next three classes in future articles.
ThumbnailUtils
- ThumbnailUtils. CreateVideoThumbnail (filePath, kind) : create video thumbnails, filePath: file path, kind: MINI_KIND or MICRO_KIND
- ThumbnailUtils. ExtractThumbnail (bitmap, width, height) : the bitmap cutting for the specified size
- ThumbnailUtils. ExtractThumbnail (bitmap, width, height, options) : clip bitmap to the specified size, can have parameters BitmapFactory. The options parameter
CreateVideoThumbnail; createVideoThumbnail; createVideoThumbnail;
/** * Create a video thumbnail for a video. May return null if the video is * corrupt or the format is not supported. * * @param filePath the path of video file * @param kind could be MINI_KIND or MICRO_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; }Copy the code
By looking at the source code: we found that this method also uses a mediametadaretriever object inside, so what is this object? We’ll talk about that later, but we get a Bitmap from this object, and then compress the image according to kind. That’s the general idea of the source code. Parameter Description:
- FilePath Indicates the path of the video file
- Thumbnails.MICRO_KIND and images.thumbnails.MINI_KIND, where MINI_KIND: 512 x 384, MICRO_KIND: 96 x 96, of course, if you read the code, you can pass in any number of ints, but that doesn’t work.
ExtractThumbnail (Bitmap source, int width, int height) :
/**
* Creates a centered bitmap of the desired size.
*
* @param source original bitmap source
* @param width targeted width
* @param height targeted height
*/
public static Bitmap extractThumbnail(
Bitmap source, int width, int height) {
return extractThumbnail(source, width, height, OPTIONS_NONE);
}
Copy the code
Source code is very simple, is to call extractThumbnail’s brother. Parameter Description:
- Source: indicates the image source file (Bitmap type)
- Width: indicates the compressed width
- Height: indicates the height after compression
ExtractThumbnail (Bitmap source, int width, int height, int options) : crop the image and specify options. Look at the source code:
/**
* Creates a centered bitmap of the desired size.
*
* @param source original bitmap source
* @param width targeted width
* @param height targeted height
* @param options options used during thumbnail extraction
*/
public static Bitmap extractThumbnail(
Bitmap source, int width, int height, int options) {
if (source == null) {
return null;
}
float scale;
if (source.getWidth() < source.getHeight()) {
scale = width / (float) source.getWidth();
} else {
scale = height / (float) source.getHeight();
}
Matrix matrix = new Matrix();
matrix.setScale(scale, scale);
Bitmap thumbnail = transform(matrix, source, width, height,
OPTIONS_SCALE_UP | options);
return thumbnail;
}
Copy the code
The processing in the source code adopts Matrix object for transformation operation, which is not very complex. Students who are not familiar with Matrix can search for usage. It’s very useful in our custom view. Parameter Description:
- Source: indicates the image source file (Bitmap type)
- Width: indicates the compressed width
- Height: indicates the height after compression
- Recycles @param source if options is OPTIONS_RECYCLE_INPUT (unless thumbnail is equal to @param source)
These three methods are at the heart of the ThumbnailUtils class, and you just need to know how to use them. See this article by Ouyang Peng for more information.
Here is a case to introduce its use. The requirements of the case are: call the camera of the system to take photos and video, and then display thumbnails. The requirements are simple, and the core is to use the ThumbnailUtils utility class for thumbnail processing. Now let’s start to fulfill this requirement. We create the project PicturePhotoDemo in Eclipse.
1. First of all, set up our home page layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.dsw.picturephotodemo.MainActivity" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:textSize="20sp"
android:padding="10dp"
android:text="@string/hello_world" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:gravity="center_horizontal"
android:orientation="horizontal">
<Button
android:id="@+id/take_picture"
android:layout_height="wrap_content"
android:layout_width="100dp"
android:text="@string/take_picture"
android:textSize="17sp"/>
<Button
android:id="@+id/take_video"
android:layout_height="wrap_content"
android:layout_width="100dp"
android:text="@string/take_video"
android:textSize="17sp"/>
</LinearLayout>
<com.dsw.horizonlistview.HorizontalListView
android:id="@+id/horizontalListView"
android:layout_width="match_parent"
android:layout_gravity="center_vertical"
android:spacing="5dp"
android:layout_height="100dp"
android:scrollbars="@null">
</com.dsw.horizonlistview.HorizontalListView>
</LinearLayout>
Copy the code
The renderings are as follows:
In the layout above, we used a custom View called HorizontalListView. The HorizontalListView source code will not be posted, too much, and not our focus, interested students can later download the demo project, in the project. We need to know that the HorizontalListView is a HorizontalListView, using the same method as the ListView.
2. We create a MeadiaInformation entity to store our photo information.
Public class MeadiaInformation {public String srcPath; Public int type=1 public int type; Public bitmap bitmap; }Copy the code
3, our custom HorizontalListViewAdapter adapter, used to handle our pictures show.
public class HorizontalListViewAdapter extends BaseAdapter{ private Context mContext; private LayoutInflater mInflater; Bitmap iconBitmap; private int selectIndex; private List<MeadiaInformation> list; public HorizontalListViewAdapter(Context context, List<MeadiaInformation> list){ this.mContext = context; this.list = list; mInflater=(LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); //LayoutInflater.from(mContext); } @Override public int getCount() { return list == null ? 0 : list.size(); } @Override public Object getItem(int position) { return list == null ? null : list.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if(convertView==null){ holder = new ViewHolder(); convertView = mInflater.inflate(R.layout.horizontal_list_item, null); holder.mImage=(ImageView)convertView.findViewById(R.id.img_list_item); holder.mVideoImage = (ImageView) convertView.findViewById(R.id.img_video); convertView.setTag(holder); }else{ holder=(ViewHolder)convertView.getTag(); If (position == selectIndex){convertView.setSelected(true); }else{ convertView.setSelected(false); } if(list ! = null && list.size() > 0){ iconBitmap = list.get(position).bitmap; holder.mImage.setImageBitmap(iconBitmap); If (list. Get (position). Type = = 1) {/ / if the video, it is show video playback button holder. MVideoImage. SetVisibility (the VISIBLE). } else {/ / if not video don't show the play button holder. MVideoImage. SetVisibility (the cause). } } return convertView; } private static class ViewHolder {private ImageView mImage; Private ImageView mVideoImage; } @param infor */ public void addInformation(MeadiaInformation infor){list.add(infor); notifyDataSetChanged(); } @param listInfo */ public void addInformationList(List<MeadiaInformation> listInfo){ list.addAll(listInfo); notifyDataSetChanged(); } public void setSelectIndex(int I){selectIndex = I; } @return */ public int getSelectIndex(){return this.selectIndex; }}Copy the code
3. Everything is in place. We need to handle our photo logic in MainActivity and then handle thumbnails. Originally, I wanted to post the code for processing that part, but I felt that the logic was a bit disconnected, so I would rather post all MainActivity.
Public class MainActivity extends Activity {private static final int REQUEST_TAKE_PITURE = 100; Private static final int REQUEST_TAKE_VIDEO = 200; private static final int REQUEST_TAKE_VIDEO = 200; private MainActivity _this; // Private Button btn_takePicture; // Private Button btn_takeVideo; // File storage path private String path; // file private file photoFile; Private HorizontalListView private HorizontalListView; / / ListView adapter private HorizontalListViewAdapter listViewAdapter; Private MeadiaInformation infor; private DisplayMetrics metrics; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); _this =this; btn_takePicture = (Button) findViewById(R.id.take_picture); btn_takeVideo = (Button) findViewById(R.id.take_video); listView = (HorizontalListView) findViewById(R.id.horizontalListView); metrics = getResources().getDisplayMetrics(); setOnListener(); initAdapter(); initPath(); } /** * Initializes the storage path */ private void initPath(){// Checks whether the storage card exists If (Environment) MEDIA_MOUNTED) equals (Environment. GetExternalStorageState ())) {/ / have a memory card access path path = Environment.getExternalStorageDirectory().getAbsolutePath()+"/PhotoDemo/"; }else{path = getApplicationContext().getFilesDir().getPath()+ "/PhotoDemo/"; } File file = new File(path); if(! file.exists()){ file.mkdirs(); Private void initAdapter(){List<MeadiaInformation> List = new ArrayList<MeadiaInformation>(); private void initAdapter(){List<MeadiaInformation> List = new ArrayList<MeadiaInformation>(); listViewAdapter = new HorizontalListViewAdapter(_this, list); listView.setAdapter(listViewAdapter); } / setting controls to monitor * * * * / private void setOnListener () {btn_takePicture. SetOnClickListener (new an OnClickListener () {@ Override public void onClick(View v) { Date date = new Date(); String name = path + "/" + date.getTime() + ".jpg"; photoFile = new File(name); Uri uri = Uri.fromFile(photoFile); Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 10); StartActivityForResult (intent, REQUEST_TAKE_PITURE); }}); btn_takeVideo.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Date date = new Date(); String name = path + "/" + date.getTime() + ".3gp"; photoFile = new File(name); Uri uri = Uri.fromFile(photoFile); Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 10); StartActivityForResult (intent, REQUEST_TAKE_VIDEO); }}); listView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<? > adapterView, View view, int position, long arg3) { listViewAdapter.setSelectIndex(position); listViewAdapter.notifyDataSetChanged(); }}); } @override protected void onActivityResult(int requestCode, int resultCode, Intent data) { If (resultCode == RESULT_OK){infor = new MeadiaInformation(); infor.srcPath = photoFile.getAbsolutePath(); switch(requestCode){ case REQUEST_TAKE_PITURE: infor.type =0; break; case REQUEST_TAKE_VIDEO: infor.type =1; break; } getBitmapFromFile(); / / add the MeadiaInformation to the Adapter listViewAdapter. AddInformation (infor); }} private void getBitmapFromFile() {** * Android provides us with the ThumbnailUtils utility class to get thumbnail processing. * * ThumbnailUtils createVideoThumbnail (filePath, kind) to create video thumbnails, filePath: file path, kind: MINI_KIND or MICRO_KIND * ThumbnailUtils.extractThumbnail(bitmap, width, Height) * * ThumbnailUtils bitmap cutting for the specified size. ExtractThumbnail (bitmap, width, height, options) * clip bitmap to the specified size, Bitmapfactory. Options * */ Bitmap Bitmap = null; Bitmap = bitmapFactory.decodefile (infor.srcpath); bitmap = bitmapFactory.decodefile (infor. }else if(infor.type == 1){ The shooting video / / use ThumnailUtils bitmap = ThumbnailUtils. CreateVideoThumbnail (infor. SrcPath, Images. The Thumbnails. MINI_KIND); } // After the image is obtained, we compress the image and get the specified size if(bitmap! = null) {/ / cutting bitmap size = ThumbnailUtils. ExtractThumbnail (bitmap, (int) (100 * metrics. Density), (int)(100*metrics.density)); } else {/ / if is empty, use our default bitmap picture. = BitmapFactory decodeResource (getResources (), R.d. Rawable ic_launcher); } infor.bitmap = bitmap; }}Copy the code
In MainActivity, we click the “Take photo” and “Take video” buttons to take photos and video, and then rewrite the onActivityResult method to process the returned video. Finally, we get the thumbnail of the picture or video. Finally add to listviewAdatper for display. The overall processing logic is like this, code annotations are also very detailed, interested students can download demo to play. First post a few effect pictures: