HTML5, la etiqueta video y la maldición de los códecs

Que levanten la mano las personas que han intentado ver un vídeo en un ordenador y se han llevado la sorpresa de «se oye, pero no se ve». «Mierda, los putos códecs, ¿cómo se llamaba el pack ese que me dijeron…»

Acabo de leer un artículo muy interesante que trata precisamente de esto mismo: los códecs, pero en un contexto mucho más grande: la web. Como sabéis, el futuro estándar HTML5 posee una nueva etiqueta <video /> que permitirá añadir vídeos fácilmente a las webs como lo hacemos ahora mismo con la etiqueta <img /> por ejemplo.

¿Qué podría permitir esto? Que Youtube no use Flash en sus reproductores o que DailyMotion haga lo mismo. ¿Habéis visitado las páginas? ¿No? Hacedlo. Visitad la primera con Firefox y la segunda con Safari (con Quicktime instalado). Ahora haced lo contrario. La primera con Safari y la segunda con Firefox.

¿Ya? Vale, ¿habéis visto lo que pasa? ¿Que Youtube sólo funciona con Safari + Quicktime pero no con Firefox y que DailyMotion sólo con Firefox y no con Safari?. Pues eso mismo es lo que os pasaba en los ordenadores de los demás: CÓDECS.

726F88B2-BFC5-40E2-B675-59B4D03FB7E9.jpg

Analicemos la situación. Esta versión de prueba de Youtube que sólo utiliza etiquetas válidas de HTML5 hace uso de la etiqueta <video />, pero el pequeño problema es que HTML5 quitó qué códecs usar por defecto. Empezaron con OGG/Theora, pero se desechó esa opción (cualquier compañía grande ha creado su estándar cerrado y con patentes de vídeo: Microsoft WMV, Apple con h.264…). Así que cada uno puede elegir qué códec utilizar, y claro, ahí ya dependes de plugins exteriores para cargar el vídeo o bien de internos… pero un navegador no puede ser un VLC en potencia. Lo mismo que pasa ahora con los objetos flash, que dependemos del Plugin Flash (instalado casi de facto en todos los ordenadores).

77E8D07C-F316-4972-993F-81090009C39D.jpg

Bien, así que Youtube usa un formato que DailyMotion no, porque Firefox no funciona en Youtube pero sí en este último.

Esta versión de prueba de Youtube usa vídeos en MP4, un formato con licencias, no libre, por el que hay que pagar patentes o canon para poder crear un reproductor o para utilizar las librerías para codificar/decodificar… (es más, cuando eliges un vídeo en Youtube en alta definición realmente estás eligiendo el vídeo en MP4 aunque sea Flash realmente el reproductor/decodificador). DailyMotion de hecho ha firmado un acuerdo con Mozilla para pasar sus vídeos al formato libre OGG/Theora (que hoy por hoy da menos calidad que el MP4, todo hay que decirlo) para que se use un formato de vídeo libre, estándar y sin patentes, por eso se puede ver sin ningún tipo de códec externo y todo de forma transparente al usuario.

Si os habéis fijado, el HTML5 está de moda, el <video /> está de moda… wait… ¿de qué navegadores estamos hablando? Safari y Firefox. Un 30% de cuota de mercado. ¿Quién sigue teniendo el 70% restante? ¿Alguien se cree que en un periodo razonable de tiempo (¿1 año?) Microsoft va a ser capaz de adaptar su navegador a los nuevos estándares propuestos por el grupo que desarrolla HTML5? Es más, ¿creéis que va a aceptar que se use un formato abierto cuando ellos tienen un formato propietario, licencias de por medio, con DRM llamado Windows Media Video?

7055B8C8-2D0F-4E54-B1F1-B39B4C0577C9.jpg

Como acaba rezando el artículo <video /> es un gran avance, pero estarán durante mucho, mucho, mucho tiempo los reproductores Flash de por medio, comiéndonos los recursos de la CPU hasta que por lo menos Adobe decida optimizarlo o bien Microsoft se decida a usar <video />

Lo bueno es que Chrome ha decidido unirse a los navegadores (Firefox sólo por ahora) para soportar el formato OGG/Theora en su próxima versión, la 3.0. Ojalá dejemos de depender de formatos propietarios y lentos…

Actualización: Se me olvidaba comentar que hubo un excelente debate en Slashdot acerca de si HTML5 sustituirá a Flash como reproductor de vídeo. No os lo perdáis.

Actualización2: Me comenta Julen, que Opera también soporta la etiqueta <video /> desde ¡Noviembre de 2007! Incluso en sus últimas versiones estables. Además vía OGG/Theora como Firefox y en un futuro Google Chrome. Muy interesante

video tag, Dreamhost and Firefox 3.5

I’m copy-pasting a blog post from blizzard, as we had a conversation on IRC about using the video tag on Firefox and Dreamhost hosting (due a problem with my other blog (in Spanish)):

A quick note if you’re going to be using OGG open web video hosted on web servers. There’s an important configuration change that you should make so that Firefox recognizes it as video. In my Apache configuration I’ve added this directive:

AddType application/ogg .ogg

AddType application/ogg .ogx

AddType video/ogg .ogv

AddType audio/ogg .oga

Most web servers are likely to return the mime type as “text/plain” which Mozilla will not show as video. If you don’t set it, and it’s served up as text/plain then Firefox is likely to show either an error or endless buffering. (Although I suspect that the endless buffering is actually a bug in our internal player and will likely be fixed.)

Update 2: You should look at this post from Silvia for the correct information. Thanks, Frank.

Anyway, you should follow the original post, as it could be updated since the publish of this post.

And I have sent an email to Dreamhost support to get a global support for .ogv files. I will post the decision as soon as I’m getting the answer.

Karatsuba en C++

Por razones de clase, me tuve que ver en el apuro de programar un algoritmo de multiplicación rápida de enteros largos. Dimos algo de teoría en clase, pero necesitábamos programarlo mediante recursión. Vimos cómo era más eficaz frente a la multiplicación normal (la que nos enseñan en las escuelas, de multiplicar uno a uno y en cada iteración aumentar la sangría). En concreto el orden de la multiplicación de toda la vida es de O(n2), mientras que el de Karatsuba es del orden de O(n1.59). Esta ligera mejoría se nota sobre todo en multiplicaciones de números de más de 300 bits.

Y ¿para qué cojones queremos multiplicar enteros de más de 300bits? Criptografía. El cifrado de los datos se basan en la multiplicación de dos números enteros muy largos y primos, por lo que su factorización es muy muy costosa.

En fin, que evitando matemáticas y demás tonterías variadas, el código de Karatsuba en C++ añadiendo las funciones necesarias para que funcione (sacado de uno en Java) queda en:


/* Alumno: Guillermo López Leal 2IM1
 * Compilador usado: GCC 4.0 en MacOS 10.5, pero debería funcionar en
 * cualquier Linux con su correspondiente configuración o incluso
 * en Windows bajo cygwin y mingw.
 *
 */
#include 
#include 

 using namespace std;

/*
 * Función Power(double x, int y)
 * calcula el número que resulta de calcular
 * x elevado a y. Se realiza por recursión.
 * Devuelve un tipo T, que se supone será
 * un número: int, double, float...
 *
 */
 int Power(int x, int y) {
    if (y == 0)
        return (1);
    else if (y == 1)
        return(x);
    else
        return(x * Power(x, y-1));
}

/*
 * Función Digitos (T n, int &dig)
 * calcula el número de dígitos (dig) que tiene el número n, que
 * podría ser cualquier tipo de número: int, float, double...
 * Devuelve el número de dígitos (int).
 * He preferido cambiar la función para que devuelva el número
 * de dígitos en vez de mostrarlo por pantalla ya que en el algoritmo de
 * Karatsuba es necesario saber el número de dígitos de un número.
 *
 */

 int Digitos (int n, int &dig) {
    if (n < 10) return (dig+1);
    else {
        dig++;
        return(Digitos(n/10, dig));
    }
}

/*
 * Recibimos el número de dígitos que queremos ver como últimos
 * y el número, claro
 * Devolvemos el módulo de dividir el número entre la potencia de 10
 * elevado al número de dígitos:
 * e.g. sacar los últimos 3 dígitos de 3454567:
 * 3454567 % power(10, 3) -> 3454567 % 1000 -> 567
 *
 */
 int ultimos(int digitos, int &numero) {
    return numero % Power(10, digitos);
}

/*
 * Al igual que con los últimos, devolvemos los n primeros "digitos" de "numero".
 * para ello usamos algo simple: dividimos el número entre la potencia de 10 elevado
 * al número de dígitos que queremos sacar.
 *
 */
 int primeros(int digitos, int &numero) {
    return numero/Power(10, digitos);
}

/*
 * Algoritmo de Karatsuba. Multiplicación rápida de enteros largos
 * @param: int &u -> pasamos por referencia uno de los números a multiplicar.
 * @param: int &v -> pasamos por referencia el segundo número.
 */
 int multiplica (int &u, int &v) {
    int dig1=0, dig2=0;
    //División en trozos iguales de los números. Tenemos que dividir según
    //el mayor de ambos entre 2: 3457689 -> 345 y 7689
    //                           3455 -> 0 y 3455
    int numDigitos = max(Digitos(u, dig1), Digitos(v, dig2));
    //Caso base, cuando se puede hacer una multiplicación directa (1 cifra)
    //En teoría si se lograba beneficio con números de más de 300 bits, se podría
    //sustituir ese 1 por 300.
    if (numDigitos <= 1) return u*v;
    //Número de dígitos redondeados HACIA ARRIBA para sacar la división.
    //e.g -> 9 dígitos de máximo -> sacamos los 5 últimos y después los 4 primeros
    //NO podemos sacar los 4.5 mayores y los 4.5 menores
    numDigitos = (numDigitos / 2) + (numDigitos % 2);
    //Vamos calculando los diferentes w, x, y, z…
    int w = primeros(numDigitos, u);
    int x = ultimos(numDigitos, u);
    int y = primeros(numDigitos, v);
    int z = ultimos(numDigitos, v);
    //Operaciones intermedias
    int p=multiplica(w, y);
    int q=multiplica(x, z);
    int wMasx = w + x;
    int zMasy = z + y;
    //Volvemos a llamar al algoritmo hasta que (como se ve arriba en el if) lleguemos al
    //caso base de n=numDigitos=1. Llamada recursiva
    int r=multiplica(wMasx, zMasy);
    // Salida final, usamos la función Power implementada arriba
    return Power(10, 2*numDigitos)*p+Power(10, numDigitos)*(r-p-q)+q;
}

//Funcion aleatoria para sacar números aleatorios menores que el parámetro x
int MiRandom(int x)
{
    int Numero=0;
    Numero=(rand()%x);
    return Numero;
}

int main () {
    //Inicializamos la semilla apuntando al tiempo
    srand(time(NULL));
    int numero=0;
    //Menor que 46340 -> raiz(max_int)=raiz(2147483647)...
    //Obviamente podría funcionar con más de 46340, pero podría producirse overflow.
    //Sólo ocurriría en el caso de que la semilla hiciera dos 46341 -> bum!!
    // Se podría poner hasta semilla 2147483647 si se tuviera la suerte que el random
    // fuera 1 y 2147483647
    //Además es que hemos limitado a "int", si hubiéramos puesto un valor más grande, como
    //unsigned long long int, tendríamos valores perfectos y muy grandes
    cout << "Número máximo a multiplicar (menor que 46341, leer código fuente) :";
    cin >> numero;
    //Creamos dos enteros aleatorios máximo "numero"
    int num1 = MiRandom(numero);
    int num2 = MiRandom(numero);
    //Les mostramos
    cout << "nnum1=" << num1;
    cout << "nnum2=" << num2;
    //Les multiplicamos!
    cout << "nEl resultado del producto es: " << multiplica(num1, num2);
    return EXIT_SUCCESS;
}

Sigue leyendo