\chapter{El protocolo JPIP}

\section{Introducción}

El protocolo JPIP \cite{Part9, Taubman.jpip, Taubman.jpip2} es un
protocolo para la interacción con imágenes JPEG2000 remotas,
desarrollado por el ISO/IEC \emph{Joint Technical Commitee of
Photographic Experts} (JPEG), que forma parte de la Parte 9 del
estándar JPEG2000. El protocolo JPIP es una evolución del
protocolo JPIK, desarrollado por David Taubman
\cite{Taubman.Browsing}.

\section{Arquitectura}

El protocolo JPIP se basa en una arquitectura típica
cliente/servidor. La parte del servidor es en la que se encuentra
el servidor JPIP y la colección de archivos de imágenes JPEG2000
(\emph{raw} .J2C, .JP2, .JPX, etc.) a la cual tendrá acceso el
cliente. En la parte del cliente tendremos la aplicación, que
generalmente será un visualizador interactivo de imágenes remotas,
que solicitará información al servidor. En la figura
\ref{fig:arquitecturaJPIP} podemos ver la arquitectura básica para
el protocolo JPIP.

\begin{figure}
  \begin{center}
    \resizebox{\textwidth}{!}{\input{figuras/arquitecturaJPIP}}
    \caption{Arquitectura del protocolo JPIP.}
    \label{fig:arquitecturaJPIP}
  \end{center}
\end{figure}

Cuando el cliente desea visualizar una región determinada, a una
resolución determinada, de una imagen determinada, no precisa
conocer en qué lugar del archivo remoto de la imagen se encuentra
la información necesaria para la reconstrucción de dicha región,
sino que simplemente realiza una petición al servidor indicándole
el nombre de la imagen, la resolución y la región de interés. El
servidor es el encargado entonces de leer la información necesaria
del archivo de la imagen para reconstruir la región solicitada.
Además de la región de interés y la resolución, el cliente puede
añadir más requerimientos en sus peticiones al servidor, como
podría ser el número de capas de calidad, el número de
componentes, etc.

El cliente contendrá una \emph{cache} en donde va almacenando los
datos que el servidor le envía, organizados en \emph{data-bins},
cuyo concepto es analizado más adelante. Esto permite el poder
comenzar la visualización de una determinada región si de ella se
conservan datos de anteriores peticiones al servidor. El servidor
puede de forma opcional mantener el modelo de \emph{cache} del
cliente para evitar transmitirle datos que ya le ha transmitido
anteriormente.

En el cliente, el proceso de descompresión/visualización (la parte
\emph{Aplicación} y \emph{Descompresión} de la figura
\ref{fig:arquitecturaJPIP}) está separado del proceso de
comunicación (la parte \emph{Cliente JPIP} de la figura
\ref{fig:arquitecturaJPIP}). Ambos procesos se ejecutarán
paralelamente, de forma que mientras uno, el de comunicación, esté
realizando la petición al servidor de la región de interés y
recibiendo los \emph{data-bins} apropiados y almacenándolos en la
\emph{cache}, el otro, el de visualización, puede ir recogiendo
los \emph{data-bins} de la \emph{cache} relacionados con la región
a visualizar y reconstruyendo la imagen. El proceso de
visualización comenzaría cuando el usuario solicita una nueva
región de la imagen y finalizaría cuando el proceso de
comunicación termina de leer todos los \emph{data-bins}
asociados. El proceso de visualización estaría continuamente
reconstruyendo la imagen una y otra vez y no debe importarle si no
están todos los \emph{data-bins} necesarios para ello (si alguna
porción no es posible reconstruirla, se podría rellenar de algún
color, por ejemplo).

El protocolo JPIP ha sido diseñado para ser independiente del
protocolo de transporte finalmente utilizado. De esta forma,
aunque inicialmente fue concebido para usar HTTP/1.1, también es
capaz de correr sobre UDP y TCP.

Actualmente el protocolo JPIP sólo ha sido implementado para
emplear el protocolo HTTP solamente, o el protocolo HTTP en
asociación con el protocolo TCP. En este último caso, el
funcionamiento es similar al primero, pero los \emph{data-bins}
son enviados por el servidor al cliente a través de una conexión
en TCP simple separada de la conexión HTTP.

\subsection{Concepto de \emph{data-bin}}

La información almacenada en un archivo de imagen, tanto un
archivo \emph{raw} .J2C, como otro más complejo como .JP2 o .JPX,
es dividida bajo el protocolo JPIP en bloques llamados
\emph{data-bins}. Cada \emph{data-bin} es identificado por dos
valores: el tipo de \emph{data-bin} y el identificador, que
identifica de manera única al \emph{data-bin} dentro del grupo al
cual pertenece en función del tipo.

Los diferentes \emph{data-bins} con los que trabaja el protocolo
JPIP son los siguientes:

\begin{itemize}

\item \textbf{Precinto (\emph{Precinct data-bins}):} Como su
propio nombre indica, este \emph{data-bin} contiene la información
de un precinto, a una resolución $r$, de una componente $c$, de un
\emph{tile} $t$. Esta está formada por todos los paquetes de un
precinto, ordenados por capa de calidad, desde la menor hasta la
mayor. El identificador $I$ es obtenido mediante la siguiente
formula:

\begin{equation*}
I = t + ((c + (s \times numComponentes)) \times numTiles)
\end{equation*}

Tanto el índice de \emph{tile}, $t$, como el índice de componente
$c$, y el valor $s$, comienzan en cero. A cada precinto de cada
\emph{tile}-componente, incluyendo todas las resoluciones, le es
asignado un único número de secuencia $s$. A todos los precintos
de la resolución más baja le son asignados en primer lugar un
número de secuencia que empezaría con el precinto situado en la
esquina superior izquierda e iría avanzando por columna y por
fila. En las resoluciones siguientes, a los precintos se les va
asignando un número de secuencia correlativo de la misma forma.

 \item \textbf{Cabecera (\emph{Header data-bins}):} Un
\emph{data-bin} de cabecera puede ser tanto la cabecera principal,
como la cabecera de un \emph{tile}. Si el identificador es igual a
0, el \emph{data-bin} contiene la cabecera principal del
\emph{code-stream}, desde el marcador SOC (incluido) hasta el
primer marcador SOT (no incluido). Si el identificador es igual a
$n$, donde $n \geq 1$, el \emph{data-bin} contiene la cabecera del
\emph{tile} $n - 1$, pero sin incluir ni el marcador SOT ni el
marcador SOD. Bajo el protocolo JPIP no existen \emph{tile-parts},
por lo que si en un archivo de imagen los \emph{tiles} está
divididos en \emph{tile-parts}, el servidor JPIP, cuando vaya a
enviar el \emph{data-bin} de la cabecera de un \emph{tile}
determinado, deberá unir todas las cabeceras de todos los
\emph{tile-parts} que forman dicho \emph{tile} en una sola.

\item \textbf{Meta información (\emph{Meta data-bins}):} Estos
\emph{data-bins} son opcionales y su existencia dependerá de si el
archivo de imagen es un archivo de la familia .JP2 (.JPX, .JPM,
etc.) o no. En el caso de así sea, cada \emph{data-bin} contendrá
un conjunto de cajas \emph{boxes} (Sección 1.5). El servidor
elegirá el número de cajas a incluir en un \emph{data-bin},
teniendo presente que todos los \emph{data-bins} de una imagen
deben tener el mismo número de cajas. El valor del identificador
no es relevante salvo en el caso de ser igual a cero, en cuyo caso
el \emph{data-bin} contiene el conjunto de cajas esenciales de la
imagen, que en el caso de ser un archivo .JP2 éstas serían la caja
JPEG2000 Firma (\emph{JPEG2000 signature box}), la caja Tipo de
Archivo (\emph{File Type box}) y la caja Cabecera JP2 (\emph{JP2
Header box}), con todas sus subcajas asociadas.

\item \textbf{Catálogo (\emph{Catalog data-bins}):} Un cliente que
recibe uno o más \emph{data-bins} con meta información, puede
analizar su contenido para averiguar qué cajas contiene. Sin
embargo, en algunos caso, la interpretación de esas cajas puede
depender de su posición con respecto a otras cajas que podrían
aparecer almacenados en otros \emph{data-bins}, algo que no se
puede conocer de antemano. Con el fin de solucionar este problema
se crean los \emph{data-bins} de catálogo, que contienen como
información la estructura de cajas de un archivo determinado. No
contiene ningún dato de ninguna caja. Cada caja representada en
dicha estructura posee un índice mediante el cual encontrar la
información asociada a la misma (en que \emph{data-bin} de meta
información se encuentra qué tamaño ocupa y en que posición).

\end{itemize}

\subsection{Sesiones y canales}

Una petición del cliente al servidor puede ser con estado
(\emph{stateful}) o sin estado (\emph{stateless}). Las peticiones
con estado son realizadas en el contexto de una sesión de
comunicación, cuyo estado es mantenido por el servidor. Las
peticiones sin estado no requieren ninguna sesión. El uso de
sesiones mejora el rendimiento del servidor, ya que, por ejemplo,
al establecer una sesión con un archivo de imagen determinado, el
servidor abre dicho archivo y lo prepara para ser transmitido en
\emph{data-bins}, con lo que todas las peticiones bajo esa misma
sesión no provocan que el servidor realice nuevamente este
proceso, como ocurriría con peticiones sin estado (o peticiones
asociadas a otras sesiones). Las peticiones sin estado pueden
considerarse bajo una sesión única que termina cuando finaliza la
respuesta a la petición.

Bajo una sesión, con peticiones con estado, el cliente puede abrir
múltiples canales, pudiendo realizar múltiples peticiones con
estado asociadas a la misma sesión concurrentemente. Esto es
especialmente útil para aplicaciones que visualizan
simultáneamente diversas regiones de interés de una misma imagen.
Los canales se pueden cerrar y abrir otros de forma independiente
y sin afectar a la sesión. El cerrar una sesión supondría cerrar
todos los canales abiertos asociados a ella.

\subsection{\emph{Caching}}

Como vimos anteriormente, la arquitectura del protocolo JPIP
aconseja una \emph{cache} para el cliente (aunque no es
estrictamente necesaria). En ella el cliente va almacenando los
distintos \emph{data-bins} recibidos del servidor, y es utilizada
para la descompresión de la imagen.

Vimos también que el servidor puede opcionalmente mantener un
modelo de \emph{cache} del cliente. Los modelos se crean por cada
sesión que se abra. Este modelo consistiría en almacenar el rango
de bytes de cada \emph{data-bin} enviado al cliente. El modelo se
desecha una vez cerrada la sesión asociada.

Los clientes pueden rehusar su \emph{cache} entre diferentes
sesiones. Incluso los clientes que realicen sólo peticiones sin
estado, al ser consideradas éstas como peticiones bajo una sesión
única que se cierra al terminar la respuesta del servidor, podrían
mantener la misma \emph{cache} para todas sus peticiones. Esto
provoca que el servidor no tenga un modelo de \emph{cache} que se
corresponda con el contenido de la \emph{cache} del cliente. El
protocolo JPIP permite al cliente en sus peticiones al servidor
especificar el contenido de su \emph{cache}, parcial o totalmente,
con el fin de que el servidor actualice su modelo. De esta forma,
si el cliente mantiene su \emph{cache} entre sesiones, ya sean con
peticiones con o sin estado, podría enviarle su contenido al
servidor con el fin de actualizar el modelo. Esto no es
obligatorio, pero sí recomendable para un rendimiento óptimo.
Cuando sí puede resultar obligatorio es cuando, bajo una sesión,
en la cual el servidor mantiene el modelo de \emph{cache} del
cliente, el cliente, por el motivo que sea (por ejemplo, falta de
memoria), descarta \emph{data-bins} de la \emph{cache}. Si
posteriormente estos \emph{data-bins} son requeridos, bajo la
misma sesión, mediante una petición al servidor, éste no se los
enviará al cliente, ya que para él ya se los ha enviado. En este
caso sería imprescindible que el cliente le notificará al servidor
los cambios producidos en su \emph{cache}.

\subsection{Peticiones}

Las peticiones JPIP consisten en una secuencia de pares ``parámetro
$=$ valor''. Esta secuencia es indicada como una cadena ASCII. Esto
permite que una petición JPIP pueda ser encapsulada dentro de una
consulta GET del protocolo HTTP, a continuación del carácter '?',
concatenando todos los pares con el símbolo '\&'.

Algunos de los parámetros disponibles para una petición JPIP son
los siguientes:

\begin{itemize}

\item \textbf{``fsiz=$R_{x}$,$R_{y}$'':} Especifica la resolución
asociada a la región de interés solicitada. El servidor escogerá
la más pequeña resolución de la imagen tal que la dimensión de la
misma, $R_{x}'$ y $R_{y}'$ cumpla que $R_{x}' \geq R_{x}$ y
$R_{y}' \geq R_{y}$.

\item \textbf{``roff=$P_{x}$,$P_{y}$'':} Especifica la posición de
la esquina superior izquierda de la región de interés requerida
dentro de la resolución solicitada. Si esta posición no es
indicada, el servidor asumirá que es $0,0$.

\item \textbf{``rsiz=$S_{x}$,$S_{y}$'':} Especifica el tamaño de
la región de interés requerida. El servidor cortará este tamaño
para ajustarlo a la imagen real según la resolución especificada.

\item \textbf{``comps=$C_{0}$, $C_{1}$, \dots, $C_{N}$'':} Indica
las componentes que el servidor debe enviar de la región de
interés. Las demás componentes serán ignoradas. Si este parámetro
es ignorado, el servidor envía todas las componentes existentes.

\item \textbf{``len=número de bytes'':} El cliente le indica con
este parámetro al servidor el número máximo de bytes máximo que
debe enviar en la respuesta. El servidor tendrá en cuenta este
límite, no sólo en la respuesta a la petición actual, sino en las
restantes respuestas al resto de las peticiones que el cliente
haga bajo la misma sesión.

\item \textbf{``layers=$L$'':} Con este parámetro el cliente puede
limitar el número de capas de calidad a enviar por el servidor en
la respuesta.

\item \textbf{``target=imagen'':} Este parámetro identifica al
archivo de imagen del cual extraer la región de interés. Cuando se
emplea el servidor actúa como servidor HTTP, este parámetro no es
necesario ya que el nombre de la imagen se obtiene de la propia
URL indicada en el comando GET.

\item \textbf{``cnew=transporte'':} Cuando el cliente desee abrir
un nuevo canal bajo la misma sesión, empleará este parámetro, en
el cual se incluye el protocolo que se debe utilizar para el nuevo
canal. Los tipos de transporte permitidos hasta el momento son
"http" y "http-tcp".

\item \textbf{``cid=identificador de canal'':} Al crear el cliente
un nuevo canal, el servidor le envía el identificador del canal,
que debe ser incluido en todas las peticiones asociadas a ese
canal.

\item \textbf{``model=\ldots'':} Como se ha comentado, el cliente
puede necesitar comunicarle al servidor el contenido de su
\emph{cache} para que éste actualice el contenido del modelo que
mantiene. Esto lo puede hacer con este parámetro. Un ejemplo sería
el siguiente:
\begin{verbatim}
model=Hm,H*,M0,P0:20,-P1001
\end{verbatim}
con lo que le estaríamos indicando al servidor que incluyese en el
modelo de \emph{cache} que posee la cabecera principal del
\emph{codestream}, las cabeceras de todos los \emph{tiles}, el
\emph{data-bin} de meta información número cero (el principal),
que incluya los primeros 20 bytes del precinto 0 y que elimine el
precinto número 1001.

\item \textbf{``quality=calidad'':} El cliente le indica la
servidor cual es el máximo de calidad de la imagen a transmitir
(desde 0 a 100). El servidor puede ignorar este parámetro.

\end{itemize}

Un ejemplo de una petición JPIP usando el protocolo HTTP/1.1 sería
la siguiente:

\small\begin{verbatim}
GET imagen.jp2?fsiz=512,640&roff=0,0&fsiz=512,478&
               comps=0,1,2&len=2000 HTTP/1.1
Host: www.servidor.com
\end{verbatim}

\normalsize En ella estamos requiriendo las tres primeras
componentes de una región de interés de tamaño (512x478) cuya
esquina superior izquierda está situada en la posición (0,0) de la
mínima resolución de la imagen \emph{imagen.jp2} en la que quepa
una región de tamaño (512x640). También se limita la máxima
longitud de la respuesta del servidor en 2000 bytes.

\subsection{Respuestas}

Las respuestas del servidor bajo el protocolo JPIP son similares a
las respuestas de los servidor HTTP: una primera parte ASCII que
contiene un conjunto de cabeceras, y a continuación los datos de
la respuesta en forma de \emph{data-bins}.

Algunas de las cabeceras que puede enviar el servidor al cliente
son las siguientes:

\begin{itemize}

\item \textbf{``JPIP-fsiz: $R_{x}'$, $R_{y}'$'':} El servidor le
envía el tamaño de la resolución al cliente, que puede ser
diferente del requerido por éste.

\item \textbf{``JPIP-rsiz: $S_{x}'$, $S_{y}'$'':} El servidor le
envía el tamaño de la región de interés al cliente, que puede ser
diferente del requerido por éste.

\item \textbf{``JPIP-roff: $P_{x}'$, $P_{y}'$'':} El servidor le
envía la posición de la región de interés al cliente, que puede
ser diferente de la requerida por éste.

\item \textbf{``JPIP-comps: $C_{0}'$, $C_{1}'$, \ldots,
$C_{N}'$'':} El servidor le envía al cliente las componentes que
forman parte de la región de interés enviada, que pueden no ser
las mismas que fueron requeridas por el cliente.

\item \textbf{``JPIP-layers: $L'$'':} El servidor le envía al
cliente el número de capas de calidad incluidas en la región de
interés enviada, que puede no ser el mismo número requerido por el
cliente.

\item \textbf{``JPIP-cnew: cid=\ldots'': } Cuando el cliente
solicita la apertura de un canal nuevo, el servidor le envía el
identificador de canal \emph{cid} y una serie de información
relativa al canal, como el puerto y el \emph{host} a los que tiene
que dirigirse el cliente para las peticiones a través de este
canal, el protocolo empleado para el canal, etc.

\end{itemize}

Como se puede ver, el servidor tiene total libertad para alterar
los parámetros enviados por el cliente. Las razones por las que el
servidor cambie los parámetros especificados por el cliente en una
petición pueden ser varias: puede ocurrir que el responder fielmente a
lo requerido por el cliente requiriera un uso excesivo de recursos
por parte del servidor, en cuyo caso el servidor puede limitar la
respuesta, alterándola con el fin de optimizar el uso de los
recursos; también la petición del cliente puede que no sea
válida, con lo que el servidor podría modificarla para poder
tratarla. El cliente debe de estar preparado para aceptar
respuestas del servidor que no concuerden con sus peticiones.

A continuación podemos ver un ejemplo completo de petición y
respuesta, con el protocolo JPIP empleando al protocolo HTTP como
base:\\
\\
\small
\verb+Servidor+ $\longleftrightarrow$ \verb+Cliente+\\
\\
$\longleftarrow$
\verb+GET imagen.jp2&fsiz=12000,8000&rsiz=600,400&roff=5000,6000 HTTP/1.1+\\
$\longleftarrow$ \verb+Host: jpip.servidor+\\
$\longleftarrow$\\
\\
$\longrightarrow$ \verb+HTTP/1.1 200 OK+\\
$\longrightarrow$ \verb+JPIP-fsiz: 6000,8000+\\
$\longrightarrow$ \verb+JPIP-rsiz: 300,200+\\
$\longrightarrow$ \verb+JPIP-roff: 2500,3000+\\
$\longrightarrow$ \verb+Content-type: image/jpp-stream+\\
$\longrightarrow$ \verb+(Resto de cabeceras...)+\\
$\longrightarrow$ \\
$\longrightarrow$ \verb+(Data-bins de la respuesta...)+\\
\normalsize

\normalsize En este ejemplo el cliente solicita una región de
interés de tamaño 600x400 y cuya esquina superior izquierda esté
situada en la posición (5000,6000) de la resolución mínima de la
imagen \emph{imagen.jp2} encuadrada por un área de 12000x8000. El
servidor acepta la petición, pero la respuesta es ligeramente
diferente a la esperada por el cliente: la región devuelta tendrá
un tamaño de 300x200 y su esquina superior izquierda se situará en
la posición (2500x3000) de una resolución de 6000x8000.

\section{Indexado de archivos JP2}

Si bien el protocolo JPIP es el núcleo de la Parte 9 del estándar
JPEG2000, el grupo ISO/IEC JPEG no podía dar una solución tan
cerrada a la interacción de imágenes remotas; si fuese así,
cualquier aplicación que se quisiera explotar las estupendas
cualidades del nuevo formato de compresión para la visualización
remota de imágenes, necesitaría obligatoriamente un servidor, cuya
implementación no es poco compleja y su implantación no siempre es
posible. Por ello comprendió que debía ofrecer una solución
parcial \cite{Part9}, a parte del protocolo, para que quien
quisiera pudiese simular la funcionalidad del protocolo JPIP, sin
necesidad del servidor, utilizando solamente la posibilidad que
ofrece el tan difundido protocolo HTPP/1.1 para acceder a partes
de un archivo llamada \emph{byte-ranging}, que se verá más
adelante.

Esta solución consiste en la definición de un conjunto de cajas
para el formato de archivo definido por el estándar JPEG2000
(.JP2, .JPX, etc.) con las que poder indexar el archivo de imagen,
con el fin de que el cliente, leyendo estas cajas, sepa en qué
posición está cada \emph{data-bin} y qué tamaño tiene, de forma
que puede leerlos él directamente, sin necesidad de servidor
alguno.

Para cada \emph{codestream} que exista dentro de un archivo de
imagen, por ejemplo, un archivo .JP2, se incluiría una caja
\emph{Codestream Index}, cuyo tipo es 'cidx'. Esta caja contiene a
su vez una caja \emph{Codestream Finder}, una caja
\emph{Manifest}, y una secuencia de cajas de índice.

\begin{figure}
  \begin{center}
    \input{figuras/cajaCIDX}
    \caption{Caja \emph{Codestream Index}.}
    \label{fig:cajaCIDX}
  \end{center}
\end{figure}

La caja \emph{Codestream Finder}, cuyo tipo es 'cptr', contiene la
información necesaria para acceder directamente al
\emph{codestream} asociado a la supercaja \emph{Codestream Index}.
Esta información ocupa un total de 20 bytes y está divida en los
siguientes valores:

\begin{itemize}

\item \textbf{$DR$:} Un entero sin signo de 2 bytes que especifica
la posición del \emph{codestream} o de la caja \emph{Fragment
Table} asociada. Si $DR = 0$, el \emph{codestream} o la caja
\emph{Fragment Table} existe en el mismo archivo. Si $DR > 0$, el
valor de $DR$ es la entrada de la tabla contenida en la caja
\emph{Data Reference} que posee la referencia del archivo que
contiene el \emph{codestream} o la caja \emph{Fragmente Table}.

\item \textbf{$CONT$:} Es un entero sin signo de 2 bytes. Si $CONT
= 0$, quiere decir que el \emph{codestream} no está fragmentado,
dentro del archivo referenciado por $DR$, por lo que los valores
de $COFF$ y $CLEN$ se refieren al \emph{codestream} entero. Si
$CONT = 1$ el \emph{codestream} está fragmentado, y requiere por
tanto una caja \emph{Fragment Table}. Entonces, los valores de
$COFF$ y $CLEN$ se refieren a esta caja. Nótese que aún a pesar de
tener tan sólo dos valores posibles, 0 o 1, el valor de $CONT$ se
almacena inexplicablemente con dos bytes.

\item \textbf{$COFF$:} Entero sin signo de 8 bytes que contiene el
\emph{offset} del \emph{codestream} o la caja \emph{Fragment
Table} con respecto al comienzo del archivo referenciado por $DR$.

\item \textbf{$CLEN$:} Entero sin signo de 8 bytes que contiene la
longitud en bytes del \emph{codestream} o la caja \emph{Fragment
Table}.

\end{itemize}

En nuestro caso, asumiremos que $DR = 0$ y $CONT = 0$ en todos los
casos, por lo que obviaremos la descripción de las cajas
\emph{Data Reference} y \emph{Fragment Table}.

\begin{figure}
  \begin{center}
    \resizebox{!}{!}{\input{figuras/cajaCPTR}}
    \caption{Caja \emph{Codestream Finder}.} \label{fig:cajaCPTR}
  \end{center}
\end{figure}

La caja \emph{Manifest}, cuyo tipo es 'manf', es empleada para
indexar las cajas que se encuentren a continuación, en el mismo
nivel. Por ejemplo, en el caso de la caja \emph{Codestream Index},
la caja \emph{Manifest} incluida en ella contendrá un índice de
todas las cajas también incluidas en la caja \emph{Codestream
Index} situadas a continuación de la caja \emph{Manifest}. El
contenido de la caja está formado por una secuencia de $N$ pares
$(TBox_{i}, XLBox_{i})$. El valor de $N$ corresponderá al número
de cajas que se presenten a continuación de la caja
\emph{Manifest}. $TBox_{i}$ es una cadena ASCII de cuatro bytes
que contiene el tipo de la caja $i$. $XLBox_{i}$ es un entero sin
signo de 8 bytes con la longitud en bytes de la caja $i$.

\begin{figure}
  \begin{center}
    \resizebox{\textwidth}{!}{\input{figuras/cajaMANF}}
    \caption{Caja \emph{Manifest}.} \label{fig:cajaMANF}
  \end{center}
\end{figure}

A continuación de la caja \emph{Manifest}, incluida en la caja
\emph{Codestream Index}, nos encontramos con una caja de índice
por cada \emph{data-bin} del \emph{codestream} asociado, esto es:
cabecera principal, caja \emph{Main Header Index Table}, cabecera
de \emph{tile}, caja \emph{Tile Header Index Table} y precinto,
caja \emph{Precinct Packet Index Table}. Además es posible incluir
otro tipo de cajas como caja de \emph{tile-part}, caja
\emph{Tile-part Index Table}, y la caja para la cabecera de los
paquetes, caja \emph{Packet Header Index Table}.

La caja \emph{Main Header Index Table}, de tipo 'mhix', contiene
el valor $TLEN$ y una secuencia de $N$ pares $(OFF_{i}, LEN_{i})$,
donde $N$ es el número de partes en las que está dividida la
cabecera principal del \emph{codestream}. $TLEN$ es un entero sin
signo de 4 bytes que indica la longitud total de la cabecera en
bytes. $OFF_{i}$ es un entero sin signo de 4 bytes que contiene el
\emph{offset} de la parte $i$ de la cabecera. $LEN_{i}$ es un
entero sin signo de 4 bytes que almacena la longitud en bytes de
la parte $i$ de la cabecera.

\begin{figure}
  \begin{center}
    \resizebox{!}{!}{\input{figuras/cajaMHIX}}
    \caption{Caja \emph{Main Header Index Table}.}
    \label{fig:cajaMHIX}
  \end{center}
\end{figure}

Excepto la caja \emph{Main Header Index Table}, todas las demás
cajas de índice utilizan la caja \emph{Fragment Array Index}, de
tipo 'faix', que es una caja que alberga una tabla bidimensional
de fragmentos. En su contenido encontramos el valor $V$, el valor
$NMAX$, y una secuencia de $M \times NMAX$ pares $(OFF_{i,j},
LEN_{i,j})$, donde $0 \leq i < M$ y $0 \leq j < NMAX$. $V$ es un
valor de 1 byte que indica el tamaño del resto de valores: si $V =
0$ el resto de valores ocupan 4 bytes, pero si $V = 1$ el resto de
valores ocuparán 8 bytes. $NMAX$ es un entero sin signo que
contiene el número de elementos en cada fila de la tabla.
$OFF_{i,j}$ es un entero sin signo que almacena el \emph{offset}
del fragmento $(i,j)$ de la tabla. $LEN_{i,j}$ es un entero sin
signo con la longitud en bytes del fragmento $(i,j)$ de la tabla.
El valor de $M$ se obtendría mediante la longitud total de la caja
(contenida en la cabecera de la misma).

\begin{figure}
  \begin{center}
    \resizebox{\textwidth}{!}{\input{figuras/cajaFAIX}}
    \caption{Caja \emph{Fragment Array Index}.}
    \label{fig:cajaFAIX}
  \end{center}
\end{figure}

La caja \emph{Tile-part Index Table}, de tipo 'tpix', contiene en
su interior una única caja, una caja \emph{Fragment Array Index},
en la cual habrá tantas filas como \emph{tiles} haya, y tantas
columnas como \emph{tile-parts} haya por \emph{tile}, de forma que
el par $(OFF_{i,j},LEN_{i,j})$ sería el \emph{offset} y la
longitud del \emph{tile-part} $j$ del \emph{tile} $i$. Con esta
caja indexamos los \emph{tile-parts} enteros, desde el marcador
SOT hasta el último paquete del mismo, ambos incluidos.

\begin{figure}
  \begin{center}
    \resizebox{!}{!}{\input{figuras/cajaTPIX}}
    \caption{Caja \emph{Tile-part Index Table}.}
    \label{fig:cajaTPIX}
  \end{center}
\end{figure}

La caja \emph{Tile Header Index Table}, de tipo 'thix', contiene
también en su interior una única caja \emph{Fragment Array Index},
la cual también contendrá tantas filas como \emph{tiles} haya y
tantas columnas como \emph{tile-parts} haya por \emph{tile}. Pero
en esta ocasión esta caja no indexa el contenido total de cada
\emph{tile-part} sino únicamente su cabecera, por lo que el par
$(OFF_{i,j},LEN_{i,j})$ sería el \emph{offset} y la longitud de la
cabecera del \emph{tile-part} $j$ del \emph{tile} $i$. Las
cabeceras de cada \emph{tile-part} no son incluidas enteras, sino
que sólo se incluye entera la cabecera del primer \emph{tile-part}
y del resto, sólo se incluye el marcador PPT, si existe. Esto es
necesario tenerlo en cuenta porque, aunque el resto de los
marcadores se ignores, ignorar el marcador POC si existiese puede
repercutir en una descodificación errónea.

\begin{figure}
  \begin{center}
    \resizebox{!}{!}{\input{figuras/cajaTHIX}}
    \caption{Caja \emph{Tile Header Index Table}.}
    \label{fig:cajaTHIX}
  \end{center}
\end{figure}

La caja \emph{Precinct Packet Index Table}, de tipo 'ppix',
contiene en su interior una caja \emph{Manifest}, que indexa las
cajas que vienen a continuación, y que forman un conjunto de $N$
cajas, $faix_{i}$, de tipo \emph{Fragment Array Index}. Cada caja
$faix_{i}$ contiene información de todos los paquetes de la
componente $i$ de la imagen, de forma que, el par $(OFF_{j,k},
LEN_{j,k})$ de la caja $faix_{i}$, contiene el \emph{offset} y la
longitud del paquete $k$, del \emph{tile} $j$, de la componente
$i$. Los paquetes aparecerán de un mismo precinto aparecerán
contiguos, y el orden será el mismo empleado para construir el
número de secuencia $s$ para calcular el identificador del
\emph{data-bin} del precinto.

\begin{figure}
  \begin{center}
    \resizebox{!}{!}{\input{figuras/cajaPPIX}}
    \caption{Caja \emph{Precinct Packet Index Table}.}
    \label{fig:cajaPPIX}
  \end{center}
\end{figure}

La caja \emph{Precinct Header Index Table}, de tipo 'phix', sigue
la misma estructura que la anterior: contiene una caja
\emph{Manifest} que indexa las cajas que vienen a continuación, y
que forman un conjunto de $N$ cajas, $faix_{i}$, de tipo
\emph{Fragment Array Index}. Cada caja $faix_{i}$ contiene la
información de todas las cabeceras de todos los paquetes de la
componente $i$, de forma que, el par $(OFF_{j,k}, LEN_{j,k})$ de
la caja $faix_{i}$ contiene el \emph{offset} y la longitud de la
cabecera del paquete $k$, del \emph{tile} $j$, de la componente
$i$. La ordenación de las cabeceras de los paquetes seguirá la
misma regla que la empleada en la caja \emph{Precinct Packet Index
Table} para los paquetes.

\begin{figure}
  \begin{center}
    \resizebox{!}{!}{\input{figuras/cajaPHIX}}
    \caption{Caja \emph{Precinct Header Index Table}.}
    \label{fig:cajaPHIX}
  \end{center}
\end{figure}
