You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android+Chaquopy:Python接收视频URI路径无法读取文件

问题解决:Chaquopy中Python无法访问Android视频文件

核心原因

  1. Scoped Storage限制:Android 10及以上版本采用分区存储,READ_EXTERNAL_STORAGE权限不再赋予直接访问文件路径的权限,MediaStore.MediaColumns.DATA字段可能返回无效路径或为空。
  2. 路径访问失效:直接传递文件路径给Python后,OpenCV无法通过路径访问受Scoped Storage保护的视频文件,导致权限校验失败。

解决方案

放弃通过文件路径访问视频,改用**文件描述符(File Descriptor)**传递给Python,利用Android ContentResolver打开文件的可读描述符,让OpenCV通过描述符直接读取视频内容。同时适配Android 13+的新权限体系。

步骤1:修改权限配置

在AndroidManifest.xml中添加适配高版本的权限:

<!-- Android 13+ 视频读取权限 -->
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<!-- 兼容Android 12及以下版本 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />

步骤2:更新权限检查逻辑

修改MainActivity中的checkPermission方法,适配Android 13的权限:

private boolean checkPermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_VIDEO)
                != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.READ_MEDIA_VIDEO},
                    REQUEST_PERMISSION_READ_EXTERNAL_STORAGE);
            return false;
        }
    } else {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
                    REQUEST_PERMISSION_READ_EXTERNAL_STORAGE);
            return false;
        }
    }
    return true;
}

步骤3:修改VideoProcessor类,传递文件描述符

删除getRealPathFromUri方法,更新processVideo逻辑,通过ContentResolver获取文件描述符并传递给Python:

public class VideoProcessor {

    private static final String TAG = "APP_TAG";
    private static List<byte[]> processedFrames;

    public static void processVideo(Context context, Uri videoUri) {
        Python py = Python.getInstance();
        if (!Python.isStarted()) {
            Python.start(new AndroidPlatform(context));
        }

        processedFrames = new ArrayList<>(); // 初始化列表,避免空指针
        try (ParcelFileDescriptor pfd = context.getContentResolver().openFileDescriptor(videoUri, "r")) {
            if (pfd == null) {
                Log.e(TAG, "Failed to open file descriptor for video");
                return;
            }
            int fileDescriptor = pfd.getFd();

            PyObject videoProcessingModule = py.getModule("script");
            // 传递文件描述符给Python处理函数
            PyObject processedData = videoProcessingModule.callAttr("process_video", fileDescriptor);

            PyObject[] processedFramesArray = processedData.toJava(PyObject[].class);
            for (PyObject frame : processedFramesArray) {
                processedFrames.add(frame.toJava(byte[].class));
            }
        } catch (IOException e) {
            Log.e(TAG, "Error accessing video file: " + e.getMessage());
            e.printStackTrace();
        }
    }

    public static List<byte[]> getProcessedFrames() {
        return processedFrames;
    }
}

步骤4:修改Python脚本,通过文件描述符读取视频

更新Python的process_video函数,接收文件描述符并让OpenCV通过该描述符打开视频:

import cv2
import numpy as np
import os
from contextlib import closing

def process_video(fd):
    print("Received file descriptor:", fd)

    # 用文件描述符打开视频,确保资源正确释放
    with closing(os.fdopen(fd, 'rb')):
        cap = cv2.VideoCapture(fd)
        frames = []
        
        while cap.isOpened():
            ret, frame = cap.read()
            if not ret:
                break
            # 帧处理:转为灰度图
            processed_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
            frames.append(processed_frame)
        
        cap.release()

    print("Number of processed frames:", len(frames))
    # 返回转为字节数组的帧列表
    return [frame.tobytes() for frame in frames]

关键说明

  • 文件描述符是Android系统级的文件访问凭证,不受Scoped Storage路径限制,能让Python直接读取视频内容。
  • 使用try-with-resources和closing上下文管理器确保文件资源正确释放,避免内存泄漏。
  • Android 13+必须使用READ_MEDIA_VIDEO权限,旧版本仍用READ_EXTERNAL_STORAGE。

内容的提问来源于stack exchange,提问作者Matheus Fortunato Alves

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 17:02:32