Member of The Internet Defense League Últimos cambios
Últimos Cambios
Blog personal: El hilo del laberinto Geocaching

Instalación de "mplayer" sobre Solaris 10

Última Actualización: 20 de enero de 2008 - Domingo

"mplayer" es un reproductor de audio/video de última generación. En este caso en particular estoy interesado en su componente "mencoder", para generar videos. En concreto, me interesa poder utilizar mis servidores Solaris, que tienen CPUs, disco y memoria para parar un tren, y están muy aburridos.

Como no podía ser de otra forma, tener una instalación "mplayer" completa y eficiente bajo Solaris 10 es un proceso trabajoso, por dos motivos: dependencia de un montón de librerías y programas que hay que instalar previamente (cada uno con sus propias dependencias), y que muchos de esos componentes contienen dependencias implícitas de Linux o las herramientas GNU, y hay que retocar para funcionar en Solaris.

Es muy importante señalar que mi objetivo es crear una instalación "mplayer" para poder utilizar su componente "mencoder". Dicho componente se utiliza para crear videos. Éste es un proceso que consume toda la memoria y potencia de CPU que le puedas dar, así que es tarea perfecta para mis servidores Solaris, que son unas bestias de cuidado. Como es natural, estos servidores ni siquiera tienen un monitor conectado, al margen de que los tengo físicamente al otro lado del edificio, así que la parte de salida de audio y video no me interesan.

Por tanto, un usuario Solaris que necesite "mplayer" como reproductor de audio/video tendrá que refinar el proceso un poco más.

Adicionalmente mis sistemas Solaris están muy retocados. En especial, tienen versiones actualizadas de las herramientas de desarrollo GNU (gmake, GCC, binutils, autoconf y familia, etc). Los pasos que se describen no funcionarán tal cual en una instalación Solaris "limpia".

Un último detalle: mis máquinas son AMD Opteron. Las cosas pueden cambiar trabajando con CPUs Sparc, sobre todo en lo que a rendimiento se refiere.

Una vez aclarados estos punto, he aquí la epopeya.

Primeros pasos

Me descargo la versión actual de mplayer, que en este momento es la 1.0rc2. Tras descomprimirla, ejecuto el "configure". Desactivo el soporte de "iconv" porque me da problemas y no es algo que me interese:

$ ./configure --enable-largefiles --disable-iconv
[...]
Creating config.h
./configure: !: not found
[...]

Tras investigar el asunto, el problema está en la linea 8478 del fichero "configure". En esa linea pone:

[...]
! cmp -s "$TMPH" config.h && mv -f "$TMPH" config.h
[...]

y lo cambiamos por:

[...]
mv -f "$TMPH" config.h
[...]

Volvemos a repetir el "configure". Se ejecuta sin problemas. Compilamos con "make". Tenemos un error de compilación que dice que no puede encontrar la función "inet_ntoa". Nos ocuparemos de ello más adelante. De momento lo que queremos es compilar correctamente, así que hacemos "make distclean; ./configure --enable-largefiles --disable-iconv --disable-network; make". Ahora compila limpiamente; nos ocuparemos de la red más adelante.

En este momento tenemos una versión de "mplayer" (y "mencoder") compilada, pero muchas de las funciones que nos interesan están desactivadas, porque dependen de librerías externas que no tenemos en el sistema (aún). Si revisamos el texto que sale tras el "configure", vemos cosas como:

[...]
Checking for libamr narrowband ... no
Checking for libamr wideband ... no
Checking for libdv-0.9.5+ ... no
Checking for XviD ... no
Checking for x264 ... no (in libavcodec: no)
Checking for libnut ... no
Checking for libmp3lame (for mencoder) ... no
[...]

Vamos a resolver eso.

El primer paso será compilar LAME. En el momento de escribir esto la versión más moderna es la 3.97. Se configura y se compila de forma estándar, sin ningún problema.

El siguiente paso es compilar XviD. En este momento se trata de la versión 1.1.3:

$ cd xvidcore-1.1.3/build/generic
$ ./configure
[...]
checking for yasm... no
checking for nasm... no
configure: WARNING: no correct assembler was found - Compiling generic sources only
[...]
config.status: creating platform.inc

El configurador nos está diciendo que no disponemos de un ensamblador adecuado y que compilará las rutinas críticas desde C genérico, en vez de emplear las rutinas optimizadas en ensamblador (especialmente importantes por emplear las funcionalidades SIMD de nuestra CPU, que incrementan el rendimiento notablemente). Antes de seguir compilaremos "yasm", cuya versión en este momento es la 0.6.2. Este programa se configura y compila sin problemas bajo Solaris 10.

Una vez que instalamos el ensamblador avanzado, volvemos a configurar XivD. Esta vez nos aparecerá:

$ ./configure
[...]
checking for whether to use assembly code... yes
checking for architecture type... ia32
[...]
config.status: creating platform.inc

Ahora usará rutinas en ensamblador nativo. El rendimiento se incrementará notablemente. Mis máquinas son 64 bits, lo cual permite incrementar aún más el rendimiento, pero veremos ese tema más adelante.

Antes de compilar XviD hay que editar el fichero "platform.inc". En la línea 48 hay que cambiar

[...]
SPECIFIC_LDFLAGS=-Wl,-soname,libxvidcore.$(SHARED_EXTENSION).$(API_MAJOR) -shared -Wl,--version-script=libxvidcore.ld -lc -lm
[...]

por

[...]
SPECIFIC_LDFLAGS=-G -h libxvidcore.$(SHARED_EXTENSION).$(API_MAJOR) -lc -lm
[...]

Este cambio es necesario porque estamos usando el "linker" de Solaris, no el de GNU.

Ahora compilamos el código con "make" y lo instalamos con "make install". En mi caso las librerías se instalan en "/usr/local/lib", pero veo dos problemas. Por un lado, me instala un "libxvidcore.a" que no me interesa. Lo borro sin más. Por otro lado me instala un "libxvidcore.so.4.1". Creo un enlace simbólico a ese fichero, llamado "libxvidcore.so.4", y otro apuntando a ese nuevo enlace, llamado "libxvidcore.so" a secas.

Por último vamos a compilar "x264". Al contrario que con el resto de los módulos, los desarrolladores de "x264" no publican versiones oficiales de vez en cuando, sino que tienes que bajarte "la versión del día" y rezar para que no se haya introducido ninguna regresión :-). En mi caso la versión descargada es la 719.

Lo primero es cambiar la primera linea de "configure" de

#! /bin/sh
[...]

a

#!/bin/bash
[...]

A continuación configuramos la librería:

[root@tesalia x264]# ./configure --enable-debug --enable-pic --enable-shared --enable-pthread --extra-cflags=-std=c99
Platform:   X86
System:     SunOS
avis input: no
mp4 output: no
pthread:    yes
gtk:        no
debug:      yes
gprof:      no
PIC:        yes
shared:     yes
visualize:  no

You can run 'make' or 'make fprofiled' now.

Pedimos que se compile con "debug" para que nos mantenga los símbolos en la librería generada. También generaremos una librería compartida. Hay que poner lo de "c99" para que se incluyan varias funciones adicionales en el lenguaje. Pedimos el uso de "threads" para aprovechar todas las CPUs disponibles, ya que la codificación de un video en x264 es un proceso lento.

Tras la configuración, editamos el fichero "config.mak". En la línea de "ECHON" escribimos "/usr/local/bin/echo -n". A continuación cambiamos el "Makefile" de

[...]
$(SONAME): .depend $(OBJS) $(OBJASM)
        $(CC) -shared -o $@ $(OBJS) $(OBJASM) -Wl,-soname,$(SONAME) $(LDFLAGS)
x264$(EXE): $(OBJCLI) libx264.a
        $(CC) -o $@ $+ $(LDFLAGS)
[...]
install: x264 $(SONAME)
        install -d $(DESTDIR)$(bindir) $(DESTDIR)$(includedir)
        install -d $(DESTDIR)$(libdir) $(DESTDIR)$(libdir)/pkgconfig
        install -m 644 x264.h $(DESTDIR)$(includedir)
        install -m 644 libx264.a $(DESTDIR)$(libdir)
        install -m 644 x264.pc $(DESTDIR)$(libdir)/pkgconfig
        install x264 $(DESTDIR)$(bindir)
        ranlib $(DESTDIR)$(libdir)/libx264.a
        $(if $(SONAME), ln -sf $(SONAME) $(DESTDIR)$(libdir)/libx264.so)
        $(if $(SONAME), install -m 755 $(SONAME) $(DESTDIR)$(libdir))
[...]

a

[...]
$(SONAME): .depend $(OBJS) $(OBJASM)
        /usr/ccs/bin/ld -G -h $(SONAME) -o $@ $(OBJS) $(OBJASM) $(LDFLAGS)
x264$(EXE): $(OBJCLI) $(SONAME)
        $(CC) -o $@ $+ $(LDFLAGS)
[...]
install: x264 $(SONAME)
        install -d $(DESTDIR)$(bindir) $(DESTDIR)$(includedir)
        install -d $(DESTDIR)$(libdir) $(DESTDIR)$(libdir)/pkgconfig
        install -m 644 x264.h $(DESTDIR)$(includedir)
        install -m 644 x264.pc $(DESTDIR)$(libdir)/pkgconfig
        install x264 $(DESTDIR)$(bindir)
        $(if $(SONAME), ln -sf $(SONAME) $(DESTDIR)$(libdir)/libx264.so)
        $(if $(SONAME), install -m 755 $(SONAME) $(DESTDIR)$(libdir))
[...]

Este cambio es necesario porque "x264" pasa parámetros como si se tratase del "linker" GNU, cuando en realidad se ejecutará el de Solaris. Además, queremos que el ejecutable utilice la librería dinámica, no la versión estática. De hecho eliminamos las lineas indicadas en negrita porque no quiero instalar la versión estática.

Una vez hecho estos cambios podemos compilar e instalar la librería de forma normal.

Volvemos al código de "mplayer" y lo configuramos otra vez. Ahora vemos:

$ ./configure --enable-largefiles --disable-network
[...]
Checking for XviD ... yes
Checking for XviD two pass plugin ... yes
Checking for x264 ... yes (in libavcodec: yes)
Checking for libnut ... no
Checking for libmp3lame (for mencoder) ... yes
[...]

Vemos que nos detecta correctamente "lame", XviD y x264.

Compilamos e instalamos.

Resultados

Ahora tenemos instalado un "mplayer" (a mí me interesa el componente "mencoder") con las siguientes características:

$ mencoder -oac help
[...]
Available codecs:
   copy     - frame copy, without re-encoding (useful for AC3)
   pcm      - uncompressed PCM audio
   mp3lame  - cbr/abr/vbr MP3 using libmp3lame
   lavc     - FFmpeg audio encoder (MP2, AC3, ...)

$ mencoder -ovc help
[...]
Available codecs:
   copy     - frame copy, without re-encoding. Doesn't work with filters.
   frameno  - special audio-only file for 3-pass encoding, see DOCS.
   raw      - uncompressed video. Use fourcc option to set format explicitly.
   lavc     - libavcodec codecs - best quality!
   vfw      - VfW DLLs, read DOCS/HTML/en/encoding-guide.html.
   qtvideo  - QuickTime DLLs, currently only SVQ1/3 are supported.
   xvid     - XviD encoding
   x264     - H.264 encoding

Todos los módulos están compilados en 32 bits, aunque muchos se benefician de código ensamblador nativo.

Faltan muchas cosas, como el soporte 64 bits, codecs como OGG o Theora, etc. También falta el soporte de red, pero es suficiente de momento.

En cuanto a rendimiento, hago la primera pasada de un "transcoding" con todos los parámetros por defecto de un video, originariamente un MPEG de una hora de duración, a MPEG4 y a x264 (una variante más avanzada del MPEG4 básico):

$ time mencoder *mpg -oac mp3lame -lameopts cbr:br=128 -ovc xvid -xvidencopts pass=1 -o /dev/null
[...]
Video stream: 1285.792 kbit/s  (160724 B/s)  size: 567053773 bytes  3528.120 secs  88208 frames

Audio stream:  128.000 kbit/s  (15999 B/s)  size: 56452075 bytes  3528.255 secs

real    9m42.753s
user    9m18.682s
sys     0m14.872s

$ time mencoder *mpg -oac mp3lame -lameopts cbr:br=128 -ovc x264 -x264encopts bitrate=1300:pass=1 -o /dev/null
[...]
Video stream: 1294.024 kbit/s  (161753 B/s)  size: 570690618 bytes  3528.160 secs  88208 frames

Audio stream:  128.000 kbit/s  (15999 B/s)  size: 56452075 bytes  3528.255 secs
x264 [info]: slice I:551   Avg QP:16.48  size: 22769
x264 [info]: slice P:87652 Avg QP:19.24  size:  6367
x264 [info]: mb I  I16..4: 10.8%  0.0% 89.2%
x264 [info]: mb P  I16..4:  4.7%  0.0%  5.5%  P16..4: 37.7% 22.9% 14.6%  0.0%  0.0%    skip:14.6%
x264 [info]: final ratefactor: 17.14
x264 [info]: kb/s:1294.0

real    36m8.790s
user    34m55.108s
sys     0m9.127s

$ time mencoder *mpg -oac mp3lame -lameopts cbr:br=128 -ovc x264 -x264encopts bitrate=1300:threads=2:pass=1 -o /dev/null
[...]
Video stream: 1294.008 kbit/s  (161751 B/s)  size: 570677136 bytes  3528.120 secs  88208 frames

Audio stream:  128.000 kbit/s  (15999 B/s)  size: 56452075 bytes  3528.255 secs
x264 [info]: slice I:581   Avg QP:16.42  size: 22375
x264 [info]: slice P:87621 Avg QP:19.24  size:  6364
x264 [info]: mb I  I16..4: 11.6%  0.0% 88.4%
x264 [info]: mb P  I16..4:  4.7%  0.0%  5.5%  P16..4: 37.7% 22.9% 14.6%  0.0%  0.0%    skip:14.6%
x264 [info]: final ratefactor: 17.15
x264 [info]: kb/s:1294.0

real    18m44.988s
user    34m54.758s
sys     0m14.461s

El módulo x264 utiliza "threads" y el rendimiento es prácticamente lineal. ¡¡Bien!!.

Soporte de red

La versión de "mplayer" que hemos compilado no tiene soporte de red, lo que me resulta interesante para cosas como la recepción de radio por Internet. Veamos:

$ make distclean
$ ./configure --enable-largefiles --disable-iconv
[...]
$ make
[...]
ld: warning: symbol `__p_class_syms' has differing sizes:
        (file /usr/local/lib/gcc/i386-pc-solaris2.10/4.2.1/../../../libbind.so value=0x60; file /usr/lib/libresolv.so value=0x54);
        /usr/local/lib/gcc/i386-pc-solaris2.10/4.2.1/../../../libbind.so definition taken
Undefined                       first referenced
 symbol                             in file
inet_ntoa                           stream/stream.a(tcp.o)  (symbol belongs to implicit dependency /usr/lib/libnsl.so.1)
ld: fatal: Symbol referencing errors. No output written to mencoder
collect2: ld returned 1 exit status
make: *** [mencoder] Error 1

El segundo problema, es de "inet_ntoa" es fácilmente solucionable, sin más que añadir la librería Solaris "nsl". Para eliminar el primer problema, prescindamos de la librería "bind". Para ello editamos el fichero "config.mak", buscamos la referencia a "-lbind" y la cambiamos por "-lnsl".

Volvemos a compilar, y nos surgen nuevos problemas:

Undefined                       first referenced
 symbol                             in file
gethostbyname2                      stream/stream.a(tcp.o)
strsep                              libaf/libaf.a(af.o)
ld: fatal: Symbol referencing errors. No output written to mplayer
collect2: ld returned 1 exit status
make: *** [mplayer] Error 1

Solaris no tiene esas rutinas, pero la autodetección parece no funcionar correctamente. No tengo muchas ganas de investigar por qué falla la autodetección, así que retoco directamente los ficheros de configuración.

Cambiamos el fichero "config.mak" de

[...]
NEED_STRSEP  = no
[...]

a

[...]
NEED_STRSEP  = yes
[...]

También cambiamos el fichero "config.h" de

[...]
#define HAVE_GETHOSTBYNAME2 1
[...]
#define HAVE_STRSEP 1
[...]

a

[...]
#undef HAVE_GETHOSTBYNAME2
[...]
#undef HAVE_STRSEP
[...]

Ahora compila correctamente.

Podemos probar que todo va bien descargando una emisora de radio por Internet.

Compilación en 64 bits

Mis servidores son AMD Opteron. Es decir, soportan 64 bits. En otras arquitecturas utilizar 64 bits puede suponer una pérdida de rendimiento, debido a la mayor presion en la caché de datos (debido a que los punteros ocupan el doble). La ganancia de operar con 64 bits se ve, por ejemplo, al trabajar con aritmética de múltiple precisión (por ejemplo, criptografía de clave pública tradicional) o, simplemente, cuando un proceso requiere un espacio de direcciones de más de 32 bits.

En el mundo x86, las extensiones de 64 bits incluyen ventajas adicionales, como disponer del doble de registros. Esto es muy importante, porque x86 es una arquitectura especialmente "cutre", y toda ayuda es poca. La mejora de rendimiento debido al mayor número de registros disponibles es muy notable, en rutinas que que puedan beneficiarse de ello.

Compilar 64 bits en Solaris es trivial. En la mayor parte de los casos basta con añadir "-m64" a la linea de comando del compilador. Lamentablemente los módulos que nos ocupan suelen incluir optimizaciones en ensamblador y no reconocen los 64 bits, así que en esa configuración se desactivan las optimizaciones nativas y se usan rutinas en C. El rendimiento cae, por supuesto.

Por ejemplo, la versión actual de LAME (3.97) no incluye optimizaciones 64 bits, así que en una prueba experimentar, generar un MP3 supone un 50% más de tiempo si utilizamos una versión compilada en 64 bits. En la versión 3.98 experimental, que aún no se ha hecho pública, y que incluye soporte 64 bits optimizado, la versión 64 bits es entre dos y tres veces más rápida. Pero he visto que los MP3's generados con la versión de 32 y la de 64 bits no son iguales (los generados con la versión de 64 bits eran un 15% más grandes, con la misma configuración de calidad), así que he dejado el asunto para el futuro.

Uno de los objetivos de este proyecto es poder generar contenido multimedia desde Python, y mi Python es 32 bits, así que el soporte 64 bits no es, ahora, una prioridad (sobre todo mientras haya librerías que en 64 bits sean más lentas, por no tener código nativo aún).

En cualquier caso, material para otro artículo a medio plazo.


Historia

  • 20/ene/08. Discusión sobre compilación en 64 bits.

  • 11/ene/08: Primera versión de este documento.



Python Zope ©2008 jcea@jcea.es

Más información sobre los OpenBadges

Donación BitCoin: 19niBN42ac2pqDQFx6GJZxry2JQSFvwAfS