将视频插入图库 [Android Q]

Mou*_*ALI 7 java android android-mediascanner android-external-storage android-10.0

要录制SurfeceView我使用的 3rd-party library,该库需要一个路径,其中保存在我的案例中的输出(录制的视频)是savedVideoPath

 mRenderPipeline = EZFilter.input(this.effectBmp)
                    .addFilter(new Effects().getEffect(VideoMaker.this, i))
                    .enableRecord(savedVideoPath, true, false)
                    .into(mRenderView);
Run Code Online (Sandbox Code Playgroud)

录制停止后,视频应该以savedVideoPath为路径保存,当我测试代码时,也就是说,当我打开图库应用程序时,我在那里看到保存的视频,但是当我在Android Q上测试时,我什么也看不见。

由于getExternalStoragePublicDirectorygetExternalStorageDirectory已弃用,我尝试使用getExternalFilesDir如下:

private void getPath() {
        String videoFileName = "video_" + System.currentTimeMillis() + ".mp4";
        fileName = videoFileName;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            File imageFile = null;
            File storageDir = new File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), "Folder");
            source = storageDir;
            boolean success = true;
            if (!storageDir.exists()) {
                success = storageDir.mkdirs();
            }
            if (success) {
                imageFile = new File(storageDir, videoFileName);
                savedVideoPath = imageFile.getAbsolutePath();
            }
        } 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();
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

录制停止后,我转到Files Explorer app > Android > data > com.packageName > files > Movies > Folder,我可以在那里看到所有保存的视频,但在图库中看不到它们。

我试图用来Intent.ACTION_MEDIA_SCANNER_SCAN_FILE刷新画廊,但不幸的是不起作用。

我也试过MediaScannerConnection

 MediaScannerConnection.scanFile(context, new String[]{savedVideoPath}, new String[]{"video/mp4"}, new MediaScannerConnection.MediaScannerConnectionClient() {
            public void onMediaScannerConnected() {
            }

            public void onScanCompleted(String s, Uri uri) {

            }
        });
Run Code Online (Sandbox Code Playgroud)
  • 谁能帮我解决这个问题?我坚持了将近2天

Fra*_*ank 11

您必须更改库才能使其与 Android Q 配合使用。如果您不能这样做,您可以将视频复制到媒体库,然后删除在 getExternalFilesDir() 中创建的旧视频。在此之后,您将获得视频的 uri,并且可以使用 uri 执行您想要的操作

如果您使用 getExternalFilesDir() 保存了视频,则可以在此处使用我的示例:您获得的媒体 uri 是 "uriSavedVideo" 。这只是一个例子。还应在后台复制大型视频。

Uri uriSavedVideo;
    File createdvideo = null;
    ContentResolver resolver = getContentResolver();
    
    

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

    ContentValues valuesvideos;
    valuesvideos = new ContentValues();


    if (Build.VERSION.SDK_INT >= 29) {

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

        Uri collection = MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
        uriSavedVideo = resolver.insert(collection, valuesvideos);


    } else {

        String directory  = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator+ Environment.DIRECTORY_MOVIES + "/"+"YourFolder";

        createdvideo = new File(directory, videoFileName);

        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.DATA, createdvideo.getAbsolutePath());
        uriSavedVideo = getContentResolver().insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, valuesvideos);


    }


    if (Build.VERSION.SDK_INT >= 29) {
        valuesvideos.put(MediaStore.Video.Media.DATE_TAKEN, System.currentTimeMillis());
        valuesvideos.put(MediaStore.Video.Media.IS_PENDING, 1);


    }


  
    
    
    ParcelFileDescriptor pfd;

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

        FileOutputStream out = new FileOutputStream(pfd.getFileDescriptor());

        // get the already saved video as fileinputstream

        // The Directory where your file is saved
        File storageDir = new File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), "Folder");


        //Directory and the name of your video file to copy
        File videoFile = new File(storageDir, "Myvideo"); 

        FileInputStream in = new FileInputStream(videoFile);


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





    if (Build.VERSION.SDK_INT >= 29) {
        valuesvideos.clear();
        valuesvideos.put(MediaStore.Video.Media.IS_PENDING, 0);
        getContentResolver().update(uriSavedVideo, valuesvideos, null, null);

    }
Run Code Online (Sandbox Code Playgroud)


nAk*_*dov 8

这是我的解决方案 - 将照片/视频保存到图库。

private fun saveMediaFile2(filePath: String?, isVideo: Boolean, fileName: String) {
filePath?.let {
    val context = MyApp.applicationContext
    val values = ContentValues().apply {
        val folderName = if (isVideo) {
            Environment.DIRECTORY_MOVIES
        } else {
            Environment.DIRECTORY_PICTURES
        }
        put(MediaStore.Images.Media.DISPLAY_NAME, fileName)
        put(MediaStore.Images.Media.MIME_TYPE, MimeUtils.guessMimeTypeFromExtension(getExtension(fileName)))
        put(MediaStore.Images.Media.RELATIVE_PATH, folderName + "/${context.getString(R.string.app_name)}/")
        put(MediaStore.Images.Media.IS_PENDING, 1)
    }

    val collection = if (isVideo) {
        MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
    } else {
        MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
    }
    val fileUri = context.contentResolver.insert(collection, values)

    fileUri?.let {
        if (isVideo) {
            context.contentResolver.openFileDescriptor(fileUri, "w").use { descriptor ->
                descriptor?.let {
                    FileOutputStream(descriptor.fileDescriptor).use { out ->
                        val videoFile = File(filePath)
                        FileInputStream(videoFile).use { inputStream ->
                            val buf = ByteArray(8192)
                            while (true) {
                                val sz = inputStream.read(buf)
                                if (sz <= 0) break
                                out.write(buf, 0, sz)
                            }
                        }
                    }
                }
            }
        } else {
            context.contentResolver.openOutputStream(fileUri).use { out ->
                val bmOptions = BitmapFactory.Options()
                val bmp = BitmapFactory.decodeFile(filePath, bmOptions)
                bmp.compress(Bitmap.CompressFormat.JPEG, 90, out)
                bmp.recycle()
            }
        }
        values.clear()
        values.put(if (isVideo) MediaStore.Video.Media.IS_PENDING else MediaStore.Images.Media.IS_PENDING, 0)
        context.contentResolver.update(fileUri, values, null, null)
    }
}
}
Run Code Online (Sandbox Code Playgroud)