如何快速检测Android视频文件的指定元数据?
我明白你在Android上提取特定视频元数据时遇到的困扰——原生MediaMetadataRetriever既慢又不可靠,而社区里现有的FFmpeg或原生API相关方案都没完全命中你的需求。下面我就针对你的三个核心需求,给出具体的实现方案,用FFmpegMediaMetadataRetriever来做,它虽然速度不算快,但胜在稳定可靠,能解决你的痛点。
一、判断视频是否包含音频
要判断视频里有没有音频流,我们可以通过FFmpegMediaMetadataRetriever提取所有流的信息,然后检查是否包含音频标识:
FFmpegMediaMetadataRetriever retriever = new FFmpegMediaMetadataRetriever(); try { retriever.setDataSource(videoFilePath); // 获取所有媒体流的描述信息 String streamInfo = retriever.extractMetadata(FFmpegMediaMetadataRetriever.METADATA_KEY_STREAMS); // 检查是否存在音频流 boolean hasAudio = streamInfo != null && streamInfo.contains("audio"); } finally { // 务必释放资源,避免内存泄漏 retriever.release(); }
这个方法的核心是METADATA_KEY_STREAMS返回的内容会包含所有流的类型、编码等信息,只要里面出现"audio"字段,就说明视频包含音频轨道。
二、获取视频创建日期和时间
视频的创建时间可能存在两个地方:一是视频文件内置的元数据,二是文件系统记录的创建/修改时间。我们优先读取内置元数据,因为它更准确;如果内置数据不存在,再 fallback 到文件系统信息:
FFmpegMediaMetadataRetriever retriever = new FFmpegMediaMetadataRetriever(); String creationTime = null; try { retriever.setDataSource(videoFilePath); // 尝试读取视频内置的创建时间元数据 creationTime = retriever.extractMetadata(FFmpegMediaMetadataRetriever.METADATA_KEY_CREATION_TIME); // 如果内置元数据为空,读取文件系统的时间 if (creationTime == null || creationTime.trim().isEmpty()) { File videoFile = new File(videoFilePath); long fileTimestamp = videoFile.lastModified(); // 格式化时间为可读格式,可根据需求调整日期格式 creationTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()) .format(new Date(fileTimestamp)); } } finally { retriever.release(); }
注意:不同Android版本对文件lastModified()的返回值可能有差异,部分设备返回的是文件修改时间,部分是创建时间,你可以根据目标设备进行适配测试。
三、提取视频缩略图
FFmpegMediaMetadataRetriever提取缩略图的稳定性远高于原生API,我们可以指定提取视频的第一帧(或任意时间点的帧)作为缩略图:
FFmpegMediaMetadataRetriever retriever = new FFmpegMediaMetadataRetriever(); Bitmap thumbnail = null; try { retriever.setDataSource(videoFilePath); // 提取视频第一帧作为缩略图,OPTION_CLOSEST_SYNC确保获取关键帧 thumbnail = retriever.getFrameAtTime(0, FFmpegMediaMetadataRetriever.OPTION_CLOSEST_SYNC); // 如果需要调整缩略图尺寸,可进行缩放 if (thumbnail != null) { thumbnail = Bitmap.createScaledBitmap(thumbnail, 320, 240, true); } } finally { retriever.release(); }
getFrameAtTime的第一个参数是时间戳(单位微秒),传入0就会提取第一帧;OPTION_CLOSEST_SYNC参数能保证获取到最接近指定时间的关键帧,避免出现黑屏或模糊的无效缩略图。
内容的提问来源于stack exchange,提问作者Zulqurnain Haider




