Search code examples
androidandroid-mediaplayerm3u8

How to play local m3u8 files?


My task is to download some part of HLS stream from server and play it locally in android app.

I've download required .ts chunks and formed playlist:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:1
#EXTINF:10.000000,
/storage/emulated/0/Android/data/com.example.myapp/files/savedMovies/chunk0.ts
#EXTINF:10.000000,
/storage/emulated/0/Android/data/com.example.myapp/files/savedMovies/chunk1.ts
#EXTINF:10.000000,
/storage/emulated/0/Android/data/com.example.myapp/files/savedMovies/chunk2.ts
#EXTINF:10.000000,
/storage/emulated/0/Android/data/com.example.myapp/files/savedMovies/chunk3.ts
#EXT-X-ENDLIST

Next, I've passed the link to playlist to android.media.MediaPlayer instance:

String fileLink = "/storage/emulated/0/Android/data/com.example.myapp/files/savedMovies/savedPlaylist.ts";
mediaPlayer.setDataSource(fileLink);

As result I've received such exception:

W/System.err: java.io.IOException: Prepare failed.: status=0x1    
W/System.err:     at android.media.MediaPlayer._prepare(Native Method)    
W/System.err:     at android.media.MediaPlayer.prepare(MediaPlayer.java:1408)    
W/System.err:     at com.example.myapp.MainActivity.surfaceCreated(MainActivity.java:305)    
W/System.err:     at android.view.SurfaceView.updateWindow(SurfaceView.java:656)    
W/System.err:     at android.view.SurfaceView$3.onPreDraw(SurfaceView.java:172)    
W/System.err:     at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:1013)    
W/System.err:     at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2542)    
W/System.err:     at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1537)    
W/System.err:     at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7183)    
W/System.err:     at android.view.Choreographer$CallbackRecord.run(Choreographer.java:959)    
W/System.err:     at android.view.Choreographer.doCallbacks(Choreographer.java:734)    
W/System.err:     at android.view.Choreographer.doFrame(Choreographer.java:670)    
W/System.err:     at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:945)    
W/System.err:     at android.os.Handler.handleCallback(Handler.java:751)    
W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:95)    
W/System.err:     at android.os.Looper.loop(Looper.java:154)    
W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:6776)    
W/System.err:     at java.lang.reflect.Method.invoke(Native Method)    
W/System.err:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1518)    
W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1408) 

The same thing is happening if I pass to player file's path with original server's playlist saved locally (with http links to chunks)

I've tried to play local file in VLC player:

intent.setDataAndType(Uri.parse(fileUrl), "video/m3u8");

But causes an error too (both with local and http links)

Can anyone help me with this?

I've already checked permissions:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

My code:

private void playVideo(String fileUrl) {
    surfaceView.setVisibility(View.VISIBLE);

    this.fileUrl = fileUrl;

    holder = surfaceView.getHolder();
    holder.addCallback(this);
}

@Override
public void onPrepared(MediaPlayer player) {
    mediaPlayer.start();
}


@Override
public void surfaceCreated(SurfaceHolder holder) {
    try {
        mediaPlayer = new MediaPlayer();

        File file = new File(fileUrl);
        FileInputStream inputStream = new FileInputStream(file);
        mediaPlayer.reset();
        mediaPlayer.setDataSource(inputStream.getFD());
        inputStream.close();

        mediaPlayer.setDisplay(holder);

        mediaPlayer.prepare();

        mediaPlayer.setOnErrorListener(this);
        mediaPlayer.setOnBufferingUpdateListener(this);
        mediaPlayer.setOnCompletionListener(this);
        mediaPlayer.setOnPreparedListener(this);
        mediaPlayer.setOnVideoSizeChangedListener(this);
        mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
    } catch (IOException e) {
        e.printStackTrace();
    }
}


@Override
public void onPrepared(MediaPlayer player) {
    mediaPlayer.start();
}

Solution

  • As I understand MediaPlayer is unable to play local m3u8 files.

    I used ExoPlayer instead, works well now