MediaPlayer setDataSource,使用路径还是FileDescriptor更好?

22

假设我有一个文件的完整路径,那么将该文件加载到 MediaPlayer 中,哪种方法更好?

String filePath = "somepath/somefile.mp3";
mediaPlayer.setDataSource(filePath);

或者

String filePath = "somepath/somefile.mp3";
File file = new File(filePath);
FileInputStream inputStream = new FileInputStream(file);
mediaPlayer.setDataSource(inputStream.getFD());
inputStream.close();

有关紧要性吗?直接使用路径似乎更容易,但是否有理由做额外的工作来使用FileDescriptor?


FileDescriptor 可以用于从 ContentProvider 或资产文件夹等位置播放内容。 - Jens
从Android 10开始,我们无法访问完整路径。我们只能使用来自MediaStore的Content Uri与FileDescriptor。 - Jashanpreet singh Chakkal
2个回答

33
实际上,在某些情况下确实存在差异。
如果您尝试从getApplicationContext().getFilesDir()加载文件并且文件保存方式有所不同,那么在调用mediaPlayer.prepare()时,mediaPlayer.setDataSource(String path)将失败。例如,如果我使用new RandomAccessFile(filePath, "rw")编写一个文件,则如果您使用mediaPlayer.setDataSource(String path),mediaplayer实际上无法读取该文件。prepare()将立即从mediaplayer触发error(1, -2147483648);这本质上是一个文件权限错误。SDK 9引入了file.setReadable(boolean readable, boolean ownerOnly),这可能允许您通过将ownerOnly设置为false来解决此问题...但如果您需要支持较旧的SDK,则无济于事。
然而,mediaPlayer.setDataSource(FileDescriptor fd)就没有这个问题,可以成功准备完全相同的文件,而不会有权限问题。

1
无论出于何种原因,使用字符串将媒体播放器指向应用程序文件目录中的文件会失败,但使用文件描述符则可以。 - Robert Nekic
相关的是,当从加密的APK扩展文件(.OBB)播放视频时,您需要使用FileDescriptor才能使您的视频在MediaPlayer中播放。 MediaPlayer尝试访问应用程序上下文之外的文件,但它没有正确的权限来读取您的OBB文件。 使用FileDescriptor可以解决此问题。 - Reinier

2

MediaPlayer.java有两种setDataSource()签名,一种接受字符串(路径),另一种接受FD(文件描述符)。 它们最终都进入本地C代码。虽然其中一种可能会稍微更有效,但除非您每秒钟设置数据源超过一次,否则这将是可以忽略的。

/**
 * Sets the data source (file-path or http/rtsp URL) to use. Call this after 
 * reset(), or before any other method (including setDataSource()) that might
 * throw IllegalStateException in this class.
 * 
 * @param path the path of the file, or the http/rtsp URL of the stream you want to play
 * @throws IllegalStateException if it is called
 * in an order other than the one specified above
 */
public native void setDataSource(String path) throws IOException, IllegalArgumentException, IllegalStateException;

/**
 * Sets the data source (FileDescriptor) to use. It is the caller's responsibility
 * to close the file descriptor. It is safe to do so as soon as this call returns.
 * Call this after reset(), or before any other method (including setDataSource()) 
 * that might throw IllegalStateException in this class.
 * 
 * @param fd the FileDescriptor for the file you want to play
 * @throws IllegalStateException if it is called
 * in an order other than the one specified above
 */
public void setDataSource(FileDescriptor fd) 
        throws IOException, IllegalArgumentException, IllegalStateException {
    // intentionally less than LONG_MAX
    setDataSource(fd, 0, 0x7ffffffffffffffL);
}

/**
 * Sets the data source (FileDescriptor) to use.  It is the caller's responsibility
 * to close the file descriptor. It is safe to do so as soon as this call returns.
 * Call this after reset(), or before any other method (including setDataSource()) 
 * that might throw IllegalStateException in this class.
 * 
 * @param fd the FileDescriptor for the file you want to play
 * @param offset the offset into the file where the data to be played starts, in bytes
 * @param length the length in bytes of the data to be played
 * @throws IllegalStateException if it is called
 * in an order other than the one specified above
 */
public native void setDataSource(FileDescriptor fd, long offset, long length) 
        throws IOException, IllegalArgumentException, IllegalStateException;

谢谢!我曾认为FileDescriptor可能会带来一些不明显的好处,例如缓冲优势或类似的东西。 - Robert Nekic

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