Android: MediaPlayer Воспроизведение видео без зазоров или без швов - PullRequest
25 голосов
/ 07 октября 2010

Я могу нормально воспроизводить видео, применяя OnCompletionListener , чтобы установить источник данных в другой файл. Там нет проблем. Я звоню reset () и prepare () просто отлично.

Что я не смог выяснить, так это как избавиться от мерцания экрана с промежутком в 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);
        }
    }

Ответы [ 7 ]

4 голосов
/ 14 марта 2012

У меня тоже та же проблема, что описана ниже по ссылке

VideoView Исчезает на секунду при изменении видео

Но эта проблема не возникнет, если вы попытаетесь использовать Android 4.0+ (ICS). Я начал портировать VideoView.java и MediaPlayer.java с 4.0 на мое приложение, но это кажется сложным и до сих пор не повезло. В основном это похоже на ошибку в нативном коде старых версий.

2 голосов
/ 27 февраля 2012

после слишком большого количества потраченного времени, пытаясь понять, как воспроизводить последовательные видео без «пробела», я склоняюсь к невозможному. если, конечно, вы не можете копать до исходного уровня и реализовывать свой собственный проигрыватель, медиаплеер Android просто не поддерживает плавное воспроизведение на данный момент.

1 голос
/ 28 февраля 2012

Я не думаю, что это возможно.

Причина: Mortplayer также был доступен для Windows Mobile, и одной из его сильных сторон было то, что он поддерживал игру без пауз.Однако этого не происходит в версии приложения для Android, и сам разработчик пишет, что SDK не позволяет его на xda: http://forum.xda -developers.com / showpost.php? P = 5364530 & postcount = 5

HTH, Daniele

1 голос
/ 28 февраля 2012

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

Я думаю, что задержкавы видите, что медиаплеер буферизирует входной файл.Так, может быть, вы можете определить обоих игроков в начале?Вы должны определить источник данных и подготовить обоих игроков, но только запустить одного из них.

Тогда в вашем onCompletionListener вы можете перевернуть их вместо сброса существующего и установки нового источника данных.

  player.release();
  player = flipPlayer;
  flipPlayer = null;
  player.start();

Очевидно, что вам нужно либо использовать другой onPreparedListener для flipPlayer, либо вывести player.start () из onPrepare.(Так как вы звоните синхронно, я бы не подумал, что это проблема).

0 голосов
/ 28 августа 2015

В вашей реализации exoplayer (или медиаплеере) используйте обработчик для многократной публикации исполняемого файла во время воспроизведения, который получает текущее время отслеживания и передает его обратному вызову:

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 (так как это всего лишь интерфейс и обработчик).

Надеюсь, это поможет!

0 голосов
/ 22 июня 2012

@ user1263019 - вы смогли портировать Android 4.0 MediaPlayer на ваше приложение?Я сталкиваюсь с той же проблемой, и я ищу хорошее решение.В моем случае изображение поверх SurfaceView должно быть скрыто, чтобы показать воспроизводимое видео, но между вызовом start () и фактическим началом видео есть разрыв.Пока единственное решение - запустить поток, который проверяет, равен ли getCurrentPosition ()> 0.

По теме - я думаю, что невозможно воспроизводить без пауз, хотя Winamp утверждает, что такие возможности есть.Грязный хак состоит в том, чтобы подготовить второго игрока за несколько секунд до окончания воспроизведения первого игрока, а затем вызвать start () второго игрока за 100-200 мс до конца воспроизведения.

0 голосов
/ 28 февраля 2012

Вы пытались иметь готовые (открытые / подготовленные) 2 VideoView, один из которых был видимым, другой невидимым и остановленным, и вскоре вы получаете обратный вызов OnCompletionListener, делаете 2-й видимым, запускаете его и скрываете 1-й.В то же время во время воспроизведения 2nd вы можете вызвать open / prepare на 1st VideoView, чтобы открыть / подготовить другой файл.

...