Agregar otros códecs de video / soporte de DVD a JavaFX 2.2

Actualizar:

Dado que el lado de los medios de JFX ha sido de origen abierto, he investigado esto y es posible, pero es necesario cambiar y reconstruir el código fuente de JFX (tanto en partes de Java como de C.) El proceso se describe aquí para cualquiera que quiera pruébalo. Añado compatibilidad con MKV en ese ejemplo, pero debería ser muy similar para otros complementos.

El rest de la pregunta es principalmente histórica, pero la dejaré aquí para referencia.

Fondo

Hasta ahora, he usado VLCJ para reproducir videos en mi aplicación. Funciona, pero si es posible me gustaría ver si puedo alcanzar un nivel similar de soporte para códecs comunes migrando a JavaFX y ahorrándome mucha molestia con múltiples máquinas virtuales y cosas así que VLCJ necesita reproducir múltiples videos de manera confiable. No entraré aquí, pero veré mi respuesta a esta pregunta si está interesado en los detalles. También está el tema de la compatibilidad multiplataforma, funciona bien en Mac y Linux, pero todavía no he resuelto cómo mostrarlo en Mac (creo que hay alguna seguridad para evitar que un proceso acceda a otro nativo). componentes, pero de nuevo eso está más allá del scope de esta pregunta.)

Todo se reduce al hecho de que, aunque funciona, es mucho mantenimiento y trabajo molesto con varias máquinas virtuales y un puente estable si hay otra solución que sería más fácil. VLC tiene un nivel de soporte bastante legendario para reproducir prácticamente cualquier cosa, por lo que he seguido hasta el momento, y me gustaría ver si puedo obtener un resultado similar en JavaFX, o al menos si es posible. proporcionar los medios para hacerlo de forma cruzada.

Investigación

JavaFX 2.0 admite video, ¡genial! Pero por el momento, la línea oficial es compatible con “FLV que contiene video VP6 y audio MP3”. ¿Hay alguna forma de ampliar esto para agregar compatibilidad con más códecs? No hay un códec rígido que me gustaría admitir, es más un caso de tantos como puedo, así que estoy buscando un método extensible para hacer lo anterior.

Me preguntaba si reproduciría video para códecs instalados de forma nativa en la máquina y que simplemente no se anuncia como tal (porque esa funcionalidad obviamente depende de la máquina y no de plataformas cruzadas). Pero no hay dados, he intentado un número de formatos comunes y realmente se niega a jugar nada más de lo que dice.

Al mirar JavaFX 1.3, también es compatible con otros códecs dependientes de la plataforma según dónde esté instalado . ¿Hay alguna forma de obtener este comportamiento con JavaFX 2? ¿O está previsto para un lanzamiento posterior? No he podido encontrar ninguna información al respecto en la hoja de ruta ni ningún comentario de Oracle al respecto.

Lo único que pude encontrar buscando exhaustivamente es aquí, lo que implica que puede ser posible, pero nadie parece saber cómo. También me gustaría saber si está basado en GStreamer, ¿por qué todos los formatos soportados por GStreamer tampoco están incluidos por defecto?

En términos de reproducir DVD con JavaFX, no tengo absolutamente nada, así que supongo que es un no-go en este momento. Si alguien tiene alguna idea o información, soy todo oídos.

Otros enfoques

Un enfoque que estaba medio preguntándome que podría ser posible es excluir el JMC jar del viejo JavaFX como se describe aquí e intentar hacerlo funcionar junto con JavaFX 2. ¿Supongo que nadie ha tenido suerte con ese enfoque o algo similar?

Todo falla, si alguien tiene información o enlaces sobre si / cuando el soporte para códecs adicionales será soportado de manera inmediata, entonces estaría interesado en escuchar eso también. O si alguien tiene información de contacto para alguien en Oracle, podría pedir que también sea apreciada. He estado esperando soporte de video decente en Java desde hace un tiempo, y supongo que esto se reduce a tratar de averiguar si JavaFX es la respuesta a esto, o simplemente otro bash a medias que nunca jugará más de lo que lo hace en este momento! Espero que no sea esto último, pero aún no he visto mucho para mostrar que ese es el caso.

Créame, siento y conozco su frustración. He reflexionado sobre esto por un tiempo, pero tuve que usar medios no directos para resolver mis problemas.

Hay muchas formas de evitar esto, cada una con limitaciones, pero depende de lo que funcione para usted:

  1. Los documentos dicen que WebView funciona con HTML5, que reproduce videos compatibles con la plataforma (aunque lamentablemente no es flash). Si usar una vista web para reproducir video funciona para usted, puede probar esto. Incluso puede dibujar sobre él con otros nodos.

  2. Reproductor portátil VLC! Si tal vez estás desarrollando algún tipo de aplicación de proyector / director y quieres un video a pantalla completa, puedes hacer que el reproductor VLC portátil reproduzca el video en pantalla completa en una pantalla con sus controles en la otra. Usé esta solución y funciona bastante bien para Mac y Windows. 🙂 Lo único es que no puede dibujar nodos en el video ya que es una aplicación externa, con la ilusión de tener un video a pantalla completa de su aplicación.

  3. Si alguna vez necesita utilizar el poder del flash dentro de su aplicación javafx 2.0, entonces use un navegador basado en swt (o algo así como DJ Project si es un Swinger) ya que son compatibles con todas las características de su navegador nativo.

Ahora he logrado comstackr la compatibilidad MKV en JavaFX con éxito, y se necesita un poco, pero no mucho esfuerzo en la capa nativa también. Vea aquí la discusión que lo rodea, y aquí el resultado enviado como un parche / boleto JIRA.

He escrito una guía mucho más completa sobre el proceso aquí, que puede ser de interés para cualquier otra persona que quiera seguir esta ruta.

Lo que sigue es mi breve investigación antes de analizar seriamente el soporte de otros medios, aunque lo dejo aquí para referencia.

Ahora que JFX8 ha sido lanzado y es de código abierto, he dedicado un poco de tiempo a ver cómo se podría hacer esto, y si se podría hacer sin parchar la fuente JFX. Desafortunadamente, la respuesta a este último punto es casi nula, al menos no sin hacks de manipulación de bytecode horribles. Puedo ver esto más prácticamente en una fecha posterior, pero documentaré lo que he calculado hasta ahora de la fuente disponible.

La magia comienza desde el constructor Media , que es donde MediaException la MediaException (con el indicador MEDIA_UNSUPPORTED si intentas reproducir un formato no compatible). Desde allí crea el Localizador , cuyo constructor asegura que la URL sea compatible. Su método init() se llama en un subproceso separado, que realiza una comprobación de cordura en la cadena de URL, lee el archivo y luego intenta averiguar cuál es el formato.

El código relevante para esta parte del método es así:

 if (scheme.equals("file") || scheme.equals("jar")) { InputStream stream = getInputStream(uri); stream.close(); isConnected = true; contentType = MediaUtils.filenameToContentType(uriString); // We need to provide at least something } if (isConnected) { // Check whether content may be played. // For WAV use file signature, since it can detect audio format // and we can fail sooner, then doing it at runtime. // This is important for AudioClip. if (MediaUtils.CONTENT_TYPE_WAV.equals(contentType)) { contentType = getContentTypeFromFileSignature(uri); if (!MediaManager.canPlayContentType(contentType)) { isMediaSupported = false; } } else { if (contentType == null || !MediaManager.canPlayContentType(contentType)) { // Try content based on file name. contentType = MediaUtils.filenameToContentType(uriString); if (Locator.DEFAULT_CONTENT_TYPE.equals(contentType)) { // Try content based on file signature. contentType = getContentTypeFromFileSignature(uri); } if (!MediaManager.canPlayContentType(contentType)) { isMediaSupported = false; } } } // Break as connection has been made and media type checked. break; } 

De esto podemos ver que se realiza un primer bash “tonto” de capturar el contenido del archivo en función de su nombre (esto es lo que hace MediaUtils.filenameToContentType() . Hay algunos casos especiales para verificar diferentes tipos de archivos wav, pero si que falla luego recurrimos a un cheque más inteligente que mira la firma del archivo real. Ambos controles están en MediaUtils . Esta última comprobación es mucho más extensa y examina los primeros bytes del archivo para ver si puede resolver un formato de esa manera. Si no puede, se rescata y arroja la excepción que luego aparece como nuestra temida bandera MEDIA_UNSUPPORTED .

Sin embargo, si el tipo se identifica correctamente, todavía hay otro obstáculo que superar: tiene que ser compatible con la plataforma actual. Algunas plataformas se cargan dinámicamente dependiendo del entorno, sin embargo, la GSTPlatform siempre existe, por lo tanto, deberíamos incluir aquí cualquier formato adicional (universal). Esto es relativamente simple, existe una matriz CONTENT_TYPES que solo contiene la matriz de formatos admitidos.

Desafortunadamente la clonación del repository JavaFX parece estar fallando para mí en este momento, de lo contrario trataría de poner algo de esto en práctica. Pero en lugar de lo anterior, ¿qué necesita suceder para agregar soporte para otros formatos? En realidad, no parece muy difícil.

  1. En MediaUtils , se necesita agregar soporte al método filenameToContentType() para manejar la nueva extensión de archivo. Esto es trivial.

  2. En la misma clase, se necesita agregar soporte al método fileSignatureToContentType() para calcular el tipo de archivo en función de su firma. Esto es un poco más complejo, pero aún así no está mal. Esto incluso puede ser opcional, ya que el código actual solo parece utilizar esto como una alternativa si el formato no se identifica correctamente (o no se identifica) de la extensión del archivo. Aquí puede encontrar una lista completa de firmas de archivos para diferentes formatos, lo que debería ayudar con esta tarea.

  3. En GSTPlatform, el nuevo tipo de contenido debe agregarse a la lista de tipos de contenido admitidos.

En lo que respecta a Java, esto parece ser todo lo que hace falta para que acepte el tipo de contenido y, al menos, intente pasarlo a la capa nativa de Gstreamer .

Sin embargo, no soy un experto en GStreamer, así que aunque soy consciente de que hay muchos más formatos que puede manejar y jugar que JavaFX actualmente rechaza, no estoy seguro de cómo exactamente han eliminado esta capacidad. Definitivamente lo han hecho en la capa de Java anterior, pero también pueden haberlo hecho en el nivel nativo de GStreamer; en este momento no estoy seguro.

Supongo que han realizado algunos cambios en GStreamer para JFX8, pero en este momento no figuran en la página del proyecto relevante , por lo que es bastante difícil determinar exactamente qué han cambiado para esta versión.

El siguiente paso sería tomar la fuente JFX8, comstackr con los cambios propuestos anteriormente para un nuevo tipo de contenido, y luego ver qué errores (si hay alguno) ocurren en el nivel nativo, y luego tomarlo desde allí.

Y ahora, Javafx2.1 finalmente es compatible con mp4 H.264, por lo que ahora debería estar listo para continuar sin las acrobacias publicadas anteriormente. 🙂

El diseño de la API no parece tener soporte para rodar sus propios códecs. Prácticamente todas las clases son finales (por ejemplo, VideoTrack, Media, MediaPlayer, etc.). Supongo que la deencoding de video actual se realiza con clases internas en el presente, lo que significa que no hay forma de anularlas.

Existe un plan para Open Source JavaFX 2.0 , sospecho a medida que nos acercamos al lanzamiento de JDK8. Esperemos que cuando lo hagan podamos ver cómo resuelven sus códecs desde el constructor Media(String source) y ver si podemos conectarnos de alguna manera.

Solicitudes actuales de funciones abiertas para esto en el sistema de seguimiento de fallas de JavaFX:

  • JDK-8091656 Lista de deseos para obtener más soporte de formato de medios
  • JDK-8091755 Los medios deben ser compatibles con InputStream

Lea las solicitudes de funciones vinculadas y los comentarios asociados sobre ellas para comprender su estado actual (o la falta de eso 😉 para la versión de distribución de JavaFX que está utilizando.

Tenga en cuenta que para la Media API basada en InputStream, uno de los comentarios posteriores de un desarrollador JavaFX es “Propongo que consideremos esto para JDK 10”, así que supongo que puede ser una posibilidad en el futuro …

También tenga en cuenta que si no está seguro de si JavaFX tiene actualmente soporte incorporado para un tipo de encoding dado o no, se proporciona una descripción general completa de las codificaciones de medios compatibles y los tipos de contenedores de medios en el javadoc para el paquete javafx.media (solo asegúrese de que revisa la versión de javadoc que coincide con su versión de JavaFX).

Aquellos que puedan estar interesados ​​en otras soluciones para al menos obtener un video para jugar desde JavaFX, incluso si se trata de un tipo de medios no admitidos nativamente por JavaFX y no desea piratear la compatibilidad nativa con medios JavaFX solo para que su video se reproduzca juego, también puede ver mi respuesta a la pregunta relacionada:

  • Reproducción de H265 HEVC en un cliente JavaFX