La transmisión eficiente de secuencias de video, ya sea por redes o para su almacenamiento en archivos, es un proceso fundamental para garantizar que el contenido se pueda visualizar con calidad y sin interrupciones. Para ello, se utiliza la codificación, un proceso en el cual una secuencia de video se divide en unidades más pequeñas, como cuadros o bloques de datos, que pueden ser transmitidos de forma más eficiente y reconstruidos por el receptor. Este proceso no solo busca comprimir el contenido, sino también optimizar su transmisión para asegurar una buena calidad de reproducción.

En la codificación de video moderna, como la usada en el estándar HEVC (H.265), la elección del tamaño y la estructura de los bloques juega un papel crucial en la eficiencia del proceso. Por ejemplo, en áreas de un video que son visualmente homogéneas, como un campo de césped sin mucho movimiento, el codificador optará por bloques grandes, como los de 64x64 píxeles, lo que reduce la cantidad de información necesaria para representar esa sección. En cambio, en áreas con movimiento complejo, como alrededor de un jinete y un caballo, se elegirán bloques más pequeños para seguir de manera más precisa los límites y el movimiento de los objetos.

Una vez que la secuencia de video es codificada, se almacena o transmite en forma de paquetes de datos adecuados para la red o el archivo de salida. Es aquí donde surgen varios retos. El primero de estos desafíos es el acceso aleatorio, que permite al usuario saltarse a una parte específica del video sin tener que empezar desde el principio. Esto es crucial en aplicaciones como el streaming, donde el usuario quiere saltar entre diferentes puntos de una película o un programa sin tener que esperar demasiado.

Otro desafío importante es la reproducción en streaming. El objetivo es encontrar un equilibrio entre una alta calidad de reproducción y la necesidad de evitar pausas o rebuffers. La calidad del video debe ser lo suficientemente alta como para que el espectador no note pérdidas, pero al mismo tiempo se debe evitar la sobrecarga de la red, lo que podría interrumpir la transmisión. Para lograr esto, los codificadores deben garantizar que los datos se transmitan de manera eficiente, minimizando los errores en la codificación y permitiendo que la secuencia de video se decodifique correctamente en el otro extremo, incluso cuando se presentan problemas como paquetes de datos perdidos.

La transmisión de video también debe ser resistente a errores. Un paquete perdido o una sección corrupta no debe arruinar la totalidad del video. Para ello, los videos codificados se estructuran en secuencias que incluyen cuadros clave, que se pueden decodificar de manera independiente. Este tipo de cuadros son cruciales, ya que permiten a un receptor iniciar la reproducción de un video desde cualquier punto sin necesidad de depender de los cuadros anteriores. Estos cuadros clave son generalmente imágenes intra-codificadas, que no dependen de otras imágenes para su decodificación. Además, el proceso de codificación de video suele organizarse en estructuras llamadas GoPs (Group of Pictures), donde cada GoP contiene un cuadro clave seguido de varios cuadros inter-codificados. Esto facilita el acceso aleatorio, ya que el sistema puede saltar a cualquier punto del video siempre que se haya encontrado un cuadro clave.

Una secuencia codificada puede estar formada por varios cuadros codificados, y cada cuadro contiene una serie de parámetros esenciales para la decodificación correcta. Estos parámetros no solo están presentes en cada cuadro individual, sino que también se organizan en conjuntos de parámetros que se aplican a múltiples cuadros dentro de una secuencia. Por ejemplo, un conjunto de parámetros de secuencia (SPS, por sus siglas en inglés) define los parámetros comunes a toda la secuencia, como la resolución espacial, la tasa de cuadros por segundo o la profundidad de color. Además, los conjuntos de parámetros de imagen (PPS) contienen parámetros específicos para cada cuadro o grupo de cuadros. Estos parámetros son necesarios para que un decodificador reconstruya correctamente el video.

En términos de los cuadros dentro de una secuencia codificada, existen diferentes tipos. Los cuadros intra-codificados (o I-pictures) son aquellos que se codifican sin ninguna predicción de otros cuadros, mientras que los cuadros inter-codificados (P-pictures o B-pictures) dependen de otros cuadros para su decodificación. Esto permite una mayor eficiencia en la compresión, ya que solo se almacenan las diferencias entre cuadros sucesivos. Los P-pictures dependen de un cuadro anterior, mientras que los B-pictures pueden depender tanto de cuadros anteriores como posteriores, lo que mejora aún más la eficiencia en la compresión.

Para que una secuencia de video sea decodificada correctamente, se necesitan tanto los parámetros de la secuencia (SPS) como los de la imagen (PPS). La decodificación de una imagen o cuadro requiere no solo los parámetros de la imagen actual, sino también los parámetros definidos en el SPS de la secuencia completa. Esto asegura que el decodificador tenga toda la información necesaria para reconstruir la imagen de manera precisa, independientemente de las variaciones que puedan existir entre diferentes imágenes en la secuencia.

La codificación de video no solo se limita a la calidad visual, sino que también es un proceso intrincado que tiene en cuenta la estructura de los cuadros, los parámetros comunes a lo largo de la secuencia y las relaciones entre los cuadros. Es un equilibrio entre compresión, calidad y eficiencia en la transmisión, y la correcta organización de los parámetros y estructuras de cuadros es fundamental para garantizar una experiencia de visualización sin interrupciones.

¿Cómo se lleva a cabo la partición y codificación en el sistema HEVC?

En el sistema HEVC (High Efficiency Video Coding), la codificación de imágenes comienza con la partición de las Unidades de Codificación de Imagen (CTU, por sus siglas en inglés). Tomemos como ejemplo la figura 4.47, en la que se observa cómo una CTU de 64×64 se divide en Unidades de Codificación (CU) mediante un árbol quaternario. El primer nivel de este árbol divide la CTU de 64×64 en cuatro cuadrantes de 32×32 muestras. Tres de estos cuadrantes se convierten en hojas, formando las CUs 1, 2 y 3. El cuarto cuadrante de 32×32 se divide nuevamente en el siguiente nivel del árbol quaternario, resultando en cuatro cuadrantes de 16×16. Cada uno de estos cuadrantes se convierte en hojas adicionales, completando la partición en tres CUs de 32×32 y cuatro CUs de 16×16.

La cantidad de banderas de partición, denominadas split_cu_flags, que se envían depende del tamaño más pequeño de las CUs. Si el tamaño más pequeño se define como 8×8, se envían un total de 9 split_cu_flags para señalar esta partición de la CTU. Si, por otro lado, el tamaño más pequeño se define como 16×16, las CUs 4–7 no se subdividen más, por lo que solo se envían 5 split_cu_flags.

Además de la partición en CUs, HEVC permite una partición adicional opcional de la CTU en Grupos de Cuantificación (Quantisation Groups). Un Grupo de Cuantificación es un múltiplo del tamaño de la CU y permite agrupar varias CUs para facilitar la señalización y el cálculo del parámetro de Cuantificación (QP). Dentro de un Grupo de Cuantificación, el delta QP, es decir, el cambio respecto al QP previamente señalado, se envía como máximo una vez, por lo que todas las CUs comparten el mismo QP.

Cada CU se divide a su vez en una o más Unidades de Predicción (PU) y en una o más Unidades de Transformación (TU). Las Unidades de Predicción (PU) son bloques que contienen la información de luminancia y crominancia, mientras que las Unidades de Transformación (TU) contienen bloques de transformación de luminancia y crominancia. La partición de las PU y TU en HEVC no tiene que coincidir exactamente, y pueden ser de diferentes tamaños, como se observa en la figura 4.15.

En cuanto a las Unidades de Predicción, cada CU se codifica utilizando predicción intra o inter. Una CU codificada en modo intra puede tratarse como una única PU del mismo tamaño que la CU, o bien, puede dividirse en cuatro PU cuadradas, dado que los modos de predicción intra de HEVC operan sobre bloques cuadrados. Por otro lado, una CU codificada en modo inter puede dividirse en dos o cuatro PU de distintas formas, como cuadradas o rectangulares, lo cual es ilustrado en la figura 4.48.

El proceso de partición continúa en el caso de las Unidades de Transformación (TU), que siguen una estructura de árbol quaternario. Comenzando desde la CU, en cada nivel del árbol de transformación se envía un flag de partición, llamado split_transform_flag. Si el flag es 0, el árbol no se divide más. Si el flag es 1, el árbol se divide en cuatro árboles de transformación, cada uno con dimensiones horizontales y verticales reducidas a la mitad. Este proceso continúa recursivamente hasta que se alcanza el nivel más bajo del árbol de transformación, en el que las hojas representan las TUs.

Es importante resaltar que los bloques de transformación más grandes que 4×4 se codifican como una serie de sub-bloques de transformación (TSB, por sus siglas en inglés), que siempre son de tamaño 4×4. El número de niveles permitidos en el árbol de transformación depende del tamaño mínimo y máximo de las TUs, así como de la profundidad máxima del árbol, parámetros que están especificados en la configuración del sistema (SPS).

Cada CU en una secuencia de video coloreado está compuesto por una TBU de luminancia y dos TBU de crominancia. A medida que el sistema HEVC avanza en la codificación de imágenes, se utilizan técnicas de partición adaptativas, es decir, que dependen de las características de la escena a codificar. En áreas de movimiento complejo, el codificador tiende a elegir particiones más detalladas, es decir, bloques más pequeños de CUs, PUs y TUs. En áreas estáticas o planas, se seleccionan particiones menos detalladas con bloques más grandes, lo que ayuda a optimizar la eficiencia de la codificación.

A través de estos procesos, HEVC logra una codificación altamente eficiente de secuencias de video, permitiendo la transmisión de video de alta calidad con un menor ancho de banda. La adaptabilidad del sistema permite que se ajusten las particiones en función de las características de cada escena, lo que asegura un balance adecuado entre calidad visual y eficiencia de compresión.

¿Cómo funciona la codificación binaria aritmética (BAC) y el proceso de renormalización en la decodificación de secuencias binarias?

El proceso de codificación binaria aritmética (BAC) se basa en dividir un rango continuo en subrangos, donde cada subrango representa un valor específico en el proceso de codificación. Durante la codificación de una secuencia binaria, como el ejemplo de codificación de un conjunto de bits b0, b1, b2, se toma un rango inicial que se ajusta iterativamente en función de la información proporcionada por los bits sucesivos. La renormalización es un paso clave en este proceso, ya que garantiza que el rango no se vuelva demasiado pequeño y, por lo tanto, no sea capaz de representar más datos sin precisión.

En el ejemplo de codificación, si tomamos el rango (0.4, 0.96), este se divide en dos subrangos: (0.4, 0.68) y (0.68, 0.96). Dependiendo del bit que se va a codificar, se selecciona uno de estos subrangos. Si el bit a codificar es 1, se elige el rango superior (0.68, 0.96), y el proceso continúa con la subdivisión del rango para cada nuevo bit. La codificación va generando fracciones binarias, y estas se envían de manera continua, lo que permite que el decodificador comience a interpretar los bits a medida que los recibe. Así, el codificador no espera a tener todos los datos de entrada para empezar a enviar los bits correspondientes.

La renormalización, entonces, es el proceso mediante el cual se asegura que el rango siempre esté lo suficientemente grande como para seguir representando correctamente los valores que se desean codificar. Al renormalizar, el rango se escala hacia arriba antes de que se vuelva demasiado pequeño, lo que evita la necesidad de agregar más bits para mantener la precisión. Esto optimiza la cantidad de bits necesarios para representar la secuencia binaria, lo que a su vez permite una codificación más eficiente.

Desde la perspectiva del decodificador BAC, el proceso de renormalización tiene lugar cuando el decodificador recibe suficientes bits de la fracción binaria como para hacer que el bit más significativo (MSB) del string binario sea inequívoco. Esto significa que el decodificador puede comenzar a interpretar el siguiente bit de la secuencia. El decodificador recibe los bits fraccionarios uno a uno, y en cada paso determina si el siguiente bit en la secuencia es claro. Cuando un bit es inconfundible, se descifra y el rango se escala para continuar con el proceso. Si no es claro, el decodificador espera a recibir más bits para hacer una suposición más precisa.

Este tipo de codificación se utiliza para comprimir secuencias de datos como video o audio, donde la eficiencia de la compresión es crucial. En un flujo continuo de datos, el codificador BAC y el decodificador trabajan en paralelo, lo que permite la codificación y decodificación de datos en tiempo real. A medida que el codificador procesa los bits, va generando los MSBs que serán utilizados por el decodificador para reconstruir la secuencia original.

El proceso de codificación BAC es un ejemplo de cómo se puede representar información de manera eficiente mediante fracciones binarias, y cómo la renormalización y el escalado continuo de rangos optimizan el uso de bits. Este proceso es fundamental en la compresión de datos, como en la codificación de video y otros medios, donde la eficiencia en el uso de espacio y tiempo es esencial.

Es importante notar que, en el proceso de codificación y decodificación BAC, la renormalización no solo afecta a la eficiencia, sino que también juega un papel crucial en la precisión de los datos transmitidos. Al renormalizar constantemente el rango, se asegura que el codificador no pierda precisión y que el decodificador pueda trabajar con datos más claros y confiables.

Además de entender el proceso básico de codificación y decodificación, es necesario comprender cómo las probabilidades influyen en la selección del modelo de contexto utilizado por el codificador y decodificador. En el caso de los sistemas más avanzados, como el CABAC (Context-Adaptive Binary Arithmetic Coding), las probabilidades de que un bit sea 0 o 1 no son fijas, sino que se ajustan dinámicamente en función del contexto de los bits previamente codificados. Este tipo de adaptabilidad aumenta significativamente la eficiencia de la codificación, ya que se aprovechan las dependencias estadísticas entre los bits cercanos en la secuencia.

Por último, en la codificación CABAC, los símbolos no binarios son transformados en secuencias binarias mediante un proceso conocido como binarización. Este paso permite que cualquier tipo de dato, no solo los valores binarios, pueda ser procesado de manera eficiente utilizando el sistema de codificación binaria aritmética. La capacidad de adaptarse a diferentes tipos de datos y optimizar el uso de bits según el contexto es lo que hace que CABAC sea tan poderoso en la compresión de datos, especialmente en estándares como H.264/AVC y H.265/HEVC, que requieren una alta eficiencia para la transmisión y almacenamiento de video de alta calidad.

¿Cómo se selecciona y utiliza el modelo de contexto en la codificación de video H.265 y VVC?

En los estándares de codificación de video como H.265 (HEVC) y H.266 (VVC), la selección del modelo de contexto juega un papel crucial en la eficiencia de la compresión de los datos. El proceso de codificación de entropía, que convierte los valores de los elementos de sintaxis en un flujo de bits, depende de la correcta elección de un modelo de contexto adecuado. Este proceso no es unívoco y se ve influenciado por diversos factores, que incluyen el tipo de elemento de sintaxis, el número de bin en la binarización, el tipo de slice (I, P o B), el tamaño del TB (macrobloque de transformación) actual, el contenido del TSB (subbloque de transformación) y estadísticas locales como la disponibilidad o el contenido de bloques vecinos previamente codificados.

La codificación basada en el contexto se lleva a cabo de la siguiente manera:

  1. Se selecciona una tabla de contexto para el elemento de sintaxis X actual.

  2. El elemento de sintaxis se binariza en uno o más bins.

  3. Para cada bin codificado en contexto:
    a) Se calcula un incremento de contexto, ctxInc, que puede ser un valor fijo o dependiente de las estadísticas locales.
    b) Se calcula un índice de contexto, ctxIdx = ctxOffset + ctxInc, que identifica un modelo de contexto específico. Se codifica el bin utilizando los valores almacenados pStateIdx y valMPS para este modelo de contexto.
    c) Se actualizan los valores de pStateIdx y valMPS para este modelo de contexto, dependiendo del resultado de la codificación del bin.

Un ejemplo claro de esta selección de contexto se puede observar en el elemento coded_sub_block_flag, que es una bandera de un solo bit. La binarización consiste en un solo bin (bin 0), y la tabla de contexto especifica un total de 12 contextos, numerados del 0 al 11. El valor inicial de ctxOffset se selecciona en función del tipo de slice (I, P o B) y se establece en 0, 4 u 8. Cuando se codifica un nuevo valor para coded_sub_block_flag, el incremento de contexto ctxInc se deriva en función de la ubicación del subbloque y los valores previamente decodificados. Dependiendo de esta derivación, ctxInc puede ser 0, 1, 2 o 3, y el índice de contexto ctxIdx se obtiene como la suma de ctxOffset y ctxInc.

Otro ejemplo es el elemento cu_qp_delta_abs, que representa el cambio de magnitud en el parámetro de cuantización QP para el CU (Unidad de Codificación) actual. Este valor no es binario y se binariza utilizando un mapeo definido en el estándar H.265. La tabla de contexto para este valor especifica seis contextos, numerados del 0 al 5. Al igual que en el ejemplo anterior, el valor de ctxOffset se selecciona en función del tipo de slice, y los bins de la binarización se codifican utilizando un índice de contexto derivado de ctxOffset y ctxInc.

El proceso de codificación de entropía en VVC (Versatile Video Coding) sigue un enfoque similar al de HEVC, con una importante mejora: en lugar de usar un solo valor de probabilidad para cada modelo de contexto, se almacenan y actualizan dos estimaciones de probabilidad para cada contexto, lo que mejora la adaptación a las estadísticas locales de los bins previamente codificados. Esto permite una codificación más eficiente y precisa, reduciendo la redundancia de datos y mejorando la compresión en comparación con los métodos anteriores.

La codificación de entropía es un componente esencial en la eficiencia de la compresión de video. Permite que los elementos de sintaxis se representen en una forma compacta, optimizando el uso de los recursos y reduciendo el tamaño del flujo de bits sin perder calidad. Sin embargo, a pesar de su complejidad, el proceso de selección de contexto y la actualización de los modelos de probabilidad es clave para lograr una codificación eficiente, tanto en HEVC como en VVC.

Es fundamental entender que la elección adecuada de un modelo de contexto no solo depende del tipo de datos que se están codificando, sino también de cómo los datos vecinos, el tipo de slice y otros factores locales afectan las decisiones de codificación. La actualización de las probabilidades de los modelos de contexto durante la codificación también juega un papel esencial en mantener la eficiencia del proceso a lo largo de todo el video. Esto no solo mejora la calidad del video comprimido, sino que también asegura una tasa de compresión más alta y un mejor rendimiento de la decodificación.