使用ExoPlayer播放res/raw中音频资源

来源:互联网 发布:安卓6.0源码下载 编辑:程序博客网 时间:2024/05/29 19:48

前言

关于ExoPlayer的使用,很多前人已经帮我们翻译了官方文档,例如ExoPlayer使用,这里不再阐述。
但是上述文章一般就是将官方文档翻译一下,针对具体的使用,可能会遇到很多难以解决问题。

正文

某天,我想用ExoPlayer播放一段存放在res/raw文件夹下的ogg格式的音频,在之前代码中,使用Mediaplayer播放,一切正常。
但是,有了高逼格的ExoPlayer,肯定要放弃Mediaplayer啊,毕竟程序员都是喜新厌旧的嘛(手动滑稽)。所以,那就根据官方API开整,这里就放核心代码

        DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();        TrackSelection.Factory selectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);        TrackSelector trackSelector = new DefaultTrackSelector(selectionFactory);        currentPlayer = ExoPlayerFactory.newSimpleInstance(this.context, trackSelector);        DataSource.Factory dataSourceFactory = buildDataSourceFactory(this.context, bandwidthMeter);        ExtractorMediaSource mediaSource = new ExtractorMediaSource(FmManager.getUriById(context, resId),                dataSourceFactory, new DefaultExtractorsFactory(), null, null);        LoopingMediaSource loopingMediaSource = new LoopingMediaSource(mediaSource);  //循环播放        currentPlayer.prepare(loopingMediaSource);        currentPlayer.addListener(this);        currentPlayer.setPlayWhenReady(true);      private DataSource.Factory buildDataSourceFactory(Context context, DefaultBandwidthMeter bandwidthMeter) {        return new DefaultDataSourceFactory(context,                Util.getUserAgent(context, context.getString(R.string.app_name)), bandwidthMeter);    }    //根据raw资源ID获取URI    public static Uri getUriById(Context context, int rawId) {        String basePath = "android.resource://";        StringBuilder stringBuilder = new StringBuilder(basePath);        String uriStr = stringBuilder.append(context.getPackageName()).append("/").append(rawId).toString();        return Uri.parse(uriStr);    }

代码基本是根据官方Demo提供的,一运行,哎哟,报错了:

com.google.android.exoplayer.upstream.HttpDataSource$HttpDataSourceException: Unable to connect to android.resource://

纳尼?报资源找不到,可是获取Uri的方法没错啊,打开Chrome,上Google,不搜不要紧,一搜好多人都遇到这个问题,看来代码没写错,那就一个个帖子找吧。
找来找去,大家的解决办法竟然是将raw中音频资源放到assets目录下,这真是没办法的办法,但是转念一想,Google不至于这么坑爹吧,难道放在raw中的资源就无法使用了么?
打开官方文档(http://google.github.io/ExoPlayer/doc/reference/)

看构造函数名字

这里肯定是和raw资源有关,继续往下看

Paste_Image.png

1.使用buildRawResourceUri(int rawResourceId)传入资源ID,得到Uri

public static Uri buildRawResourceUri(int rawResourceId)Builds a Uri for the specified raw resource identifier.

2.使用DataSpec(Uri uri),得到DataSpec对象,

DataSpec(Uri uri)Construct a DataSpec for the given uri and with key set to null.

3.创建RawResourceDataSource对象,最后使用 open(DataSpec dataSpec)打开之前的DataSpec对象

public long open(DataSpec dataSpec)          throws RawResourceDataSource.RawResourceDataSourceExceptionDescription copied from interface: DataSourceOpens the source to read the specified data. 

4.使用RawResourceDataSource的getUri();得到Uri

public Uri getUri()Description copied from interface: DataSourceWhen the source is open, returns the Uri from which data is being read. The returned Uri will be identical to the one passed DataSource.open(DataSpec) in the DataSpec unless redirection has occurred. If redirection has occurred, the Uri after redirection is returned.

那就修改根据资源ID获取Uri的方法,完整代码如下:

        DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();        TrackSelection.Factory selectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);        TrackSelector trackSelector = new DefaultTrackSelector(selectionFactory);        currentPlayer = ExoPlayerFactory.newSimpleInstance(this.context, trackSelector);        try {            DataSpec dataSpec = new DataSpec(RawResourceDataSource.buildRawResourceUri(this.resId));            RawResourceDataSource rawResourceDataSource = new RawResourceDataSource(context);            rawResourceDataSource.open(dataSpec);            DataSource.Factory factory = () -> rawResourceDataSource;            ExtractorMediaSource mediaSource = new ExtractorMediaSource(rawResourceDataSource.getUri(),                    factory, new DefaultExtractorsFactory(), null, null);            LoopingMediaSource loopingMediaSource = new LoopingMediaSource(mediaSource);            currentPlayer.prepare(loopingMediaSource);            currentPlayer.addListener(this);            currentPlayer.setPlayWhenReady(true);        } catch (RawResourceDataSource.RawResourceDataSourceException e) {            e.printStackTrace();        }

重新编译运行,ok,顺利播放,看来还是官方靠谱


总结

针对ExoPlayer播放raw中资源,不同于Mediaplayer方式,需要通过下列代码获取Uri,才能成功

            DataSpec dataSpec = new DataSpec(RawResourceDataSource.buildRawResourceUri(this.resId));            RawResourceDataSource rawResourceDataSource = new RawResourceDataSource(context);            rawResourceDataSource.open(dataSpec);            rawResourceDataSource.getUri()
阅读全文
0 0