美文网首页
关于给Android视频播放器封面加载的一种解决方案

关于给Android视频播放器封面加载的一种解决方案

作者: 安知鱼未忆_ | 来源:发表于2018-08-03 13:55 被阅读0次

    借鉴自这里,请点击

    总体思路就是开线程获取第一帧并存到本地,用数据库保存播放链接和第一帧图片的本地地址,第二次打开做判断,先在数据库存储查询,看是否存在,如果存在就把地址取出来加载。

    首先你需要写一个Thread类,用来调用获取视频第一帧的封面,为什么要建一个线程类呢,因为在获取封面过程中调用包括setDataSource(String url)getFrameAtTime(long timeMs,int option)方法都是很耗时的操作,所以要在子线程中获取,获取完成之后,在用handler去更新适配器UI。
    好了,下面咱们开始吧:
    Thread类:

    package cn.wangcy.demo.ffcd.thread;
    
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.Matrix;
    import android.media.MediaMetadataRetriever;
    import android.os.Build;
    import android.os.Environment;
    import android.os.Handler;
    import android.os.Message;
    import android.text.TextUtils;
    import android.widget.ImageView;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    
    import cn.wangcy.demo.ffcd.bean.VideoDataBean;
    import cn.wangcy.demo.ffcd.db.DbManager;
    import cn.wangcy.demo.ffcd.utils.LogUtils;
    import cn.wangcy.demo.ffcd.utils.PictureUtils;
    
    /**
     * Created by wangchuanyu on 2018/7/16.
     */
    
    public class CreateFirstFrameBitmapThread extends Thread {
    
        private List<VideoDataBean> mDatas;
        private int width = 0;
        private int height = 0;
        private ImageView videoCover = null;
        private final String OutPutFileDirPath = Environment.getExternalStorageDirectory() + "/first_frame";
        private Handler handler;
        private DbManager manager;
        private long fileLength;
        private int posIndex = 0;
    
    
        public CreateFirstFrameBitmapThread(List<VideoDataBean> mDatas, int width, int height, ImageView videoCover, Handler handler) {
            this.mDatas = mDatas;
            this.width = width;
            this.height = height;
            this.videoCover = videoCover;
            this.handler = handler;
        }
    
        public CreateFirstFrameBitmapThread(Context context, List<VideoDataBean> mDatas, Handler handler) {
            this.mDatas = mDatas;
            this.handler = handler;
            manager = new DbManager(context);
        }
    
        public CreateFirstFrameBitmapThread(Context context, List<VideoDataBean> mDatas, Handler handler, int i) {
            this.mDatas = mDatas;
            this.handler = handler;
            this.posIndex = i;
            manager = new DbManager(context);
        }
    
        public CreateFirstFrameBitmapThread() {
    
        }
    
        @Override
        public void run() {
            super.run();
            for (int i = posIndex; i < mDatas.size(); i++) {
                createBitmapFromVideoPath(i, mDatas.get(i).getmVideoUrl());
            }
        }
    
        /**
         * 获取第一帧的方法,通过上方for循环进行获取第一帧
         * @param positon
         * @param url
         */
        public void createBitmapFromVideoPath(int positon, String url) {
            synchronized (this) {
                Bitmap bitmap = null;
                MediaMetadataRetriever retriever = new MediaMetadataRetriever();
                try {
                    if (Build.VERSION.SDK_INT >= 12) {
                        retriever.setDataSource(url, new HashMap<String, String>());
                    } else {
                        retriever.setDataSource(url);
                    }
                    bitmap = retriever.getFrameAtTime(1000, MediaMetadataRetriever.OPTION_CLOSEST_SYNC);
                    String len = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
                    fileLength = TextUtils.isEmpty(len) ? 0 : Long.valueOf(len);
    
                    Bitmap bitmapNew = /*scaleImage(bitmap)*/bitmap;
    //                Bitmap bitmapNew = /*scaleImage(bitmap)*/zoomImage(bitmap,100,100);
                    String path = PictureUtils.saveImageToSDForEdit(bitmapNew, OutPutFileDirPath, positon + "_FirstFrame_ffcd"  + PictureUtils.POSTFIX);
                    VideoDataBean bean = mDatas.get(positon);
                    manager.addImage(bean);
    
    //            sendPic(bitmapNew, positon);
                    sendPic(path, bitmapNew, positon);
                } catch (IllegalArgumentException ex) {
                    ex.printStackTrace();
                } catch (RuntimeException ex) {
                    ex.printStackTrace();
                } catch (Exception ex) {
    
                } finally {
                    try {
                        retriever.release();
                    } catch (RuntimeException ex) {
                        ex.printStackTrace();
                    }
                }
            }
    
        }
    
        /**
         * 压缩图片
         * @param bitmap
         * @param newWidth
         * @param newHeight
         * @return
         */
        public static Bitmap zoomImage(Bitmap bitmap, int newWidth, int newHeight) {
            // 获得图片的宽高
            int width = bitmap.getWidth();
            int height = bitmap.getHeight();
            // 计算缩放比例
            float scaleWidth = ((float) newWidth) / width;
            float scaleHeight = ((float) newHeight) / height;
            // 取得想要缩放的matrix参数
            Matrix matrix = new Matrix();
            matrix.postScale(scaleWidth, scaleHeight);
            // 得到新的图片
            return Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
        }
    
        /**
         * 发送图片到handler,更新UI
         * @param path
         * @param bitmap
         * @param positon
         */
        public void sendPic(String path, Bitmap bitmap, int positon) {
            Message msg = new Message();
            msg.what = 0;
            msg.arg1 = positon;
            msg.obj = path;
            handler.sendMessage(msg);
        }
    
        /**
         * 发送图片到handler,更新UI(以list形式传递数据,主要用于更新bitmap类型的数据)
         * @param bitmap
         * @param positon
         */
        public void sendPic(Bitmap bitmap, int positon) {
            Message msg = new Message();
            msg.what = 0;
            List list = new ArrayList();
            list.add(bitmap);
            msg.obj = list;  //handler传递对象
            msg.arg1 = positon;
            handler.sendMessage(msg);
        }
    }
    

    有了这个线程,就可以在适当的时候不耗时的状态下进行获取第一帧。

    接下来就是数据库的创建

    /**
    * 数据库基础类,用于创建数据库
    **/
    public class DbHelper extends SQLiteOpenHelper {
        private static final String name = "your dbName"; //数据库名称
        private static final int version = 1; //数据库版本
    
        public DbHelper(Context context) {
            super(context, name, null, version);
        }
    
        @Override
        public void onCreate(SQLiteDatabase db) {
            db.execSQL("CREATE TABLE IF NOT EXISTS "+ "your table name"+" (id integer primary key autoincrement, name text, imgurl text, videourl text)");
        }
    
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        }
    }
    
    
    
    /**
     * 数据库工具类
     */
    public class DbManager {
        private BaisongDbHelper dbHelper;
        private SQLiteDatabase db;
        public static int dbSize = 0;
    
        public DbManager(Context context) {
            dbHelper = new BaisongDbHelper(context);
            db = dbHelper.getReadableDatabase();
        }
    
        /**
         * 添加图片到数据库
         */
        public void addMustImage(String video_url, String image_url) {
            if (find_video_url(video_url)!=null){
                updateMustVideo(video_url);
                return;
            }
            if (find_image_url(image_url)!=null){
                updateMustImage(video_url,image_url);
                return;
            }
            ContentValues cv = new ContentValues();
            cv.put("videourl", video_url);
            cv.put("imgurl", image_url);
            long id = db.insert(ConfigYibaisong.MUST_IMAGE, null, cv);//插入数据库
    
          //--------以下是利用数组打印插入数据的代码--------------
            Cursor cursor = db.query(ConfigYibaisong.MUST_IMAGE, null, "videourl=?" + " and " + "imgurl=?", new String[]{video_url, image_url}, null, null, null);
            ArrayList<HashMap<String, String>> AL = new ArrayList<HashMap<String, String>>();
            if (cursor.moveToNext()) {
                for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
                    HashMap<String, String> hm = new HashMap<>();
                    hm.put("videourl", cursor.getString(cursor.getColumnIndex("videourl")));
                    hm.put("imgurl", cursor.getString(cursor.getColumnIndex("imgurl")));
                    AL.add(hm);
                }
                cursor.close();
            }
            if (id != -1) Log.d("zzzzzzzzz", "插入成功  " + AL.toString());
            else Log.d("zzzzzzzzz", "插入失败");
    //        db.close();
    //        db.insert(ConfigYibaisong.MUST_IMAGE, null, cv);
        }
       /**
         * 更新图片
         */
        public void updateMustVideo(String video_url){
            ContentValues cv = new ContentValues();
            cv.put("videourl", video_url);
            long id = db.update(ConfigYibaisong.MUST_IMAGE,  cv,"videourl=?",new String[]{video_url});//插入数据库
            if (id != -1) LogHelper.d("zzzzzzzzz", "更新成功  ");
            else LogHelper.d("zzzzzzzzz", "更新失败");
        }
       /**
         * 更新图片
         */
        public void updateMustImage(String video_url,String image_url){
            ContentValues cv = new ContentValues();
            cv.put("imgurl", image_url);
            long id = db.update(ConfigYibaisong.MUST_IMAGE,  cv,"videourl=?",new String[]{video_url});//插入数据库
            if (id != -1) Log.d("zzzzzzzzz", "更新成功  ");
            else Log.d("zzzzzzzzz", "更新失败");
        }
    
       /**
         * 查找video地址
         */
        public String find_video_url(String video_url){
            Cursor cursor = db.query(ConfigYibaisong.MUST_IMAGE, null, "videourl=?" , new String[]{video_url}, null, null, null);
            if (cursor.moveToNext()) {
                for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
                    return cursor.getString(cursor.getColumnIndex("videourl"));
                }
                cursor.close();
            }
            return null;
        }
       /**
         * 查找图片地址
         */
        public String find_image_url(String image_url){
            Cursor cursor = db.query(ConfigYibaisong.MUST_IMAGE, null, "imgurl=?" , new String[]{image_url}, null, null, null);
            if (cursor.moveToNext()) {
                for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
                    return cursor.getString(cursor.getColumnIndex("imgurl"));
                }
                cursor.close();
            }
            return null;
        }
    
        public void DbClose() {
            db.close();
        }
    
        public long getCount() {
            return db.getMaximumSize();
        }
    
         /**
         * 根据给定video地址查询本地图片地址
         */
        public String findMustImage(int position, String video_url, String image_url) {
            if (TextUtils.isEmpty(video_url) || TextUtils.isEmpty(image_url))
                return "";
            if (tabbleIsExist(db, ConfigYibaisong.MUST_IMAGE)) {
                Cursor cursor = db.query(ConfigYibaisong.MUST_IMAGE, null, "videourl=?" + " and " + "imgurl=?", new String[]{video_url, image_url}, null, null, null);
                String cursorStr = "";
                try {
                    cursorStr = cursor.getString(cursor.getColumnIndex("imgurl"));
                    cursor.close();
                } catch (CursorIndexOutOfBoundsException e) {
                    cursorStr = null;
                }
                return cursorStr;
    //            }
    
            }
            return null;
        }
    
       /**
         * 根据给定video地址查询本地图片地址
         */
        public String findMustImage(String video_url) {
            if (TextUtils.isEmpty(video_url))
                return "";
            if (tabbleIsExist(db, ConfigYibaisong.MUST_IMAGE)) {
                Cursor cursor = db.query(ConfigYibaisong.MUST_IMAGE, new String[]{"imgurl"}, "videourl=?", new String[]{video_url}, null, null, null);
                String cursorStr = "";
                if(cursor.moveToNext()){
                    try {
                        cursorStr = cursor.getString(0);
                        cursor.close();
                        return cursorStr;
                    } catch (CursorIndexOutOfBoundsException e) {
                        cursorStr = null;
                       
                    }
                    return cursorStr;
                }
    
    //            }
    
            }
            return null;
        }
    
        public List<NewMustClassBean.DataBean> findAllImageForMustCover(List<NewMustClassBean.DataBean> mDatas) {
            for (int i = 0; i < mDatas.size(); i++) {
                try {
                    Cursor cursor = db.query(ConfigYibaisong.MUST_IMAGE, new String[]{"imgurl"}, "videourl=?", new String[]{mDatas.get(i).getVideo()}, null, null, null);
                    mDatas.get(i).setVideoCover(cursor.getString(cursor.getColumnIndex("imgurl")));
                } catch (CursorIndexOutOfBoundsException e) {
                    return mDatas;
                }
    
            }
            return mDatas;
        }
       /**
         * 根据给定video地址查询本地图片地址
         */
        public void findImageMustCover(String videourl,List<NewMustClassBean.DataBean> mDatas,int position) {
            try {
                List<NewMustClassBean.DataBean> mMusts = new ArrayList<>();
                    Cursor cursor = db.query(ConfigYibaisong.MUST_IMAGE, new String[]{"imgurl"}, "videourl=?", new String[]{videourl}, null, null, null);
                    while (cursor.moveToNext()) {
                        NewMustClassBean.DataBean bean = new NewMustClassBean.DataBean();
                        bean.setVideoCover(cursor.getString(cursor.getColumnIndex("imgurl")));
                        mMusts.add(bean);
                }
    
                mDatas.get(position).setVideoCover(mMusts.get(position).getVideoCover());
           
                
            } catch (CursorIndexOutOfBoundsException e) {
              
    
            }
        }
    
    
        //删除某一个表
        public void dropTable() {
            db.delete(ConfigYibaisong.MUST_IMAGE, null, null);
        }
    
        //判断一个表是否存在
        public boolean tabbleIsExist(SQLiteDatabase db, String tableName) {
            boolean result = false;
            if (tableName == null) {
                return false;
            }
            Cursor cursor = null;
            try {
                String sql = "select count(*) as c from Sqlite_master  where type ='table' and name ='" + tableName.trim() + "' ";
                cursor = db.rawQuery(sql, null);
                if (cursor.moveToNext()) {
                    int count = cursor.getInt(0);
                    if (count > 0) {
                        result = true;
                    }
                }
    
            } catch (Exception e) {
                // TODO: handle exception
            }
            return result;
        }
    
    }
    
    
    

    创建完数据库,接下来就是把图片存入内存,拿到地址,放到数据库,以方便对本地图片的取出加载。

    /**
    * 保存图片到本地
    **/
    public class PictureUtils {
        public static final String POSTFIX = ".jpeg";
    
        public static String saveImageToSD(Bitmap bmp, String dirPath) {
            if (bmp == null) {
                return "";
            }
            File appDir = new File(dirPath);
            if (!appDir.exists()) {
                appDir.mkdir();
            }
            String fileName = System.currentTimeMillis() + ".jpg";
            File file = new File(appDir, fileName);
            try {
                FileOutputStream fos = new FileOutputStream(file);
                bmp.compress(Bitmap.CompressFormat.JPEG, 100, fos);
                fos.flush();
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return file.getAbsolutePath();
        }
    
    
    
        public static String saveImageToSDForEdit(Bitmap bmp, String dirPath, String fileName) {
            if (bmp == null) {
                return "";
            }
            File appDir = new File(dirPath);
            if (!appDir.exists()) {
                appDir.mkdir();
            }
            File file = new File(appDir, fileName);
            if (file.exists()){
                return file.getAbsolutePath();
            }
            try {
                FileOutputStream fos = new FileOutputStream(file);
                bmp.compress(Bitmap.CompressFormat.JPEG, 80, fos);
                fos.flush();
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
                return "null";
            }
            return file.getAbsolutePath();
        }
    
        public static void deleteFile(File f) {
            if (f.isDirectory()) {
                File[] files = f.listFiles();
                if (files != null && files.length > 0) {
                    for (int i = 0; i < files.length; ++i) {
                        deleteFile(files[i]);
                    }
                }
            }
            f.delete();
        }
    
    }
    

    保存完图片了,也建立了数据库了,那接下来就是把图片地址存到数据库,并在第二次开启时取出本地图片,利用glide加载到界面上就行了。再贴一个handler吧,用于更新获取完第一帧,实时更新UI的过程。

    /**
         * 在更新UI的方法
         */
        private Handler handler = new Handler() {
    
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case 0:  //接到从线程内传来的图片bitmap和imageView.
                        //这里只是将bitmap传到imageView中就行了。只所以不在线程中做是考虑到线程的安全性
                        mDatas.get(msg.arg1).setmVideoCover("file://" + msg.obj);
                    try {
                        if (!TextUtils.equals(mDatas.get(msg.arg1).getmVideoCover(), "file://null"))
                            manager.addImage(mDatas.get(msg.arg1));
    
                    }catch (Exception ex){
                    }
                        notifyItemChanged(msg.arg1);
    //                    notifyDataSetChanged();
    
    
                        break;
    
                    default:
                        super.handleMessage(msg);
                        break;
                }
            }
    
            ;
        };
    

    当然别忘了添加网络请求和动态请求读写的使用权限~。
    希望这个思路能对大家有所帮助。

    相关文章

      网友评论

          本文标题:关于给Android视频播放器封面加载的一种解决方案

          本文链接:https://www.haomeiwen.com/subject/hfvlpftx.html