Введение
Воспроизведение мультимедиа становится одной из наиболее популярных моделей использования на мобильных устройствах. Пользователи ожидают, что мобильные устройства должны быть способны воспроизводить на ходу распространенные типы мультимедиа и воспроизводить видео. В этом документе рассматриваются основы создания мультимедиа приложений Android и предоставляется образец кода, использующего API MediaPlayer, на платформах с архитектурой Intel®.
Мультимедиа платформа Android: API MediaPlayer
Мультимедиа платформа Android дает разработчикам возможность удобно интегрировать возможности воспроизведения звука и видео в приложения с поддержкой распространенных форматов мультимедиа. Основой платформы мультимедиа Android является класс MediaPlayer. Этот класс можно использовать для воспроизведения данных мультимедиа, находящихся в локальной файловой системе, хранящихся в ресурсах приложения или поступающих в виде потока по сетевому подключению.
Управление состоянием
Класс MediaPlayer работает на основе состояний. Он обладает внутренним конечным автоматом — машиной состояний, которая управляет всеми состояниями жизненного цикла объекта MediaPlayer. На приведенной ниже схеме показано изменение состояния объекта MediaPlayer для элемента управления воспроизведением. На этой схеме одиночная стрелка означает синхронные вызовы метода, а двойная стрелка означает асинхронные вызовы метода и обратные вызовы.
Рисунок 1. Изменения состояния объекта MediaPlayer. (Одиночная стрелка означает синхронные вызовы метода, двойная стрелка означает асинхронные вызовы метода и обратные вызовы)
На схеме видно, что жизненный цикл объекта MediaPlayer содержит несколько состояний. Вначале при создании нового объекта MediaPlayer или при вызове метода reset() объект MediaPlayer переходит в состояние Idle (бездействие). Это начальное состояние, но воспроизведение пока невозможно. Если вызвать какие-либо методы управления воспроизведением, например start(), stop(), seekTo(int) и т. д., возникнет программная ошибка.
Приложение должно вызвать метод setDataSource(), чтобы указать на допустимый источник мультимедиа. В результате этого проигрыватель переходит в состояние Initialized (Инициализирован). Источником может быть локальный файл или потоковые данные, поступающие по сетевому подключению.
В состоянии Initialized перед тем, как можно будет начать воспроизведение, приложение может вызвать метод prepare() или prepareAsync() для перехода в состояние Prepared (Подготовлен). Метод prepare() осуществляет получение данных, их буферизацию и декодирование файла мультимедиа. Однако, возврат метода prepare() может занять весьма длительное время при получении данных мультимедиа с сетевого URL-адреса, особенно при низкоскоростном подключении к сети. Поэтому запускать метод prepare() в потоке пользовательского интерфейса приложения не рекомендуется: из-за этого приложение может перестать реагировать на действия пользователя. Вместо этого следует использовать метод prepareAsync(), разработанный, чтобы справиться с этой проблемой и обеспечить удобный способ подготовки данных мультимедиа, сохраняя способность пользовательского интерфейса реагировать на действия пользователя. Метод prepareAsync() выполняется в фоновом режиме и возвращается сразу же после завершения, отправляя обратный вызов OnPreparedListener.onPrepared(), чтобы привести объект MediaPlayer в состояние Prepared.
Из состояния Prepared можно запустить воспроизведение и управлять им, вызывая методы start() и seekTo(). После начала воспроизведения мультимедиа объект MediaPlayer переходит в состояние Started (Запущен).
После начала воспроизведения можно управлять им, вызывая метод pause() для перевода объекта в состояние Paused (Приостановлен) или вызывая метод start() для возврата объекта в состояние Started. Если воспроизведение доходит до конца и при этом не включен повтор воспроизведения с начала, объект MediaPlayer переходит в состояние PlaybackCompleted (Воспроизведение завершено). На этом этапе также можно вызвать метод start(), чтобы снова начать воспроизведение. В этом случае состояние изменится на Started. Если же вызвать метод stop() из состояния Started, Paused или PlaybackCompleted, конечный автомат перейдет в состояние Stopped (Остановлен). Из этого состояния можно перейти в состояние End (Конец) и высвободить объект MediaPlayer, либо, если нужно повторно воспроизвести мультимедиа, потребуется вновь подготовить данные перед вызовом метода start().
Помните, что следует всегда вызывать метод release() после каждого использования, чтобы переводить объект MediaPlayer в состояние End. В противном случае объект будет по-прежнему расходовать ресурсы системы. Если продолжать создавать новые экземпляры MediaPlayer, не вызывая метод release(), ваше приложение может очень быстро исчерпать все ресурсы системы.
Если зарегистрирован обработчик OnErrorListener, метод обратного вызова OnErrorListener.onError() будет вызван при любых ошибках, чтобы можно было их обрабатывать надлежащим образом.
Использование MediaPlayer для воспроизведения звука и видео
Теперь посмотрим, как выглядит код для воспроизведения звука и видео с помощью MediaPlayer.
Для звука:
private void playAudio(Integer media) { try { switch (media) { case LOCAL_AUDIO: path = "/sdcard/Download/music/1.mp3"; mMediaPlayer = new MediaPlayer(); mMediaPlayer.setDataSource(path); mMediaPlayer.prepare(); mMediaPlayer.start(); break; case RESOURCES_AUDIO: mMediaPlayer = MediaPlayer.create(this, R.raw.test_cbr); mMediaPlayer.start(); } } catch (Exception e) { Log.e(TAG, "error: " + e.getMessage(), e); } } @Override protected void onDestroy() { super.onDestroy(); // TODO Auto-generated method stub if (mMediaPlayer != null) { mMediaPlayer.release(); mMediaPlayer = null; } }
Для видео:
private void playVideo(Integer Media) { doCleanUp(); try { switch (Media) { case LOCAL_VIDEO: path = "/sdcard/Download/video/2.mp4"; break; case STREAM_VIDEO: path = "Your URL here"; break; } mMediaPlayer = new MediaPlayer(); mMediaPlayer.setDataSource(path); mMediaPlayer.setDisplay(holder); mMediaPlayer.prepare(); mMediaPlayer.setOnBufferingUpdateListener(this); mMediaPlayer.setOnCompletionListener(this); mMediaPlayer.setOnPreparedListener(this); mMediaPlayer.setOnVideoSizeChangedListener(this); mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); } catch (Exception e) { Log.e(TAG, "error: " + e.getMessage(), e); } } public void onBufferingUpdate(MediaPlayer arg0, int percent) { Log.d(TAG, "onBufferingUpdate percent:" + percent); } public void onCompletion(MediaPlayer arg0) { Log.d(TAG, "onCompletion called"); } public void onVideoSizeChanged(MediaPlayer mp, int width, int height) { Log.v(TAG, "onVideoSizeChanged called"); if (width == 0 || height == 0) { Log.e(TAG, "invalid video width(" + width + ") or height(" + height + ")"); return; } mIsVideoSizeKnown = true; mVideoWidth = width; mVideoHeight = height; if (mIsVideoReadyToBePlayed && mIsVideoSizeKnown) { startVideoPlayback(); } } public void onPrepared(MediaPlayer mediaplayer) { Log.d(TAG, "onPrepared called"); mIsVideoReadyToBePlayed = true; if (mIsVideoReadyToBePlayed && mIsVideoSizeKnown) { startVideoPlayback(); } } @Override protected void onPause() { super.onPause(); releaseMediaPlayer(); doCleanUp(); } @Override protected void onDestroy() { super.onDestroy(); releaseMediaPlayer(); doCleanUp(); } private void releaseMediaPlayer() { if (mMediaPlayer != null) { mMediaPlayer.release(); mMediaPlayer = null; } } private void doCleanUp() { mVideoWidth = 0; mVideoHeight = 0; mIsVideoReadyToBePlayed = false; mIsVideoSizeKnown = false; } private void startVideoPlayback() { Log.v(TAG, "startVideoPlayback"); holder.setFixedSize(mVideoWidth, mVideoHeight); mMediaPlayer.start(); }
Как видно в коде, и для звука, и для видео MediaPlayer перемещается между состояниями жизненного цикла согласно рассмотренной выше схеме изменений состояния.
Visit Intel Android для получения дополнительных ресурсов для ваших приложений в рамках проектов для ОС Android с архитектурой Intel.
Справочные материалы
- http://developer.android.com/reference/android/media/MediaPlayer.html
- http://developer.android.com/reference/android/widget/MediaController.html
IIntel и эмблема Intel являются товарными знаками корпорации Intel в США и в других странах. © Intel Corporation, 2013. Все права защищены. * Прочие наименования и товарные знаки могут быть собственностью третьих лиц.