В продолжении темы о воспроизведении потокового аудио в Андроид сегодня рассмотрим небольшой пример того, как, используя только возможности ОС Android можно прочитать метаданные mp3-файла. Да, я в курсе, что есть замечательная библиотека «ID3v2 Library» (и даже активно её использую в одном проектике), но если есть «родной» способ прочитать теги, то почему бы им не воспользоваться?
Итак, в прошлый раз я рассмотрел два примера того как воспроизвести потоковое аудио. При этом, во втором случае для доступа к данным нам потребовалось передать в заголовках запроса ключ авторизации. Ключ может потребоваться, например, если вы захотите воспроизводить звук из Dropbox или ещё какого-нибудь сервиса. Естественно, если мы захотим написать свой собственный аудио-плеер для Андроид, то нам придётся также задуматься и о том, чтобы получить непосредственно из потока всю информацию о песне (исполнителя, название альбома, номер трека на диске и т.д. и т.п.). И здесь нам на помощь приходит Android SDK, а точнее класс MediaMetadataRetriever.
С помощью MediaMetadataRetriever мы можем получить довольно много полезной информации об аудио- или видео-файле, в т.ч.:
- Название альбома
- Исполнителя
- Название песни
- Номер песни на диске
- Битрейт
- Год выпуска альбома
- Жанр
- Имя композитора
- и т.д.
Конечно, абсолютно всё, что можно затолкать в ID3v2 файла мы с помощью MediaMetadataRetriever вытащить не сможем, но наиболее часто используемые теги — вполне можем.
Как и MediaPlayer (о котором я писал в прошлый раз) MediaMetadataRetriever имеет несколько переопределенных методов SetDataSource:
procedure setDataSource(path: JString); cdecl; overload; procedure setDataSource(uri: JString; headers: JMap); cdecl; overload; procedure setDataSource(fd: JFileDescriptor; offset: Int64; length: Int64); cdecl; overload; procedure setDataSource(fd: JFileDescriptor); cdecl; overload; procedure setDataSource(context: JContext; uri: Jnet_Uri); cdecl; overload;
Все эти методы задают источник данных для извлечения метаданных. Вторая, третья и четвертая реализация метода предназначены для работы с файлами, расположенными непосредственно на устройстве, а первая и пятая — для работы как раз-таки с потоковым аудио.
Для запроса данных предназначен метод:
function extractMetadata(keyCode: Integer): JString; cdecl;
здесь KeyCode — константа, определяющая какую информацию нам необходимо получить.
Запрос сведений о содержимом какого-либо тега в Delphi XE7, в самом простом случае, может выглядеть так:
var MediaMetadataRetriever: JMediaMetadataRetriever; Album: string; begin MediaMetadataRetriever:=TJMediaMetadataRetriever.Create; MediaMetadataRetriever.setDataSource(SharedActivityContext, StrToJURI('URL_ФАЙЛА_В_СЕТИ')); Album:=JStringToString(MediaMetadataRetriever.extractMetadata(TJMediaMetadataRetriever.JavaClass.METADATA_KEY_ALBUM)); MediaMetadataRetriever.release; MediaMetadataRetriever:=nil; end;
Однако на поверку оказалось, что именно при таком использовании метода setDataSource вылетает ошибка IllegalArgumentException, которая говорит о том, что URL задан неверно, несмотря на то, что как раз URL задан 100% верно, по всем правилам. И это тот самый случай, когда разработчики Embarcadero здесь вообще не при чём. Как оказалось, этот баг присутствует уже давно в Android, ещё с 2012 года и, по-моему, будет присутствовать ещё долго. Поэтому, чтобы запросить данные о содержимом ID3 из mp3-файла сейчас необходимо воспользоваться вот такой конструкцией:
uses Androidapi.Helpers, Androidapi.JNI.Net, Androidapi.JNI.Os, Androidapi.JNI.JavaTypes,Androidapi.JNIBridge; var MediaMetadataRetriever: JMediaMetadataRetriever; Album: string; O: JHashMap; M: JMap; begin MediaMetadataRetriever:=TJMediaMetadataRetriever.Create; if TJBuild_VERSION.JavaClass.SDK_INT>=14 then begin O:=TJHashMap.Create; M:=TJMap.Wrap((O as ILocalObject).GetObjectID); MediaMetadataRetriever.setDataSource(StringToJString(FURL), M); end else MediaMetadataRetriever.setDataSource(SharedActivityContext, StrToJURI(FURL)); Album:=JStringToString(MediaMetadataRetriever.extractMetadata(TJMediaMetadataRetriever.JavaClass.METADATA_KEY_ALBUM)); MediaMetadataRetriever.release; MediaMetadataRetriever:=nil; end;
То есть здесь мы воспользовались версией метода setDatasource в которой дополнительно передаются заголовки запроса, но список заголовков оставили пустым.
В качестве примера, я накидал небольшой проектик в Delphi XE7, который демонстрирует проигрывание файла из Сети и получение основных сведений о композиции. В дизайнере формы приложение выглядит так:
В Edit’е задаем URL по которому расположен файл, жмем кнопочку «Play» и в запущенном приложении получаем:
Видео-ролик, демонстрирующий работу приложения:
[…] Продолжение статьи о воспроизведении потокового аудио в Android — здесь […]
Здравствуйте Большое Спасибо за пример, а можно воспроизводить потоковое видео если да то как, сделайте пример-проект
Ваня Борисов, для видео используется тот же самый объект + что-то на чем показывается видео (не могу сказать сейчас что это за объект — надо смотреть исходники MediaControl в Delphi).
Посмотрите пожалуйста, и ещё кроме mp3 он может воспроизводить может кодеки надо подключать какието
Пожалуйста посмотрите, и ещё как сделать поддержку других форматов кроме mp3
Скажите пожалуйста почему при воспроизведении потока радио,отображается только битрейт,хотя тэг заполнен у проигрываемого трека?
ftp сервер для потокового воспроизведения??? что надо изменять
Как реализовать потоковое видео в формате hls?