Android MediaMetadataRetriever取視頻封面,Kotlin(1)

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%…