Сохранить и вставить видео в галерею на Android 10

Я пытаюсь сохранить видео в галерее. Следующий код работает со всеми версиями 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();
            }
        }
    }

Я также пробовал использовать get 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, кроме Android Q.

После сохранения видео при проверке у меня в галерее появляется пустое видео

введите здесь описание изображения


person Mouaad Abdelghafour AITALI    schedule 13.09.2019    source источник
comment
Где ваш fileOutputStream? В приведенном выше коде вы просто создаете каталог и файл.   -  person Mohan Sai Manthri    schedule 13.09.2019
comment
@MohanSaiManthri, спасибо за ваш комментарий, на самом деле, я хочу создать путь для его использования   -  person Mouaad Abdelghafour AITALI    schedule 13.09.2019
comment
@MohanSaiManthri, пожалуйста, проверьте вопрос еще раз, я обновил его   -  person Mouaad Abdelghafour AITALI    schedule 13.09.2019
comment
@MouaadAbdelghafourAITALI Вы нашли решение ??   -  person Parag Pawar    schedule 05.12.2019
comment
@ParagPawar, просто временное решение. Я закончил это, добавив android:requestLegacyExternalStorage="true" внутри тега Application   -  person Mouaad Abdelghafour AITALI    schedule 05.12.2019


Ответы (2)


Я ответил вам на другой пост ... Вам нужен поток ввода (файл, растровое изображение и т. Д.) И записать поток вывода из файла ввода.

Вам нужно изменить библиотеку, чтобы она работала с Android Q. Если вы не можете этого сделать, вы можете скопировать видео в медиа-галерею, а затем удалить старое видео, созданное в getExternalFilesDir (). После этого у вас есть 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);
person Frank    schedule 15.09.2019
comment
Могу ли я получить доступ к этому сохраненному видеофайлу с помощью любого приложения File Manager? - person Bugs Happen; 30.04.2020
comment
есть ли способ сделать это без копирования? - person user924; 01.09.2020
comment
Что ты имеешь в виду ? Записывать видео и вставлять его прямо в магазин мультимедиа? - person Frank; 02.09.2020
comment
Взгляните на этот пример кода из Документов Android. Вы должны использовать VOLUME_EXTERNAL_PRIMARY вместо EXTERNAL_CONTENT_URI для Android Q. - person Marion Piloo; 24.02.2021

Я хочу создать путь для его использования

Вы получаете Uri от MediaStore. Нет никакого «пути». Мало того, что Uri нельзя преобразовать в путь, у вас нет доступа файловой системы к этому месту на Android 10 и выше.

Избавьтесь от этого:

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

так как работать не будет.

Замените его своим кодом, чтобы записать видео в место, указанное Uri. Используйте resolver.openOutputStream(), чтобы получить OutputStream в это место. В частности, сделайте это перед вызовом resolver.update() для получения IS_PENDING 0, поскольку в нем конкретно говорится: «Я закончил писать в Uri; теперь вы можете использовать содержимое».

Или используйте одно из расположений файловой системы, к которым у вас есть доступ, например getExternalFilesDir() на Context, и избавьтесь от MediaStore материала.

person CommonsWare    schedule 13.09.2019
comment
если бы у Марка было пенни на каждый вопрос, на который он отвечал с помощью функции resolver.openOutputStream (), он был бы самым богатым человеком на планете. - person Mohammed Aouf Zouag; 13.09.2019
comment
@pic: не могли бы вы рассказать мне, как я могу получить местоположение из OutputStream - я не знаю, что вы имеете в виду, извините. - person CommonsWare; 14.09.2019
comment
как переместить сохраненный файл в getExternalFilesDir в общедоступную папку DCIM или Movies с помощью MediaStore? - person user924; 01.09.2020