google / ExoPlayer

This project is deprecated and stale. The latest ExoPlayer code is available in https://github.com/androidx/media
https://developer.android.com/media/media3/exoplayer
Apache License 2.0
21.7k stars 6.02k forks source link

Can't play local file whose path contains '#' #1859

Closed yhd4711499 closed 7 years ago

yhd4711499 commented 7 years ago

Exoplayer failed to play media file with file path containing '#'.

This could be easily reproduced.

dev-v2. rev 846f8e1

Nexus 5X running Android 6.0.1

The media file I was playing was /storage/emulated/0/netease/cloudmusic/Music/Jerry Martin - SIMnata #15.mp3 Stacktrace:

Source error.
com.google.android.exoplayer2.upstream.FileDataSource$FileDataSourceException: java.io.FileNotFoundException: /storage/emulated/0/netease/cloudmusic/Music/Jerry Martin - SIMnata : open failed: ENOENT (No such file or directory)
   at com.google.android.exoplayer2.upstream.FileDataSource.open(FileDataSource.java:72)
   at com.google.android.exoplayer2.upstream.DefaultDataSource.open(DefaultDataSource.java:105)
   at ornithopter.wave.exoplayer.BufferInfoDataSource.open(BufferInfoDataSource.java:29)
   at com.google.android.exoplayer2.source.ExtractorMediaSource$ExtractingLoadable.load(ExtractorMediaSource.java:675)
   at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:296)
   at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:423)
   at java.util.concurrent.FutureTask.run(FutureTask.java:237)
   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
   at java.lang.Thread.run(Thread.java:818)
Caused by: java.io.FileNotFoundException: /storage/emulated/0/netease/cloudmusic/Music/Jerry Martin - SIMnata : open failed: ENOENT (No such file or directory)
   at libcore.io.IoBridge.open(IoBridge.java:452)
   at java.io.RandomAccessFile.<init>(RandomAccessFile.java:117)
   at java.io.RandomAccessFile.<init>(RandomAccessFile.java:149)
   at com.google.android.exoplayer2.upstream.FileDataSource.open(FileDataSource.java:64)
   at com.google.android.exoplayer2.upstream.DefaultDataSource.open(DefaultDataSource.java:105) 
   at ornithopter.wave.exoplayer.BufferInfoDataSource.open(BufferInfoDataSource.java:29) 
   at com.google.android.exoplayer2.source.ExtractorMediaSource$ExtractingLoadable.load(ExtractorMediaSource.java:675) 
   at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:296) 
   at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:423) 
   at java.util.concurrent.FutureTask.run(FutureTask.java:237) 
   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) 
   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) 
   at java.lang.Thread.run(Thread.java:818) 
Caused by: android.system.ErrnoException: open failed: ENOENT (No such file or directory)
   at libcore.io.Posix.open(Native Method)
   at libcore.io.BlockGuardOs.open(BlockGuardOs.java:186)
   at libcore.io.IoBridge.open(IoBridge.java:438)
   at java.io.RandomAccessFile.<init>(RandomAccessFile.java:117) 
   at java.io.RandomAccessFile.<init>(RandomAccessFile.java:149) 
   at com.google.android.exoplayer2.upstream.FileDataSource.open(FileDataSource.java:64) 
   at com.google.android.exoplayer2.upstream.DefaultDataSource.open(DefaultDataSource.java:105) 
   at ornithopter.wave.exoplayer.BufferInfoDataSource.open(BufferInfoDataSource.java:29) 
   at com.google.android.exoplayer2.source.ExtractorMediaSource$ExtractingLoadable.load(ExtractorMediaSource.java:675) 
   at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:296) 
   at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:423) 
   at java.util.concurrent.FutureTask.run(FutureTask.java:237) 
   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) 
   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) 
   at java.lang.Thread.run(Thread.java:818) 
ojw28 commented 7 years ago

I was able to play a file containing a # symbol, but you have to be careful when you construct the Uri that gets passed to ExtractorRendererBuilder because # is a reserved character. See this page for details. The way the demo app works, you can add a sample to Samples.java by percent encoding the # as %23:

/storage/emulated/0/netease/cloudmusic/Music/Jerry Martin - SIMnata %2315.mp3

If you're creating the Uri using your own code, you'll have to come up with an equivalent way to create a valid Uri that points to the file.

yhd4711499 commented 7 years ago

Yes. Building the Uri with encoded file path is the correct way.