在Android 10上保存并插入视频到相册

3

我正在尝试将视频保存到图库中,以下代码在所有Android版本(除了Android Q)上都可以正常工作:

private void getPath() {
    String videoFileName = "video_" + System.currentTimeMillis() + ".mp4";
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    ContentResolver resolver = getContentResolver();
    ContentValues contentValues = new ContentValues();
    contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, videoFileName);
    contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "video/mp4");
    contentValues.put(
        MediaStore.MediaColumns.RELATIVE_PATH, 
        "Movies/" + "Folder");
    contentValues.put(MediaStore.Video.Media.IS_PENDING, 1);
    Uri collection = 
        MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
    Uri videoUri = resolver.insert(collection, contentValues);
    if (videoUri != null) {
        try (ParcelFileDescriptor pfd = resolver.openFileDescriptor(videoUri, "w", null)) {
            OutputStream outputStream = null;
            if (pfd != null) {
                outputStream = resolver.openOutputStream(videoUri);
                outputStream.flush();
                outputStream.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    contentValues.clear();
    contentValues.put(MediaStore.Video.Media.IS_PENDING, 0);
    if (videoUri != null) {
        resolver.update(videoUri, contentValues, null, null);
    }
    } else {
        File storageDir = new File(
            Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES)
            + "/Folder");
        boolean success = true;
        if (!storageDir.exists()) {
            success = storageDir.mkdirs();
        }
        if (success) {
            File videoFile = new File(storageDir, videoFileName);
            savedVideoPath = videoFile.getAbsolutePath();
        }
    }
}

我也尝试使用getExternalFilesDir(),但是没有效果,在相册中没有创建视频。
String videoFileName = "video_" + System.currentTimeMillis() + ".mp4";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    File imageFile = null;
    File storageDir = new File(
        getExternalFilesDir(Environment.DIRECTORY_DCIM),
        "Folder");
    boolean success = true;
    if (!storageDir.exists()) {
        success = storageDir.mkdirs();
    }
    if (success) {
        imageFile = new File(storageDir, videoFileName);
    }
    savedVideoPath = imageFile.getAbsolutePath();

我使用第三方库来录制SurfaceView,该库需要一个路径来保存录制的视频:

 mRenderPipeline = EZFilter.input(this.effectBmp)
                    .addFilter(new GalleryEffects().getEffect(VideoMaker.this, i))
                    .enableRecord(savedVideoPath, true, false)
                    .into(mRenderView);

当录制视频结束时,录制的视频会保存在给定路径savedVideoPath中,在所有安卓版本中都能正常工作,但不包括Android Q

保存视频后,当我检查时,在相册中得到了一个空白视频。

输入图像描述


1
你的fileOutputStream在哪里?在上面的代码中,你只是创建了一个目录和一个文件。 - Mohan Sai Manthri
@MohanSaiManthri 感谢您的评论,实际上我想创建一个路径来使用它。 - Mouaad Abdelghafour AITALI
@MohanSaiManthri,您能否再次检查一下问题,我已经更新了它。 - Mouaad Abdelghafour AITALI
@MouaadAbdelghafourAITALI 你找到解决方案了吗? - Parag Pawar
@ParagPawar,这只是一个临时解决方案,我通过在Application标签内添加android:requestLegacyExternalStorage="true"来结束了这个问题。 - Mouaad Abdelghafour AITALI
2个回答

10

我已经回答了你在其他帖子中的问题。你需要一个输入流(文件、位图等),并从输入文件中编写输出流。

你需要更改这个库,使它能够与Android Q兼容。如果你不能做到这一点,你可以将视频复制到媒体库中,然后删除在getExternalFilesDir()中创建的旧视频。之后,你就有了视频的URI,并且可以对URI进行操作。

如果你使用getExternalFilesDir()保存了视频,你可以使用我的示例:你获得的媒体URI是"uriSavedVideo"。这只是一个例子。大型视频也应该在后台中复制。

String videoFileName = "video_" + System.currentTimeMillis() + ".mp4";

ContentValues valuesvideos;
valuesvideos = new ContentValues();
valuesvideos.put(MediaStore.Video.Media.RELATIVE_PATH, "Movies/" + "Folder");
valuesvideos.put(MediaStore.Video.Media.TITLE, videoFileName);
valuesvideos.put(MediaStore.Video.Media.DISPLAY_NAME, videoFileName);
valuesvideos.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4");
valuesvideos.put(
    MediaStore.Video.Media.DATE_ADDED, 
    System.currentTimeMillis() / 1000);
valuesvideos.put(MediaStore.Video.Media.DATE_TAKEN, System.currentTimeMillis());
valuesvideos.put(MediaStore.Video.Media.IS_PENDING, 1);

ContentResolver resolver = mContext.getContentResolver();
Uri collection = 
    MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
Uri uriSavedVideo = resolver.insert(collection, valuesvideos);
ParcelFileDescriptor pfd;

try {
    pfd = mContext.getContentResolver().openFileDescriptor(uriSavedVideo, "w");

    FileOutputStream out = new FileOutputStream(pfd.getFileDescriptor());
    // Get the already saved video as fileinputstream from here
    File storageDir = new File(
        mContext.getExternalFilesDir(Environment.DIRECTORY_MOVIES), 
        "Folder");
    File imageFile = new File(storageDir, "Myvideo");
    FileInputStream in = new FileInputStream(imageFile);

    byte[] buf = new byte[8192];
    int len;
    while ((len = in.read(buf)) > 0) {
        out.write(buf, 0, len);
    }

    out.close();
    in.close();
    pfd.close();
} catch (Exception e) {
    e.printStackTrace();
}

valuesvideos.clear();
valuesvideos.put(MediaStore.Video.Media.IS_PENDING, 0);
mContext.getContentResolver().update(uriSavedVideo, valuesvideos, null, null);

我可以使用任何文件管理器应用程序访问此保存的视频文件吗? - Bugs Happen
有没有不复制的方法可以实现它? - user924
你的意思是什么?录制视频并直接插入到媒体库中吗? - Frank
查看 Android 文档中的此代码示例,在 Android Q 中,您必须使用 VOLUME_EXTERNAL_PRIMARY 而不是 EXTERNAL_CONTENT_URI - Marion Piloo
谢谢你的回答。 - Mohamed Mohy

5

我想创建一个路径来使用它

您从MediaStore获取了一个Uri,但不存在“路径”。不仅Uri无法转换为路径,而且在Android 10及更高版本上,您也无法访问该位置的文件系统。

请删除此内容:

        if (videoUri != null) {
            savedVideoPath = getRealPathFromURI(videoUri);
        }

因为它将无法工作,请更换你的代码来将视频写入由Uri指定的位置。使用resolver.openOutputStream()获取一个OutputStream到那个位置。特别要在调用resolver.update()之前执行这个操作,而IS_PENDING的值为0,因为这明确表示“我已经完成了对Uri的写入;现在可以使用内容了”。

或者,使用你有权限访问的文件系统位置,例如Context中的getExternalFilesDir(),并且摆脱MediaStore的东西。


4
如果Mark回答每个问题都用"Use resolver.openOutputStream()"这句话的话,他会成为全球最富有的人。 - Mohammed Aouf Zouag
@pic:“请问您能告诉我如何从OutputStream获取位置吗?”-- 抱歉,我不知道您的意思。 - CommonsWare
如何使用MediaStore将保存在getExternalFilesDir中的文件移动到公共DCIM或电影文件夹? - user924

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接