Android uses FFmpegMediaMetadataRetriever to get video thumbnails

1. Use MediaMetadataRetriever to get video metadata

Generally, to obtain the metadata information of media files such as video and audio, we will use the MediaMetadataRetriever class that comes with android.
For example, get information such as the title, duration, and screenshot of a certain frame (usually used as a thumbnail of the video).

Specific usage reference: Android uses the MediaMetadataRetriever class to get the first frame of the video


but…

Everything is not so smooth sailing. If you are lucky like me, you will successfully get thumbnails on certain models and certain API versions, and the following errors will be reported on some models and lower versions of the API :

MediaMetadataRetrieverJNI: getFrameAtTime: videoFrame is a NULL pointer

After searching for a long time, nothing has been resolved. This problem is enough~
Later, I saw a discussion in one place and said that this problem may be a bug in Android itself... Well, maybe I hit the south wall before turning around~

If you want to solve it completely, you can change to a library and use the powerful FFmpegMediaMetadataRetriever,
then please follow my steps and see how to use it...

2. Use FFmpegMediaMetadataRetriever to get video metadata (thumbnail)

Open source address: the github address of FFmpegMediaMetadataRetriever
There is also a backup magic address: the backup github address of FFmpegMediaMetadataRetriever

Let me take the first official open source address as an example.

2.1 Integration method

2.1.1 Use gradle to configure dependencies.

Click on the open source address above, and you will see the following page.

Use gradle to configure dependencies

This is the configuration method mentioned on github.
I verified that the first sentence Add the following maven dependency to your project's build.gradle file is wrong! ! !
Sister, I’m not too pitted...not to add the phrase compile in the build.gradle of the project, but add it to the dependencies of the app’s build.gradle compile 'com.github.wseemann:FFmpegMediaMetadataRetriever:1.0.14'! ! !

That's it , FFmpegMediaMetadataRetriever is integrated.

What about the next piece? Just

Optionally, to support individual ABIs:

dependencies {
    compile 'com.github.wseemann:FFmpegMediaMetadataRetriever-armeabi:1.0.14'
    compile 'com.github.wseemann:FFmpegMediaMetadataRetriever-armeabi-v7a:1.0.14'
    compile 'com.github.wseemann:FFmpegMediaMetadataRetriever-x86:1.0.14'
    compile 'com.github.wseemann:FFmpegMediaMetadataRetriever-mips:1.0.14'
    compile 'com.github.wseemann:FFmpegMediaMetadataRetriever-x86_64:1.0.14'
    compile 'com.github.wseemann:FFmpegMediaMetadataRetriever-arm64-v8a:1.0.14'
}

This one is optional and adapts to models with different physical architectures. For example, if you develop an application only for x86 mobile phones, just add the x86 dependency. The above-mentioned one without architecture type should be all-adapted work.

Note: There is only one drawback of this method, that is, the final installation package will be very large, and it will be more than ten M more. Hahaha, it comes at a price to be easy to use. If you want to be smaller, just video a certain model

2.1.2 Using the aar package

If your android studio can't download the dependencies, the compile method above can't be used, you can also download its aar package, similar to the java jar package.

aar package download

Still the above open source github address, find Prebuilt AARs and click download, you will get a compressed package, after decompression, as shown below:
spike 包

Look at the name and you know that it corresponds to compile. The first all-fmmr.aar matches all architecture phones, and the rest matches the corresponding architecture. Looking at the size of the aar package, you can also know that the first aar package is close to 23M, and the installation package that comes out is not big.

What? Can't use aar in android studio?

Well, send the Buddha to the west, take the integration of all-fmmr.aar as an example

  • First, copy all-fmmr.aar to the app/libs/ directory of the project, as shown below:
    Insert picture description here
  • Then, add the following sentence in the dependencies of the app's build.gradle file:
compile(name:'all-fmmr',ext:'aar')
  • Then, add the following code to the android in the build.gradle file of the app:
 repositories {
        flatDir {
            dirs 'libs'   // aar目录
        }
    }
  • After adding, the build.gradle file of your app should look like this:
apply plugin: 'com.android.application'

android {
    compileSdkVersion 26
    defaultConfig {
        applicationId "com.example.fxjzzyo.helloworld"
        minSdkVersion 15
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    sourceSets{
        main{
            jniLibs.srcDirs=['libs']
        }
    }
    repositories {
        flatDir {
            dirs 'libs'   // aar目录
        }
    }
}

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation 'com.android.support:appcompat-v7:26.1.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    androidTestCompile('com.android.support:support-annotations:26.1.0') {
        force = true;
    }
    compile(name:'all-fmmr',ext:'aar')
//    compile 'com.github.wseemann:FFmpegMediaMetadataRetriever:1.0.14'
}

In this way, you can happily use FFmpegMediaMetadataRetriever in your code!

2.2 Use FFmpegMediaMetadataRetriever in the code

As the code introduced on github is

//new出对象
FFmpegMediaMetadataRetriever mmr = new FFmpegMediaMetadataRetriever();

//设置数据源
mmr.setDataSource(mUri);

//获取媒体文件的专辑标题
mmr.extractMetadata(FFmpegMediaMetadataRetriever.METADATA_KEY_ALBUM);

//获取媒体文件的专辑艺术家
mmr.extractMetadata(FFmpegMediaMetadataRetriever.METADATA_KEY_ARTIST);

//获取2秒处的一帧图片(这里的2000000是微秒!!!)
Bitmap b = mmr.getFrameAtTime(2000000, FFmpegMediaMetadataRetriever.OPTION_CLOSEST); 

//释放资源
mmr.release();

In fact, this is the same usage as the MediaMetadataRetriever that comes with Android, that is, the additional class name becomes FFmpegMediaMetadataRetriever, and the rest are the same.

3. Complete code

I heard that people who don't post the complete code are not kind, so of course I am so kind. Surprise~

3.1 Layout file activity_video_info.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:onClick="getVideoInfo"
        android:text="获取信息" />

    <ImageView
        android:id="@+id/iv_thumbnail"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_below="@id/iv_thumbnail"
        android:layout_centerHorizontal="true" />

</RelativeLayout>

3.2 java code VideoInfoActivity.java


public class VideoInfoActivity extends AppCompatActivity {

    private ImageView imageView;

    //这个网络视频url可能失效,很可能!所以你要自己找一个可以浏览器种打开播放的url
    String url = "http://219.238.7.67/mp4files/418000000CE88BD1/202.108.250.226/youku/657259485123b717b789144ef/03000801005C009A1DA6539003E880F6C38754-67FB-4855-9645-7E00B1822316.mp4";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_video_info);
        //android 6.0权限申请
        checkPermission();

    }
    public void checkPermission(){
        //检查权限(NEED_PERMISSION)是否被授权 PackageManager.PERMISSION_GRANTED表示同意授权
        if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED) {
            //用户已经拒绝过一次,再次弹出权限申请对话框需要给用户一个解释
            if (ActivityCompat.shouldShowRequestPermissionRationale(this, android.Manifest.permission
                    .WRITE_EXTERNAL_STORAGE)) {
                Toast.makeText(this, "请开通相关权限,否则无法正常使用本应用!", Toast.LENGTH_SHORT).show();
            }
            //申请权限
            ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0);

        } else {
            Toast.makeText(this, "授权成功!", Toast.LENGTH_SHORT).show();
            //初始化
            init();
        }
    }
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if(requestCode==0){
            if(grantResults.length>0&&grantResults[0]==PackageManager.PERMISSION_GRANTED){
                //申请成功
                init();
            }else {
                Toast.makeText(this,"相机权限申请被拒绝!",Toast.LENGTH_SHORT).show();
            }
            return;
        }
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

    private void init() {
        imageView = findViewById(R.id.iv_thumbnail);
    }

  /**
     * 点击按钮,获取视频缩略图
     * @param view
     */
    public void getVideoInfo(View view) {
        Bitmap videoThumbnail = null;
       
        //获取本地视频缩略图,在sdk根目录下准备一个test.mp4的文件
//        String videoPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/test.mp4";
//         videoThumbnail = getVideoThumbnail(videoPath);
        
        //获取网络视频缩略图
        videoThumbnail = getNetVideoThumbnail(url);
        
        imageView.setImageBitmap(videoThumbnail);

    }

    /**
     * 获取本地视频缩略图
     * @param filePath
     * @return
     */
    public Bitmap getVideoThumbnail(String filePath) {
        Bitmap b=null;
        //使用MediaMetadataRetriever
//        MediaMetadataRetriever retriever = new MediaMetadataRetriever();
        
        //FFmpegMediaMetadataRetriever
        FFmpegMediaMetadataRetriever retriever = new FFmpegMediaMetadataRetriever();
        File file = new File(filePath);
        try {

            retriever.setDataSource(file.getPath());
            b=retriever.getFrameAtTime();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (RuntimeException e) {
            e.printStackTrace();

        } finally {
            try {
                retriever.release();
            } catch (RuntimeException e) {
                e.printStackTrace();
            }
        }
        return b;
    }


    /**
     * 获取网络视频缩略图
     * @param url
     * @return
     */
    public Bitmap getNetVideoThumbnail(String url) {
        Bitmap b=null;
        //使用MediaMetadataRetriever
//        MediaMetadataRetriever retriever = new MediaMetadataRetriever();

        //FFmpegMediaMetadataRetriever
        FFmpegMediaMetadataRetriever retriever = new FFmpegMediaMetadataRetriever();

        try {
            retriever.setDataSource(url,new HashMap<String, String>());
            b=retriever.getFrameAtTime(400*1000,FFmpegMediaMetadataRetriever.OPTION_CLOSEST);
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (RuntimeException e) {
            e.printStackTrace();

        } finally {
            try {
                retriever.release();
            } catch (RuntimeException e) {
                e.printStackTrace();
            }
        }
        return b;
    }

}

4. Running effect

A picture is worth a thousand words, and it is incomplete if it has no operational effect.
running result
It's over, sprinkle flowers~

Reference article:
https://blog.csdn.net/u012561176/article/details/47858099
https://blog.csdn.net/u010499721/article/details/50338623

Guess you like

Origin blog.csdn.net/fxjzzyo/article/details/84989285