Android : 비디오 섬네일을 표시 할 수 있습니까?


91

라이브러리 대화 상자로 비디오 녹화 응용 프로그램을 만들었습니다. 라이브러리 대화 상자에는 각 항목이 아이콘, 비디오 제목, 태그 및 위치 정보로 구성된 녹화 된 비디오 목록이 다음과 같은 방식으로 표시됩니다.

대체 텍스트

아이콘을 비디오 섬네일 (단일 프레임 미리보기)로 대체 할 수 있는지 아는 사람이 있습니까?

감사!


답변:


71

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);

9
그래서 정확히 무엇 id입니까?
phunehehe 2011

1
휴대폰에서 MediaStore에 비디오를 쿼리 할 수 ​​있습니다. "id"는 쿼리하는 정보 중 하나 일뿐입니다. developer.android.com/reference/android/provider/
Greg Zimmers 2011

4
놀란 모든 사람이이 작업을 수행하는 것 같습니다. 나는 이것을 시도했지만 curThumb은 결국 null이됩니다.
BlueVoodoo 2012-06-06

7
URL의 비디오는 어떻습니까?
jayellos 2011


91

커서를 통과하지 않거나 이동할 수없고 경로 또는 File 객체 만있는 경우 API 레벨 8 (2.2) 공용 정적 비트 맵 createVideoThumbnail (String filePath, int kind)부터 사용할 수 있습니다.

Android 문서

다음 코드는 완벽하게 실행됩니다.

Bitmap bMap = ThumbnailUtils.createVideoThumbnail(file.getAbsolutePath(), MediaStore.Video.Thumbnails.MICRO_KIND);

6
썸네일을 만들려고 할 때 null이 생깁니다. 내 길을 걷다 보면 괜찮지 않을까요? myPath = "/ external / video / media / 14180"
haythem

마법처럼 작동합니다. 나는 돈에도 t have my video ID. For better quality use MediaStore.Video.Thumbnails.FULL_SCREEN_KIND`
사미 Eltamawy

이상하게 잘 ;-( 비디오가 DB에 존재하는 한, 나는 썸네일 이름 / 크기를 검색 할 수는 없지만 작업을 나던
토마스 Decaux

haythem souussi 이것은 경로가 아니기 때문에 Uri이므로 경로로 변환해야합니다.
Nadir Novruzov

이것은 작동하지만 비디오의 잘못된 부분에서 이미지를 반환합니다. 첫 번째 프레임을 원하지만 5 ~ 6 초 정도 걸리나요? 어떤 아이디어?
speedynomads

38

수업 사용 :

import android.provider.MediaStore.Video.Thumbnails;

비디오에서 두 가지 미리보기 썸네일 크기를 얻을 수 있습니다.

Thumbnails.MICRO_KIND 96 x 96 용

Thumbnails.MINI_KIND 512 x 384 픽셀 용

다음은 코드 예입니다.

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);

파일 경로에 대해 이와 같은 링크가있는 경우 이미지보기로 설정하려고하는데 아무것도 표시되지 않기 때문에 작동하지 않습니다. 이것은 파일 경로 "http : / /unknown.com/v3-"입니다. 1aox9d1 .mp4 "는 분명히 실제 도메인이지만 해당 경로는 축소판으로 표시 할 수 없습니까?
Lion789 2015

() ThumbnailUtils.createVideoThumbnail : ThumbnailUtils 클래스를 사용하려면 방법 디스크로 사용하여 파일을 저장해야
Jorgesys

감사합니다. 그러면 생성 엄지 손가락에 대한 새 파일 경로를 어떻게 얻습니까?
Lion789 2015-07-29

Android 4 이상에서 Dose가 작동하지 않는 이유는 무엇입니까?
Criss

1
안녕하세요 Cris, 저는 3 개의 장치 4.1 4.2.2 및 5.0을 가지고 있으며 문제없이 작동하며 문제와 일부 코드로 질문을 게시하면 도와 드릴 수 있습니다.
Jorgesys 2015-08-23

19

현재 다음 코드를 사용합니다.

Bitmap bMap = ThumbnailUtils.createVideoThumbnail(file.getAbsolutePath(), MediaStore.Video.Thumbnails.MICRO_KIND);

그러나 다음 코드 로 Glide 라이브러리로 더 나은 솔루션을 찾았습니다 (또한 이미지를 캐시하고 이전 접근 방식보다 더 나은 성능을 제공합니다)

Glide.with(context)
                .load(uri)
                .placeholder(R.drawable.ic_video_place_holder)
                .into(imageView);

19

Glide 라이브러리 를 사용하는 것이 좋습니다 . 로컬 비디오 파일에 대한 비디오 썸네일을 생성하고 표시하는 가장 효율적인 방법 중 하나입니다.

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

건배!


4
글라이드는 로컬 비디오가 아닌 URL 비디오, 밤은이이 간단한 방법으로 작동
Lutaaya Huzaifah 이드리스

6

이 솔루션은 모든 버전의 Android에서 작동합니다. 1.5 및 2.2에서 작동하는 것으로 입증되었습니다. 이것은 또 다른 "This is for Android 2.0+"솔루션이 아닙니다. 이메일 게시판 컬렉션 페이지를 통해 찾았는데 원본 링크를 찾을 수 없습니다. 모든 크레딧은 원래 포스터에 있습니다.

앱에서 다음을 호출하여이를 사용합니다.

Bitmap bm = getVideoFrame(VideoStringUri);

자체 기능 (OnCreate 외) 어딘가에 다음이 필요합니다.

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가 필요합니다. 이 부분은 변경하거나 이름을 바꾸거나 다른 곳에 배치해서는 안됩니다. 이 모든 것이 작동하려면 MediaMetadataRetriever.java가 소스 폴더의 android.media 아래에 있어야합니다.

/*
 * 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...
}

이것은 나를 위해 작동하지 않습니다. System.loadLibrary ( "media_jni");
DArkO

1
이것이 작동하지 않는 것을 확인할 수 있습니다. 이 기능도 필요했습니다. 일반 응용 프로그램에 사용할 권한이없는 기본 시스템 호출을 사용하기 때문에 작동하지 않습니다.
Andy

MediaMetadataRetrieverAPI 레벨 10에서 지원됩니다
아사히

MediaMetadataRetriever는 두 번째 코드 블록입니다. 10 이전의 API (작성 당시에는 사용할 수 없었던)가 시스템 대신 애플리케이션에서 코드에 액세스 할 수 있도록 허용합니다. 기본 시스템 호출이 가능하지만이를 사용하려면 시스템에 대한 대략적인 이해가 필요합니다. 많은 문제가 제공된 소스를 부적절하게 구현하는 것 같습니다.
Abandoned Cart

@LoungeKatt는 같은 비디오의 여러 이미지를 여러 번 캡처 할 수 있습니까?
안드로이드 개발자

6

나를 위해 일하는 이것을 시도하십시오

RequestOptions requestOptions = new RequestOptions();
 Glide.with(getContext())
      .load("video_url")
      .apply(requestOptions)
      .thumbnail(Glide.with(getContext()).load("video_url"))
      .into("yourimageview");

5

Android 1.5 및 1.6은이 미리보기 이미지를 제공하지 않지만 2.0은 공식 출시 노트표시된 대로 제공 합니다 .

미디어

  • MediaScanner는 이제 모든 이미지가 MediaStore에 삽입 될 때 축소판을 생성합니다.
  • 필요에 따라 이미지 및 비디오 섬네일을 검색하기위한 새로운 섬네일 API.

1

이 질문에 늦게 대답하고 있지만 같은 문제에 직면 한 다른 후보에게 도움이되기를 바랍니다.

두 가지 방법을 사용하여 동영상 목록의 미리보기 이미지를로드했습니다.

    Bitmap bmThumbnail;
    bmThumbnail = ThumbnailUtils.createVideoThumbnail(FILE_PATH
                    + videoList.get(position),
            MediaStore.Video.Thumbnails.MINI_KIND);

    if (bmThumbnail != null) {
        Log.d("VideoAdapter","video thumbnail found");
        holder.imgVideo.setImageBitmap(bmThumbnail);
    } else {
        Log.d("VideoAdapter","video thumbnail not found");
    }

보기에는 좋지만 비디오 목록을 스크롤하면 큰 처리로 인해 잠시 멈추기 때문에이 솔루션에 문제가 있습니다.

그래서이 후 Glide Library를 사용하여 완벽하게 작동하는 또 다른 솔루션을 찾았습니다.

 Glide
            .with( mContext )
            .load( Uri.fromFile( new File( FILE_PATH+videoList.get(position) ) ) )
            .into( holder.imgVideo );

비디오 목록과 함께 썸네일을 표시하기 위해 최신 솔루션을 권장했습니다. 감사


-4

라이브 비디오 썸네일 코드입니다.

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");
        }

    }

2
Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(mMediaPath, MediaStore.Video.Thumbnails.MICRO_KIND);모든 매개 변수가 설정되어 있음 을 참고하십시오.
Chulo

1
비트 맵에서 null 값 bitmap = ThumbnailUtils.createVideoThumbnail (mMediaPath, MediaStore.Video.Thumbnails.MICRO_KIND);
Prasad 2014
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.