Просмотр текстур и растровое изображение

У меня есть TextureView, которое отображает растровое изображение (изображение заполнителя), и когда пользователь загружает видео, TextureView должно показать видео.

Мне удалось воспроизвести видео в текстурном виде и показать растровое изображение в текстурном виде, но когда все было сделано последовательно, я просто получил черный экран.

В моем методе onSurfaceTextureAvailable я рисую растровое изображение на виде поверхности следующим образом:

@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
    Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.ic_add_clip);
    Canvas canvas = lockCanvas();
    canvas.drawBitmap(bm, (width/2)-(bm.getWidth()/2), (height/2)-(bm.getHeight()/2), null);
    unlockCanvasAndPost(canvas);
}

Когда пользователь выбирает видео из своей галереи, я загружаю Uri в медиаплеер и устанавливаю поверхность для медиаплеера. Но растровое изображение все еще отображается. Я попытался удалить растровое изображение, очистив холст, и он действительно удаляет растровое изображение, но тогда текстурный вид просто черный и не будет отображать видео.

public void setMediaPlayer(MediaPlayer mediaPlayer) {
    // Canvas canvas = lockCanvas();
    // canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
    // unlockCanvasAndPost(canvas);

    Surface s = new Surface(getSurfaceTexture());
    mMediaPlayer = mediaPlayer;
    mMediaPlayer.setSurface(s);
    mMediaPlayer.setOnPreparedListener(this);
}

Что-то говорит мне, что вид поверхности, который я использую для отображения видео, находится за растровым изображением, которое я рисую в TextureAvailble. И когда я пытаюсь очистить холст, я также очищаю поверхность, которую хочет использовать медиаплеер. Какие-либо решения?

2 ответа

Решение

Ваш подход не сработает.

Поверхность - это очередь буферов с отношениями производитель-потребитель. Может быть только один производитель за раз, и у вас есть два производителя (Canvas и MediaPlayer). Когда вы звоните mMediaPlayer.setSurface() он присоединяет MediaPlayer; когда ты звонишь lockCanvas() он прикрепляет холст. Вам нужно отсоединить один, прежде чем вы сможете прикрепить другой.

(Проверьте вывод logcat - там, вероятно, есть некоторые "уже подключенные" жалобы.)

Проблема в том, что, хотя вы должны иметь возможность отключить MediaPlayer, вы не можете отключить Canvas. Там просто нет вызова, который делает это. Это неудачный артефакт в API. (Подтверждено через 4.4 "KitKat", и я сомневаюсь, что это изменилось с тех пор.)

У вас есть несколько вариантов:

  1. Нарисуйте растровое изображение с GLES вместо. Вы можете увидеть пример в игре Grafika PlayMovieSurface - см. clearSurface() метод, который просто очищает экран. С GLES, вы можете прикрепить и отсоединить от поверхности.
  2. Преобразуйте ваше растровое изображение в однокадровое видео и воспроизводите его через MediaPlayer.
  3. Поместите ImageView поверх окна видео с помощью FrameLayout. Скройте ImageView во время воспроизведения видео.

Я должен добавить, что на самом деле я не пытался отсоединить MediaPlayer от Surface. MediaCodec более низкого уровня работает таким образом, как показано плеером Grafika, поэтому я предполагаю, что MediaPlayer также будет отсоединяться без ошибок. Однако для вашего случая использования #3, вероятно, самое простое решение, которое не требует прикрепления / отсоединения гимнастики.

Вы можете использовать открытые окна для рисования растрового изображения на поверхности дисплея, а затем рисовать видеокадр таким же образом. Я так и сделал, и все работает отлично.

Другие вопросы по тегам