natario1 / CameraView

📸 A well documented, high-level Android interface that makes capturing pictures and videos easy, addressing all of the common issues and needs. Real-time filters, gestures, watermarks, frame processing, RAW, output of any size.
https://natario1.github.io/CameraView
Other
4.94k stars 933 forks source link

Android 10(SDK Version 29) Shared Storage rules adaptation (Uri oriented) #799

Open yaroslavkulinich opened 4 years ago

yaroslavkulinich commented 4 years ago

Problem (inconvenience)

New Android shared storage concept dictates a set of new rules for media files access. Developers have to leave Java File API approach and start work with files through content provider. In order to create a video file using CameraView on SDK 29 and higher I have to:

1. Create and publish new video item to MediaStore collection using ContentResolver and mark that item with MediaStore.Video.Media.IS_PENDING flag(so this item will be unavailable until this flag present).

val videoCollection = MediaStore.Video.Media
                .getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
val videoDetails = ContentValues().apply {
      put(MediaStore.Video.Media.DISPLAY_NAME, name)
      put(MediaStore.Video.Media.MIME_TYPE, "video/mp4")
      put(MediaStore.Video.Media.IS_PENDING, 1)
}
val uri: Uri = resolver.insert(videoCollection, videoDetails)

2. Get FileDescriptor with item Uri using ContentResolver and save it somewhere (viewModel for example) for later.

val videoFileDescriptor = resolver.openFileDescriptor(uri, "w", null)?.fileDescriptor 

3. Start video recording by putting videoFileDescriptor to cameraView.takeVideo(fileDescriptor: FileDescriptor) function.

4. After video captured in CameraListener onVideoTaken(result: VideoResult) function inactivate MediaStore.Video.Media.IS_PENDING flag to make video available using that "saved for later" video Uri.

val fileDetails = ContentValues().apply {
      put(MediaStore.Video.Media.IS_PENDING, 0)
}
resolver.update(uri, fileDetails, null, null)

5. We are done. Happy end.

So, I just described the process of video creation using new Android 10 Shared Storage rules approach and CameraView. Remember that we do not have to use Java File API, so FileDescriptor is the only way to record a video.

If you look on described flow, you can easily notice that we have one inconvenience - we have to generate FileDescriptor with Uri and store that Uri somewhere to use it later for making video available(MediaStore.Video.Media.IS_PENDING flag).

Solution

It would be much easier for developers to have a function like cameraView.takeVideo(uri: Uri), so step 2 (resolving FileDescriptor from Uri) can be done by CameraView directly. AND to make the solution complete, add uri: Uri parameter to VideoResult class.

So a developer creates media item using ContentResolver.insert() function and gets Uri of that item, then provides it to new cameraView.takeVideo(uri: Uri) function and when video capture is finished use that Uri (just from VideoResult in onVideoTaken(result: VideoResult) listener function) in ContentResolver.update() function. As a result there is no need to store Uri somewhere, we provide it to CameraView and then get it back in listener.

The same is for "take photo" use case.

natario1 commented 4 years ago

Thanks for the clear description! The proposed solution sounds good to me. Would you like to work on it?

j22purikas commented 4 years ago

@yaroslavkulinich or @natario1, any update about this issue? Will URI support be added in the future?

jake-newsom commented 3 years ago

So what's the right way to use this for VideoSnapshot with Android 10+ and the new file system?

We need to be able to take videos with images overlayed and the takeVideoSnapshopt functions don't have an option to use a FileDescriptor as the parameter.

colorgold commented 1 year ago

I would like to know how I can help implement this solution?

SweetD3v commented 1 year ago

You can store it in cache directory then export that video using MediaStore API, or you can take persistable permission of specific folder and save video into that folder directly.

colorgold commented 1 year ago

You can store it in cache directory then export that video using MediaStore API, or you can take persistable permission of specific folder and save video into that folder directly.

I was able to add @yaroslavkulinich's solution to the project. I created a pull request, but I am not sure if it went through.