卧式纯绿 2024-04-19 20:03 采纳率: 26.9%
浏览 1

安卓开发视频抽帧处理

求问各位在安卓开发中对于从相册已获取的视频uri如何进行抽帧处理?
以前采用的retriver类进行处理,但是setDataSource函数的参数永远出错

  • 写回答

3条回答 默认 最新

  • 专家-赤兔[在线] 全栈领域优质创作者 2024-04-19 20:03
    关注

    引自免费微信小程序:皆我百晓生

    在Android开发中,如果你想从已有的视频uri中提取帧(即抽帧),你可以使用MediaMetadataRetriever类或者ExifInterface类。这里我会提供一个使用MediaMetadataRetriever的示例。

    首先,确保你在build.gradle文件中的dependencies部分添加了多媒体相关的库:

    dependencies {
        implementation 'com.android.support:multidex:1.0.3'
    }
    

    然后按照以下步骤操作:

    1. 创建一个MediaMetadataRetriever实例,并设置数据源。
    2. 设置你要抓取的帧的时间戳。
    3. 调用方法extractFrame()获取帧图片。
    4. 将图片保存到本地或者进行其他处理。

    以下是完整的Java代码示例:

    import android.content.Context;
    import android.graphics.Bitmap;
    import android.media.MediaMetadataRetriever;
    import android.net.Uri;
    
    import java.io.File;
    import java.io.FileOutputStream;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class VideoFrameExtractor {
    
        public static void extractFramesFromVideo(Context context, Uri videoUri, int frameIntervalInSecs) {
            MediaMetadataRetriever retriever = new MediaMetadataRetriever();
            try {
                retriever.setDataSource(context, videoUri);
    
                // 获取视频总时长(单位:毫秒)
                long durationMs = Long.parseLong(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION));
                int totalFrames = (int) Math.ceil(durationMs / 1000 / frameIntervalInSecs); // 计算总的帧数
    
                for (int i = 0; i < totalFrames; i++) {
                    long timeMs = i * frameIntervalInSecs * 1000; // 计算当前帧的时间戳
                    Bitmap bitmap = retriever.getFrameAtTime(timeMs, MediaMetadataRetriever.OPTION_CLOSEST);
    
                    if (bitmap != null) {
                        String fileName = generateFileName(i, "jpg");
                        saveBitmapToFile(bitmap, context, fileName);
                        System.out.println("Saved frame " + fileName);
                    }
                }
    
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    retriever.release(); // 释放资源
                } catch (Exception ignored) {}
            }
        }
    
        private static String generateFileName(int index, String extension) {
            SimpleDateFormat formatter = new SimpleDateFormat("frame_%05d." + extension);
            return formatter.format(new Date());
        }
    
        private static boolean saveBitmapToFile(Bitmap bitmap, Context context, String fileName) {
            File storageDir = getExternalFilesDir(context, "frames"); // 获取外部存储目录
            if (storageDir == null) {
                return false;
            }
            File outputFile = new File(storageDir, fileName);
            try (FileOutputStream out = new FileOutputStream(outputFile)) {
                bitmap.compress(Bitmap.CompressFormat.JPEG, 80, out);
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
    
        // 在Android 10及以上版本,需要动态请求写入外部存储权限
        public static boolean hasWritePermission(Context context) {
            return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)
                    && ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
        }
    
        public static void requestWritePermission(Context context) {
            ActivityCompat.requestPermissions(context,
                    new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                    1);
        }
    }
    

    要使用这段代码,你需要在你的Activity或者Fragment中调用extractFramesFromVideo()方法:

    if (!VideoFrameExtractor.hasWritePermission(this)) {
        VideoFrameExtractor.requestWritePermission(this);
    } else {
        VideoFrameExtractor.extractFramesFromVideo(this, uri, 5); // 每5秒抽取一帧
    }
    

    其中,uri是你要抽取帧的视频uri,5表示每5秒抽取一帧。如果需要动态请求权限,根据用户的授权情况决定是否调用extractFramesFromVideo()

    注意:这个例子没有处理所有异常情况,实际应用中可能需要对错误进行更详细的处理。另外,如果你的设备运行的是Android 10或更高版本,你还需要处理写入外部存储的权限。

    评论 编辑记录

报告相同问题?

问题事件

  • 创建了问题 4月19日

悬赏问题

  • ¥15 phython如何实现以下功能?查找同一用户名的消费金额合并—
  • ¥15 孟德尔随机化怎样画共定位分析图
  • ¥18 模拟电路问题解答有偿速度
  • ¥15 CST仿真别人的模型结果仿真结果S参数完全不对
  • ¥15 误删注册表文件致win10无法开启
  • ¥15 请问在阿里云服务器中怎么利用数据库制作网站
  • ¥60 ESP32怎么烧录自启动程序
  • ¥50 html2canvas超出滚动条不显示
  • ¥15 java业务性能问题求解(sql,业务设计相关)
  • ¥15 52810 尾椎c三个a 写蓝牙地址