首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >MediaPlayer.setDataSource(字符串)不处理本地文件

MediaPlayer.setDataSource(字符串)不处理本地文件
EN

Stack Overflow用户
提问于 2015-10-12 16:55:44
回答 7查看 41.1K关注 0票数 37

如果我使用静态方法mp3 (context,id),我可以播放本地MediaPlayer.create,但是如果我使用非静态方法MediaPlayer.setDataSource(String),它就不能工作。正在发生的情况是,当调用MediaPlayer.prepare()时,我得到了一个同步异常:

prepare exceptionjava.io.IOException: Prepare failed.: status=0x1

下面是我的代码(省略日志):

代码语言:javascript
运行
复制
String filename = "android.resource://" + this.getPackageName() + "/raw/test0";

mp = new MediaPlayer();
try { mp.setDataSource(filename); } catch (Exception e) {}
try { mp.prepare(); } catch (Exception e) {}
mp.start();

请注意,我没有得到一个关于文件找不到或任何错误。文件的全名是test0.mp3,我将其放在Eclipse中的/res/raw/目录中。

我假设我设置的路径不正确,但是我在网上找到的所有示例都使用FileDescriptor版本的setDataPath,而不是setDataPath的字符串版本。

编辑:如果我使用MediaPlayer.setDataSource(FileDescriptor)方法并将文件放在Eclipse中的/assets/目录中,我也可以播放本地的FileDescriptor。

编辑2:我接受了这是不可能的答案,但后来意识到我使用的库(openFrameworks)确实使用String方法来加载文件。见这里:

https://github.com/openframeworks/openFrameworks/blob/master/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidSoundPlayer.java

EN

Stack Overflow用户

回答已采纳

发布于 2015-10-21 18:29:53

替代解决方案#1:使用Resources.getIdentifier()

为什么不像往常一样使用getResources().getIdentifier()来获取资源的id并使用静态MediaPlayer.create()呢?

代码语言:javascript
运行
复制
public int getIdentifier (String name, String defType, String defPackage)

getIdentifier()获取资源名称(test0)、资源类型(Raw)、包名并返回实际的资源id。

代码语言:javascript
运行
复制
 MediaPlayer mp;
 //String filename = "android.resource://" + this.getPackageName() + "/raw/test0";
 mp=MediaPlayer.create(getApplicationContext(), getResources().getIdentifier("test0","raw",getPackageName()));
 mp.start();

我已经测试过这段代码了,而且效果很好。

更新#1:

替代解决方案2:使用Uri.parse()

我也测试过这段代码,而且它也能工作。将资源路径作为URI传递给setDataSource()。我只是对你的代码做了些修改才能让它正常工作。

代码语言:javascript
运行
复制
String filename = "android.resource://" + this.getPackageName() + "/raw/test0";

mp = new MediaPlayer();
try { mp.setDataSource(this,Uri.parse(filename)); } catch (Exception e) {}
try { mp.prepare(); } catch (Exception e) {}
mp.start();

更新#2:答案不是

关于setDataSource(字符串)调用

在看到您的评论之后,您似乎完全希望setDataSource(string)用于您的目的。我不明白为什么。但是,我假设,由于某种原因,您正试图避免使用“上下文”。如果不是这样的话,那么以上两种解决方案应该完全适用于您,或者如果您试图避免上下文,那么使用带有签名的setDataSource(String)调用的函数恐怕是不可能的。原因如下,

MediaPlayer setDataSource()函数具有以下选项,其中您只对setDataSource(String)感兴趣,

setDataSource(String)内部调用setDataSource( String[],String[]键,String[]值)函数。如果你能检查它的来源

代码语言:javascript
运行
复制
public void setDataSource(String path)
            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
        setDataSource(path, null, null);
    }

如果您检查setDataSource(String,String[]键,String[]值)代码,您将看到以下条件根据路径的方案过滤路径,特别是如果它是它调用setDataSource(FileDescriptor)的“文件”方案,或者如果它是非“文件”,则调用本机JNI媒体函数。

代码语言:javascript
运行
复制
{
        final Uri uri = Uri.parse(path);
        final String scheme = uri.getScheme();
        if ("file".equals(scheme)) {
            path = uri.getPath();
        } else if (scheme != null) {
            // handle non-file sources
            nativeSetDataSource(
                MediaHTTPService.createHttpServiceBinderIfNecessary(path),
                path,
                keys,
                values);
            return;
        }
        final File file = new File(path);
        if (file.exists()) {
            FileInputStream is = new FileInputStream(file);
            FileDescriptor fd = is.getFD();
            setDataSource(fd);
            is.close();
        } else {
            throw new IOException("setDataSource failed.");
        }
}

在上面的代码中,您的资源文件URI方案不会为null (android.resources://),而setDataSource(String)将尝试使用本机JNI函数nativeSetDataSource(),认为您的路径是http/https/rtsp,显然该调用也会失败,而不会引发任何异常。这就是为什么您对setDataSource(String)的调用没有异常地转义,并使用以下异常准备()调用的原因。

代码语言:javascript
运行
复制
Prepare failed.: status=0x1

因此,setDataSource(字符串)覆盖无法处理资源文件。你需要选择另一个覆盖。

另一方面,检查setDataSource( context,Uri uri,Map headers),它由setDataSource( context,URI,Uri uri)使用,它使用AssetFileDescriptor、上下文中的ContentResolver和openAssetFileDescriptor来打开URI,因为openAssetFileDescriptor()可以打开资源文件,最终结果fd用于调用setDataSource(FileDescriptor)覆盖。

代码语言:javascript
运行
复制
    AssetFileDescriptor fd = null;
    try {
        ContentResolver resolver = context.getContentResolver();
        fd = resolver.openAssetFileDescriptor(uri, "r");
        //  :
        //  :
        //  :
        if (fd.getDeclaredLength() < 0) {
                setDataSource(fd.getFileDescriptor());
            } else {
                setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getDeclaredLength());
            }

总之,不能像使用资源setDataSource文件那样使用mp3 (String)覆盖。相反,如果您想使用字符串来播放资源文件,您可以使用MediaPlayer.create()静态函数和上面给出的getIdentifier(),或者使用Update#1中给定的setDataSource(上下文、uri)。

要了解更多信息,请参阅完整的源代码:Android MediaPlayer

更新#3:

openFrameworks setDataSource(字符串):

正如我在下面的评论中提到的,openFrameworks使用MediaPlayer代码asis。如果您可以参考编号: 4线,

代码语言:javascript
运行
复制
import android.media.MediaPlayer;

第26、27、28及218号线

代码语言:javascript
运行
复制
        player = new MediaPlayer();       //26
        player.setDataSource(fileName);   //27
        player.prepare();                 //28

        private MediaPlayer player;       //218

因此,如果您尝试将ardroid.resources//+ this.getPackageName() + "raw/test0"传递给使用openFrameworks的setDataSource(),您仍然会得到与我在Update#2中解释的相同的例外情况。话虽如此,我还是很幸运地搜索了Google,以确定我在说什么,并找到了一个openFrameworks核心开发人员arturo所说的openFrameworks论坛链接

不知道mediaPlayer到底是如何工作的,但是res/raw或bin/数据中的所有内容都被复制到/sdcard/cc.openFraworks.Packagename

基于该注释,您可以尝试使用setDataSource()中复制的路径。在setDataSource(String)上使用MediaPlayer的资源文件是不可能的,因为它不能接受资源文件路径。请注意,我说的“资源文件路径”是从方案android.resource//开始的,它实际上是一个jar位置(在您的apk中),而不是物理位置。本地文件将使用以方案file://.()开头的setDataSource(String)。

为了使您清楚地了解您试图对资源文件做什么,请尝试执行下面的代码并在logcat中看到结果,

代码语言:javascript
运行
复制
    try{
      Log.d("RESURI", this.getClass().getClassLoader().getResource("res/raw/test0").toURI().toString());
    } 
    catch(Exception e) {

    }

你会得到这样的结果,

代码语言:javascript
运行
复制
jar:file:/data/app/<packagename>/<apkname>.apk!/res/raw/test0

也就是说,您要访问的资源文件实际上不是物理路径中的文件,而是一个jar位置(apk内),您不能使用setDataSource(String)方法访问该位置。(尝试使用7zip解压缩apk文件,您将在其中看到res/raw/test0 )。

希望这能有所帮助。

PS:我知道它的答案有点长,但我希望这能详细解释它。如果可以帮助其他人的话,把替代解决方案放在最上面。

票数 46
EN
查看全部 7 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33086417

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档