понедельник, 17 сентября 2012 г.

Медиа-плеер и буфферинг видео по HTTP

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

Ещё, поведение VideoView/SurfaceView при переключении видов в пределе одного лэйаута тоже работает очень неоднозначно (чёрный экран через раз), поэтому пришлось банально оставлять в лэйауте один-единственный VideoView и показывать ProgressDialog поверх него, пока видео загружается. Опять же, если вы знаете что-то про потоковое воспроизведение видео средствами MediaPlayer (или о получении чанков вручную), пишите в комментариях.

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

Если же вам тоже пришлось получать поток вручную, я обращу ваше внимание на пару моментов, в остальном просто продемонстрирую код, он должен рассказать всё сам:
Пример из vimeoid: VimeoVideoPlayingTask
Вызывается из активити: Player
Лэйаут: player.xml
Загружать поток лучше используя AsyncTask. Я просто агрегирую MediaPlayer внутри ...PlayingTask для удобства, вы можете выбрать любой другой способ, но получать поток определённо лучше через AsyncTask. При этом, в методе onPreExecute можно подготовить плеер и настроить его, в doInBackground получить поток видео и вернуть этот поток в onPostExecute, в котором и запустить проигрывание. Опять же, удобно показывать процентный прогресс загрузки, потому что в doInBackground известно количество полученных данных.

Если при загрузке потока возникает исключение, сообщение о нём приходится показывать через runOnUiThread, потому что выполнение задачи было прервано.

Выполнение getWindow().setFormat(PixelFormat.TRANSPARENT); предназначено, чтобы отображённые поверх плеера виды не оставались поверх него после скрытия. Хотя если нужно использовать ViewSwitcher, это всё равно не помогает.

Код получения потока по URL примерно таков:

public static InputStream getVideoStream(long videoId)
throws FailedToGetVideoStreamException, VideoLinkRequestException {
try {
final HttpClient client = new DefaultHttpClient();
. . .
HttpResponse response = client.execute(request);
if ((response == null) || (response.getEntity() == null))
throw new FailedToGetVideoStreamException("Failed to get video stream");
lastContentLength = response.getEntity().getContentLength();
return response.getEntity().getContent();
} catch (URISyntaxException use) {
throw new VideoLinkRequestException("URI creation failed : " + use.getLocalizedMessage());
} catch (ClientProtocolException cpe) {
throw new VideoLinkRequestException("Client call failed : " + cpe.getLocalizedMessage());
} catch (IOException ioe) {
throw new VideoLinkRequestException("Connection failed : " + ioe.getLocalizedMessage());
}
}

Комментариев нет:

Отправить комментарий