MediaPlayer.setDataSource (String) ne fonctionne pas avec les fichiers locaux

Je suis capable de lire un mp3 local si j'utilise la méthode statique MediaPlayer.create (context, id) mais cela ne fonctionne pas si j'utilise la méthode non statique MediaPlayer.setDataSource (chaîne). Ce qui se passe, c'est que je reçois une exception synchrone quand j'appelle MediaPlayer.préparer ():

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

Voici mon code (journalisation omise):

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();

Notez que je ne reçois pas d'erreurs sur le fichier introuvable ou quoi que ce soit. Le nom complet du fichier est test0. mp3 et je le place dans le répertoire/res/ raw / dans Eclipse.

Je suppose que je définis le chemin de manière incorrecte, mais tous les exemples que je trouve en ligne utilisent la version FileDescriptor de setDataPath au lieu de la version String de setDataPath.

EDIT: je suis également capable de lire un mp3 local si j'utilise la méthode MediaPlayer.setDataSource (FileDescriptor) et placez les fichiers dans le répertoire/ assets / dans Eclipse.

EDIT # 2: j'ai accepté la réponse que ce n'est pas possible, mais j'ai ensuite réalisé que la bibliothèque que je suis l'utilisation de (openFrameworks) utilise réellement la méthode String pour charger un fichier. Voir ici:

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

21
demandé sur Naren Neelamegam 2015-10-12 19:55:44

6 réponses

Solution Alternative #1: Utilisation Des Ressources.getIdentifier ()

Pourquoi ne pas utiliser getResources ().getIdentifier() pour obtenir l'id de la ressource et utiliser le MediaPlayer statique.créer (comme d'habitude?

public int getIdentifier (String name, String defType, String defPackage)

GetIdentifier () prend le nom de votre ressource (test0), le type de ressource(raw), le nom de votre paquet et renvoie l'id de ressource réel.

 MediaPlayer mp;
 //String filename = "android.resource://" + this.getPackageName() + "/raw/test0";
 mp=MediaPlayer.create(getApplicationContext(), getResources().getIdentifier("test0","raw",getPackageName()));
 mp.start();

J'ai testé ce code et ça marche.


mise à jour # 1:

Solution Alternative #2: Utilisation URI.parse ()

J'ai également testé ce code et cela fonctionne aussi. Passez votre chemin de ressource en URI à setDataSource (). Je viens de modifier votre code pour le faire fonctionner.

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();


mise à jour # 2: la réponse est non

À propos de l'appel setDataSource(String)

Après avoir vu votre commentaire, il semble que vous vouliez exactement que setDataSource (string) soit utilisé dans votre but. Je ne comprends pas pourquoi. Mais, ce que je suppose est, pour quelque raison que vous essayez d'éviter utilisation de "contexte". Si ce n'est pas le cas, les deux solutions ci-dessus devraient fonctionner parfaitement pour vous ou si vous essayez d'éviter le contexte, j'ai peur que ce ne soit pas possible avec la fonction avec signature setDataSource(string) appel. La raison est comme ci-dessous,

La fonction MediaPlayer setDataSource () a ces options ci-dessous dont vous n'êtes intéressé que par setDataSource (String),

setDataSource fonctions

SetDataSource (String) appelle en interne setDataSource (String chemin, chaîne [] clés, Chaîne [] valeurs) fonction. Si vous pouvez vérifier sa source ,

public void setDataSource(String path)
            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
        setDataSource(path, null, null);
    }

Et si vous cochez le code setDataSource(string path, string[] keys, string[] values), vous verrez la condition ci-dessous filtrer le chemin en fonction de son schéma, en particulier s'il s'agit d'un schéma "file" qu'il appelle setDataSource(FileDescriptor) ou si scheme n'est pas "file", il appelle une fonction multimédia JNI native.

{
        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.");
        }
}

Dans le code ci-dessus, votre schéma d'URI de fichier de ressources ne sera pas null (Android.resource://) et setDataSource (String) essayeront d'utiliser la fonction JNI native nativeSetDataSource() en pensant que votre chemin est http/https/rtsp et évidemment cet appel échouera également sans lancer d'exception. C'est pourquoi votre appel à setDataSource (String) s'échappe sans exception et obtient l'appel prepare () avec l'exception suivante.

Prepare failed.: status=0x1

Donc setDataSource (string) override ne peut pas gérer votre fichier de ressources. Vous devez choisir un autre remplacement pour que.

De l'autre côté, Vérifiez setDataSource(Context context, Uri uri, map headers) qui est utilisé par setDataSource(Context context, Uri uri), il utilise AssetFileDescriptor, ContentResolver de votre contexte et openAssetFileDescriptor pour ouvrir l'URI qui obtient le succès comme openAssetFileDescriptor() peut ouvrir votre fichier de ressources et enfin le FD résultant est utilisé pour appeler setdatasource(FileDescriptor) override.

    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());
            }

Pour conclure, vous ne pouvez pas utiliser setDataSource (String) remplacer comme est d'utiliser votre fichier MP3 de ressource. Au lieu de cela, si vous voulez utiliser string pour lire votre fichier de ressources, vous pouvez utiliser MediaPlayer.create () fonction statique avec getIdentifier () comme indiqué ci - dessus ou setDataSource(context,uri) comme indiqué dans la mise à jour#1.

Reportez-vous au code source complet pour plus de compréhension ici: Android MediaPlayer


mise à jour # 3:

OpenFrameworks setDataSource (chaîne):

Comme je l'ai mentionné dans les commentaires ci-dessous, openFrameworks utilise android MediaPlayer code asis. Si vous pouvez vous référer à la ligne no: 4,

import android.media.MediaPlayer;

Et ligne no: 26, 27, 28 et 218

        player = new MediaPlayer();       //26
        player.setDataSource(fileName);   //27
        player.prepare();                 //28

        private MediaPlayer player;       //218

Donc, si vous essayez de passer ardroid.ressource / / + ceci.getPackageName () + "raw / test0" pour setDataSource () en utilisant openFrameworks, vous obtiendrez toujours la même exception que je l'ai expliqué dans la mise à jour # 2. Cela dit, je viens de tenter ma chance en cherchant Google pour doubler ce que je dis et j'ai trouvé ce lien forum openFrameworks lorsque l'un des développeurs openFrameworks core Arturo dit,

Je ne sais pas exactement comment fonctionne mediaPlayer mais tout en res / raw ou bin/données est copié dans /sdcard/cc.openframeworks.packagename

Sur la base de ce commentaire, vous pouvez essayer d'utiliser le chemin copié dans setDataSource (). L'utilisation du fichier de ressources sur setDataSource (String) de MediaPlayer n'est pas possible car elle ne peut pas accepter le chemin du fichier de ressources. Veuillez noter que, j'ai dit" Chemin du fichier de ressources " commence avec le schéma android.resource / / qui est en fait un emplacement jar (dans votre apk), pas un emplacement physique. Le fichier Local fonctionnera avec setDataSource(String) qui commence par le schéma file: / / .

Pour vous faire comprendre clairement ce que vous essayez de faire avec un fichier de ressources, essayez d'exécuter ce code ci-dessous et voyez le résultat dans logcat,

    try{
      Log.d("RESURI", this.getClass().getClassLoader().getResource("res/raw/test0").toURI().toString());
    } 
    catch(Exception e) {

    }

Vous obtiendrez le résultat comme,

jar:file:/data/app/<packagename>/<apkname>.apk!/res/raw/test0

C'est pour vous montrer que le fichier de ressources que vous essayez l'accès n'est pas réellement un fichier dans le chemin physique mais un emplacement jar (dans apk)auquel vous ne pouvez pas accéder en utilisant la méthode setDataSource (String). (Essayez d'utiliser 7zip pour extraire votre fichier apk et vous verrez le res/raw/test0 en elle).

J'espère que ça aide.

PS: je connais sa réponse un peu longue, mais j'espère que cela l'explique en détail. Laissant les solutions alternatives en haut si cela peut aider les autres.

31
répondu Naren Neelamegam 2015-10-27 16:39:13

Comme la documentation android dit

Fichiers arbitraires à enregistrer sous leur forme brute. Pour ouvrir ces ressources avec un InputStream brut, appelez des ressources.openRawResource() avec le ID de ressource, qui est R. raw.filename.

Toutefois, si vous avez besoin d'accéder aux noms de fichiers et à la hiérarchie de fichiers d'origine, vous pouvez envisager d'enregistrer certaines ressources dans le répertoire assets / (au lieu de res/raw/). Les fichiers dans assets/ ne reçoivent pas D'ID de ressource, donc vous pouvez les lire uniquement en utilisant AssetManager.

Vous devez donc utiliser un InputStream pour lire le fichier audio avant de le configurer sur le lecteur multimédia.

Je vous suggère de mettre le fichier audio dans le dossier assets comme vous avez dit que vous avez joué

:)

2
répondu DeKoServidoni 2015-10-12 17:42:08

Lorsque vous traitez une ressource brute, vous devez vous fier au constructeur suivant:

Public static MediaPlayer create (Context context, int resid)

Méthode pratique pour créer un MediaPlayer pour un ID de ressource donné. En cas de succès, prepare() aura déjà été appelé et ne doit pas être appelé à nouveau.

Le code ressemble à

mediaPlayer = MediaPlayer.create(this, R.raw.test0);
mediaPlayer.start();

N'oubliez pas d'appeler mediaPlayer.release() lorsque vous avez terminé avec elle.

(source)

2
répondu Sebastiano 2015-10-15 08:00:39

Ci-dessous code de travail pour moi je pense que ce code va vous aider

    player = MediaPlayer.create(this,R.raw.test0);
    player.setLooping(true); // Set looping

    player.setVolume(100,100);
    player.start();

@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
player.stop();
player.release();
}
2
répondu Ravi Vaghela 2015-10-21 10:21:42

À Partir de ici,

Lorsque path fait référence à un fichier local, le fichier peut effectivement être ouvert par un processus autre que l'application appelante. Cela implique que le chemin d'accès doit être un chemin absolu (comme tout autre processus s'exécute avec un répertoire de travail courant non spécifié), et que le chemin d'accès doit référencer un fichier lisible par le monde. comme alternative, l'application pourrait d'abord ouvrir le fichier pour la lecture, puis utiliser le formulaire de descripteur de fichier setDataSource (FileDescriptor).

Essayez,

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

J'espère que ça aide!

1
répondu AKMafia001 2015-10-21 18:15:08

, Vous devez utiliser setDataSource(@NonNull Context context, @NonNull Uri uri) au lieu de setDataSource(String path)

Puisque vous voulez résoudre les ressources d'application internes de la ressource, vous devez fournir Context qui serait utilisé pour résoudre ce problème

Aussi, si vous jetez un oeil à l'intérieur de ces deux méthodes, vous remarquerez qu'ils utilisent des stratégies différentes pour trouver la ressource résultante.

0
répondu Dmitry 2018-02-27 10:35:44