JavaFX MediaPlayer: заморозка петли MP4, искажение звука, Windows 7 - PullRequest
0 голосов
/ 26 сентября 2018

У нас проблема с JavaFX MediaPlayer уже более месяца.Мы прочитали и попробовали все подобные проблемы здесь, ничего не получалось.Простейший пример: это информационное приложение с 2 видео из папки, воспроизводимой непрерывно в цикле.Через некоторое время (иногда 2 часа, иногда 2 дня) видео начинает замедляться, продолжительность увеличивается, время от времени останавливается, звук искажается.

ОС: win7 64b (Ultimate) SP1 Процессор Intel Celeron N3150 @ 1.6 ГГц 8ГБ Ram java 1.8 и 1.10, 64b

Пробовал: обновление ОС, последнее.Обновления драйверов, другие драйверы.JDK 64b, 1.8 последние обновления, JDK 1.10 последние.Изменение кода (добавление удаления, закрытие, установка нуля, кэширование ... каждое предложение по стеку) Изменение кодировщиков видео: MPEG-4, H.264 и H.264-HD, 1500/2000/4000/8000 кбит / с, 25 кадров в секунду Изменение разрешения: 1280x720, звук: AAC, 1 и 2 канала, 48 и 44 кГц, битрейт 128 кбит / с и другие.Пробные видео без звука.

Практически каждая возможная комбинация этих видео / звуковых кодеров, битрейта, разрешения, частоты кадров ... Мы профилировали на утечки памяти: память растет некоторое время и перестает расти.Это нормально (мы думаем).

Ничто из того, что мы пробовали, не сработало.Нет ошибок, нет исключений на MediaView, Media, Player.Системных событий нет.

Запутано: мы заметили, что при нормальной работе CPU составляет 20-30%, но когда видео начинает зависать, оно ниже, 5-15%.

Код (последняя версия):

import java.io.File
import akka.actor.{Actor, ActorLogging, Props, Timers}
import akka.pattern._
import com.commercial.activity.MMDriver.ShowNextMedia
import javafx.event.EventHandler
import javafx.scene.media.{Media, MediaErrorEvent, MediaPlayer, MediaView}

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future

object MMDriver {
  def props(rootFolder: File, allowedExtension: List[String],
            showMedia: (MMedia) => Unit): Props = Props(new MMDriver(rootFolder, allowedExtension, showMedia))

  case object Start
  case class MediaCreated(list: List[MMedia])
  case object ShowNextMedia
}

class MMDriver(rootFolder: File, allowedExtensions: List[String],
               showMedia: (MMedia) => Unit) extends Actor with ActorLogging with Timers {

  object TimerKey
  var started = false
  var medias = List[MMedia]()
  var index = 0

  override def receive: Receive = {

    case MMDriver.Start if (!started) =>
      started = true
      Future {
        loadMedia(rootFolder, allowedExtensions)
          .map { file =>
            val media = new Media(file.toURI.toURL.toString)
            val player = new MediaPlayer(media)
            //next video
            player.setOnEndOfMedia(new Runnable {
              override def run(): Unit = {
                self ! ShowNextMedia
              }
            })
            val mediaView = new MediaView(player)
            setErrorHandlers(player, media, mediaView)
            MMedia(file, media, player, mediaView)
          }
      }
        .map(media => MMDriver.MediaCreated(media.toList))
        .pipeTo(self)

    case MMDriver.MediaCreated(list) =>
      medias = list
      if (medias.nonEmpty) {
        self ! ShowNextMedia
      }

    case MMDriver.ShowNextMedia =>
      val media = medias(index)
      showMedia(media)
      index = index + 1
      index = index % medias.size

    case msg =>
      log.info("not processed message {}", msg)
  }

  private def loadMedia(folder: File, allowedExtensions: List[String]): Array[File] = {
    folder.listFiles()
      .filter { file =>
        allowedExtensions.exists(file.getName.endsWith(_))
      }
  }

  private def setErrorHandlers(player: MediaPlayer, media: Media, mediaView: MediaView): Unit = {
    player.setOnError(new Runnable {
      override def run(): Unit = {
        log.error(player.getError, "error in player")
      }
    })

    media.setOnError(new Runnable {
      override def run(): Unit = {
        log.error(media.getError, "error in media")
      }
    })

    mediaView.setOnError(new EventHandler[MediaErrorEvent] {
      override def handle(event: MediaErrorEvent): Unit = {
        log.error(event.getMediaError, "error in mediaView")
      }
    })
  }

}

Любое предложение, что попробовать дальше - у нас нет идей?!

...