Android: MediaPlayer безразличный или бесшовный Воспроизведение видео
Я могу воспроизводить видео очень хорошо, реализуя OnCompletionListener, чтобы установить источник данных в другой файл. Проблем нет. Я вызываю reset() и готовлю() просто отлично.
То, что я не смог выяснить, заключается в том, как избавиться от мерцания экрана на 1-2 секунды между изменением источника данных и запуском нового видео. Зазор показывает черный экран, и я не нашел способа обойти его.
Я попытался установить фон родительского представления на изображение, но ему удается обойти это. Даже если SurfaceView прозрачен (по умолчанию он по умолчанию.) Я также пытался одновременно воспроизводить несколько видеофайлов и переключать отображение медиапланера, когда он заканчивается, а другой должен начинаться.
Последнее, что я пробовал, - это иметь второе представление в фоновом режиме, которое я показываю временно, пока видео "готовит" и удаляет его, когда видео готово к запуску. Это также было не очень легко.
Есть ли способ избавиться от этого пробела. Запуск видео в цикле прекрасно работает и делает именно то, что я хочу, за исключением того, что он просматривает одно и то же видео, вместо того, чтобы играть в другое, которое я выбираю.
main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:background="@drawable/background"
android:layout_height="fill_parent">
<SurfaceView
android:id="@+id/surface"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center">
</SurfaceView>
</FrameLayout>
Player.java
public class Player extends Activity implements
OnCompletionListener, MediaPlayer.OnPreparedListener, SurfaceHolder.Callback {
private MediaPlayer player;
private SurfaceView surface;
private SurfaceHolder holder;
public void onCreate(Bundle b) {
super.onCreate(b);
setContentView(R.layout.main);
surface = (SurfaceView)findViewById(R.id.surface);
holder = surface.getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void onCompletion(MediaPlayer arg0) {
File clip = new File(Environment.getExternalStorageDirectory(),"file2.mp4");
playVideo(clip.getAbsolutePath());
}
public void onPrepared(MediaPlayer mediaplayer) {
holder.setFixedSize(player.getVideoWidth(), player.getVideoHeight());
player.start();
}
private void playVideo(String url) {
try {
File clip = new File(Environment.getExternalStorageDirectory(),"file1.mp4");
if (player == null) {
player = new MediaPlayer();
player.setScreenOnWhilePlaying(true);
}
else {
player.stop();
player.reset();
}
player.setDataSource(url);
player.setDisplay(holder);
player.setOnPreparedListener(this);
player.prepare();
player.setOnCompletionListener(this);
}
catch (Throwable t) {
Log.e("ERROR", "Exception Error", t);
}
}
Ответы
Ответ 1
У меня тоже такая же проблема, как описано ниже ссылкой
Видеообзор исчезает в течение секунды при изменении видео
Но эта проблема не возникнет, если вы попытаетесь использовать Android 4.0+ (ICS). Я начал переносить VideoView.java и MediaPlayer.java с 4.0 на мое приложение, но это кажется сложным и не повезло до сих пор. В основном это кажется ошибкой в собственном коде старых версий.
Ответ 2
после слишком много потраченного времени, пытаясь понять, как играть в последовательные видео без "пробела", я склоняюсь к невозможности. если, конечно, вы не можете выкопать до родного уровня и реализовать своего собственного игрока, мультимедийный плеер Android просто не поддерживает плавное воспроизведение с момента.
Ответ 3
Я не делал этого с воспроизведением видео на MediaPlayer, но я сделал что-то подобное с аудиофайлами, когда поток прерывается, потому что пользователь переключился с 3G на Wi-Fi.
Я думаю, что задержка, которую вы видите, пока медиаплеер буферизует входной файл.
Может быть, вы можете определить обоих игроков в начале? Вы должны определить источник данных и подготовить обоих игроков, но только запустить один из них.
Затем в вашем onCompletionListener вы можете перевернуть их вместо сброса существующего и установки нового источника данных.
player.release();
player = flipPlayer;
flipPlayer = null;
player.start();
Очевидно, вам нужно либо использовать другой onPreparedListener для flipPlayer, либо взять player.start() из onPrepare. (Поскольку вы называете это синхронно, я бы не подумал, что это проблема).
Ответ 4
Я не думаю, что это возможно.
Причина: Mortplayer также был доступен для Windows Mobile, и одна из его сильных сторон заключалась в том, что он поддерживал беспроблемную игру. Однако это не в Android-версии приложения, и сам разработчик пишет, что SDK не разрешает его на xda:
http://forum.xda-developers.com/showpost.php?p=5364530&postcount=5
HTH, Даниэле
Ответ 5
Пробовал ли вы готовый (открытый/подготовленный) 2 VideoView, один из которых был видимым, другим невидимым и остановился, и задница вскоре вы получите обратный вызов OnCompletionListener, сделайте 2-й вид видимым, запустите его и скройте 1-й.
В то же время, когда играет 2-й, вы можете вызвать open/prepare на 1st VideoView, чтобы открыть/подготовить другой файл.
Ответ 6
@user1263019 - вы могли переносить Android 4.0 MediaPlayer в свое приложение? Я сталкиваюсь с той же проблемой, и я ищу хорошее решение. У моего случая есть изображение поверх SurfaceView, которое должно быть скрыто, чтобы показать воспроизведение видео, но есть разрыв между вызовом start() и фактическим началом видео. Единственным решением до сих пор является запуск Thread, который проверяет, есть ли getCurrentPosition() > 0.
По теме - я думаю, что невозможно безщелезное воспроизведение, хотя Winamp претендует на такие способности. Грязный взлом состоит в том, чтобы подготовить второго игрока за несколько секунд до конца воспроизведения первого игрока, а затем вызвать start() второго игрока на 100-200 мс до окончания воспроизведения.
Ответ 7
В вашей реализации exoplayer (или медиаплеере) используйте обработчик для повторной отправки runnable во время воспроизведения, который получает текущее время отслеживания и передает его на обратный вызов:
public interface MediaAction {
public void onTrackingChanged(long currentPosition);
}
public class ExoPlayerImplementation implements Exoplayer {
..
private MediaAction mediaActionCallback;
public void setMediaActionCallback(MediaAction ma) {
mediaActionCallback = ma;
}
public void releaseMediaAction() { mediaActionCallback = null; }
private Handler trackingCallback = new Handler(Looper.getMainLooper());
Runnable trackingTask;
private Runnable getTrackingTask() {
Runnable r = new Runnable {
@Override public void run() {
long currentPosition = getCurrentPosition();
if (mediaActionCallback != null) {
mediaActionCallback.onTrackingChanged(currentPosition);
}
// 60hz is 16 ms frame delay...
trackingCallback.postDelayed(getTrackingTask(), 15);
}
};
trackingTask = r;
return r;
}
public void play() {
// exoplayer start code
trackingCallback.post(getTrackingTask());
}
public void pause/stop() {
trackingCallback.removeCallbacks(trackingTask);
}
..
}
И теперь вы можете отслеживать, когда текущая позиция фактически изменилась, - если она изменилась, вы можете отобразить вид вывода видео или просмотреть/удалить предварительный просмотр (т.е. использовать MediaExtractor для захвата исходных кадров, наложения в виде предварительного просмотра в ImageView затем скрывается, когда текущая позиция увеличивается). Вы можете сделать этот код более полным, объединив его с слушателем состояния: тогда вы знаете, буферизуете ли вы (проверяете положение буферизации по сравнению с текущей позицией), фактически играете, приостанавливаете или останавливаете с помощью соответствующих обратных вызовов (в MediaAction). Вы можете применить этот метод к классам MediaPlayer и ExoPlayer (поскольку это всего лишь интерфейс и обработчик).
Надеюсь, что это поможет!