Save and Insert video to gallery on Android 10
Asked Answered
O

2

3

I'm trying to save a video to the gallery,the following code works well an all Android versions except the 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();
        }
    }
}

I also tried using get getExternalFilesDir() , but doesn't work, no video created in the gallery

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();

I use a 3rd-party library to record SurfaceView, this library requires a path to save the recorded video :

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

When record video finished, the recorded video saved with the given path savedVideoPath , everything works just fine on all android version except the Android Q

After saving the video, when I check, I get an empty video in the gallery

enter image description here

Outofdate answered 13/9, 2019 at 12:4 Comment(5)
Where is your fileOutputStream? In above code you're just making an directory and a file.Badmouth
@MohanSaiManthri thank you for your comment,actually, I want to create a path to use itOutofdate
@MohanSaiManthri can you please check the question again,I have updated itOutofdate
@MouaadAbdelghafourAITALI Did you find the solution??Keynesianism
@ParagPawar , just a temporary solution I ended this by adding android:requestLegacyExternalStorage="true" inside the Application tagOutofdate
C
10

I have answered you to your other post to... You need an inputstream (file, bitmap etc.) and write an outputstream from the inputfile.

You have to change the library to make it work with Android Q . If you cannot do this you could copy the video to the media gallery and then delete the old video created in getExternalFilesDir(). After this you have the uri of the video and can do what you want with the uri

If you have saved the video with getExternalFilesDir() you could use my example here : The media uri you get is "uriSavedVideo" . This is only an example. A large video should also be copied in the background.

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);
Campbellbannerman answered 15/9, 2019 at 2:11 Comment(5)
Can I access this saved video file with any File Manager app?Gladdie
is there any way to do it without copying?Spasmodic
What do you mean ? Recording a video and inserting it directly into the media store ?Campbellbannerman
Look at this code example from the Android Docs. You have to use VOLUME_EXTERNAL_PRIMARY instead of EXTERNAL_CONTENT_URI for Android Q.Eupatrid
Thank you for the answerFriesland
W
5

I want to create a path to use it

You are getting a Uri from MediaStore. There is no "path". Not only can a Uri not be converted to a path, but you do not have filesystem access to that location on Android 10 and higher.

Get rid of this:

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

as it will not work.

Replace it with your code to write out your video to the location identified by the Uri. Use resolver.openOutputStream() to get an OutputStream to that location. In particular, do this before you call resolver.update() for an IS_PENDING of 0, as that specifically says "I am done writing to the Uri; you can use the content now".

Or, use one of the filesystem locations that you do have access to, such as getExternalFilesDir() on Context, and get rid of the MediaStore stuff.

Weidman answered 13/9, 2019 at 12:30 Comment(3)
if Mark had a penny for every question he answered with "Use resolver.openOutputStream()", he would have been the richest man on the globe.Altamirano
@pic: "can you please tell me how I can I get location from OutputStream" -- I do not know what you mean by this, sorry.Weidman
how to move saved file in getExternalFilesDir to public DCIM or Movies folder using MediaStore?Spasmodic

© 2022 - 2024 — McMap. All rights reserved.