La situación GStreamer

Recientemente mencioné el lío que había montado alrededor de GStreamer y que merecía una entrada para él solíto. Vamos a ello.

GStreamer, que originalmente comenzó como un componente del proyecto GNOME, actualmente se ha convertido en una biblioteca independiente del sistema de escritorio utilizado que gestiona la reproducción multimedia tanto de audio como de video. Se basa en una arquitectura de plugins, que le permite añadir soporte para todo tipo de formatos de audio y video, tanto como entrada (capturadores, editores) como salida (reproductores, ...).

GStreamer consiguió la independencia de escritorio deshaciéndose de todas las dependencias de GNOME. Actualmente sólo depende de GLib2.0. Ello le permite, por ejemplo, que pueda ser usado en escritorios basados en Qt —como KDE— a través de los bindings Qt. De esta forma GStreamer se ha convertido en parte de la "fontanería" estándar de un sistema Linux (aunque funcione además en otras plataformas). Con GStreamer, cualquier aplicación tiene acceso a un API único que le proporciona servicios multimedia con aceleración por hardware —si la hay—, independientemente si es una aplicación de texto o gráfica, del toolkit gráfico empleado o del lenguaje de programación que utilice.

O al menos esa es la teoría. En la práctica las cosas se vuelven un poco más complicadas. Para empezar, porque existen 2 versiones estables no compatibles: la vieja 0.10 y la nueva 1.x (actualmente 1.2). En Debian, cuyo sistema de paquetes no soporta tener instaladas en paralelo varias versiones de un mismo paquete, lo que se hace en estos casos es incorporar la versión en el nombre. De esta forma, tenemo paquetes gstreamer0.10* y paquetes gstreamer1.0*, y lo mismo con otros nombres de paquete.

Además, los plugins de gstreamer están divididos en tres conjuntos:

  • Good: plugins de alta calidad, bajo la licencia preferida por el proyecto (LGPL).
  • Bad: plugins de baja calidad, o pendientes de un revisión, o carentes de algo.
  • Ugly: plugins de buena calidad pero que pueden tener problemas de distribución (licencias, patentes, etc).

A estos hay que añadir el conjunto de plugins esenciales llamados Base.

Si hacéis las cuentas, salen 5 paquetes source por versión, es decir un total de 10 paquetes source básicos:

¡Y estos son sólo los básicos! Luego hay más, como los de ffmpeg/libav, fluendo-mp3 y más. Si además se tiene en cuenta la costumbre de Debian de trocear cada paquete source en varios paquetes binarios —arquitecturas aparte—, no os extrañará saber que me salen 96 paquetes binarios (contando 12 virtuales) entre ambas versiones.

Dejadme mostraros un gráfo con las dependencias1 entre paquetes gstreamer. Para que no sea un embrollo de líneas, lo limitaré a los paquetes que tengo instalados:

Dependencias de GStreamer 1.0 instaladas en mi
sistema

(Ampliar - Fichero .dot)

Leyenda: Las flechas negras representan dependencias (Depends:) y las rojas recomendaciones (Recommends:). Los paquetes de color naranja son paquetes pertenecientes a GStreamer (de ellos los naranjas oscuro son bibliotecas). Los paquetes azul claro son paquetes adicionales GStreamer y los blancos son paquetes instalados que dependen de ellos.

Una de las prácticas del empaquetado Debian consiste en separar bibliotecas libXXX.so de sus paquetes madre. Aquí por ejemplo tenemos gstreamer1.0-plugins-base y libgstreamer-plugins-base1.0-0, o gstreamer1.0-x y libgstreamer1.0-0 (por alguna razón que desconozco gstreamer1.0-plugins-bad tiene un paquete separado con biblioteca mientras que Good y Ugy no). Esta división tiene que ver con la forma de funcionar de los paquetes .deb (por ejemplo, se invoca ldconfig tras la instalación o el borrado de un paquete que contiene una biblioteca).

Esta división no tendría demasiado impacto en el grafo de dependencias si no fuera porque, debido también a cómo se construyen los paquetes .deb, se establece una dependencia directa entre todo paquete que usa una biblioteca y el paquete de la biblioteca (por ejemplo tumbler con libgstreamer1.0-0 y libgstreamer-plugins-base1.0-0), independientemente de si esa biblioteca ya tenía una dependencia indirecta a través de otro.

Mejor pongamos un ejemplo. Imaginemos el paquete A, y su biblioteca asociada en el paquete libA. Ambos tienen obviamente una dependencia:

Dependencia A a libA

El paquete B depende de A y usa la biblioteca libA. Se podría esperar que B solo tuviera como dependencia A, ya que libA es una dependencia indirecta (pero obligatoria) a través de A:

Dependencia B a A y A a libA

Sin embargo lo que ocurre en la realidad es que B tiene como dependencias tanto A como libA:

Dependencia B a A y a libA

Ahora extended esto a los varios paquetes en los que está dividido GStreamer, y entenderéis el motivo del lío de paquetes.

No siempre que existe la dependencia B → libA, existe también la B → A, como en el caso mencionado de tumbler arriba. Es más, ni libgstreamer-plugins-base1.0-0 ni libgstreamer1.0-0 dependen, recomiendan ni sugieren sus correspondientes paquetes madre. Esto plantea dos cuestiones: cuando se divide un paquete source A en A y libA ¿hasta que punto es necesario A? Y si A es necesario para el funcionamiento de libA, pero libA no obliga a A a estar instalado mediante una dependencia, entonces ¿cómo se garantiza que A está instalado? Por ejemplo en el caso de arriba, si gstreamer1.0-plugins-base no estuviera instalado por otras dependencias ¿fallarían las invocaciones de tumbler a los .so contenidos en libgstreamer-plugins-base1.0-0?

Por si hubiera pocas dependencias, aún no hemos tenido en cuenta los paquetes de la versión 0.10 de gstreamer. Así es cómo están ahora mismo en mi sistema:

Dependencias de GStreamer 0.10 instaladas en mi
sistema

(Ampliar - Fichero .dot)

GStreamer 0.10 está declarada obsoleta, y no debería usarse en programas nuevos. Sin embargo, todavía existen muchos programas que migrar a la nueva versión, y eso se observa claramente en el anterior gráfico. Varias de las aplicaciones que uso (exaile, workrave, subtitleeditor) usan todavía GStreamer 0.10. Y lo que es más grave: el escritorio Xfce 4.10 depende directamente de la versión antigua (aunque algunas partes como tumbler hayan sido ya migradas), lo que significa que no me puedo deshacer de ella y tengo que mantener ambas versiones por el momento.

Si calculáis todas las dependencias inversas de GStreamer 0.10, veréis que un gran número de aplicaciones todavía la emplean, con lo que la transición me temo que durará, y habrá que convivir con ambas versiones instaladas durante mucho tiempo.

Conclusiones

Puede que toda la situación con los paquetes GStreamer sea un follón, pero ¡oye! para eso está el sistema de paquetes, y para eso los mantenedores se encargan de establecer las dependencias entre los mismos, ¿no? El problema es cuando ese sistema de dependencias no lleva a los resultados esperados.

Para mí está claro que hay un problema cuando, por ejemplo, tumbler depende de funcionalidad de GStreamer que no instala, recomienda o sugiere, y no sé si es algo achacable a tumbler o a GStreamer. Me imagino que ambos tendrán sus buenas razones para no hacerlo, pero el resultado final de cara al usuario es que (dependiendo de los paquetes que tenga instalados) algo falla. Y no hay una forma clara de saber qué falla, por qué falla, o cómo repararlo. Confías en las dependencias del sistema de paquetes, pero éstas me han demostrado que no siempre son de fiar. Y las dependencias y paquetes han llegado a tal nivel de complejidad que cada vez en más ocasiones es difícil tener un panorama general de lo que está pasando, y por lo tanto detectar esos fallos.

Para luchar contra este creciente complejidad hace falta una visión de conjunto del sistema de paquetes, pero no sé si en Debian, con una estructura en la que cada empaquetador es el rey de sus paquetes, están preparados para afrontar este problema.

:wq


  1. Estos gráficos han sido realizados mediante apt-rdepends y graphviz, y un poco de intervención manual. 

blogroll

social