当前位置:   article > 正文

[Android多媒体技术] 播放Raw/Assets音视频方法总结

音频raw文件怎么打开

前言

本文介绍如何通过系统MediaPlayerIjkPlayerExoPlayer分别播放安卓项目下的Raw或Assets文件夹中的音视频文件。

在某些情况下,我们会把一些音视频文件,如Mp3,Mp4等,直接放在安装包中的Raw或者Assets文件夹里,这些音视频文件可能作为特定场景的提示音,或者视频片头等等。关于Raw和Assets资源文件,这里不作过多讨论,总的来讲,他们都是被打包进APK中的文件,不会被编译成二进制,程序可以直接访问,无需额外的权限。

先说明一下本文代码的构建环境和使用的播放内核版本:

  • Java 1.7
  • Android Studio 3.1.2
  • Gradle 4.4
  • IjkPlayer 0.8.8
  • ExoPlayer 2.8.3

效果演示

Raw/Assets资源文件访问方式

在项目文件夹中的位置:

Raw文件访问方式

  • Raw文件位于res/raw目录下,Raw文件会被映射到R.java文件中,所以访问的时候直接使用资源ID即可,如
  1. R.raw.raw_video
  2. 复制代码

或者获得该文件的AssetFileDescriptor:

  1. AssetFileDescriptor afd = getResources().openRawResourceFd(R.raw.raw_video);
  2. 复制代码

Assets文件访问方式

  • Assets文件夹下的文件不会被映射到R.java中,访问的时候需要AssetManager类。
  1. AssetManager am = getAssets();
  2. try {
  3. AssetFileDescriptor afd= am.openFd(fileName);
  4. } catch (IOException e) {
  5. e.printStackTrace();
  6. }
  7. 复制代码

AssetFileDescriptor可以理解成访问Raw/Assets文件的一个入口,或者说是一把钥匙。

Raw/Assets文件还有其他的访问方式,比如通过ContentResolver,又或者直接开启一个InputStream去读取文件,这应该是播放器内核需要做的事情,我们只需要给播放器提供以上的信息即可。

········································································································· 下面直接上代码

通过系统MediaPlayer播放音视频

  • Raw文件
  1. //实例化播放内核
  2. android.media.MediaPlayer mediaPlayer = new android.media.MediaPlayer();
  3. //获得播放源访问入口
  4. AssetFileDescriptor afd = getResources().openRawResourceFd(R.raw.raw_video); // 注意这里的区别
  5. //给MediaPlayer设置播放源
  6. mediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
  7. //设置准备就绪状态监听
  8. mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
  9. @Override
  10. public void onPrepared(MediaPlayer mp) {
  11. // 开始播放
  12. mediaPlayer.start();
  13. }
  14. });
  15. //准备播放
  16. mediaPlayer.prepareAsync();
  17. 复制代码
  • Assets 文件
  1. //实例化播放内核
  2. android.media.MediaPlayer mediaPlayer = new android.media.MediaPlayer();
  3. //获得播放源访问入口
  4. AssetManager am = getAssets();
  5. try {
  6. AssetFileDescriptor afd = am.openFd("assets_video.mp4");// 注意这里的区别
  7. //给MediaPlayer设置播放源
  8. mediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
  9. } catch (IOException e) {
  10. e.printStackTrace();
  11. }
  12. //设置准备就绪状态监听
  13. mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
  14. @Override
  15. public void onPrepared(MediaPlayer mp) {
  16. // 开始播放
  17. mediaPlayer.start();
  18. }
  19. });
  20. //准备播放
  21. mediaPlayer.prepareAsync();
  22. 复制代码

代码中每一步都有注释,可以说非常详细了。简单总结一下,无论播放Raw文件还是Assets文件,我们首先获得AssetFileDescriptor,然后设置给MediaPlayer。

·········································································································

通过IjkPlayer播放音视频

  • Raw 文件
  1. //实例化播放内核
  2. tv.danmaku.ijk.media.player.IjkMediaPlayer ijkPlayer = new tv.danmaku.ijk.media.player.IjkMediaPlayer();
  3. //获得播放源访问入口
  4. AssetFileDescriptor afd = getResources().openRawResourceFd(R.raw.raw_video); // 注意这里的区别
  5. //构建IjkPlayer能识别的IMediaDataSource,下面的RawDataSourceProvider实现了IMediaDataSource接口
  6. RawDataSourceProvider sourceProvider = new RawDataSourceProvider(fd);
  7. //给IjkPlayer设置播放源
  8. ijkPlayer.setDataSource(sourceProvider);
  9. //设置准备就绪状态监听
  10. ijkPlayer .setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
  11. @Override
  12. public void onPrepared(MediaPlayer mp) {
  13. // 开始播放
  14. ijkPlayer.start();
  15. }
  16. });
  17. //准备播放
  18. ijkPlayer.prepareAsync();
  19. 复制代码
  • Assets 文件
  1. //实例化播放内核
  2. tv.danmaku.ijk.media.player.IjkMediaPlayer ijkPlayer = new tv.danmaku.ijk.media.player.IjkMediaPlayer();
  3. //获得播放源访问入口
  4. AssetManager am = getAssets();
  5. try {
  6. AssetFileDescriptor afd = am.openFd("assets_video.mp4");// 注意这里的区别
  7. //构建IjkPlayer能识别的IMediaDataSource,下面的RawDataSourceProvider实现了IMediaDataSource接口
  8. RawDataSourceProvider sourceProvider = new RawDataSourceProvider(fd);
  9. //给IjkPlayer设置播放源
  10. ijkPlayer.setDataSource(sourceProvider);
  11. } catch (IOException e) {
  12. e.printStackTrace();
  13. }
  14. //设置准备就绪状态监听
  15. ijkPlayer .setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
  16. @Override
  17. public void onPrepared(MediaPlayer mp) {
  18. // 开始播放
  19. ijkPlayer.start();
  20. }
  21. });
  22. //准备播放
  23. ijkPlayer.prepareAsync();
  24. 复制代码

补充下,其中的RawDataSourceProvider实现了IMediaDataSource 接口,IMediaDataSourceIjkPlayer包中的接口,实现了IMediaDataSource接口的类可以设置给IjkPlayer作为播放源。就像下面这样:

  1. import tv.danmaku.ijk.media.player.misc.IMediaDataSource;
  2. public class RawDataSourceProvider implements IMediaDataSource {
  3. private AssetFileDescriptor mDescriptor;
  4. private byte[] mMediaBytes;
  5. public RawDataSourceProvider(AssetFileDescriptor descriptor) {
  6. this.mDescriptor = descriptor;
  7. }
  8. @Override
  9. public int readAt(long position, byte[] buffer, int offset, int size) {
  10. if (position + 1 >= mMediaBytes.length) {
  11. return -1;
  12. }
  13. int length;
  14. if (position + size < mMediaBytes.length) {
  15. length = size;
  16. } else {
  17. length = (int) (mMediaBytes.length - position);
  18. if (length > buffer.length)
  19. length = buffer.length;
  20. length--;
  21. }
  22. // 把文件内容copy到buffer中;
  23. System.arraycopy(mMediaBytes, (int) position, buffer, offset, length);
  24. return length;
  25. }
  26. @Override
  27. public long getSize() throws IOException {
  28. long length = mDescriptor.getLength();
  29. if (mMediaBytes == null) {
  30. InputStream inputStream = mDescriptor.createInputStream();
  31. mMediaBytes = readBytes(inputStream);
  32. }
  33. return length;
  34. }
  35. @Override
  36. public void close() throws IOException {
  37. if (mDescriptor != null)
  38. mDescriptor.close();
  39. mDescriptor = null;
  40. mMediaBytes = null;
  41. }
  42. //读取文件内容
  43. private byte[] readBytes(InputStream inputStream) throws IOException {
  44. ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
  45. int bufferSize = 1024;
  46. byte[] buffer = new byte[bufferSize];
  47. int len;
  48. while ((len = inputStream.read(buffer)) != -1) {
  49. byteBuffer.write(buffer, 0, len);
  50. }
  51. return byteBuffer.toByteArray();
  52. }
  53. }
  54. 复制代码

小结一下,我们首先获取到Raw/Assets文件的AssetFileDescriptor,然后用它去构建一个IMediaDataSource,最后设置给IjkPlayer

·········································································································

通过ExoPlayer播放音视频

  • ExoPlayer播放器内核的实例化有点复杂,这里单独写
  1. //实例化播放内核
  2. TrackSelection.Factory videoTrackSelectionFactory =
  3. new AdaptiveTrackSelection.Factory(new DefaultBandwidthMeter());
  4. DefaultTrackSelector mTrackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
  5. boolean preferExtensionDecoders = true;
  6. boolean useExtensionRenderers = true;//是否开启扩展
  7. @DefaultRenderersFactory.ExtensionRendererMode int extensionRendererMode = useExtensionRenderers
  8. ? (preferExtensionDecoders ? DefaultRenderersFactory.EXTENSION_RENDERER_MODE_PREFER
  9. : DefaultRenderersFactory.EXTENSION_RENDERER_MODE_ON)
  10. : DefaultRenderersFactory.EXTENSION_RENDERER_MODE_OFF;
  11. DefaultRenderersFactory rendererFactory = new DefaultRenderersFactory(mAppContext, extensionRendererMode);
  12. DefaultLoadControl loadControl = new DefaultLoadControl();
  13. //工厂方法获得播放器实例
  14. om.google.android.exoplayer2.SimpleExoPlayer exoPlayer =
  15. ExoPlayerFactory.newSimpleInstance(rendererFactory, mTrackSelector, loadControl, null);
  16. 复制代码
  • Raw 文件
  1. //构建Raw文件播放源--RawResourceDataSource
  2. DataSpec dataSpec = new DataSpec(RawResourceDataSource.buildRawResourceUri(R.raw.raw_video));
  3. RawResourceDataSource rawResourceDataSource = new RawResourceDataSource(this);
  4. try {
  5. rawResourceDataSource.open(dataSpec);
  6. } catch (RawResourceDataSource.RawResourceDataSourceException e) {
  7. e.printStackTrace();
  8. }
  9. //构建ExoPlayer能识别的播放源--MediaSource
  10. String url = rawDataSource.getUri().toString();
  11. MediaSource mediaSource = ExoSourceManager.newInstance(mAppContext, getHeaders()).getMediaSource(
  12. url, false, false, MediaPlayerManager.instance().isLooping(), null
  13. );
  14. //给ExoPlayer设置播放源,并准备播放
  15. exoPlayer.prepare(mediaSource);
  16. //让ExoPlayer准备好后就开始播放
  17. exoPlayer.setPlayWhenReady(true);
  18. 复制代码
  • Assets 文件
  1. //构建ExoPlayer能识别的播放源--MediaSource
  2. String url = "file:///android_asset/" + "assets_video.mp4";
  3. MediaSource mediaSource = ExoSourceManager.newInstance(mAppContext, getHeaders()).getMediaSource(
  4. url, false, false, MediaPlayerManager.instance().isLooping(), null
  5. );
  6. //给ExoPlayer设置播放源,并准备播放
  7. exoPlayer.prepare(mediaSource);
  8. //让ExoPlayer准备好后就开始播放
  9. exoPlayer.setPlayWhenReady(true);
  10. 复制代码

小结:ExoPlayer实例化的时候复杂一点,需要按照官方文档一步步来。播放Raw文件的时候,需要先构建出RawResourceDataSource,这是ExoPlayer为了播放Raw音视频文件提供的类,然后获取其中的Uri构建MediaSource,最后设置给ExoPlayer。播放Assets文件就更简单了,形如String url = "file:///android_asset/" + "filename"的Assets文件播放地址可以直接用来构建MediaSource

项目地址:github.com/maiwenchang… 欢迎各位Star~~

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/299296
推荐阅读
相关标签
  

闽ICP备14008679号