Подтвердить что ты не робот

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

4b9b3361

Ответ 1

Альтернативное решение №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 Functions

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 Media Media Player. Если вы можете обратиться к строке №: 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//который на самом деле является местоположением банки (в пределах вашего apk), а не физическим местоположением. Локальный файл будет работать с setDataSource (String), который начинается со схемы file://.

Чтобы вы четко понимали, что вы пытаетесь сделать с файлом ресурсов, попробуйте выполнить этот ниже код и увидеть результат в 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: Я знаю его длинный ответ, но я надеюсь, что это объяснит это подробно. Оставляя альтернативные решения в верхней части, если это может помочь другим.

Ответ 2

Как и андроид документация сказал

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

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

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

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

:)

Ответ 3

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

public static MediaPlayer create (контекст контекста, int остаток)

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

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

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

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

(источник)

Ответ 4

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

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

Ответ 5

Из здесь,

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

Попробуйте,

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

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