Android:можно ли отображать миниатюры видео?
Я создал приложение для записи видео с диалоговым окном библиотеки. В диалоговом окне библиотека отображается список записанных видео, где каждый элемент состоит из значка, заголовка видео, тегов и информации о местоположении следующим образом:
кто-нибудь знает, можно ли заменить значки миниатюрами видео (предварительный просмотр одного кадра)?
спасибо!
8 ответов:
Если вы используете API 2.0 или новее, это будет работать.
int id = **"The Video's ID"** ImageView iv = (ImageView ) convertView.findViewById(R.id.imagePreview); ContentResolver crThumb = getContentResolver(); BitmapFactory.Options options=new BitmapFactory.Options(); options.inSampleSize = 1; Bitmap curThumb = MediaStore.Video.Thumbnails.getThumbnail(crThumb, id, MediaStore.Video.Thumbnails.MICRO_KIND, options); iv.setImageBitmap(curThumb);
Если вы не можете или не можете пройти через курсор, и если у вас есть только пути или файловые объекты, вы можете использовать начиная с уровня API 8 (2.2) публичный статический растровый createVideoThumbnail (строку путь к файлу, инт рода)
следующий код прекрасно работает:
Bitmap bMap = ThumbnailUtils.createVideoThumbnail(file.getAbsolutePath(), MediaStore.Video.Thumbnails.MICRO_KIND);
использование класса:
import android.provider.MediaStore.Video.Thumbnails;
мы можем получить два размера предварительного просмотра миниатюр из видео:
Thumbnails.MICRO_KIND
для 96 x 96
Thumbnails.MINI_KIND
для 512 x 384 pxЭто пример кода:
String filePath = "/sdcard/DCIM/Camera/my_video.mp4"; //change the location of your file! ImageView imageview_mini = (ImageView)findViewById(R.id.thumbnail_mini); ImageView imageview_micro = (ImageView)findViewById(R.id.thumbnail_micro); Bitmap bmThumbnail; //MICRO_KIND, size: 96 x 96 thumbnail bmThumbnail = ThumbnailUtils.createVideoThumbnail(filePath, Thumbnails.MICRO_KIND); imageview_micro.setImageBitmap(bmThumbnail); // MINI_KIND, size: 512 x 384 thumbnail bmThumbnail = ThumbnailUtils.createVideoThumbnail(filePath, Thumbnails.MINI_KIND); imageview_mini.setImageBitmap(bmThumbnail);
В настоящее время я использую следующий код :
Bitmap bMap = ThumbnailUtils.createVideoThumbnail(file.getAbsolutePath(), MediaStore.Video.Thumbnails.MICRO_KIND);
но я нашел лучшее решение с скольжения библиотека со следующим кодом (он также кэширует изображение и имеет лучшую производительность, чем предыдущий подход )
Glide.with(context) .load(uri) .placeholder(R.drawable.ic_video_place_holder) .into(imageView);
Я действительно предлагаю вам использовать скольжения библиотека. Это один из наиболее эффективных способов создания и отображения миниатюр видео для локального видеофайла.
просто добавьте эту строку в файл gradle:
compile 'com.github.bumptech.glide:glide:3.7.0'
и это станет так же просто, как:
String filePath = "/storage/emulated/0/Pictures/example_video.mp4"; Glide .with( context ) .load( Uri.fromFile( new File( filePath ) ) ) .into( imageViewGifAsBitmap );
Вы можете найти больше информации здесь : https://futurestud.io/blog/glide-displaying-gifs-and-videos
Ура !
Android 1.5 и 1.6 не предлагают эти миниатюры, но 2.0 делает, как видно на официальные заметки о выпуске:
СМИ
- MediaScanner теперь генерирует эскизы для всех изображений, когда они вставляются в MediaStore.
- новый Thumbnail API для получения изображений и видео миниатюр по требованию.
Это решение будет работать на любой версии Android. Он доказал свою работу в 1.5 и 2.2 это не другое решение" это для Android 2.0+". Я нашел это через страницу сбора сообщений электронной почты и не могу найти исходную ссылку. Вся заслуга принадлежит оригинальному плакату.
в вашем приложении вы будете использовать этот вызов:
Bitmap bm = getVideoFrame(VideoStringUri);
где-то в его собственной функции (вне OnCreate, ect), вам понадобится:
private Bitmap getVideoFrame(String uri) { MediaMetadataRetriever retriever = new MediaMetadataRetriever(); try { retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY); retriever.setDataSource(uri); return retriever.captureFrame(); } catch (IllegalArgumentException ex) { ex.printStackTrace(); } catch (RuntimeException ex) { ex.printStackTrace(); } finally { try { retriever.release(); } catch (RuntimeException ex) { } } return null; }
в вашем src папка, вам нужен новый подкаталог android / media, в котором будет размещен класс (скопированный из самого источника android), который позволяет использовать эту функцию. Эта часть не должна быть изменена, переименована или размещена где-либо еще. MediaMetadataRetriever.java должна быть под android.носитель в вашей исходной папке для этого все работает.
/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.media; import java.io.FileDescriptor; import java.io.FileNotFoundException; import java.io.IOException; import android.content.ContentResolver; import android.content.Context; import android.content.res.AssetFileDescriptor; import android.graphics.Bitmap; import android.net.Uri; /** * MediaMetadataRetriever class provides a unified interface for retrieving * frame and meta data from an input media file. {@hide} */ public class MediaMetadataRetriever { static { System.loadLibrary("media_jni"); native_init(); } // The field below is accessed by native methods private int mNativeContext; public MediaMetadataRetriever() { native_setup(); } /** * Call this method before setDataSource() so that the mode becomes * effective for subsequent operations. This method can be called only once * at the beginning if the intended mode of operation for a * MediaMetadataRetriever object remains the same for its whole lifetime, * and thus it is unnecessary to call this method each time setDataSource() * is called. If this is not never called (which is allowed), by default the * intended mode of operation is to both capture frame and retrieve meta * data (i.e., MODE_GET_METADATA_ONLY | MODE_CAPTURE_FRAME_ONLY). Often, * this may not be what one wants, since doing this has negative performance * impact on execution time of a call to setDataSource(), since both types * of operations may be time consuming. * * @param mode * The intended mode of operation. Can be any combination of * MODE_GET_METADATA_ONLY and MODE_CAPTURE_FRAME_ONLY: 1. * MODE_GET_METADATA_ONLY & MODE_CAPTURE_FRAME_ONLY: For neither * frame capture nor meta data retrieval 2. * MODE_GET_METADATA_ONLY: For meta data retrieval only 3. * MODE_CAPTURE_FRAME_ONLY: For frame capture only 4. * MODE_GET_METADATA_ONLY | MODE_CAPTURE_FRAME_ONLY: For both * frame capture and meta data retrieval */ public native void setMode(int mode); /** * @return the current mode of operation. A negative return value indicates * some runtime error has occurred. */ public native int getMode(); /** * Sets the data source (file pathname) to use. Call this method before the * rest of the methods in this class. This method may be time-consuming. * * @param path * The path of the input media file. * @throws IllegalArgumentException * If the path is invalid. */ public native void setDataSource(String path) throws IllegalArgumentException; /** * Sets the data source (FileDescriptor) to use. It is the caller's * responsibility to close the file descriptor. It is safe to do so as soon * as this call returns. Call this method before the rest of the methods in * this class. This method may be time-consuming. * * @param fd * the FileDescriptor for the file you want to play * @param offset * the offset into the file where the data to be played starts, * in bytes. It must be non-negative * @param length * the length in bytes of the data to be played. It must be * non-negative. * @throws IllegalArgumentException * if the arguments are invalid */ public native void setDataSource(FileDescriptor fd, long offset, long length) throws IllegalArgumentException; /** * Sets the data source (FileDescriptor) to use. It is the caller's * responsibility to close the file descriptor. It is safe to do so as soon * as this call returns. Call this method before the rest of the methods in * this class. This method may be time-consuming. * * @param fd * the FileDescriptor for the file you want to play * @throws IllegalArgumentException * if the FileDescriptor is invalid */ public void setDataSource(FileDescriptor fd) throws IllegalArgumentException { // intentionally less than LONG_MAX setDataSource(fd, 0, 0x7ffffffffffffffL); } /** * Sets the data source as a content Uri. Call this method before the rest * of the methods in this class. This method may be time-consuming. * * @param context * the Context to use when resolving the Uri * @param uri * the Content URI of the data you want to play * @throws IllegalArgumentException * if the Uri is invalid * @throws SecurityException * if the Uri cannot be used due to lack of permission. */ public void setDataSource(Context context, Uri uri) throws IllegalArgumentException, SecurityException { if (uri == null) { throw new IllegalArgumentException(); } String scheme = uri.getScheme(); if (scheme == null || scheme.equals("file")) { setDataSource(uri.getPath()); return; } AssetFileDescriptor fd = null; try { ContentResolver resolver = context.getContentResolver(); try { fd = resolver.openAssetFileDescriptor(uri, "r"); } catch (FileNotFoundException e) { throw new IllegalArgumentException(); } if (fd == null) { throw new IllegalArgumentException(); } FileDescriptor descriptor = fd.getFileDescriptor(); if (!descriptor.valid()) { throw new IllegalArgumentException(); } // Note: using getDeclaredLength so that our behavior is the same // as previous versions when the content provider is returning // a full file. if (fd.getDeclaredLength() < 0) { setDataSource(descriptor); } else { setDataSource(descriptor, fd.getStartOffset(), fd.getDeclaredLength()); } return; } catch (SecurityException ex) { } finally { try { if (fd != null) { fd.close(); } } catch (IOException ioEx) { } } setDataSource(uri.toString()); } /** * Call this method after setDataSource(). This method retrieves the meta * data value associated with the keyCode. * * The keyCode currently supported is listed below as METADATA_XXX * constants. With any other value, it returns a null pointer. * * @param keyCode * One of the constants listed below at the end of the class. * @return The meta data value associate with the given keyCode on success; * null on failure. */ public native String extractMetadata(int keyCode); /** * Call this method after setDataSource(). This method finds a * representative frame if successful and returns it as a bitmap. This is * useful for generating a thumbnail for an input media source. * * @return A Bitmap containing a representative video frame, which can be * null, if such a frame cannot be retrieved. */ public native Bitmap captureFrame(); /** * Call this method after setDataSource(). This method finds the optional * graphic or album art associated (embedded or external url linked) the * related data source. * * @return null if no such graphic is found. */ public native byte[] extractAlbumArt(); /** * Call it when one is done with the object. This method releases the memory * allocated internally. */ public native void release(); private native void native_setup(); private static native void native_init(); private native final void native_finalize(); @Override protected void finalize() throws Throwable { try { native_finalize(); } finally { super.finalize(); } } public static final int MODE_GET_METADATA_ONLY = 0x01; public static final int MODE_CAPTURE_FRAME_ONLY = 0x02; /* * Do not change these values without updating their counterparts in * include/media/mediametadataretriever.h! */ public static final int METADATA_KEY_CD_TRACK_NUMBER = 0; public static final int METADATA_KEY_ALBUM = 1; public static final int METADATA_KEY_ARTIST = 2; public static final int METADATA_KEY_AUTHOR = 3; public static final int METADATA_KEY_COMPOSER = 4; public static final int METADATA_KEY_DATE = 5; public static final int METADATA_KEY_GENRE = 6; public static final int METADATA_KEY_TITLE = 7; public static final int METADATA_KEY_YEAR = 8; public static final int METADATA_KEY_DURATION = 9; public static final int METADATA_KEY_NUM_TRACKS = 10; public static final int METADATA_KEY_IS_DRM_CRIPPLED = 11; public static final int METADATA_KEY_CODEC = 12; public static final int METADATA_KEY_RATING = 13; public static final int METADATA_KEY_COMMENT = 14; public static final int METADATA_KEY_COPYRIGHT = 15; public static final int METADATA_KEY_BIT_RATE = 16; public static final int METADATA_KEY_FRAME_RATE = 17; public static final int METADATA_KEY_VIDEO_FORMAT = 18; public static final int METADATA_KEY_VIDEO_HEIGHT = 19; public static final int METADATA_KEY_VIDEO_WIDTH = 20; public static final int METADATA_KEY_WRITER = 21; public static final int METADATA_KEY_MIMETYPE = 22; public static final int METADATA_KEY_DISCNUMBER = 23; public static final int METADATA_KEY_ALBUMARTIST = 24; // Add more here... }
это код для живого видео миниатюры.
public class LoadVideoThumbnail extends AsyncTask<Object, Object, Bitmap>{ @Override protected Bitmap doInBackground(Object... params) {try { String mMediaPath = "http://commonsware.com/misc/test2.3gp"; Log.e("TEST Chirag","<< thumbnail doInBackground"+ mMediaPath); FileOutputStream out; File land=new File(Environment.getExternalStorageDirectory().getAbsoluteFile() +"/portland.jpg"); Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(mMediaPath, MediaStore.Video.Thumbnails.MICRO_KIND); ByteArrayOutputStream stream = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream); byte[] byteArray = stream.toByteArray(); out=new FileOutputStream(land.getPath()); out.write(byteArray); out.close(); return bitmap; } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } @Override protected void onPostExecute(Bitmap result) { // TODO Auto-generated method stub super.onPostExecute(result); if(result != null){ ((ImageView)findViewById(R.id.imageView1)).setImageBitmap(result); } Log.e("TEST Chirag","====> End"); } }