Потоковое аудио из базы данных SQLite - PullRequest
4 голосов
/ 02 июня 2011

У меня есть база данных SQLite, и в ней есть аудиофайлы, хранящиеся в виде BLOB-объектов.

Возможно ли в Android (или где-либо еще) передавать потоковое мультимедиа из БД?

Ответы [ 2 ]

5 голосов
/ 03 июня 2011

Я бы порекомендовал не хранить аудиоданные в базе данных. Упомянутые ранее проблемы с памятью могут привести к огромным перебоям в работе ГХ, что может сделать систему нереагирующей в течение нескольких секунд или более.

Типичный подход включает несколько шагов.

  1. Сохраните аудио в файле где-нибудь в каталоге вашего приложения.

  2. Создайте два столбца в вашей базе данных. Один столбец (называемый как угодно) содержит URL «content: //», который ссылается на данные. Просмотр URL-адреса «content: //» - это триггер для системы, который затем просматривает содержимое столбца «_data» в той же строке. Содержимое этого столбца должно содержать полный путь к файлу.

  3. Затем система прозрачно читает этот файл и представляет его любому коду, который фактически запросил содержимое.

У меня есть пример кода для выполнения этого с изображениями - очевидно, это не совсем то же самое, но я могу пройтись по нему здесь, и вы должны понять суть.

Конкретная проблема, которую я пытался решить, - это сохранение обложки альбома для дорожки, хранящейся на устройстве. Я хотел, чтобы можно было отображать обложку альбома в виде списка и кэшировать его локально на устройстве, чтобы многократная прокрутка выполнялась быстро и требовала многократных сетевых загрузок для одних и тех же данных.

У меня есть база данных альбомов с различными столбцами, которые лениво заполняются с удаленного сервера. Я реализую эту базу данных с использованием инфраструктуры ContentProvider. В http://developer.android.com/guide/topics/providers/content-providers.html, есть много полезной информации о ContentProviders, и вам следует сначала прочитать ее, чтобы остальное имело смысл.

Используются следующие файлы (примечание: я связался с определенными точками в дереве, потому что эта работа еще не завершена, и я хочу, чтобы ссылки на номера строк, которые я вам предоставляю, были стабильными):

https://github.com/nikclayton/android-squeezer/blob/02c08ace43f775412cc9715bf55aeb83e7b5f2dc/src/com/danga/squeezer/service/AlbumCache.java

Этот класс определяет различные константы, которые используются в других местах, и довольно идиоматичен для всего, что реализовано как ContentProvider.

В этом классе COL_ARTWORK_PATH - это столбец, который будет содержать содержимое: // URL.

https://github.com/nikclayton/android-squeezer/blob/02c08ace43f775412cc9715bf55aeb83e7b5f2dc/src/com/danga/squeezer/service/AlbumCacheProvider.java

Это реализация ContentProvider. Опять же, это довольно идиоматично для ContentProviders, которые обертывают базы данных SQLite. Некоторые интересные места:

429: albumListCallback ()

Этот код вызывается всякий раз, когда приложение получает данные об альбоме с удаленного сервера (это относится к моему приложению и не относится к вашей проблеме). К этому моменту данные были упакованы в список SqueezerAlbums, поэтому этот код должен распаковать эти данные и передать их в строки в базе данных.

456: здесь мы вызываем updateAlbumArt с достаточным количеством данных, чтобы он мог выполнить удаленную выборку обложки альбома (и я только что понял, глядя на этот код, что могу сделать это более эффективным, поскольку он обновляет базу данных чаще, чем она должен. Но я отвлекся).

475: updateAlbumArt ()

Для этого необходимо извлечь удаленный образ, изменить его размер, сохранить как исходную, так и измененную версию в файловой системе (почему оба? Поскольку я еще не закончил, и будет код для выбора правильного кэшированного размера позже).

При необходимости создается каталог кеша, загружается удаленный образ, изменяется его размер и сохраняется в файлы.

535: Это бит, который вам, вероятно, особенно интересен. При этом создается URL-адрес content: // (с использованием констант в AlbumCache.java), который ссылается на данные, и помещает его в COL_ARTWORK_PATH. Затем он устанавливает абсолютный путь к файлу в столбце _data.

571: openFile ()

Вы должны реализовать это. Пользователи ContentProvider будут вызывать openFile (), когда они хотят открыть файл в базе данных. Эта реализация использует openFileHelper (), который представляет собой код, который ищет значение в столбце _data, открывает этот файл и возвращает вызывающему ParcelFileDescriptor.

Как вы, возможно, только что поняли, ваша открытая реализация openFile () не должна этого делать - вы можете использовать другое имя столбца или, возможно, у вас есть способ перейти прямо от URL-адреса к файлу вфайловая система.Это, кажется, очень распространенная идиома.

Предполагая, что вы сделали что-то подобное, и теперь у вас есть ContentProvider для вашей базы данных, чтобы фактически получить доступ к изображению, ваше приложение должно будет сгенерировать URIкоторый ссылается на данный фрагмент контента по его идентификатору.Код в приложении для открытия файла выглядит следующим образом:

Inputstream f = this.getContentResolver().openInputStream(theUri);

, который в конечном итоге вызывает вашу реализацию openFile (), которая в итоге вызывает openFileHelper (), который в итоге попадает в нужный файл вфайловая система.Еще одно преимущество этого подхода заключается в том, что openFile () вызывается в домене безопасности вашего приложения, поэтому он может получить доступ к файлу, и, при правильной реализации, ваш ContentProvider может вызываться совершенно разными приложениями, если вы создаете URL-адреса, на которые он отвечаетобщеизвестно.

0 голосов
/ 02 июня 2011

Если вы сохраняете фактические аудиоданные в базе данных в формате, который аудиосистема Android может изначально интерпретировать (т. Е. Mp3, 3gpp, ogg), то один из способов сделать это - реализовать веб-сервер в службе,и пусть эта служба откроет базу данных SQLite, извлечет большой двоичный объект, используя Cursor.getBlob , а затем передаст этот большой двоичный объект в экземпляр MediaPlayer через веб-сервер, обернув байтовый массив байтом ByteArrayInputStream.Я видел, как реализованы подобные реализации (в тех случаях это было из файла, а не из базы данных, но применяются те же принципы).

В качестве альтернативы вы можете использовать AudioTrack, перевести аудио, если оно не в формате PCM, и затем воспроизвестиэто и обрабатывает управление звуком самостоятельно: вероятно, намного больше работы, но более эффективно.

Обратите внимание, что это будет ЧРЕЗВЫЧАЙНО интенсивно использовать память и, вероятно, будет работать плохо: для MP3 объемом 5 Мб вам в основном придется держатьвся вещь в памяти, так как не кажется, что интерфейс SQLite в Android дает вам потоковый интерфейс для BLOB-объектов.Если вы загружаете несколько файлов мультимедиа, то ... происходят плохие вещи.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...