从 Android 内容 URI 获取 FileInputStream(或如何在 InputStream 上查找)

Get FileInputStream from Android content URI (or how to seek on an InputStream)

我有一个播放自定义 h264 传输流的视频播放器应用程序。我的任务是能够通过用户打开 "gallery"、选择 "movies" 等方法启动我们的播放器,然后在选择一部电影后选择我们的应用程序启动……这一切都完美无缺。我的问题是如何使用 ContentResolver 在 InputStream 上来回查找。

我也在这里阅读了很多帖子,例如 Android: Getting a file URI from a content URI? as well as a rant http://commonsware.com/blog/2013/08/07/for-android-apis-think-streams-not-files.html 关于使用 InputStream 而不是其他方法,但是对于大视频文件,跳过和 mark/reset 将无法在我们的搜索中工作播放器,所以一个普通的 InputStream 有点没用......一个 FileInputStream 工作得很好,作为一个 hack,我将 resolver.getInputStream 投射到一个 FileInputStream 并且它玩球,但那是一个 hack......所以......如何从内容uri 获取文件对象或FileInputStream?或者我如何有效地搜索输入流?

My issue is in how to do seeking back and forth on an InputStream using ContentResolver

这并不总是可能的。这取决于 ContentProvider 如何提供 InputStream 内容。如果它使用由文件支持的 ParcelFileDescriptor,则流将是可搜索的。如果它使用由 createPipe() 创建的管道支持的 ParcelFileDescriptor,则该流将不可搜索。我没有在 ParcelFileDescriptor 上测试一些较新的管道选项,但我希望它们也不可搜索。

but with large video files, skip and mark/reset will not work for seeking in our player

我希望这些方法适用于某些(但不是全部)content:// Uri 值。如果你说你需要 skip()mark()reset() 以外的东西,那么我不太确定你的意思。

a FileInputStream works great and as a hack I cast the resolver.getInputStream to a FileInputStream and it played ball

它肯定不会可靠 "play ball"。此外,这似乎没有用,因为我没有看到任何与您的场景相关的方法 on FileInputStream that are not inherited from InputStream。值得注意的是,mark()reset()skip()InputStream.

how do I get a File object or FileInputStream from content uri?

你不知道。例如,视频文件可能位于可移动存储上,而在 Android 4.4+ 上,您无法直接访问可移动存储上的文件。

how can i effectively seek on an input stream?

如果 markSupported() returns 为真,则使用 mark()reset()。如果不是,请告诉用户您不能播放该流,或禁用需要搜索的选项,或对您从流中读取的数据进行自己的缓存(例如,用于倒带操作)。

因此,虽然内容 URI 可能不受文件支持,但可以确定它是否...您可以使用 ParcelFileDescriptor 中的 getStatSize,它将 return 如果支持资产是文件,则为一个值,否则为 -1。如果是文件,那么显然可以得到一个FileInputStream和底层的channel