MediaPlayer.setDataSource (String) не работает с локальными файлами

Я могу воспроизвести локальный mp3, если я использую статический метод MediaPlayer.create (context, id), но он не работает, если я использую нестатический метод MediaPlayer.setDataSource (String). Что происходит, так это то, что я получаю синхронное исключение, когда я вызываю MediaPlayer.prepare ():

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

Вот мой код (опущен журнал):

 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, и я помещаю его в каталог / res / raw / в Eclipse.

Я предполагаю, что неправильно задаю путь, но все примеры, которые я нашел в Интернете, используют версию FileDescriptor для setDataPath вместо String версии setDataPath.

EDIT: Я также могу воспроизвести локальный mp3, если я использую метод MediaPlayer.setDataSource (FileDescriptor) и поместил файлы в каталог / assets / в Eclipse.

EDIT # 2: я принял ответ, что это невозможно, но потом понял, что библиотека, которую я использую (openFrameworks), действительно использует метод String для загрузки файла. Глянь сюда:

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

Solutions Collecting From Web of "MediaPlayer.setDataSource (String) не работает с локальными файлами"

Альтернативное решение №1: Использование Resource.getIdentifier ()

Почему бы не использовать getResources (). GetIdentifier (), чтобы получить идентификатор ресурса и использовать статический MediaPlayer.create (), как обычно?

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

GetIdentifier () берет ваше имя ресурса (test0), тип ресурса (raw), имя вашего пакета и возвращает фактический идентификатор ресурса.

  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 (). Я просто сделал это изменение для вашего кода, чтобы заставить его работать.

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

После просмотра вашего комментария, похоже, что вы точно хотите, чтобы setDataSource (строка) использовался для вашей цели. Я не понимаю, почему. Но, я полагаю, по какой-то причине вы пытаетесь избежать использования «контекста». Если это не так, то вышеупомянутые два решения должны отлично работать для вас или если вы пытаетесь избежать контекста, я боюсь, что это невозможно с помощью функции с сигнатурой setDataSource (String). Причина такова, как показано ниже,

Функция MediaPlayer setDataSource () имеет следующие параметры, из которых вас интересует только setDataSource (String),

Функции setDataSource

SetDataSource (String) внутренне вызывает setDataSource (String path, String [] keys, String [] values). Если вы можете проверить его источник ,

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

И если вы проверите коды setDataSource (String path, String [], String []), вы увидите условие ниже, фильтрующее путь на основе его схемы, особенно если это «файловая» схема, которая вызывает setDataSource (FileDescriptor) или Если схема не является «файлом», она вызывает встроенную функцию мультимедиа JNI.

 { 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.resource: //), а setDataSource (String) попытается использовать собственную функцию JNI nativeSetDataSource (), полагая, что ваш путь – http / https / rtsp, и, очевидно, что Вызов не удастся, не бросая никаких исключений. Вот почему ваш вызов setDataSource (String) выходит без исключения и получает вызов prepare () со следующим исключением.

 Prepare failed.: status=0x1 

Поэтому переопределение setDataSource (String) не может обрабатывать ваш файл ресурсов. Для этого вам нужно выбрать другое переопределение.

С другой стороны, проверьте setDataSource (контекст контекста, Uri uri, заголовки карт), который используется setDataSource (контекст контекста, Uri uri), он использует AssetFileDescriptor, ContentResolver из вашего контекста и openAssetFileDescriptor, чтобы открыть URI, который получает успех как openAssetFileDescriptor ( ) Может открыть файл ресурсов и, наконец, результирующий fd используется для вызова переопределения setDataSource (FileDescriptor).

  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 (String) переопределить, как использовать свой файл mp3-файла ресурса. Вместо этого, если вы хотите использовать строку для воспроизведения своего файла ресурсов, вы можете использовать статическую функцию MediaPlayer.create () с помощью getIdentifier (), как указано выше, или setDataSource (контекст, uri), как указано в обновлении №1.

Подробнее см. Полный исходный код: Android MediaPlayer


Обновление № 3:

OpenFrameworks setDataSource (String):

Как я уже упоминал в комментариях ниже, openFrameworks использует asis для Android and MediaPlayer. Если вы можете обратиться к строке № 4,

 import android.media.MediaPlayer; 

И № линии: 26, 27, 28 и 218

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

Итак, если вы попытаетесь передать ardroid.resource // + this.getPackageName () + "raw / test0" в setDataSource (), используя openFrameworks, вы все равно получите то же исключение, что и в обновлении # 2. Сказав это, я просто попробовал свою удачу в Google, чтобы удвоить уверенность в том, что я говорю, и нашел эту ссылку для форума openFrameworks, где говорит один из разработчиков ядра openframeworks arturo ,

Не знаю точно, как работает MediaPlayer, но все в res / raw или bin / data копируется в /sdcard/cc.openframeworks.packagename

На основе этого комментария вы можете попробовать использовать скопированный путь в setDataSource (). Использование файла ресурсов в файле setDataSource (String) MediaPlayer невозможно, так как он не может принимать путь к файлу ресурсов. Обратите внимание, что я сказал, что «путь к файлу ресурсов» начинается со схемы android.resource //, которая на самом деле является расположением jar (внутри вашего apk), а не физическим местоположением. Локальный файл будет работать с setDataSource (String), который начинается с файла схемы : // .

Чтобы вы четко понимали, что вы пытаетесь сделать с файлом ресурсов, попробуйте выполнить этот ниже код и увидеть результат в logcat,

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

Вы получите результат как,

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

То есть показать вам, что файл ресурсов, который вы пытаетесь получить, на самом деле не является файлом по физическому пути, а расположением jar (внутри apk), к которому вы не можете получить доступ, используя метод setDataSource (String). (Попробуйте использовать 7zip для извлечения файла apk, и вы увидите в нем res / raw / test0).

Надеюсь, это поможет.

PS: Я знаю его длинный ответ, но я надеюсь, что это объяснит это подробно. Оставляя альтернативные решения в верхней части, если это может помочь другим.

Как и в документации по Android,

Произвольные файлы для сохранения в исходном виде. Чтобы открыть эти ресурсы с помощью исходного InputStream, вызовите Resource.openRawResource () с идентификатором ресурса, который является R.raw.filename.

Однако, если вам нужен доступ к исходным именам файлов и иерархии файлов, вы можете рассмотреть возможность сохранения некоторых ресурсов в каталоге assets / resources (вместо res / raw /). Файлы в активах / не имеют идентификатор ресурса, поэтому вы можете читать их только с помощью AssetManager.

Поэтому вам необходимо использовать InputStream для чтения аудиофайла, прежде чем устанавливать его на медиаплеер.

Я предлагаю вам поместить аудиофайл в папку с ресурсами, как вы сказали, что играете

🙂

При работе с необработанным ресурсом вы должны полагаться на следующий конструктор:

Public static MediaPlayer create (Контекстный контекст, int-остаток)

Удобный метод создания MediaPlayer для заданного идентификатора ресурса. В случае успеха, prepare () уже будет вызван и не должен быть вызван снова.

Код выглядит так:

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

Не забудьте вызвать mediaPlayer.release() когда вы закончите с ним.

( Источник )

Ниже код работает для меня, я думаю, этот код поможет вам

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

Отсюда ,

Когда путь относится к локальному файлу, файл может быть фактически открыт процессом, отличным от вызывающего приложения. Это означает, что путь должен быть абсолютным путем (так как любой другой процесс выполняется с неуказанным текущим рабочим каталогом), и что путь должен ссылаться на мир-читаемый файл. В качестве альтернативы приложение может сначала открыть файл для чтения, а затем использовать форму дескриптора файла setDataSource (FileDescriptor).

Пытаться,

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

Надеюсь, поможет!