3

I have a video player app that plays custom h264 transport streams. I was tasked with being able to launch our player from methods such as the user opening "gallery", selecting "movies" and after selecting a movie picking our app to launch...this all works perfectly. My issue is in how to do seeking back and forth on an InputStream using ContentResolver.

I've read many many posts here as well, such as 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 about using InputStream over other methods, but with large video files, skip and mark/reset will not work for seeking in our player, so a plain InputStream is kind of useless...a FileInputStream works great and as a hack I cast the resolver.getInputStream to a FileInputStream and it played ball, but that's a hack...so....how do I get a File object or FileInputStream from content uri? or how can i effectively seek on an input stream?

Community
  • 1
  • 1
PapaWhiskey
  • 117
  • 1
  • 13
  • not sure why this is being downvoted? with the android 4.4 the path from uri methods apparently dont work reliably anymore and with android 5.0 you're more likely to get a content type so it's a good relevant question...if you're going to downvote, want to let me know why? – PapaWhiskey Jan 30 '15 at 22:50

2 Answers2

3

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

That's not always going to be possible. It depends upon how the ContentProvider is supplying the InputStream contents. If it uses a ParcelFileDescriptor backed by a file, the stream will be seekable. If it uses a ParcelFileDescriptor backed by a pipe created by createPipe(), the stream will not be seekable. I have not tested some of the newer pipe options on ParcelFileDescriptor, but I would expect them to be non-seekable as well.

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

I would expect those method to work for some, but not all, content:// Uri values. If you are saying that you need something other than skip(), mark(), and reset(), then I am not quite certain what you mean.

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

It certainly will not reliably "play ball". Moreover, that would appear to be useless, as I do not see any methods relevant to your scenario that are on FileInputStream that are not inherited from InputStream. Notably, mark(), reset(), and skip() are on InputStream.

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

You don't. For example, the video file may be on removable storage, and on Android 4.4+, you have no direct access to files on removable storage.

how can i effectively seek on an input stream?

If markSupported() returns true, use mark() and reset(). If not, tell the user that you cannot play that stream, or disable options that require seeking, or do your own caching (e.g., for rewind operations) of the data you read from the stream.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • 1. if i use BufferedInputStream the docs say i'm guaranteed to have support for mark/reset...however if the file is large (as video files tend to be), you can't "go back" after you've streamed (or skipped) forward a lot (or at least it hasnt worked for me). 2. FileInputStream allows me to get the underlying channel and set the position, so it works perfectly to go back and forth anywhere in the file as the user scrubs the video. 3. How does the internal media player seek in 4.4? It's obviously doable, i just can't find the methods (hence the q) 4. the hack was a test, and a hack – PapaWhiskey Feb 02 '15 at 15:28
  • @PapaWhiskey: "you can't "go back" after you've streamed (or skipped) forward a lot (or at least it hasnt worked for me)" -- that should depend upon the underlying data source. "How does the internal media player seek in 4.4?" -- if by "internal" you mean "pre-installed", pre-installed apps can access files even on removable storage, if the manufacturer sets them up that way. And, pre-installed apps can know the internal workings of `MediaStore` and can make more assumptions than can SDK apps distributed to arbitrary devices. – CommonsWare Feb 02 '15 at 15:37
  • @PapaWhiskey: To achieve what you want, you probably *do* need file access. You just don't have a reliable way of getting at files, particularly those on removable media on Android 4.4+. – CommonsWare Feb 02 '15 at 15:38
  • thanks...i was hoping for a different answer, but having read a lot of posts (you're usually on them), I felt I was not going to get what i wanted, but had to ask...looks like your "cache" suggestion might be the route i have to take – PapaWhiskey Feb 02 '15 at 16:32
3

So while it is possible that a content URI might not be backed by a File, it is possible to determine if it is...You can use getStatSize from ParcelFileDescriptor and it will return a value if the backing asset is a file, -1 if not. If it is a file, then obviously you can get a FileInputStream and the underlying channel

PapaWhiskey
  • 117
  • 1
  • 13