Android MediaMetadataRetriever取视频封面,Kotlin(1)

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /><uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@android:color/white"android:padding="1px"><ImageViewandroid:id="@+id/image"android:layout_width="match_parent"android:layout_height="180px"android:background="@android:color/darker_gray"android:scaleType="centerCrop" /></LinearLayout>

import android.content.ContentUris
import android.content.Context
import android.net.Uri
import android.os.Bundle
import android.provider.MediaStore
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launchclass MainActivity : AppCompatActivity() {companion object {const val TAG = "fly"const val SPAN_COUNT = 9const val VIDEO = 1}override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)val rv = findViewById<RecyclerView>(R.id.rv)val layoutManager = GridLayoutManager(this, SPAN_COUNT)layoutManager.orientation = GridLayoutManager.VERTICALrv.layoutManager = layoutManagerval adapter = MyAdapter(this)rv.adapter = adapterrv.layoutManager = layoutManagerval ctx = thislifecycleScope.launch(Dispatchers.IO) {val videoList = readAllVideo(ctx)Log.d(TAG, "readAllVideo size=${videoList.size}")val lists = arrayListOf<MyData>()lists.addAll(videoList)lifecycleScope.launch(Dispatchers.Main) {adapter.dataChanged(lists)}}}private fun readAllVideo(ctx: Context): ArrayList<MyData> {val videos = ArrayList<MyData>()//读取视频Videoval cursor = ctx.contentResolver.query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,null,null,null,null)while (cursor!!.moveToNext()) {//路径val path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA))val id = cursor.getColumnIndex(MediaStore.Images.ImageColumns._ID)val videoUri: Uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, cursor.getLong(id))//名称//val name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME))//大小//val size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE))videos.add(MyData(videoUri, path, VIDEO))}cursor.close()return videos}
}

import android.content.Context
import android.graphics.Bitmap
import android.media.MediaMetadataRetriever
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity
import androidx.collection.LruCache
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.RecyclerView
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContextclass MyAdapter : RecyclerView.Adapter<MyAdapter.VideoHolder> {private var mCtx: Context? = nullprivate var mItems = ArrayList<MyData>()private var mFailItemCount = 0private var mSuccessItemCount = 0private var mTotalCostTime = 0Lprivate val mCache = LruCache<String, Bitmap?>(1000)private var mIsDecoderCompleted = falseconstructor(ctx: Context) : super() {mCtx = ctx}fun dataChanged(items: ArrayList<MyData>) {this.mItems = itemsmSuccessItemCount = 0mTotalCostTime = 0mFailItemCount = 0notifyDataSetChanged()(mCtx as AppCompatActivity).lifecycleScope.launch(Dispatchers.IO) {mIsDecoderCompleted = falsemItems.forEachIndexed { idx, data ->var bmp: Bitmap? = mCache[data.toString()]if (bmp == null) {bmp = getSysMMRBmp(data)if (bmp != null) {mCache.put(data.toString(), bmp)}(mCtx as AppCompatActivity).lifecycleScope.launch(Dispatchers.Main) {notifyItemChanged(idx)}}}mIsDecoderCompleted = truewithContext(Dispatchers.Main) {notifyDataSetChanged()}}}override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VideoHolder {val v = LayoutInflater.from(mCtx).inflate(R.layout.image_layout, null, false)return VideoHolder(v)}override fun onBindViewHolder(holder: VideoHolder, position: Int) {loadVideoCover(mItems[position], holder.image)}override fun getItemCount(): Int {return mItems.size}class VideoHolder : RecyclerView.ViewHolder {var image: ImageView? = nullconstructor(itemView: View) : super(itemView) {image = itemView.findViewById<ImageView>(R.id.image)image?.setImageResource(android.R.drawable.ic_menu_gallery)}}private fun getSysMMRBmp(data: MyData): Bitmap? {val sysMMR = MediaMetadataRetriever()var bmp: Bitmap? = nullval t = System.currentTimeMillis()try {sysMMR.setDataSource(data.path)bmp = sysMMR.frameAtTimemSuccessItemCount++Log.d(MainActivity.TAG,"android MMR:total success item count=$mSuccessItemCount")} catch (e: Exception) {Log.e(MainActivity.TAG, "android MMR: total fail item count=${mFailItemCount++} , ${e.message}:$data")} finally {try {sysMMR.release()sysMMR.close()} catch (exc: Exception) {Log.e(MainActivity.TAG, "$exc")}}val costTime = System.currentTimeMillis() - tmTotalCostTime = mTotalCostTime + costTimeLog.d(MainActivity.TAG, "android MMR:total cost time= $mTotalCostTime ms")return bmp}private fun loadVideoCover(data: MyData, image: ImageView?) {val bmp: Bitmap? = mCache[data.toString()]if (bmp != null) {image?.setImageBitmap(bmp)} else {if (mIsDecoderCompleted) {image?.setImageResource(android.R.drawable.stat_notify_error)}}}
}

import android.net.Uriopen class MyData {var uri: Uri? = nullvar path: String? = nullvar lastModified = 0Lvar width = 0var height = 0var position = -1var type = -1  //-1未知。1,普通图。2,视频。constructor(uri: Uri?, path: String?, type: Int = -1) {this.uri = urithis.path = paththis.type = type}override fun toString(): String {return "MyData(uri=$uri, path=$path, lastModified=$lastModified, width=$width, height=$height, position=$position, type=$type)"}override fun equals(other: Any?): Boolean {return (this.toString()) == other.toString()}
}

MediaMetadataRetriever抽帧的耗时太长,对于异常或者超规格的视频,基本上10+秒。通常5、6秒。

500个超规格、残破视频,解码耗时和成功率情况:

android MMR: total fail item count=110

android MMR:total success item count=389

android MMR:total cost time= 198679 ms

3分钟+,500个视频才解码完,成功解码389个,解码失败110个。(0开始计数)

Android MediaMetadataRetriever获取视频宽高,Java_retriever.extractmetadata-CSDN博客文章浏览阅读1k次,点赞3次,收藏5次。文章浏览阅读914次。【Android设置头像,手机拍照或从本地相册选取图片作为头像】像微信、QQ、微博等社交类的APP,通常都有设置头像的功能,设置头像通常有两种方式:1,让用户通过选择本地相册之类的图片库中已有的图像,裁剪后作为头像。文章浏览阅读124次。【Android设置头像,手机拍照或从本地相册选取图片作为头像】像微信、QQ、微博等社交类的APP,通常都有设置头像的功能,设置头像通常有两种方式:1,让用户通过选择本地相册之类的图片库中已有的图像,裁剪后作为头像。_retriever.extractmetadata https://blog.csdn.net/zhangphil/article/details/139521977Android MediaMetadataRetriever setDataSource failed: status = 0xFFFFFFEA-CSDN博客文章浏览阅读1.6k次。文章讲述了在Android应用中使用Glide加载视频时,遇到MediaMetadataRetriever的setDataSource抛出异常的情况,原因可能是视频文件损坏或大小为0。作者介绍了如何自定义AppGlideModule来处理这种错误,例如通过添加模型筛选和容错机制来改进加载逻辑。 https://blog.csdn.net/zhangphil/article/details/133890245

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/918185.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/918185.shtml
英文地址,请注明出处:http://en.pswp.cn/news/918185.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

qt的元对象系统详解

Qt 的元对象系统&#xff08;Meta-Object System&#xff09;&#xff0c;这是 Qt 框架最核心、最强大的特性之一。 1.什么是 Qt 的元对象系统&#xff1f; Qt 的元对象系统&#xff08;Meta-Object System&#xff09;是 Qt 在标准 C 基础上扩展的一套机制&#xff0c;它为 C …

Nginx 性能优化与动态内容处理

一、压缩功能 实验目的&#xff1a;通过启用 Nginx 的 Gzip 压缩功能&#xff0c;对传输的文件&#xff08;如 HTML、日志等&#xff09;进行压缩&#xff0c;减少网络传输数据量&#xff0c;提升用户访问速度&#xff08;尤其适用于带宽有限的场景&#xff09;&#xff0c;同…

ComfyUI——舒服地让大模型为我所用

主页&#xff1a;ComfyUI | 用AI生成视频、图像、音频 https://github.com/comfyanonymous/ComfyUI 安装环境 我的环境是mac&#xff0c;芯片为M4pro。首先从github中下载工程&#xff0c;clone失败就直接下载zip压缩包。在model文件夹中&#xff0c;可以看到很多大名鼎鼎的…

【Visual Studio】使用VS调试(Debug)

确保在Debug模式下而不是Release 打断点(break point) 直接在有代码的行前单击&#xff0c;会出现红色的点(再次单击会取消)&#xff1b;或者光标停留在某行&#xff0c;按F9 这意味着程序当执行到这一行时会终止 在打完断点后点击”本地Windows调试器“或者按F5 往下翻会有代码…

B2.0:对硬件学习的一些个人心得感悟

对于硬件学习&#xff0c;所有人都会迷茫的找不到学习的路径和方向&#xff0c;都是自我摸索或者老师带领或者其他情况&#xff0c;而我倒是没有机会接触到现实的老师带我领进这个门&#xff0c;自然走的弯路比较多&#xff0c;所以引申出这篇文章&#xff0c;来聊聊硬件学习的…

Cursor设置

一&#xff1a;设置 Port: 7890TUN Mode&#xff1a;开启二&#xff1a;Editor Settings值为http://127.0.0.1:7890三&#xff1a;Cursor 测试一下

Windows下使用PyInstaller打包PyQt项目

在 Windows 环境下&#xff0c;使用 PyQt 开发的项目可以通过多种工具打包成 可执行文件&#xff08;.exe&#xff09;&#xff0c;以下是几种常见的方法及详细步骤&#xff1a;1. 使用 PyInstallerPyInstaller 是最常用的 Python 打包工具&#xff0c;支持 PyQt5/PyQt6/PySide…

AI大语言模型在生活场景中的应用日益广泛,主要包括四大类需求:文本处理、信息获取、决策支持和创意生成。

一、AI大语言模型生活应用全景图&#xff08;Mermaid流程图&#xff09;graph TDA[生活小事需求] --> B{需求分类}B --> C[文本处理类]B --> D[信息获取类]B --> E[决策支持类]B --> F[创意生成类]C --> C1[邮件写作]C --> C2[内容润色]C --> C3[文档总…

物奇路由器Wi-Fi芯片荣膺2025中国创新IC-强芯领航奖,并亮相第五届RISC-V中国峰会

近日&#xff0c;第五届中国集成电路设计创新大会在苏州举办&#xff0c;物奇携多款高性能网络通信与终端人工智能芯片亮相展会&#xff0c;其中首颗路由器Wi-Fi6芯片WQ9301凭借独特的架构创新和领先的性能优势&#xff0c;在国产IC强芯评选中脱颖而出&#xff0c;荣膺2025中国…

【已解决】npm install报错

~/autodl-tmp/App/magic_conch_frontend# npm install报错内容&#xff1a;WARN EBADENGINE Unsupported engine { npm WARN EBADENGINE package: vitejs/plugin-vue5.1.4, npm WARN EBADENGINE required: { node: ^18.0.0 || >20.0.0 }, npm WARN EBADENGINE current: { no…

IPC总结

IPC 是 Inter-Process Communication&#xff08;进程间通信&#xff09;的缩写&#xff0c;指的是操作系统中不同进程之间传递数据、交换信息或同步行为的机制。由于进程在内存中拥有独立的地址空间&#xff0c;无法直接访问彼此的内存&#xff0c;因此需要通过操作系统提供的…

java之父-新特性

目录 一.函数式接口Functional Interface 1. Supplier接口 --供给型接口 2. Consumer接口 --消费型接口 3.Function接口 --转换型接口 4. Predicate接口--断言型接口 5. Comparator接口--比较器接口 一.函数式接口Functional Interface 只有一个抽象方法的接口&#xff…

GPT-5的多模态能力如何?

GPT-5的多模态能力如何&#xff1f;概述问题1-非整点闹钟问题2-数数问题一问题3-数数问题二小结概述 2025年&#xff0c;8月8日凌晨&#xff0c;OpenAI 发布了 GPT-5&#xff0c;让我们看看其多模态能力如何&#xff0c;用之前大模型无法解决的题目测试&#xff0c;数数问题时…

多模态RAG赛题实战--Datawhale AI夏令营

参考自科大讯飞AI大赛&#xff08;多模态RAG方向&#xff09; - Datawhale 赛题意义&#xff1a; 我们正处在一个信息爆炸的时代&#xff0c;但这些信息并非以整洁的纯文本形式存在。它们被封装在各种各样的载体中&#xff1a;公司的年度财报、市场研究报告、产品手册、学术论…

SQL Server 创建 PostgreSQL 数据库 链接服务器指南

SQL Server 创建 PostgreSQL 数据库 链接服务器指南SQL Server 创建 PostgreSQL 数据库 链接服务器指南一、准备工作二、创建链接服务器三、测试连接四、常见问题解决五、注意事项SQL Server 创建 PostgreSQL 数据库 链接服务器指南 一、准备工作 安装 PostgreSQL ODBC 驱动&a…

李宏毅深度学习教程 第16-18章 终身学习+网络压缩+可解释性人工智能

【2025版】44、第十四节 机器终身学习 一 为什么今日的人工智能A_哔哩哔哩_bilibili 【2025版】42、第十三节 神经网络压缩 一 类神经网络剪枝PruA_哔哩哔哩_bilibili 【2025版】30、第九节 机器学习的可解释性 上 – 为什么神经网络可以正_哔哩哔哩_bilibili 目录 1. 终生…

LiveQing视频RTMP推流视频点播服务功能-云端录像支持按时间段下载录像时间段下载视频mp4

LiveQing视频RTMP推流视频点播服务功能-云端录像支持按时间段下载录像时间段下载视频mp41、云端录像2、配置云端录像3、查看云端录像3、列表模式4、时间段下载5、时间段下载接口6、RTMP推流视频直播和点播流媒体服务1、云端录像 LiveQing 支持服务器集中录像&#xff0c;将rtm…

Spark在什么情况下CBO才会判断失误,如何避免

在 Spark 中&#xff0c;CBO&#xff08;基于成本的优化器&#xff0c;Cost-Based Optimizer&#xff09;通过分析表的统计信息&#xff08;如行数、列基数、数据分布等&#xff09;计算不同执行计划的“成本”&#xff0c;并选择成本最低的计划。但在以下场景中&#xff0c;CB…

【第12话:感知算法基础4】图像分割:深度学习图像分割模型介绍入门及常用模型详解

深度学习图像分割模型介绍入门及常用模型详解 图像分割是计算机视觉的核心任务&#xff0c;旨在将图像划分为语义区域。随着深度学习的发展&#xff0c;分割模型在精度和效率上取得重大突破。以下按技术演进顺序详解主流模型&#xff1a;1. FCN&#xff08;全卷积网络&#xff…

AI 大模型企业级应用落地挑战与解决方案

引言&#xff1a;AI 大模型的企业价值与落地困境近年来&#xff0c;以 GPT-4、Claude 3、文心一言为代表的大语言模型&#xff08;LLM&#xff09;展现出惊人的自然语言理解与生成能力&#xff0c;吸引了众多企业的关注。据 Gartner 预测&#xff0c;到 2025 年&#xff0c;40%…