Exoplayer播放m3u8文件Android

20
尝试使用Videoview和Mediaplayer播放m3u8文件多次后,我决定放弃。每次我播放m3u8文件时,我只听到声音。(请不要写Stack Overflow的URL回答我的问题。我已经阅读过它们了。)
询问了许多人,最后得知Exoplayer可能是我在寻找的东西。然而,Exoplayer似乎是一个新手,我找不到任何适当的教程。话虽如此,我自己也是新手,所有关于跟踪器和啦啦啦的谈话对我来说都太复杂了。我只想能够在我的应用程序中打开来自不同URL的所有m3u8文件,而不需要将它们传递给VLC或任何外部意图。
值得一提的是,我使用的是KitKat及以上版本。所以Exoplayer应该是可实现的。
因此,我迫切需要一个简单的教程,以便我可以使用Exoplayer播放我的m3u8文件,或者任何其他方式,显示视频并播放音频,而不仅仅是其中之一。请不要将我链接到Google Dev上的Exoplayer页面。我也去过那里了。
提前感谢 :)

有人吗?能帮忙一下吗?我会非常感激的。 - Payam30
7个回答

7

在Android 4.1+版本中,您可以使用这个库 https://github.com/brianwernick/ExoMedia/。阅读页面上提到的示例应该足以让您开始使用。我已经复制了那段代码,并进行了一些添加/修改。

            private void setupVideoView() {
                EMVideoView emVideoView = (EMVideoView)findViewById(R.id.video_play_activity_video_view);
                emVideoView.setOnPreparedListener(this);

                //Enter your m3u8 URL below
                emVideoView.setVideoURI(Uri.parse("http://SOMESERVER/playlist.m3u8"));
            }

            @Override
            public void onPrepared(MediaPlayer mp) {
                //Starts the video playback as soon as it is ready
                emVideoView.start();
            }

            @Override
            public void onPause() {
                super.onPause();
                //Pause Video Playback
                emVideoView.pause();
            }

4
我创建了一个演示应用程序来播放m3u8媒体文件。
首先,将Gradle依赖项添加到您的文件中。
compile 'com.google.android.exoplayer:exoplayer:r2.4.0'

创建一个简单的布局文件,以存储master.m3u8路径为输入,并使用SimpleExoPlayerView视图播放已下载的文件。
 <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout mlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="match_parent" android:layout_height="match_parent">

<android.support.design.widget.TextInputEditText
  android:layout_marginTop="15dp"
android:layout_width="match_parent"
   android:id="@+id/mediaPath"
   android:layout_height="56dp" />
   <android.support.v7.widget.AppCompatButton
android:id="@+id/play"
       android:layout_marginLeft="50dp"
android:layout_marginRight="50dp"
       android:layout_below="@+id/mediaPath"
       android:background="@color/colorAccent"
android:layout_width="match_parent"
android:text="Play"
android:layout_height="56dp" />
<com.google.android.exoplayer2.ui.SimpleExoPlayerView
   android:layout_below="@+id/play"
   android:id="@+id/video_view"
   android:layout_marginTop="5dp"
   android:layout_width="match_parent"
   android:layout_height="match_parent"/>
</RelativeLayout>

创建一个简单的ExoPlayer Activity来播放文件。
public class ExoPlayer  extends AppCompatActivity{
Context mContext;
SimpleExoPlayerView playerView;
EditText editText;
private ComponentListener componentListener;
private DataSource.Factory mediaDataSourceFactory;
private Handler mainHandler;
private DefaultTrackSelector trackSelector;
SimpleExoPlayer player;
private static final DefaultBandwidthMeter BANDWIDTH_METER = new        DefaultBandwidthMeter();




@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_exoplayer);
   mContext =this;
   editText = (EditText) findViewById(R.id.mediaPath);
   Button btnPlay = (Button) findViewById(R.id.play);
   playerView  = (SimpleExoPlayerView)findViewById(R.id.video_view);
   mediaDataSourceFactory = buildDataSourceFactory(true);
   mainHandler = new Handler();
   componentListener = new ComponentListener();
   trackSelector = new DefaultTrackSelector();
   btnPlay.setOnClickListener(new View.OnClickListener() {
       @Override
       public void onClick(View view) {
      if(editText.getText()!=null && editText.getText().length()>0){
               initializePlayer(editText.getText().toString());
           }
       }
   });
}
   private DataSource.Factory buildDataSourceFactory(boolean useBandwidthMeter) {
   return ((AnalyticsApplication) getApplication())
           .buildDataSourceFactory(useBandwidthMeter ? BANDWIDTH_METER : null);
 }

   private void initializePlayer(String path) {
   player = ExoPlayerFactory.newSimpleInstance(mContext, trackSelector);
   player.addListener(componentListener);
//        String path = file:///storage/emulated/0/SugarBox/master.m3u8";
   Uri uri = Uri.parse(path);
   MediaSource mediaSource = buildMediaSource(uri);
   player.prepare(mediaSource, true, false);
   playerView.setPlayer(player);
 }
  private MediaSource buildMediaSource(Uri uri) {
 return new HlsMediaSource(uri, mediaDataSourceFactory, mainHandler, null);
 }
 private void releasePlayer() {
   if (player != null) {
       player.removeListener(componentListener);
       player.release();
       player = null;
   }
   }



 @Override
 public void onStart() {
   super.onStart();
   if (Util.SDK_INT > 23) {
       if(editText.getText()!=null && editText.getText().length()>0){
           initializePlayer(editText.getText().toString());
       }
   }
 }




@Override
   public void onResume() {
   super.onResume();
   if ((Util.SDK_INT <= 23 || player == null)) {
       if(editText.getText()!=null && editText.getText().length()>0){
           initializePlayer(editText.getText().toString());
       }
   }
 }



@Override
 public void onPause() {
   super.onPause();
   if (Util.SDK_INT <= 23) {
       releasePlayer();
   }
}



 @Override
public void onStop() {
   super.onStop();
   if (Util.SDK_INT > 23) {
       releasePlayer();
   }
}







   private class ComponentListener implements com.google.android.exoplayer2.ExoPlayer.EventListener{

   @Override
   public void onPlayerStateChanged(boolean playWhenReady,
                                    int playbackState) {
       String stateString;
       switch (playbackState) {
           case com.google.android.exoplayer2.ExoPlayer.STATE_IDLE:
               stateString = "ExoPlayer.STATE_IDLE      -";
               break;
           case com.google.android.exoplayer2.ExoPlayer.STATE_BUFFERING:
               stateString = "ExoPlayer.STATE_BUFFERING -";
               break;
           case com.google.android.exoplayer2.ExoPlayer.STATE_READY:
               stateString = "ExoPlayer.STATE_READY     -";
               break;
           case com.google.android.exoplayer2.ExoPlayer.STATE_ENDED:
               stateString = "ExoPlayer.STATE_ENDED     -";
               break;
           default:
               stateString = "UNKNOWN_STATE             -";
               break;
       }
       Log.d("ExopLayer", "changed state to " + stateString
               + " playWhenReady: " + playWhenReady);
   }

   @Override
   public void onTimelineChanged(Timeline timeline, Object manifest) {}
   @Override
   public void onTracksChanged(TrackGroupArray trackGroups,
                               TrackSelectionArray trackSelections) {}
   @Override
   public void onLoadingChanged(boolean isLoading) {}
   @Override
   public void onPlayerError(ExoPlaybackException error) {}
   @Override
   public void onPositionDiscontinuity() {}
   @Override
   public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {}
  }



private DrmSessionManager<FrameworkMediaCrypto> buildDrmSessionManager(UUID uuid,   String licenseUrl, String[] keyRequestPropertiesArray) throws UnsupportedDrmException {
   if (Util.SDK_INT < 18) {
       return null;
   }
   HttpMediaDrmCallback drmCallback = new HttpMediaDrmCallback(licenseUrl,
           buildHttpDataSourceFactory(false));
   if (keyRequestPropertiesArray != null) {
       for (int i = 0; i < keyRequestPropertiesArray.length - 1; i += 2) {
           drmCallback.setKeyRequestProperty(keyRequestPropertiesArray[i],
                   keyRequestPropertiesArray[i + 1]);
       }
   }
   return new DefaultDrmSessionManager<>(uuid,
           FrameworkMediaDrm.newInstance(uuid), drmCallback, null, mainHandler, null);
 }




  private HttpDataSource.Factory buildHttpDataSourceFactory(boolean useBandwidthMeter) {
   return ((AnalyticsApplication) getApplication())
           .buildHttpDataSourceFactory(useBandwidthMeter ? BANDWIDTH_METER : null);


  }


}

我尝试了这段代码,但它只适用于m3u8文件类型,对吗? 我尝试了以下mp4文件,但没有任何反应:https://www.w3schools.com/html/mov_bbb.mp4我不知道如何理解AnalyticsApplication是什么? 在: return ((AnalyticsApplication) getApplication ())             .buildHttpDataSourceFactory (useBandwidthMeter? BANDWIDTH_METER: null); - Paul

1

我已经使用以下代码处理过m3u8

    videoView = findViewById(R.id.videoViewXml);

    final ProgressDialog progressDialog = new ProgressDialog(VideoActivity.this);
    progressDialog.setMessage("Please Wait");
    progressDialog.setCancelable(false);
    progressDialog.show();

    MediaController mediaController = new MediaController(this);
    mediaController.setAnchorView(videoView);
    videoView.setMediaController(mediaController);

    videoView.setVideoURI(Uri.parse(VIDEO_PATH));
    videoView.start();

    videoView.setOnPreparedListener(new OnPreparedListener() {
        @Override
        public void onPrepared(MediaPlayer mp) {
            progressDialog.dismiss();
        }
    });

1
这是使用ExoPlayer库流式传输m3u8文件的最简单方法,希望能帮到您 https://github.com/karim23/SimpleStreamPlayer/tree/master
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    context = getApplicationContext();
    setContentView(R.layout.activity_main);
    //change the live streaming URL with yours. 
    contentUri = "http://abclive.abcnews.com/i/abc_live4@136330/index_1200_av-b.m3u8?sd=10&b=1200&rebase=on";
    // contentType = DemoUtil.TYPE_HLS;
    final Intent intent = new Intent(context, VideoPlayerActivity.class).setData(Uri.parse(contentUri))
            .putExtra(VideoPlayerActivity.CONTENT_ID_EXTRA, -1)
            //Change the type according to the live streaming extension.
            .putExtra(VideoPlayerActivity.CONTENT_TYPE_EXTRA, DemoUtil.TYPE_HLS);
    liveStreamingTv =(TextView)findViewById(R.id.mainActivity_liveStreamingTv);
    liveStreamingTv.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            startActivity(intent);
        }
    });
}

0
DataSource.Factory fdataSourceFactory = new FileDataSource.Factory();
DataSource.Factory ddataSourceFactory = new DefaultHttpDataSource.Factory();
if (urlAll.startsWith("http") ) {
  // Create a HLS media source pointing to a playlist uri.
  MediaSource hlsMediaSource = new HlsMediaSource.Factory(ddataSourceFactory)
                                    .setAllowChunklessPreparation(false)
                                    .createMediaSource(mediaItem);
  player.addMediaSource(index, hlsMediaSource);
}
else {
  // Create a HLS media source pointing to a playlist uri.
  MediaSource hlsMediaSource = new HlsMediaSource.Factory(fdataSourceFactory)
                                    .setAllowChunklessPreparation(false)
                                    .createMediaSource(mediaItem);
  player.addMediaSource(index, hlsMediaSource);
}

你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便其他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community

0

目前没有关于ExoPlayer的教程。 ExoPlayerMediaPlayer的最佳替代品,但目前对新手不太友好。

你需要做的是去github页面,查看demo应用程序中的DemoPlayer类。

此应用程序可以打开许多不同格式,包括hls


1
我该如何使用演示?我需要将代码复制到我的应用程序中吗? - Payam30

0
解决播放m3u8文件时出现黑屏问题,我使用以下方法解决了它:

implementation 'com.google.android.exoplayer:exoplayer:2.13.3'

媒体源代码:
    private fun buildMediaSource(uri: Uri): MediaSource {
    
            val userAgent = "exoplayer-codelab"
    
            return if (uri.lastPathSegment!!.contains("mp3") || uri.lastPathSegment!!.contains("mp4")) {
                ExtractorMediaSource.Factory(DefaultHttpDataSourceFactory(userAgent))
                    .createMediaSource(uri)
            } else {
                HlsMediaSource.Factory(DefaultHttpDataSourceFactory(userAgent))
                    .createMediaSource(uri)
            }
}

媒体源:

 val mediaSource = buildMediaSource(Uri.parse(stories[counter].mediaUrl))
 simpleExoPlayer.prepare(mediaSource, false, false)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接