Un vídeo es una secuencia de imágenes que se muestran en

Anuncio
MPEG-2
Procesamiento de imágenes Digitales
Enrique Pozo Márquez
Miguel Ángel Oliva Delgado
1
Índice
1 Introducción
3
1.1 Compresión
4
1.1.1 Técnicas básicas de compresión
4
1.2 Algunos estándares de compresión de video
5
2 MPEG-2
10
2.1 ¿Por qué MPEG-2?
11
2.2 Niveles y perfiles
12
2.2.1 Niveles
12
2.2.2 Perfiles
13
2.3 Los modos escalables de MEPG-2
14
2.4 Esquema de codificación intertrama de video
15
2.4.1 Funcionamiento del algoritmo
16
2.4.1.1 Qué ocurriría en el caso de que algunas partes se moviesen a la
izquierda y otras ala derecha
20
2.5 Audio MPEG-2
21
2.6 Sistemas MPEG-2 para multiplexaje y transporte ITU-t Rec. H.222
23
2
2.7 Donde hay MPEG-2 en la actualidad?
25
3. Transformada Discreta del Coseno (DCT)
26
4. Documentación de la aplicación
36
5. Conclusiones
40
6.Bibliografía
40
7. Anexo
41
3
1.Introducción
Un vídeo es una secuencia de imágenes que se muestran en orden. Cada una de esas
imágenes será lo que se llame “trama”. Normalmente se muestran unas 30 tramas por
segundo. Esta información se puede comprimir perdiendo cierta calidad proporcional al
nivel de compresión. Si un segundo de vídeo contiene 30 tramas podemos jugar con
estas para obtener esta compresión al basar unas tramas en otras cercanas, que pueden
contener información acerca, por ejemplo, del movimiento. Esta compresión se puede
basar en las tramas del entorno, interframes, o bien, en la información de esa trama
solamente, intraframe. Las intraframes permitirán operaciones de acceso aleatorio,
como puede ser el avance rápido, y poseen una alta tolerancia a los fallos, como es
lógico al basarse su compresión tan sólo en sí mismas. Así si una parte de una trama se
pierde, la próxima intraframe y las tramas posteriores podrán visionarse sin problema al
depender exclusivamente de su propia información.
Todo color se puede representar por la combinación de tres colores básicos, rojo,
verde y azul, este espacio de color se conoce como RGB (Red, Green, Blue), pero esta
forma de representar los colores no se tiene en cuenta ya que no considera la percepción
humana. Así tenemos el espacio de color YUV donde solo con Y ya tenemos la escala
de grises, a la cual el ojo humano es más sensitiva, y que es la que realmente se utiliza
para los temas de compresión. También se utiliza en NTSC, PAL, SECAM.
Para obtener unos mejores ratios de compresión se predicen los píxeles basándolos
en otros píxeles. Tenemos una predicción espacial donde podemos obtener un píxel
basándonos en otros píxeles de la propia imagen y la predicción temporal en la que un
píxel se puede obtener de una imagen transmitida anteriormente. También existe una
codificación híbrida que consiste una predicción temporal con una técnica de
correlación en el dominio espacial. La compensación del movimiento establece una
correspondencia entre elementos de imágenes cercanas en la secuencia de vídeo. Esta
compensación del movimiento nos suministra una fácil predicción para una imagen
dada de una imagen de referencia.
4
De todos los algoritmos de codificación estandarizados el más usado es la
Transformada Discreta del Coseno (DCT, Discrete Cosine Transform) de la cual
trataremos más adelante ampliamente.
1.1.Compresión
Básicamente la compresión se divide en:
- Compresión sin perdidas: Esta técnica se utiliza principalmente, cuando es
necesario transmitir mensajes de emisor a receptor sin que se produzca ningún tipo de
distorsión o de cambio significativo respecto al mensaje original.
Estas técnicas se basan, principalmente, en utilizar más o menos bits según la
frecuencia de utilización, es decir, se observa si se producen repeticiones para intentar
codificarlas con menos bits de los que en principio serian necesarios.
- Compresión con perdidas: Cuando es necesario llegar a unos flujos de información
que no sobrepasen unos determinados limites de ancho de banda y esto no es posible
utilizando técnicas de compresión sin perdidas, será necesario comprimir aún más la
señal aunque esto repercuta en su calidad.
Aunque en principio no lo parezca, en algunos casos nos podemos permitir el lujo de
aumentar la compresión en decremento de la calidad.
1.1.1.Técnicas básicas de compresión:
- Cuantificación: Se basan principalmente en utilizar menos bits de los necesarios
para describir una información, utilizando la misma combinación de bits para datos
semejantes o próximos.
- Predicción: Las técnicas de predicción se basan en la correlación entre píxeles
próximos o imágenes próximas, es decir, si por ejemplo tenemos una imagen donde la
mayor parte de los píxeles representan el cielo, todos estos píxeles serán semejantes, por
lo tanto la utilización de menos bits para describirlos no repercutirá de forma notable en
el decremento de la calidad.
5
-Transformación y aplicación de filtros: Una de las técnicas más utilizadas en la
compresión de señales analógicas es el filtraje. Por ejemplo, una señal de voz humana
de 20Khz puede ser transmitido por una línea telefónica con un ancho de banda de 4Khz
utilizando un filtro de paso bajo (lowpass filter)
- Compresión basada en modelos Se utiliza cuando es necesario llegar a niveles de
compresión extremos donde un gran nivel de distorsión puede ser aceptable.
1.2.Algunos estándares de compresión de video:
H.261
Fue diseñado para la transmisión de vídeo a velocidades múltiples de 64 Kbps. Se ha
aplicado en el videoteléfono y en la videoconferencia. Es similar a la compresión de
imágenes estáticas JPEG. Posee una estructura de 4 capas, que son multiplexadas para
su transmisión en serie.
H.263
Se diseñó para aplicaciones con velocidades de codificación de muy baja velocidad.
Posee una eficiencia más alta que el H.261, aunque está basado en él. La compresión se
lleva a cabo por partición de cada imagen en macrobloques, cada uno de los cuales se
compone de un bloque de luminancia de 16x16 y de dos bloques de crominancia de
8x8.
H.263+
Es una extensión del H.263 aunque incorpora muchas características adicionales.
Suministra la escalabilidad SNR y la espacial y temporal.
6
MPEG-1
MPEG está basado en un sistema de capas, con un estándar de compresión de vídeo
basado en la DCT, y que nos da unas velocidades de aproximadamente 1,5 Mbps con
una resolución de aproximadamente 352x240.
Las secuencias de vídeo se componen de diferentes capas que permiten el acceso
aleatorio a una secuencia determinada así como una especie de barrera contra la
información errónea.
Las tramas se codifican de tres formas: las Intra-coded (I-frames), las Predictivecoded (P-frames) y las Bidirectionally-predictive-coded (B-frames). Las I-frames se
codifican independientemente de cualquier otra trama, y son las que suministran los
puntos de acceso aleatorio al vídeo. Poseen el peor nivel de compresión de los tres tipos.
Las P-frames se codifican teniendo en cuenta una trama ya pasada, que puede ser una Iframe u otra P-frame. Su compresión es más alta que en el caso anterior. Y por último
las B-frames que requieren una trama anterior y otra posterior para su codificación, que
pueden ser o I-frames o P-frames, y son las que ofrecen el mayor nivel de compresión
de los tres tipos.
Un vídeo MPEG consiste en muchas secuencias de vídeo, cada una de las cuales
posee muchos grupos de imágenes. Típicamente un grupo de imágenes (GOP) posee
una única I-frame y muchas P-frames y B-frames.
Las tramas se dividen en bloques de tamaño 16x16 que reciben el nombre de
macrobloques. Una secuencia de macrobloques compone un slice. Y cada trama se
compone de muchos slices.
Muchos de los parámetros se pueden especificar en la fase de codificación.
Cada capa añade una cabecera para sincronización. Así si parte de un slice se pierde,
el decodificador se salta el resto del slice y continuará decodificando en el principio del
siguiente slice.
7
MPEG-2
Se diseña para aplicaciones que requieren velocidades de hasta 100 Mbps. Por
ejemplo, la televisión digital de alta definición, los medios de almacenamiento
interactivos, o la televisión por cable. En MPEG-2 se pueden usar múltiples formatos de
vídeo para soportar las distintas aplicaciones. Posee escalabilidad de la cadena de bits,
así es posible extraer cadenas más pequeñas para obtener una resolución o una
velocidad de trama más pequeña.
La decodificación es más costosa que en el caso anterior, aunque la escalabilidad de
las cadenas de bits permite flexibilizar un poco los requerimientos de procesamiento
para la decodificación.
MPEG-2 es compatible hacia arriba, hacia abajo, hacia delante y hacia atrás. Esto
quiere decir lo siguiente:
- Compatibilidad hacia arriba: el decodificador puede decodificar imágenes
generadas por un codificador de inferior resolución.
- Compatibilidad hacia abajo: el decodificador puede decodificar imágenes generadas
por un codificador de superior resolución.
-
Compatibilidad hacia delante: un decodificador de nueva generación puede
decodificar las imágenes generadas por un codificador ya existente.
- Compatibilidad hacia atrás: los decodificadores actuales pueden decodificar las
imágenes generadas por los nuevos codificadores.
Las capas de secuencia de vídeo en MPEG-2 son similares a las de MPEG-1.
Los macro bloques en MPEG-2 tienen dos bloques de crominancia adicionales
cuando se usa el formato de entrada 4:2:2. MPEG-2 usa el tamaño de bloque 8x8
aunque puede usar otros tamaños, 1x1, 2x2, 4x4 para resoluciones mejoradas.
Las tramas P y B poseen la trama y los vectores del campo de movimiento. La
decodificación en tiempo real es algo ardua con los procesadores normales.
8
MPEG-3:
Se intentó desarrollar para televisión con velocidades de transmisión altas pero acabó
desechándose y fusionándose con MPEG-2.
MPEG-4:
Al principio, el estándar MPEG-4 se creó como un intento para mejorar la calidad del
video codificado de bajas velocidades a través de la estandarización de nuevas técnicas
mejoradas de compresión. Más adelante, su progresión recondujo este estándar al
mundo de la TV interactiva, la computación y las telecomunicaciones.
Las nuevas características ofrecidas por este estándar se pueden resumir en:
- Las escenas se descomponen en 2 componentes básicas: Audio y Vídeo. Estos dos
objetos
son
codificados
de
forma
independiente.
- Los objetos pueden ser tanto video natural (p.ej. generado por una cámara) como
imágenes
sintéticas
(generadas
por
un
ordenador).
- Ofrece soporte para manipulación de las imágenes sintéticas (soporte para animación,
utilización
de
imágenes
estáticas
2D-3D
como
logos
etc).
- Permite interacción de los usuarios sobre la escena que se está renderizando.
- Se ha mejorado la base del algoritmo MPEG para incrementar la robustez para el trato
de errores.
Cabe destacar que tanto MPEG-4 como H.263 se encuentran principalmente
enfocados a intentar mantener una calidad de video en tiempo real utilizando los
mínimos bits posibles, por lo tanto, los dos estándares están enormemente relacionados
.
Algoritmo Motion-JPEG:
MJPEG es un estándar internacional creado para la compresión de frames estáticos.
Es decir, en este caso lo que se realiza es una compresión de cada frame de forma
estática sin utilizar técnicas de predicción y cada frame es enviado individualmente uno
detrás
de
otro.
MJPEG utiliza la DCT para transformar bloques de 8x8 píxeles, luego cuantifica los
valores en dominio transformado y finalmente utiliza una compresión con perdidas para
codificarlos.
9
Como se puede observar, la naturaleza de este tipo de técnica de compresión no se
puede considerar como un estándar de imágenes en movimiento puesto que lo que en
realidad se está haciendo es utilizar un algoritmo para imágenes estáticas y utilizarlo en
cada uno de los frames que forman la película para conseguir un efecto de movimiento.
Cabe destacar que a veces, MJPEG utiliza también un tipo de compresión por
predicción teniendo en cuenta la diferencia temporal entre frames consecutivos. En este
caso, debido a la utilización de una compresión con perdidas, este formato podrá
considerarse como una especie de MPEG degenerado, es decir, mejoramos el tamaño de
los archivos y conseguimos más simplicidad pero a la vez el resultado final presentará
una calidad menor.
Motion Wavelets
Este tipo de compresión está basado en aplicar el algoritmo de la DCT pero en toda
la
imagen
a
la
vez
y
no
en
bloques
de
8x8.
Los valores de la transformada son cuantificados con compresión sin perdidas.
En principio, este formato se utiliza de la misma forma que los MJPEG, es decir, se
destina principalmente a frames estáticos y se puede aplicar a imágenes en movimiento
mediante la transmisión individual de cada frame codificado.
La ventaja más importante respecto al formato MJPEG se puede observar a niveles
de compresión muy altos del orden de 32:1 o 64:1 ya que, mientras la utilización de
bloques de 8x8 (como en el caso de MJPEG) produce bastante distorsión en la imagen,
la no utilización de bloques, es decir, la aplicación de la transformada sobre toda la
imagen a la vez, produce un grado más subjetivo de distorsión ya que no se percibe
tanto ese efecto de "bloque".
Normalmente este formato se utiliza en el caso de necesidad de grandes factores de
compresión sin la utilización de redundancia entre frames.
10
2.MPEG-2
La segunda fase de MPEG, llamada MPEG 2, también consta de tres partes o
estándares, cubiertas por la: ISO/IEC 13818-1 Sistemas MPEG-2 (Draft ITU-T Rec.
H.222), ISO/IEC 13818-2 Vídeo MPEG-2 (Draft ITU-T Rec. H.262) y ISO/IEC 138183 Audio MPEG-2. Estas fueron aprobadas finalmente como Estándar Internacional (IS)
por la asamblea N° 29 de la ISO/IEC JTC1/SC29/WG11 (MPEG) hecha en Singapore
en Noviembre de 1994.
El registro ITU-T H.262 trata con codificación de vídeo de alta calidad con posible
vídeo entrelazado de NTSC, PAL o Televisión de Alta Definición (HDTV). Esto es un
intento para operar en un rango de 2 a 15 Mbit/s. Sin embargo puede funcionar a
velocidades superiores de 100 Mbit/s. Un amplio rango de aplicaciones, velocidades,
resolución calidades de las señales y servicios son direccionados, incluyendo todas las
formas de medios de almacenamiento digital, televisión (incluyendo HDTV),
broadcasting y comunicaciones.
Entre las varias mejoras o extensiones introducidas en los codificadores MPEG 2,
tenemos:
- Nuevos modos de predicción de campos y tramas para scanning entrelazado.
- Cuantización mejorada.
- Nuevos códigos intra-trama de longitud variable (VLC).
- Extensión escalada de resoluciones para compatibilidad, servicios jerárquicos y
robustos.
- Dos nuevas capas de sistema para multiplexaje y transporte que provee
celdas/paquetes de vídeo de alta o baja prioridad, cuando son llevados a través de una
red conmutada.
- Incrementos soportados por accesos aleatorios.
- Soporte resistente para incremento de errores.
- Múltiples programas con un multiplexor (MPEG 1 no puede hacer esto, y esto fue
un driver principal para el MPEG 2).
11
Al igual que el H.261 y JPEG (Joint Photographic Expert Group), el estándar MPEG
2 es un esquema híbrido de compresión para imágenes en pleno movimiento que usa
codificación inter-trama y codificación intra-trama y combina la codificación predictiva
con la codificación con la transformada DCT 8x8 (Discrete Cosine Transform, o sea,
transformada discreta de coseno). La DCT es un algoritmo matemático (conversión del
dominio del tiempo hacia el dominio de la frecuencia), que es aplicado típicamente a un
bloque de 8x8 elementos de imagen, dentro de un cuadro. La DCT elimina redundancia
en la imagen a través de la compresión de la información contenida en 64 píxeles. El
cuantizador otorga los bits para los coeficientes DCT más importantes, los cuales son
transmitidos
2.1.¿Por qué MPEG-2?
El concepto de MPEG 2 es similar al MPEG 1, pero incluye extensiones para cubrir
un amplio rango de aplicaciones. La principal aplicación destinada durante el proceso
de definición de MPEG 2 fue todas las transmisiones de vídeo con calidad de TV
codificadas a velocidades entre 5 y 10 Mbit/s.
Sin embargo, la sintaxis del MPEG 2 ha sido descubierta para ser eficiente para otras
aplicaciones como las de altas velocidades binarias y velocidades de muestreo (HDTV).
La característica más resaltante con respecto a MPEG 1 es la sintaxis para codificación
eficiente de vídeo entrelazado.
Otras características más específicas (precisión 10 bit DCT DC, cuantización nolineal, tablas VLC) son incluidas, y tienen un mejoramiento notable en la eficiencia de
la codificación. Otra característica clave de MPEG 2 son las extensiones escalables las
cuales permiten la división de continuas señales de vídeo dentro de dos o más cadenas
binarias codificadas, representando el vídeo en diferentes resoluciones, calidades (por
ejemplo SNR), o velocidades.
12
2.2.Niveles y perfiles
MPEG-2 es una recomendación muy compleja, tiene una larga variedad de
combinaciones (sobre 106). Sin embargo, un reducido conjunto de combinaciones son
definidas bajo "perfiles" y "niveles".
Dentro de los perfiles, una larga variación de desempeños son posibles. Por otra parte
los niveles son un conjunto de derivaciones impuestas para los perfiles. Las
combinación de un perfil y un nivel produce una arquitectura muy bien definida para
una cadena particular de bit.
Los perfile limitan la sintaxis (por ejemplo los algoritmos), mientras los niveles
limitan los parámetros (velocidad de muestreo, dimensiones de las tramas, velocidad
binaria codificada, etc.).
2.2.1.Niveles:
Proveen un rango de cualidades potenciales, definen los máximos y mínimos para la
resolución de la imagen, muestras Y por segundo (luminancia), el número de capas de
audio y vídeo soportados por los perfiles escalados, y la máxima velocidad binaria por
perfil. A continuación una explicación resumida de cada uno de ellos:
- Nivel Bajo: tiene un formato de entrada el cual es un cuarto de la imagen definida
en el registro ITU-R 601.
- Nivel Principal: tiene una trama de entrada completa definida en el registro ITU-R
601.
- Nivel Alto 1440: tiene un formato de alta definición con 1440 muestras por línea.
- Nivel Alto: tiene un formato de alta definición con 1920 muestras por línea (para
aplicaciones sin cualquier limitación en velocidades de datos).
13
2.2.2.Perfiles:
Son definidos subconjuntos con características de sintaxis (por ejemplo: algoritmos),
usados para converger la información. Hay cinco diferentes perfiles y cada uno es
progresivamente más sofisticado y agrega herramientas adicionales (y por supuesto más
costoso para el cliente) con la característica adicional de ser compatible con el anterior.
Esto significa que un decodificador equipado con un alto perfil descodificará perfiles
simples.
A continuación una pequeña explicación de los perfiles:
- Perfil Simple: es el que ofrece pocas herramientas.
- Perfil Principal: tiene herramientas extendidas o mejoradas del perfil simple y
predicción bidireccional. Tendrá mejor calidad para la misma velocidad binaria que el
perfil simple.
- Perfil Escalable SNR y Perfil Escalable Espacial: son los próximos pasos. Estos dos
niveles son llamados escalables porque ellos permitirán codificar datos de vídeo que
sean particionados dentro de una capa base y una o más señales "Top-up". La señal
Top-up puede tanto tratar la proporción S/N (SNR escalable) o la resolución (escalable
espacial).
- Perfil Alto: este incluye todas las herramientas de las versiones anteriores y
mejoradas. Tiene la habilidad de codificar diferencias de color entre líneas
simultáneamente. Este es un super sistema diseñado para aplicaciones donde no están
contraídas sobre las velocidades de los bits.
Para muchas de las aplicaciones (incluyendo transmisión de satélites) el Perfil
Principal, Nivel Principal (MP@ML, siglas en ingles) provee una buena relación entre
calidad de imagen y la complejidad VLSI, como resultado, MP@ML el punto de
desarrollo para los actuales sistemas DCTV.
14
2.3.Los modos escalables de mpeg 2
Actualmente hay cuatro modos escalables en MPEG 2. Estos modos rompen el vídeo
MPEG 2 en diferentes capas (base, media, y alta) para propósitos de proritización de
datos de vídeo. Otro propósito de la escalabilidad es para divisiones complejas. Por
ejemplo, en HDTV, la alta prioridad de la cadena binarias (720x480) puede ser
descodificada bajo condiciones de ruido donde la baja prioridad (1440x960) no pueda.
A continuación una breve explicación de los modos escalables:
- Escalabilidad espacial: Este método de dominio espacial codifica la capa base a una
dimensión de muestro bajo (por ejemplo: resolución) que las capas superiores. Las
capas bajas (base) reconstruidas del muestro son usadas como predicción de las capas
superiores.
- Particionamiento de datos: es un método de dominio de frecuencia que rompe los
bloques de 64 coeficientes cuantizados de la transformada dentro de dos cadenas
binarias. La primera, cadena de alta prioridad contiene los coeficientes más críticos de
las frecuencias bajas e información (tales como valores DC, vectores, etc.), la segunda,
cadena binaria de baja prioridad lleva datos AC de las altas frecuencias.
- Escalabilidad SNR: es un método de dominio espacial donde los canales son
codificados a velocidades de muestreo idénticas, pero con diferentes calidades de
imágenes. La cadena binaria de alta prioridad contiene datos de la capa base que pueden
ser añadidos a la capa de refinamiento de baja prioridad para construir una imagen de
alta calidad.
- Escalabilidad temporal: Un método de dominio temporal usado por ejemplo en
vídeo estereoscopico. La primera, la cadena binaria de alta prioridad codifica vídeo a
una baja velocidad de tramas, y las tramas intermedias pueden ser codificadas en una
segunda cadena binaria usando la reconstrucción de la primera cadena binaria como
predicción. Por ejemplo en una visión estereoscopica, el canal de vídeo izquierdo puede
ser predecido del canal derecho.
15
2.4.Esquema de codificacion intertrama de video
Para explorar todas las capacidades de compresión de compensación de movimiento
y para incorporar capacidades de adelantado rápido y retroceso rápido (fast forward y
fast reverse FF/FR), requeridos para servicios de almacenamiento digital, MPEG 2,
incorpora algunos esquemas de codificación intertrama. El concepto está basado en
Intra-trama (I), tramas predecibles (P), tramas interpoladas o bidireccionales (B) y
tramas D (Imágenes DC).
- Una trama I es codificada sin referencia para otras imágenes o tramas contenidas en
la secuencia del vídeo. Cualquier trama I trabaja como un punto de referencia para
funcionalidad y accesos FF/FR. Libera muy baja compresión.
- Las tramas P son codificadas con la referencia de las tramas previamente
codificadas, tanto I y P. Ellas incorporan compensación de movimiento, la compresión
es más alta que las tramas I.
- Las tramas B requieren como referencia tanto las tramas futuras como pasadas, las
tramas B usan compensación e interpolación de movimientos y logra alta compresión.
- Tramas D (imágenes DC) son imágenes que contienen solamente la DC (bloques de
8x8) para cada bloque. El soporte de éste tipo de trama es opcional, y las secuencias
pueden no contener tramas D mezcladas con los otros tipos de tramas.
La proporción entre las tramas I, P y B es conocida como N/M, donde N representa
el número de tramas entre imágenes o tramas I y M es el número de tramas entre
imágenes o tramas P. Valores típicos son de 15 y 3 para N y M respectivamente.
La incorporación de estas tres tipos de tramas, aportan alta compresión, buen acceso
aleatorio y funcionalidad FF/FR. Este esquema de codificación también incrementa
significativamente el retraso de codificación porque las tramas de las imágenes deben
ser almacenadas en un buffer. Por ejemplo, el codificador considerará la primera trama
como una trama I, la segunda y tercera trama serán tramas B, luego ellas son predecidas
e interpoladas basadas en la trama previa I (o P) y la próxima trama P, serán puestas en
el buffer y codificada la próxima trama como P, la cual sólo es referida a la trama previa
I. Después de codificar la trama P, el codificador retornará a trabajar con la trama
16
almacenada B. El descodificador revertirá el proceso. El recibirá la trama I, la trama P y
la trama B y reconstruirá la trama original del vídeo. El proceso, requiere más memoria
en el descodificador que en el codificador. Este retraso de codificación hace que MPEG
2 no sea bueno para aplicaciones interactívas.
2.4.1.Funcionamiento del algoritmo
En la figura vemos como se muestran una serie de tramas de distintos tipos, vemos
que la secuencia se compone exactamente de una trama I, que la inicia, tres tramas B,
una trama P, otras tres tramas B y por último otra trama P.
Esta es la forma en que la secuencia se nos visionará, pero que ocurre si las tres
primeras tramas B dependen de la trama I y de la trama P interior, tenemos que no
podremos visionar las tramas B hasta que hayamos recibido la trama P, por lo tanto se
nos plantea un problema, que no es tal ya que este asunto ya está pensado y se resuelve
sabiendo que el orden de codificación no es el mismo que el de visualización.
Así las tramas se codifican de tal forma que la trama referida precede a las tramas de
referencia. Veamos esto en el ejemplo. El orden de visualización era I B B B P B B B P,
pues bien, el orden de codificación será I P B B B P B B B. El decodificador tiene el
cometido de reordenar las tramas, que poseen un número de trama ascendente para cada
una en módulo 1024.
17
18
MPEG-2 se basa en la predicción para realizar una mejor compresión, así un objeto,
que puede ser un triángulo aparece en la trama I en una determinada posición, la
siguiente trama P nos muestra el mismo triángulo pero en otra posición, entonces si
pensamos un poco veremos que el triángulo es el mismo, tan solo varía su posición
dentro de la escena, por tanto podemos representarlo mediante un vector de movimiento
que nos indique como mover el triángulo desde la posición que ocupa en la trama I
hasta la posición que ocupa en la trama P. Este vector de movimiento forma parte de la
cadena de MPEG y se divide en una parte horizontal y otra vertical, las cuales pueden
ser positivas o negativas de forma indistinta, así un valor positivo significa que el
movimiento hacia la derecha o hacia abajo, y un valor negativo significa que el
movimiento es hacia la izquierda o hacia arriba.
El rango que cubren estos valores es de –64 a +63, con lo que pueden hacer
referencia a un área de 64x64 píxeles.
Sin embargo esta forma de desplazamiento no es completa, podemos encontrarnos
con el caso en que una figura se desplace de un lugar a otro y encima rote equis grados.
Aquí entramos en lo que se llama la predicción de error que MPEG contempla y para lo
cual posee los mecanismos necesarios para su compensación.
Al reconstruir tramas inter coded haremos lo siguiente, en primer lugar aplicamos el
vector de movimiento a la trama y en segundo lugar añadimos la compensación de la
predicción de error al resultado, como vemos en la siguiente figura.
19
trama I
+
Predicción hacia
delante
+
vector de movimiento
resultado
compensación del
error de la predicción
NOTA.- en la figura vemos que el rectángulo de ejemplo lleva un borde negro que ha
sido añadido simplemente para que se aprecie mejor la compensación del error de la
predicción.
Debemos señalar que la compensación del error de la predicción requiere menos
bytes que la trama completa porque las partes blancas son cero y se pueden descartar de
la cadena MPEG. De todas formas se aplica la compresión DCT a la predicción de error
lo que hace que el tamaño disminuya enormemente.
También vemos como en un principio se le aplica (añade, +) a la trama I el vector de
movimiento, y que al resultado le aplicamos la compensación del error de la predicción.
20
2.4.1.1.¿Qué ocurriría en el caso de que algunas partes se
moviesen a la izquierda y otras a la derecha?
Pues bien, en este caso no podemos aplicar el vector de movimiento a la trama
completa, sino que la trama se divide en macro bloques de 16x16 píxeles cada uno con
su propio vector de movimiento. Con esto se reduce la probabilidad de movimiento
contradictorio, aunque no lo elimina totalmente.
De todas formas si se diese un movimiento contradictorio que no se pueda evitar no
existe problema ya que no hay que cometer el fallo de suponer que la técnica de
compresión de MPEG asume que todos los macro bloques de tramas P se pueden
predecir, si existe un error de predicción muy grande el codificador puede tomar la
determinación de intra codificar un macro bloque, con lo cual se evitaría el problema.
Cada macro bloque contiene 4 bloques de luminancia y 2 de crominancia. Cada
bloque tiene una dimensión de 8x8 valores.
Los bloques de luminancia contienen información sobre el brillo de cada píxel en el
macro bloque.
Los bloques de crominancia contienen información del color. Esta información no es
sobre el color de cada píxel, ya que el ojo humano es incapaz de distinguirlo. En lugar
de eso se asocian 4 pixeles para cada valor de color. Este valor de color se divide en dos
partes, la primera es el bloque de color Cb y la segunda el bloque de color Cr. En la
figura siguiente podemos ver como son estos bloques y como se aplican.
lum
lum
lum
lum
Cb
Cr
8
8
8
8
21
En resumen, el modelo de codificación de video es el siguiente:
2.5.Audio mpeg 2
El sistema de multiplexaje MPEG 2, soporta cualquier número de canales de entrada
de audio tan largos que la velocidad de transporte seleccionada pueda soportar la suma
de datos. Los usuarios tienen la flexibilidad para seleccionar su propio algoritmo de
compresión de audio, tales como: Audio MPEG 2, MUSICAM, DOLBY AC-2 o AC-3.
Los canales pueden ser configurados independientemente o en pares estéreo. Diferentes
22
velocidades de audio es otra de las características de el sistema. Una vez más, la
velocidad también será asociada con la calidad.
La compresión de audio MPEG 2 es un algoritmo que, como el vídeo MPEG 2,
explota las limitaciones del sistema humano, en este caso el oído. Como en la
compresión de vídeo, el algoritmo de compresión de audio también elimina la
información irrelevante dentro de la señal de audio. La información irrelevante es
cualquier señal imperceptible. Por ejemplo, en presencia de una señal fuerte, todas las
señales vecinas flojas son enmascaradas y aunque son parte del espectro, no son
percibidas por el oído. El algoritmo MPEG 2 es del tipo "lossy" o con pérdidas pero la
distorsión insertada por la señal será inaudible.
La configuración básica del audio MPEG 2 ofrece seis canales de audio. Esta
característica debe ser usada para distribuir tres pares de estéreos ( o seis canales mono)
para aplicaciones multilenguajes o para crear un sistema estereofónico multicanal. Lo
anterior crea una realidad como a la de un campo de audio. La recomendación de
cornetas configuradas para sistemas estereofónicos multicanales es conocido como
estéreo -p/q , donde p es el número de cornetas en el frente y q es el número de cornetas
en el fondo. Por ejemplo un estéreo-3/2 proveerá un sistema con canales al frente en la
derecha, centro y a la izquierda más canales posteriores que rodean el área y ofrecen un
mejor e impresionante realismo a la audiencia.
Las configuraciones típicas para sistemas estereofónicos multicanales son:
1 Canal modo 1/0: Mono
2 Canales estéreo 2/0: izquierda y derecha
3 Canales estéreo 3/0: izquierda, derecha y centro
4 Canales estéreo 3/1: izquierda, derecha, centro y posterior
5 Canales estéreo 3/2: izquierda, derecha, centro, posterior izquierda y derecha
5.1 Canales estéreo 3/2: izquierda, derecha, centro, posterior izquierda y derecha y
un canal de efectos especiales de 100 Hz LFE (Low Frequency Enhancement).
23
Audio MPEG 2 ofrece tres diferentes capas de compresión (capa -I, -II, y -III). Cada
capa usa un esquema de reducción incremental de la velocidad binaria, con la ayuda de
el incremento de la velocidad de compresión mientras se mantiene la calidad.
Para la capa -II, la técnica de reducción de bit corresponde para el algoritmo
MUSICAM, el permite varias combinaciones de velocidades de bit (32 a 224 Kbit/s por
canal), y calidad de audio sin comprometer la complejidad del hardware. Por ejemplo
una velocidad de muestreo de 56 Kbit/s y 16 KHz en la capa -II ofrece mejor calidad
que la definida en el registro ITU-G.722.
El modelo de codificación de audio en MPEG es el siguiente:
2.6.Sistemas mpeg 2 para multiplexaje y transporte (ITU-T
Rec. H.222)
El multiplexaje y transporte definidos bajo MPEG 2 específica el formato de
codificación para multiplexar audio, vídeo y datos dentro de una forma manejable para
almacenar o transmitir. Hay dos formatos de cadenas de datos definidos:
1. Cadena de transporte (TS), la cual porta o lleva uno o más programas
simultáneamente, es optimo para aplicaciones donde la pérdida de datos puede ser
requerida (como los enlaces satelitales). Tales errores pueden ser manifestados como
24
errores de bit o pérdida de paquetes. Una TS es una sucesión de paquetes de 188 bytes
de longitud llamados "paquetes de transporte". Es posible construir una TS a partir de:
- Cadenas elementalmente paquetizadas (PES), vienen de múltiples programas. Cada
programa debe tener velocidad variable, sin embargo, la TS será de velocidad fija. Cada
programa tiene un Reloj Referencial Primario (PCR) asociado con el para indicar la
actual velocidad del programa.
- Cadenas de Programa u otra TS las cuales puedan contener uno o más programas.
La cadena de transporte es optima para transmisiones de satélites, cable, ISDN, redes
ATM y vídeotelefonía.
2. Cadena de programa (PS). Es optima para usarse en ambientes libres de errores,
como aplicaciones multimedia. Llevan paquetes largos de longitud variable. Cada
paquete comenzará con una cabecera. Un error en la cabecera puede causar la pérdida
del paquete completo y puede representar la corrupción de una trama entera de vídeo.
PS puede llevar uno o más programas simultáneamente, pero la PES tiene que compartir
un tiempo base común.
3. Cadena Elementalmente Paquetizada (PES): El transporte es desarrollado
dividiendo las salidas del compresor (vídeo y audio) para formar paquetes de longitud
variable marcados por tiempo llamados cadenas elementalmente paquetizadas (PES).
Las PES son paquetes de longitud variable sujeto a la máxima longitud de 64 Kbytes. El
proceso de paquetización es aplicado para tanto vídeo y audio. Cada PES es marcado
con el tiempo para darse una referencia antes y después del demultiplexaje, con la
finalidad de reproducir las tramas de vídeo completamente sincronizadas con el audio
PES. Este es un tiempo de referencia para cada programa llamado Reloj Referencial
Primario (PCR). El PCR es una información independiente usada para crear un reloj de
referencia en el descodificador. Cada programa prescinde de la velocidad y si la
velocidad es variable o fija son referidas para un PCR. Finalmente, la PES viniendo de
diferentes programas puede compartir un único PCR.
25
4. Multiplexaje: Un multiplexaje basado en paquete es muy flexible. Paquetes
pertenecientes a diferentes programas pueden ser distribuido de varias maneras. Un
buffer es usado en el descodificador para asegurarse que todos los datos son
descodificados y presentados a tiempo. Ya que la naturaleza inherente de la PES es
variable en velocidad, el multiplexaje basado en paquetes es de gran aprovechamiento
porque puede distribuir PES de diferentes fuentes con diferentes velocidades
instantáneas dentro de una salida común con velocidad fija. Explotando la no
coincidencia de picos de velocidad, se puede transportar altas velocidades
instantáneamente en una salida de baja velocidad. Este tipo de multiplexor es algunas
veces referido como "multiplexor estadístico".
Las capas del sistema ofrecen diferentes modos de operación:
- Multiplexaje estadístico, descrito anteriormente.
- Multiplexaje estadístico limitado en el cual la velocidad de cualquier cadena de
vídeo no podrá caer bajo un umbral programable.
- Multiplexaje con velocidad fija, las velocidades de vídeo son fijas.
- Modo mixto. Todos los modos previos pueden ser mezclados dentro de un simple
TS.
Después del multiplexaje, la señal sufrirá el proceso final, cada paquete de transporte
puede ser encriptado y revuelta, bajo control de acceso condicional. La salida de un
multiplexor portando múltiples canales siempre será a velocidad fija.
2.7.¿Donde hay mpeg 2 en la actualidad?
DBS (Emisión Directa de Satélite): El servicio Hughes/USSB usa vídeo y audio
MPEG 2. Hughes/USSB DBS comenzó a dar servicios en Norte America en 1994. Dos
satélites a 101 grados al oeste comparten los requerimientos de poder de unos
transponder con 120 Watts y 27 MHz.
CATV (Televisión por cable): La industria del cable ha colocado más o menos vídeo
MPEG 2. Y el audio en menor proporción.
26
DigiCipher: La sintaxis del DigiCipher I es similar a la del MPEG 2, pero usa
pequeños "macrobloques de predicción" y no tramas B. La especificación DigiCipher II
incluye modos para soportar tanto GI como sintaxis del perfil principal de vídeo MPEG
2. Servicios como HBO fueron actualizados con DigiCipher II en 1994.
HDTV: La gran alianza de Estados Unidos (Grand Alliance), un consorcio de
compañías que formalmente compiten por el estándar HDTV, ha agregado el uso de
vídeo MPEG 2 y sintaxis de los sistemas (incluyendo imágenes o tramas B). Serán
soportados ambos modos, entrelazado (1440x960x30 Hz) y progresivo (1280x720x60
Hz). Para esto, la alianza debe colocarse bajo una modulación (QAM, VSB, OFDM),
convolución (MS o Viterbi), y corrección de errores (RSPC, RSFC).
En septiembre de 1993, el consorcio de 85 compañías europeas firmó un convenio
para invertir en un proyecto conocido como Emisión de Vídeo Digital ( DVB) el cual
desarrolló un estándar para transmisión terrestre y de cable, y éste esquema usa MPEG
2. Este consorcio puso el último clavo en el ataúd del esquema D-MAC, para una
migración gradual hacia un todo digital: HDTV.
3.La transformada discreta del coseno (DCT)
Para explicar la transformada usaremos la siguiente figura:
27
La forma normal es determinar el brillo de cada uno de los 64 píxeles y escalarlos
dentro de unos limites, normalmente de 0 a 255 (en MPEG se usa un rango de –
256,255) donde 0 significa negro y 255 blanco.
12
0
10
90
8
12
7
11
97
5
13
4
12
2
13
7
12
13
1
11
7
5
10
0
89
1
8
88
70
77
59
7
5
4
4
8
3
6
2
4
2
5
1
10
0
7
5
3
8
9
6
4
10
6
3
9
9
9
8
6
10
3
9
3
5
5
9
8
95
9
6
0
0
8
8
8
89
8
7
6
2
7
8
9
8
2
9
3
6
87
7
8
10
7
3
5
2
1
10
8
10
11
6
9
9
7
9
5
10
5
5
7
85
69
58
También podemos representarlo mediante un diagrama de barras 8x8:
28
Normalmente los valores son procesados línea a línea. Esto requiere 64 bits de
almacenaje.
Pero podemos definir todos los 64 valores por solo 5 enteros, aplicando la fórmula de
la DCT:
Donde f(x,y) es el brillo del píxel en la posición [x,y]. El resultado es F, una matriz
8x8 también. Siguiendo el ejemplo anterior:
29
700
9
0
100
0 0 0 0 0
90
0
0
0 0 0 0 0
-89
0
0
0 0 0 0 0
0
0
0
0 0 0 0 0
0
0
0
0 0 0 0 0
0
0
0
0 0 0 0 0
0
0
0
0 0 0 0 0
0
0
0
0 0 0 0 0
Como se puede ver, la mayoría de los valores son 0. Como los valores distintos de 0
están concentrados en la esquina superior derecha la matriz es transferida al receptor en
orden de escaneado en zigzag:
30
Esto resulta en: 700 90 90 -89 0 100 0 0 0 .... 0. Por supuesto, los ceros no se
transmiten, en su lugar se codifica una señal de final de bloque.
El decodificador puede reconstruir los valores de los píxeles usando la fórmula de la
inversa de la transformada del coseno (IDCT):
Donde F(u,v) es el valor de la matriz transformada en la posición [u,v].
Los resultados son los valores originales de los píxeles. De esta manera, podríamos
considerar la compresión MPEG como sin perdidas, pero esto no es cierto, porque los
valores transformados están cuantizados. Están divididos (división entera) por un cierto
valor mayor o igual que 0 debido a que la DCT soporta valores hasta 2047. Para
reducirlos hasta estar al menos bajo la longitud del byte se aplica el valor de
cuantización 8. El decodificador multiplica los resultados por el mismo valor.
Lógicamente los resultados difieren de los valores originales, pero debido a algunas
propiedades del ojo humano el error no es visible.
En MPEG hay una matriz de cuantización que define un valor diferente de
cuantización para cada valor transformado dependiendo de su posición.
El valor de la esquina superior izquierda de la matriz transformada es llamado valor
DC (direct current) y determina la media de brillo en el bloque.El resto de los valores
son llamados valores AC (alternating current) y describen la variación sobre el valor
DC.
Así, supongamos una matriz transformada tal que así:
31
700
0 0 0 0 0 0 0
0
0 0 0 0 0 0 0
0
0 0 0 0 0 0 0
0
0 0 0 0 0 0 0
0
0 0 0 0 0 0 0
0
0 0 0 0 0 0 0
0
0 0 0 0 0 0 0
0
0 0 0 0 0 0 0
El valor DC seria 700.
El resultado de aplicarle la IDCT seria:
8
7
8
7
8
7
7
8
7
8
7
8
8
8
8
8
8
8
8
8
8
8
7
8
7
8
8
7
7
7
8
8
8
8
8
7
7
7
7
8
8
8
8
7
7
7
7
7
8
8
8
8
7
7
7
7
7
8
8
8
8
7
7
7
7
7
8
8
8
8
7
7
7
7
7
8
8
8
8
7
7
7
7
8
8
7
8
8
32
7
7
8
7
7
8
7
8
7
8
7
8
7
7
7
8
7
8
7
8
7
8
7
7
8
7
8
7
7
8
7
8
7
7
8
7
8
7
8
7
En diagrama de barras:
La imagen, pues, es un cuadrado gris.
Si añadimos un valor AC de 100:
700
100
0 0 0 0 0 0
0
0
0 0 0 0 0 0
0
0
0 0 0 0 0 0
0
0
0 0 0 0 0 0
0
0
0 0 0 0 0 0
33
0
0
0 0 0 0 0 0
0
0
0 0 0 0 0 0
0
0
0 0 0 0 0 0
El resultado de aplicar IDCT sería:
1
05
1
05
1
05
1
05
1
05
1
05
1
05
1
05
1
02
1
02
1
02
1
02
1
02
1
02
1
02
1
02
9 9 8 7 7 7
7 1 4 8 3 0
9 9 8 7 7 7
7 1 4 8 3 0
9 9 8 7 7 7
7 1 4 8 3 0
9 9 8 7 7 7
7 1 4 8 3 0
9 9 8 7 7 7
7 1 4 8 3 0
9 9 8 7 7 7
7 1 4 8 3 0
9 9 8 7 7 7
7 1 4 8 3 0
9 9 8 7 7 7
7 1 4 8 3 0
En diagrama de barras:
34
La imagen resultante sería:
Como ultimo ejemplo, añadamos un valor AC 100 en otra posición distinta:
35
700
0 100
0 0 0 0 0
0
0 0
0 0 0 0 0
0
0 0
0 0 0 0 0
0
0 0
0 0 0 0 0
0
0 0
0 0 0 0 0
0
0 0
0 0 0 0 0
0
0 0
0 0 0 0 0
0
0 0
0 0 0 0 0
Al aplicar la IDCT obtenemos:
10
4
9
4
10
4
9
10
4
4
4
1
4
10
1
9
4
1
1
8
1
1
1
7
1
1
10
4
9
4
8
1
4
4
1
10
9
8
7
4
4
1
10
9
8
7
4
4
1
10
9
8
7
7
4
1
1
9
8
7
7
8
1
1
1
8
7
7
8
9
1
1
1
7
7
8
9
10
1
1
4
7
8
9
10
4
1
4
4
8
10
4
9
4
10
4
36
10
4
9
4
10
4
8
1
9
4
7
1
8
1
7
1
7
1
8
1
7
1
9
4
8
1
10
4
9
4
10
4
En diagrama de barras:
La imagen resultante sería:
37
4.Documentación de la aplicación.
De las posibles aplicaciones que podrían realizarse sobre videos mpeg, hemos
pensado que la mejor opción era hacer un reproductor. La principal razón para tomar
esta decisión era que la mayoría de las veces que se utilizaba vídeo mpeg era
simplemente para su reproducción. El problema que se planteaba con esta elección era
que la realización de esta aplicación implicaba una dificultad que en principio
sobrepasaba los objetivos de la asignatura, ya que era necesario no sólo conocer el
estándar mpeg en todos sus niveles, sino que además era necesario hacer gran cantidad
de funciones de tratamiento de vídeo. Por todo esto decidimos buscar aplicaciones que
nos facilitasen la tarea.
Las aplicaciones utilizadas son libmpeg2 y libvo que a partir de ellas se obtienen las
librerías libmpeg2.lib y libvo.lib. La elección de estas librerías se debe a que la inmensa
mayoría de aplicaciones encontradas en código abierto eran para GNU/Linux y por
diversas razones era necesario que nuestra aplicación fuese para entorno Windows. Por
esto hemos utilizado estas librerías ya que son válidas para ambos sistemas operativos,
38
debido a que por una parte tiene archivos comunes a Linux y Windows y por otra tiene
archivos específicos para cada una de estas plataformas.
Aplicaciones de Linux muy utilizadas usan estas librerías, como pueden ser:
xine, Mplayer, movietime, etc.
La dirección de internet de las que nos hemos bajado los ficheros necesarios para la
obtención de las librerías libmpeg2.lib y libvo.lib es: http://libmpeg.sourceforge.net
Pues bien, el reproductor está formado a partir de dos partes bien diferenciadas una
que llamaremos mpeg y otra denominada decoder. Veamos a continuación cada uno de
ellos.
Mpeg
El
resultado de este programa son tres librerías denominadas libmpeg2dec.lib
libmpeg2.lib libvo.lib que posteriormente se utilizarán en la aplicación decoder. Para la
obtención de estas librerías se ha realizado un Workspace con tres proyectos, uno por
cada una de las librerías.
libmpeg2dec
Este proyecto está formado por un único archivo en C a partir del cual se obtiene el
fichero libmpeg2dec.lib. Este fichero utiliza las otras dos librerías y es básicamente el
reproductor de vídeo en modo consola.
mpeg2dec.c no contiene método principal, ya que el objetivo no es obtener un
ejecutable sino una librería que será usada por el programa decoder y así añadir más
funcionalidades y un entorno gráfico que facilite su uso. Las principales funciones que
contiene esta librería son:
39
static void inicializar (void)
Inicializa los drivers, llamando a la función vo_drivers() de libvo y abre el fichero
seleccionado en el reproductor. Si el fichero no se puede abrir, el programa termina.
static void decodificar_mpeg2 (uint8_t * current, uint8_t * end)
Realiza la decodificación mpeg utilizando la libreria libmpeg2
void set_fichero(char* f)
Pone el valor de la cadena fichero a f. Esta función será llamada desde decoder, y la
cadena contiene el nombre del fichero que se quiere reproducir.
char* get_fichero(void)
Devuelve el nombre de la cadena fichero, la cual contiene el nobre del fichero que se
quiere reproducir.
void set_stop(int x)
Pone el valor de la variable global stop a x.
int get_stop(void)
Devuelve el valor de la variable global stop.
void pulsar_pause(void)
Cambia el valor de la variable global pause, si este está a uno lo pone a cero y
viceversa. Esta función cuando es llamada desde el decoder cuando se pulsa el botón de
pausa y hace que la reproducción de detenga con un determinado frame en pantalla.
Cuando se pulsa el botón otra vez, la reproducción continúa por el mismo momento en
el que se dejó.
static void extraer_frames (void)
40
Va estrayendo los frames del fichero al buffer para que posteriormente sean
decodificados y visualizados.
int play (void)
Función llamada desde decoder, que inicializa las variables globales stop y pause a
cero y llama a la función inicializar(). Si todo correcto llama a ps_loop() ,
libmpeg2.lib
Está implementada en C y se ha obtenido tras la compilación del proyecto libmpeg2
con Microsoft Visual C++. El proyecto y todos los ficheros se encuentran en la carpeta
\codigo\mpeg\vc++. Muchos de los ficheros de este proyecto contienen funciones que
no son utilizadas por el reproductor, pero que incluimos para posibles ampliaciones.
El principal contenido de esta librería son funciones para la decodificación de mpeg.
libvo.lib
Está implementada en C y se ha obtenido tras la compilación del proyecto libvo con
Microsoft Visual C++. El proyecto y todos los ficheros se encuentran en la carpeta
\codigo\mpeg\vc++. Al igual que libmpeg2.lib muchos de los ficheros de este proyecto
contienen funciones que no son utilizadas por el reproductor.
El principal cometido de esta librería es el control de la salida de vídeo (drivers de la
tarjeta gráfica) y mostrarlo por pantalla.
Decoder
Este es el módulo del entorno gráfico del reproductor, para ello crea la ventana
principal y los botones y espera las pulsaciones de los mismos. Su misión es recibir las
órdenes que el usuario le mande y traducirlas en llamadas a las principales funciones del
reproductor libmpeg2dec. Las funciones de la librería libmpeg2dec.lib que decoder
utiliza son:
41
int play (play);
void pulsar_pause (void);
int get_stop (void);
void set_stop (int);
void set_fichero (char*);
char* get_fichero (void);
Para que el programa espere posibles pulsaciones de los botones una vez que se está
reproduciendo el vídeo, ha sido necesario la creación de un hilo de ejecución. De no
haber sido así, una vez que el programa estuviese reproduciendo un fichero, no se
podría haber interactuado con él hasta que concluyese la reproducción. Esto se ha hecho
de la siguiente forma:
Una vez que se crean los botones, se crea el hilo de ejecución mediante la función
_beginthread ( decod, 0, NULL ). Por otra parte la función void __cdecl decod(void *x)
lo que hace es esperar a que la variable stop valga cero, producido por la pulsación del
botón reproducir. Cuando esto ocurre llama a la función play() que hace comenzar la
reproducción del vídeo, permitiendo al mismo tiempo la emisión de nuevas órdenes
sobre el reproductor.
5.Conclusiones
El MPEG 2 es un estándar de compresión para imágenes con movimiento a
velocidades de píxel entre 5 y 10 Mbit/s. El estándar de vídeo consiste de cinco perfiles,
referido a la complejidad del algoritmo de compresión y cuatro niveles, los cuales se
refieren a la resolución del vídeo original. El nivel principal y el perfil principal es la
combinación más usada por las opciones MPEG 2.
MPEG 2 es un estándar emergente para reproducir vídeo en pantalla completa y
audio con calidad de transmisión; está mas orientado hacia TV que MPEG 1, por
ejemplo, MPEG 2 sabe cómo se entrelazan los cuadros en TV, además de que la calidad
42
de la imagen es superior. Por otra parte, como no puede dependerse de la llegada del
paquete anterior antes de descomprimir el paquete actual, MPEG 2 no es ideal para
transmisión vía Internet.
6.Bibliografía
MPEG video compresión technique
http://rnvs.informatik.tu-chemnitz.de/~jan/MPEG/HTML/mpeg_tech.html
Trabajo dirigido MPEG4
José Baena Roca
MPEG-2: Descripción del estándar
http://videomaster.dragonport.net/documentos/mpg2.htm
Decodificación de audio y video
http://www.tid.es/presencia/publicaciones/comsid/esp/articulos/vol61/decod/decod.html
Video Compression: MEPG-4 and Beyond
Ali Saman Tosun
43
7.Anexo
A continuación adjuntamos el código de los dos fichero principales que componen el
reproductor:
Codigo del fichero mpeg2dec.c
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <inttypes.h>
#include "mpeg2.h"
#include "video_out.h"
#include "convert.h"
#define BUFFER_SIZE 4096
int stop=1;
int pause=0;
char* fichero=NULL;
static uint8_t buffer[BUFFER_SIZE];
static FILE * in_file;
static int demux_track = 0;
static int demux_pid = 0;
44
static mpeg2dec_t * mpeg2dec;
static vo_open_t * output_open = NULL;
static vo_instance_t * output;
static void inicializar (void)
{
vo_driver_t * drivers;
drivers = vo_drivers ();
//Devuelve los drivers para la salida del video
demux_track = 0xe0;
if (output_open == NULL)
output_open = drivers[0].open;
in_file = fopen (fichero, "rb");
//Utiliza el primer driver
//Abre el fichero mpeg
if (!in_file) //No se puede abrir el fichero
exit (1);
}
void set_fichero(char* f)
// establece el nombre del fichero mpeg a f
{
fichero=f;
}
char* get_fichero(void)
//devuelve el nombre del fichero mpeg
{
45
return fichero;
}
void set_stop(int x)
//pone la variable stop a x
{
stop=x;
}
int get_stop(void)
//devuelve el valor de la variable stop
{
return stop;
}
void pulsar_pause(void)
//Modifica el valor de la variable pause
{
if(pause==1)
pause=0;
else
pause=1;
}
static void decodificar_mpeg2 (uint8_t * current, uint8_t * end)
{
//realiza la decodificación mpeg utilizando la libreria libmpeg2
const mpeg2_info_t * info;
int state;
vo_setup_result_t setup_result;
46
mpeg2_buffer (mpeg2dec, current, end); //donde comienza y acaba el buffer con los frames
info = mpeg2_info (mpeg2dec);
//obtiene la informacion
while (1) {
state = mpeg2_parse (mpeg2dec);
//analiza el estado
switch (state){
case -1: //si falla la funcion
return;
case STATE_SEQUENCE:
if (output->setup (output, info->sequence->width,info->sequence->height, &setup_result))
{
//Ha fallado el display
exit (1);
}
if (setup_result.convert)
mpeg2_convert (mpeg2dec, setup_result.convert, NULL);
if (output->set_fbuf)
{
uint8_t * buf[3];
void * id;
mpeg2_custom_fbuf (mpeg2dec, 1);
output->set_fbuf (output, buf, &id);
mpeg2_set_buf (mpeg2dec, buf, id);
output->set_fbuf (output, buf, &id);
mpeg2_set_buf (mpeg2dec, buf, id);
}
else if (output->setup_fbuf)
47
{
uint8_t * buf[3];
void * id;
output->setup_fbuf (output, buf, &id);
mpeg2_set_buf (mpeg2dec, buf, id);
output->setup_fbuf (output, buf, &id);
mpeg2_set_buf (mpeg2dec, buf, id);
output->setup_fbuf (output, buf, &id);
mpeg2_set_buf (mpeg2dec, buf, id);
}
break;
case STATE_PICTURE:
if (output->set_fbuf)
{
uint8_t * buf[3];
void * id;
output->set_fbuf (output, buf, &id);
mpeg2_set_buf (mpeg2dec, buf, id);
}
if (output->start_fbuf)
output->start_fbuf (output, info->current_fbuf->buf,info->current_fbuf->id);
break;
case STATE_PICTURE_2ND:
//no debe hacer nada
break;
case STATE_SLICE:
48
case STATE_END:
//termina de decodificar un frame
if (info->display_fbuf)
{
//muestra el frame
output->draw (output, info->display_fbuf->buf,info->display_fbuf->id);
}
if (output->discard && info->discard_fbuf) //descarta el frame
output->discard (output, info->discard_fbuf->buf,info->discard_fbuf->id);
break;
}
}
}
//Nota: la función demux ha sido tomada de otro reproductor que utiliza las mismas librerias
#define DEMUX_PAYLOAD_START 1
static int demux (uint8_t * buf, uint8_t * end, int flags)
{
static int mpeg1_skip_table[16] = {0, 0, 4, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
#define DEMUX_HEADER 0
#define DEMUX_DATA 1
#define DEMUX_SKIP 2
static int state = DEMUX_SKIP;
static int state_bytes = 0;
static uint8_t head_buf[264];
uint8_t * header;
int bytes;
49
int len;
#define NEEDBYTES(x)
\
do {
\
int missing;
\
\
missing = (x) - bytes;
\
if (missing > 0) {
\
if (header == head_buf) {
\
if (missing <= end - buf) {
\
memcpy (header + bytes, buf, missing); \
buf += missing;
\
bytes = (x);
\
} else {
\
memcpy (header + bytes, buf, end - buf); \
state_bytes = bytes + end - buf;
\
return 0;
\
}
\
} else {
\
memcpy (head_buf, header, bytes);
\
state = DEMUX_HEADER;
\
state_bytes = bytes;
\
return 0;
\
}
\
}
\
} while (0)
#define DONEBYTES(x)
do {
if (header != head_buf)
\
\
\
50
buf = header + (x);
\
} while (0)
if (flags & DEMUX_PAYLOAD_START)
goto payload_start;
switch (state) {
case DEMUX_HEADER:
if (state_bytes > 0) {
header = head_buf;
bytes = state_bytes;
goto continue_header;
}
break;
case DEMUX_DATA:
if (demux_pid || (state_bytes > end - buf)) {
decodificar_mpeg2 (buf, end);
state_bytes -= end - buf;
return 0;
}
decodificar_mpeg2 (buf, buf + state_bytes);
buf += state_bytes;
break;
case DEMUX_SKIP:
if (demux_pid || (state_bytes > end - buf)) {
state_bytes -= end - buf;
return 0;
}
buf += state_bytes;
break;
}
51
while (1) {
if (demux_pid) {
state = DEMUX_SKIP;
return 0;
}
payload_start:
header = buf;
bytes = end - buf;
continue_header:
NEEDBYTES (4);
if (header[0] || header[1] || (header[2] != 1)) {
if (demux_pid) {
state = DEMUX_SKIP;
return 0;
} else if (header != head_buf) {
buf++;
goto payload_start;
} else {
header[0] = header[1];
header[1] = header[2];
header[2] = header[3];
bytes = 3;
goto continue_header;
}
}
if (demux_pid) {
if ((header[3] >= 0xe0) && (header[3] <= 0xef))
goto pes;
fprintf (stderr, "bad stream id %x\n", header[3]);
52
exit (1);
}
switch (header[3]) {
case 0xb9:
/* program end code */
/* DONEBYTES (4); */
/* break;
*/
return 1;
case 0xba:
/* pack header */
NEEDBYTES (12);
if ((header[4] & 0xc0) == 0x40) {
/* mpeg2 */
NEEDBYTES (14);
len = 14 + (header[13] & 7);
NEEDBYTES (len);
DONEBYTES (len);
/* header points to the mpeg2 pack header */
} else if ((header[4] & 0xf0) == 0x20) { /* mpeg1 */
DONEBYTES (12);
/* header points to the mpeg1 pack header */
} else {
fprintf (stderr, "weird pack header\n");
exit (1);
}
break;
default:
if (header[3] == demux_track) {
pes:
NEEDBYTES (7);
if ((header[6] & 0xc0) == 0x80) { /* mpeg2 */
NEEDBYTES (9);
len = 9 + header[8];
53
NEEDBYTES (len);
/* header points to the mpeg2 pes header */
if (header[7] & 0x80) {
uint32_t pts;
pts = (((buf[9] >> 1) << 30) |
(buf[10] << 22) | ((buf[11] >> 1) << 15) |
(buf[12] << 7) | (buf[13] >> 1));
mpeg2_pts (mpeg2dec, pts);
}
} else { /* mpeg1 */
int len_skip;
uint8_t * ptsbuf;
len = 7;
while (header[len - 1] == 0xff) {
len++;
NEEDBYTES (len);
if (len > 23) {
fprintf (stderr, "too much stuffing\n");
break;
}
}
if ((header[len - 1] & 0xc0) == 0x40) {
len += 2;
NEEDBYTES (len);
}
len_skip = len;
len += mpeg1_skip_table[header[len - 1] >> 4];
NEEDBYTES (len);
54
/* header points to the mpeg1 pes header */
ptsbuf = header + len_skip;
if (ptsbuf[-1] & 0x20) {
uint32_t pts;
pts = (((ptsbuf[-1] >> 1) << 30) |
(ptsbuf[0] << 22) | ((ptsbuf[1] >> 1) << 15) |
(ptsbuf[2] << 7) | (ptsbuf[3] >> 1));
mpeg2_pts (mpeg2dec, pts);
}
}
DONEBYTES (len);
bytes = 6 + (header[4] << 8) + header[5] - len;
if (demux_pid || (bytes > end - buf)) {
decodificar_mpeg2 (buf, end);
state = DEMUX_DATA;
state_bytes = bytes - (end - buf);
return 0;
} else if (bytes > 0) {
decodificar_mpeg2 (buf, buf + bytes);
buf += bytes;
}
} else if (header[3] < 0xb9) {
fprintf (stderr,
"looks like a video stream, not system stream\n");
DONEBYTES (4);
} else {
NEEDBYTES (6);
DONEBYTES (6);
bytes = (header[4] << 8) + header[5];
55
if (bytes > end - buf) {
state = DEMUX_SKIP;
state_bytes = bytes - (end - buf);
return 0;
}
buf += bytes;
}
}
}
}
static void extraer_frames (void)
//Va estrayendo los frames
{
uint8_t * end;
do {
end = buffer + fread (buffer, 1, BUFFER_SIZE, in_file);
if (demux (buffer, end, 0))
//demultiplexa
break;
else if (stop==1)
break;
else if (pause==1)
{
while (pause==1)
{;}
}
} while (end == buffer + BUFFER_SIZE);
}
56
int play (void)
//Funcion principal, aunque no es un método main por ser una libreria
{
//inicializamos las variables globales stop y pause a cero
stop=0;
pause=0;
inicializar ();
output = output_open ();
if (output == NULL)
{
fprintf (stderr, "No se puede mostrar\n");
return 1;
}
mpeg2dec = mpeg2_init();
if (mpeg2dec == NULL)
exit (1);
extraer_frames ();
mpeg2_close (mpeg2dec);
if (output->close)
output->close (output);
return 0;
}
57
Codigo del fichero decoder.cpp
#include "stdafx.h"
#include "resource.h"
#include <process.h> /* _beginthread, _endthread */
#include <windows.h>
#include <commdlg.h>
#include <stdlib.h>
#define MAX_LOADSTRING 100
extern "C" int play();
extern "C" void pulsar_pause();
extern "C" int get_stop();
extern "C" void set_stop(int);
extern "C" void set_fichero(char*);
extern "C" char* get_fichero(void);
char* fich;
void __cdecl decod(void*);
// Variables globales:
HINSTANCE hInst;
TCHAR szTitle[MAX_LOADSTRING];
58
TCHAR szWindowClass[MAX_LOADSTRING];
static OPENFILENAME ofn ;
static char szFilter[] = "Mpeg files (*.mpg)\0*.mpg\0" \
"All Files (*.*)\0*.*\0\0" ;
const int ButtonId1 = 1;
const int ButtonId2 = 2;
const int ButtonId3 = 3;
const int ButtonId4 = 4;
const int ButtonId5 = 5;
const int ButtonId6 = 6;
// Cabeceras de funciones incluidas en este modulo.
ATOM
MyRegisterClass(HINSTANCE hInstance);
BOOL
InitInstance(HINSTANCE, int);
LRESULT CALLBACK
WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK
About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR
int
lpCmdLine,
nCmdShow)
{
MSG msg;
HACCEL hAccelTable;
char cad[_MAX_PATH+1];
59
ofn.lStructSize
= sizeof (OPENFILENAME) ;
ofn.hwndOwner
= NULL ;
ofn.hInstance
= NULL ;
ofn.lpstrFilter
= szFilter ;
ofn.lpstrCustomFilter = NULL ;
ofn.nMaxCustFilter
ofn.nFilterIndex
ofn.lpstrFile
=0;
=0;
= cad ;
// Set in Open and Close functions
ofn.nMaxFile
= _MAX_PATH ;
ofn.lpstrFileTitle
= NULL ; // Set in Open and Close functions
ofn.nMaxFileTitle
= _MAX_FNAME + _MAX_EXT ;
ofn.lpstrInitialDir = NULL ;
ofn.lpstrTitle
= "Abrir fichero" ;
ofn.nFileOffset
=0;
ofn.nFileExtension
ofn.Flags
=0;
= OFN_HIDEREADONLY | OFN_CREATEPROMPT ;
ofn.lpstrDefExt
= "mpg" ;
ofn.lCustData
= 0L ;
ofn.lpfnHook
= NULL ;
ofn.lpTemplateName
= NULL ;
// Initializamos las cadenas
strcpy(cad,"");
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_DECODER, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
if (!InitInstance (hInstance, nCmdShow))
60
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_DECODER);
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return msg.wParam;
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style
= CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc
= (WNDPROC)WndProc;
wcex.cbClsExtra
= 0;
wcex.cbWndExtra
= 0;
61
wcex.hInstance
= hInstance;
wcex.hIcon
= LoadIcon(hInstance, (LPCTSTR)IDI_DECODER);
wcex.hCursor
= LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground
= (HBRUSH)(COLOR_WINDOWFRAME+1);
wcex.lpszMenuName
= (LPCSTR)IDC_DECODER;
wcex.lpszClassName
= szWindowClass;
wcex.hIconSm
= LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
return RegisterClassEx(&wcex);
}
// En esta función se crea y muestra la ventana principal del programa
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance;
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 400, 250, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
62
return TRUE;
}
// Esta función procesa los mensajes para la ventana principal
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM
lParam)
{
int wmId, wmEvent,res;
PAINTSTRUCT ps;
HDC hdc;
TCHAR szHello[MAX_LOADSTRING];
LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);
switch (message)
{
case WM_CREATE:
//Creamos los botones del
reproductor
CreateWindow
//Botón reproducir
(
"BUTTON", "Reproducir",
WS_CHILD | WS_VISIBLE,
50, 50, 100, 50,
hWnd,
(HMENU) ButtonId1,
hInst, NULL
);
63
CreateWindow
//Botón pausa
(
"BUTTON", "Pausa",
WS_CHILD | WS_VISIBLE,
150, 50, 100, 50,
hWnd,
(HMENU) ButtonId2,
hInst, NULL
);
CreateWindow
//Botón parar
(
"BUTTON", "Parar",
WS_CHILD | WS_VISIBLE,
250, 50, 100, 50,
hWnd,
(HMENU) ButtonId3,
hInst, NULL
);
CreateWindow
//Botón para cargar el fichero
(
"BUTTON", "Cargar",
WS_CHILD | WS_VISIBLE,
50, 100, 100, 50,
hWnd,
(HMENU) ButtonId4,
hInst, NULL
);
64
CreateWindow
//Botón
para
abandonar
la
aplicación
(
"BUTTON", "Salir",
WS_CHILD | WS_VISIBLE,
150, 100, 100, 50,
hWnd,
(HMENU) ButtonId5,
hInst, NULL
);
CreateWindow
//Botón Acerca de
(
"BUTTON", "Acerca de",
WS_CHILD | WS_VISIBLE,
250, 100, 100, 50,
hWnd,
(HMENU) ButtonId6,
hInst, NULL
);
_beginthread( decod, 0, NULL );
case WM_COMMAND:
wmId
= LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch (wmId)
{
65
case IDM_ABOUT:
DialogBox(hInst,
(LPCTSTR)IDD_ABOUTBOX,
hWnd,
(DLGPROC)About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
case ButtonId1: //Se ha pulsado reproducir
if(get_fichero()==NULL)
MessageBox(hWnd, "Debe cargar el fichero",
"Info", MB_OK);
else
set_stop(0);
break;
case ButtonId2: //Se ha pulsado pausa
pulsar_pause();
break;
case ButtonId3:
//Se ha pulsado stop
set_stop(1);
break;
case ButtonId4: //Se ha pulsado cargar fichero
res=GetOpenFileName (&ofn);
fich=ofn.lpstrFile;
if(res)
set_fichero(fich);
break;
case ButtonId5: //Se ha pulsado salir
DestroyWindow(hWnd);
break;
case ButtonId6: //Se ha pulsado Acerca de
66
DialogBox(hInst,
(LPCTSTR)IDD_ABOUTBOX,
hWnd,
(DLGPROC)About);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
RECT rt;
GetClientRect(hWnd, &rt);
DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER);
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM
lParam)
{
switch (message)
{
case WM_INITDIALOG:
67
return TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
break;
}
return FALSE;
}
void __cdecl decod(void *x)
{
while(1)
{
if(!get_stop()){
play();
break;
}
else
Sleep(1);
}
_endthread();
}
68
Descargar