El control de la tasa de bits en la codificación de video es un desafío que ha sido objeto de investigación durante muchos años. Se trata de equilibrar tres factores: maximizar la calidad del video, minimizar las diferencias de calidad entre los fotogramas codificados y cumplir con los requisitos de almacenamiento o transmisión. La complejidad de este proceso se incrementa por la diversidad de escenarios en los que se usa el video, como la transmisión en vivo, la grabación de televisión o el streaming bajo demanda.

Existen diferentes enfoques para controlar la tasa de bits. Uno de ellos es el control de tasa de bits de paso único, que ajusta la calidad de los fotogramas en función de un estimado inicial del tipo de codificación más adecuado. Sin embargo, este método no siempre logra la precisión deseada, como se muestra en el ejemplo de un video codificado a 896 kbps, donde la tasa de bits está un 10% por debajo del objetivo de 1 Mbps. Una mejor opción es el control de tasa de bits de dos pasadas, en el que el codificador procesa el video dos veces: la primera para recopilar estadísticas y la segunda para aplicar esas estadísticas con el fin de ajustar los parámetros de codificación, mejorando la tasa de bits a 968 kbps, acercándose al objetivo. Este método, aunque más preciso, implica un mayor tiempo de procesamiento y un aumento en la carga computacional.

En algunos casos, como en las llamadas de video en vivo, donde el espacio para procesamiento es limitado y el retraso debe mantenerse bajo, no se puede aplicar un control de tasa de bits de dos pasadas. Esto hace que el control de tasa de bits sea aún más complejo, ya que la calidad y la tasa de bits deben ser ajustadas en tiempo real. Por otro lado, en el streaming de video bajo demanda, los proveedores de contenido tienen más margen para aplicar técnicas de procesamiento avanzadas que maximicen la calidad del video y el rendimiento de la tasa de bits.

Otro aspecto relevante es la distinción entre tasas de bits constantes (CBR) y variables (VBR). Las tasas de bits constantes se mantienen fijas durante todo el video, lo que puede ser útil para ciertos tipos de transmisión en vivo, pero en muchos casos las tasas de bits varían, sobre todo cuando se utiliza un buffer de salida del codificador y un buffer de entrada del decodificador que suavizan estas variaciones a corto plazo.

Los estándares de codificación de video como H.264, H.265 y H.266, definen límites para la tasa de bits que se deben respetar para garantizar que el flujo de video sea decodificado correctamente por cualquier dispositivo. Estos límites se especifican mediante un modelo de decodificador hipotético conocido como el "decodificador de referencia hipotético" (HRD). Este modelo verifica si el flujo de bits codificado cumple con los requisitos del estándar y si el decodificador no se queda sin datos (subdesbordamiento) ni excede su capacidad (desbordamiento). Las restricciones del HRD imponen un límite adicional a los algoritmos de control de tasa de bits, asegurando que el flujo de video se ajuste correctamente sin causar errores durante la decodificación.

A pesar de los esfuerzos para mejorar el control de tasa de bits y la calidad del video, siempre existe el riesgo de que los errores de transmisión o los fallos en los archivos causen corrupción en los datos de video. La mayoría de los sistemas de codificación de video utilizan predicción inter-frame, lo que significa que los fotogramas se codifican usando datos de fotogramas anteriores. Si ocurre un error en los datos de un fotograma, este error puede propagarse a fotogramas posteriores, afectando la calidad de toda la secuencia de video. Por ejemplo, si un error ocurre en el fotograma 1, la decodificación incorrecta de un bloque puede afectar los fotogramas 2 y 3, que dependen de este para su propia decodificación. Este tipo de error puede ser visible en el video como una distorsión que se mueve a través de los fotogramas, dependiendo de cómo se predicen los bloques de los fotogramas subsecuentes.

Es esencial entender que la precisión del control de tasa de bits no depende únicamente de la codificación de los fotogramas, sino también de los algoritmos empleados para manejar errores y mantener la calidad del video bajo diversas condiciones de transmisión. Los sistemas de codificación de video deben ser capaces de equilibrar la calidad visual con la cantidad de datos que se pueden transmitir o almacenar, y los avances en este campo continúan buscando soluciones que optimicen tanto la eficiencia como la robustez frente a errores.

¿Cómo se implementa el códec de video en software o hardware?

La implementación de un códec de video, ya sea en software o hardware, debe cumplir con los requisitos de conformidad del estándar elegido. Posteriormente, se deben tomar muchas decisiones de diseño para lograr un equilibrio adecuado entre criterios como la eficiencia computacional, el rendimiento de compresión, la calidad del video y la variación de la tasa de bits. La clave es encontrar una solución que no solo cumpla con los estándares técnicos, sino que también sea práctica y eficiente para la aplicación específica.

Uno de los mayores desafíos en la implementación de códecs de video en software es lograr un codificado y decodificado que sea lo suficientemente rápido para la aplicación en cuestión. La codificación de video es inherentemente intensiva en términos computacionales debido a la gran cantidad de datos que se deben procesar por cada fotograma de video. Por ejemplo, cada fotograma de un video 1080p en formato 4:2:0 contiene 2,073,600 píxeles para la luminancia y 1,036,800 muestras para la crominancia. Esto implica que, para operar en tiempo real a 30 fotogramas por segundo, el codificador o decodificador de video debe procesar más de 93 millones de muestras por segundo. Un decodificador debe realizar todos los pasos establecidos en el estándar, incluyendo la decodificación de entropía, el reescalado, la transformación inversa, la predicción, la reconstrucción y el filtrado. Por su parte, el codificador debe realizar los pasos correspondientes de codificación y también elegir los modos y parámetros de predicción adecuados, incluyendo tamaños de bloques, modos de predicción y parámetros de movimiento, para comprimir el video de manera eficiente.

Los estándares sucesivos de codificación de video tienden a ser cada vez más intensivos en términos computacionales, tanto para el codificador como para el decodificador. Esto es un resultado deliberado, ya que cada nuevo estándar tiene como objetivo mejorar la eficiencia de compresión aprovechando los avances en las capacidades de los procesadores y la memoria. El estándar H.264/AVC, por ejemplo, fue desarrollado teniendo en cuenta las capacidades de los procesadores típicos de consumo de mediados de la década de 2000. Sin embargo, los dispositivos actuales, como ordenadores, dispositivos móviles y televisores, son mucho más potentes que aquellos de principios de este siglo, con mayores capacidades de procesamiento, procesamiento paralelo y memoria más amplia.

¿Cuándo es suficiente la velocidad de codificación o decodificación? La respuesta depende de la aplicación en cuestión. Por ejemplo, la codificación fuera de línea, como la preparación de un archivo de video para su transmisión, no necesita realizarse en tiempo real, mientras que las aplicaciones de videollamadas como Zoom o Skype requieren codificación y decodificación simultáneas en tiempo real. Esta diferencia en los requisitos de velocidad es crucial al decidir qué tipo de implementación utilizar.

Un ejemplo común en la implementación de códecs de video es el códec de referencia HM (HEVC Test Model), utilizado para verificar la conformidad con el estándar H.265. Este códec, desarrollado por la ITU-T como parte de la recomendación H.265, está escrito en C y contiene tanto un codificador como un decodificador. El codificador genera flujos de bits que cumplen con la recomendación H.265, mientras que el decodificador se encarga de descomprimir estos flujos para producir un archivo de video decodificado. El HM es útil tanto para experimentación como para el desarrollo de nuevas implementaciones de software o hardware del estándar H.265.

En la práctica, el HM no está diseñado para ser rápido, por lo que su uso se limita a pruebas y experimentos, ya que el codificador HM suele funcionar significativamente más lento que el tiempo real, especialmente al tratar con fuentes de video de alta resolución. Sin embargo, la correcta implementación de un nuevo codificador o decodificador puede verificarse comparando su rendimiento con el software de referencia HM.

Otro ejemplo es el codificador x265, una implementación de código abierto del estándar H.265. x265 es significativamente más rápido que el HM, ya que aprovecha los recursos del procesador, como las instrucciones Intel MMX y la paralelización en múltiples núcleos, lo que acelera las operaciones de codificación de video. Este codificador está diseñado para ser utilizado tanto como una biblioteca de software como en aplicaciones independientes. Una de las características destacadas de x265 es su capacidad para ajustar la relación entre velocidad y compresión a través de "preajustes" de codificación, lo que permite a la aplicación elegir entre una codificación más rápida con menor compresión o una codificación más lenta pero con mayor compresión.

Es importante comprender que el uso de estos codificadores no solo depende de la capacidad de procesamiento disponible, sino también de las necesidades específicas del proyecto. Si bien x265 puede ser más rápido, esto no siempre implica que sea la mejor opción si la prioridad es obtener la máxima calidad de compresión. Al elegir un códec y su implementación, es crucial considerar el entorno en el que se va a utilizar, ya sea un dispositivo de consumo con recursos limitados o un entorno de servidor de alto rendimiento.

El conocimiento de las distintas implementaciones de codificadores como HM y x265 permite a los desarrolladores tomar decisiones más informadas sobre cuál utilizar según los requisitos específicos de su proyecto. Sin embargo, siempre es importante no solo considerar la velocidad de la implementación, sino también la compatibilidad con los estándares y la eficiencia en el uso de los recursos.

¿Cómo funciona la decodificación paralela en HEVC mediante tiles y CTUs?

En los sistemas de codificación y decodificación de video, la eficiencia en el procesamiento de los datos es crucial. HEVC, el estándar de codificación de video de alta eficiencia, optimiza esta eficiencia mediante varias técnicas, una de las cuales es el uso de tiles y unidades de codificación de árbol (CTUs, por sus siglas en inglés). Estos métodos permiten dividir el proceso de decodificación en tareas más pequeñas y distribuirlas entre múltiples núcleos de procesamiento, lo que mejora considerablemente el rendimiento, especialmente en aplicaciones que requieren procesamiento en tiempo real.

Una de las características clave de HEVC es la posibilidad de dividir el flujo de bits en unidades llamadas tiles. Cada tile contiene el mismo número de CTUs, lo que significa que, a pesar de la posible complejidad de los datos de video, la carga de trabajo de cada tile es prácticamente equivalente. Esto facilita que cada tile sea decodificado utilizando la misma cantidad de recursos de procesamiento. La decodificación de un tile no depende de otros tiles, lo que permite que los procesos de decodificación ocurran de manera independiente y simultánea. En esta estructura, los tiles no cruzan los límites de las secciones de corte (slices), y los slices tampoco cruzan los límites de los tiles. Esta segmentación modular permite que el proceso de decodificación se distribuya eficazmente entre diferentes núcleos del procesador sin que se cree una dependencia entre los tiles.

Cada segmento de slice en el flujo de bits HEVC puede contener un marcador de punto de entrada en su encabezado. Este marcador es útil porque indica el desplazamiento en bytes al comienzo de un tile en el flujo de bits codificados. Esto permite que el proceso de decodificación de un tile se inicie en el lugar adecuado del flujo de bits, sin necesidad de esperar que toda la imagen sea decodificada completamente. Por ejemplo, después de que el encabezado de un segmento de slice ha sido decodificado, un núcleo de procesamiento puede comenzar a decodificar el tile N en su posición adecuada, mientras que otro núcleo puede hacer lo mismo con el tile N+1. Este enfoque de decodificación paralela acelera significativamente el proceso de decodificación y es ideal para aplicaciones en tiempo real.

El uso de tiles no es la única estrategia de paralelización disponible en HEVC. También existe la opción de decodificación paralela mediante el uso de slices, aunque esta técnica puede ser más compleja y menos eficiente que la de los tiles. A diferencia de los tiles, los segmentos de slice no tienen un tamaño fijo, lo que hace que el tiempo de procesamiento por segmento sea impredecible. Además, los segmentos de slice dependientes no pueden ser decodificados hasta que el segmento independiente asociado haya sido procesado, ya que la información del encabezado del segmento independiente es necesaria para decodificar el segmento dependiente. Aunque el uso de múltiples segmentos de slice para paralelizar la decodificación puede ser una estrategia útil, también puede resultar ineficiente debido a la sobrecarga adicional que implica gestionar los encabezados de los segmentos de slice.

Una alternativa interesante en HEVC es el procesamiento paralelo mediante rows de CTUs, conocido como procesamiento paralelo de Wavefront (WPP, por sus siglas en inglés). Este método permite decodificar filas completas de CTUs de manera simultánea, siempre que se cumplan ciertas condiciones. En primer lugar, el encabezado de cada segmento de slice contiene un desplazamiento de punto de entrada para algunas o todas las filas de CTUs, lo que permite que cada fila se decodifique independientemente en función de su desplazamiento dentro del flujo de bits. En segundo lugar, la codificación CABAC (Context-based Adaptive Binary Arithmetic Coding) está restringida para que cada fila sucesiva de CTUs pueda comenzar a decodificarse solo después de que se hayan decodificado los primeros dos CTUs de la fila anterior. Esta sincronización entre las filas crea un efecto de onda o ripple, lo que permite que la decodificación de las filas se realice de manera paralela pero con una dependencia controlada entre las filas consecutivas.

El tamaño de las unidades de codificación también juega un papel fundamental en la estructura de decodificación de HEVC. Tradicionalmente, las unidades de codificación más pequeñas eran bloques de 16×16 píxeles, conocidos como macroblocks. HEVC introduce la Unidad de Árbol de Codificación (CTU), que puede tener tamaños de 16×16, 32×32 o 64×64 píxeles, lo que aumenta la flexibilidad y eficiencia del sistema. Cada CTU puede contener bloques de codificación de luminancia (CTB) y crominancia (CB), que se ajustan según el formato de muestreo, por ejemplo, el 4:2:0. Este enfoque modular permite que la decodificación de video sea más eficiente, ya que el tamaño de los bloques puede adaptarse a las necesidades del flujo de datos sin comprometer la calidad del video.

El proceso de división de CTUs en bloques de codificación (CUs) utiliza una técnica conocida como partición en quadtree. Esta técnica divide los bloques de manera recursiva en cuatro cuadrantes, permitiendo que cada cuadrante sea dividido nuevamente según sea necesario. El uso de esta estructura permite adaptar el tamaño de los bloques de codificación de manera eficiente, minimizando el número de bits necesarios para señalizar cómo se deben dividir los bloques.

Es fundamental entender que estas técnicas de decodificación paralela no son solo una cuestión de rendimiento; también implican una gestión precisa de la memoria y los recursos de procesamiento. Mientras más eficiente sea la distribución del trabajo entre los núcleos de procesamiento, más rápido y fluido será el proceso de decodificación. Además, la coordinación de la decodificación entre las diferentes unidades (tiles, slices, filas de CTUs) debe ser cuidadosamente gestionada para evitar bloqueos o esperas innecesarias entre los núcleos.