28.11.2012 Views

Procesamiento digital de video en tiempo real y - Maestría en ...

Procesamiento digital de video en tiempo real y - Maestría en ...

Procesamiento digital de video en tiempo real y - Maestría en ...

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y<br />

“vi<strong>de</strong>o wall” con la PC<br />

Tesis para obt<strong>en</strong>er el grado <strong>de</strong><br />

Maestro <strong>en</strong> Ci<strong>en</strong>cias <strong>de</strong> la Computación<br />

Nombre <strong>de</strong>l alumno: Ukranio Coronilla Contreras<br />

Matricula: 98380044<br />

Nombre <strong>de</strong>l asesor: Dr. Carlos Avilés Cruz<br />

Marzo <strong>de</strong>l 2005


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 2<br />

Síntesis<br />

En el <strong>de</strong>sarrollo <strong>de</strong> la pres<strong>en</strong>te tesis se abordaron tres tipos <strong>de</strong> problemas, el primero<br />

fue establecer el hardware mínimo necesario para llevar acabo el <strong>de</strong>spliegue <strong>de</strong> una imag<strong>en</strong><br />

<strong>de</strong> vi<strong>de</strong>o <strong>en</strong> forma <strong>de</strong> vi<strong>de</strong>owall(arreglo cuadrado <strong>de</strong> monitores que pres<strong>en</strong>ta una sola<br />

imag<strong>en</strong>), haci<strong>en</strong>do uso <strong>de</strong> la PC y con cuatro monitores. El segundo problema consiste <strong>en</strong><br />

hacer uso <strong>de</strong>l sistema operativo para controlar las cuatro tarjetas <strong>de</strong> vi<strong>de</strong>o, lo cual<br />

correspon<strong>de</strong> a un procesami<strong>en</strong>to <strong>de</strong> escalami<strong>en</strong>to <strong>en</strong> la imag<strong>en</strong>, y finalm<strong>en</strong>te el problema<br />

fundam<strong>en</strong>tal <strong>de</strong> construir el software que permita el procesami<strong>en</strong>to <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong>,<br />

el cual se apoya <strong>en</strong> el sistema <strong>de</strong> <strong>de</strong>sarrollo SDK <strong>de</strong> DirectX® y <strong>en</strong> particular la<br />

herrami<strong>en</strong>ta DirectShow. Se elaboraron procesami<strong>en</strong>tos básicos <strong>de</strong> vi<strong>de</strong>o que consist<strong>en</strong> <strong>en</strong><br />

filtrado <strong>de</strong> compon<strong>en</strong>tes <strong>de</strong> color, adición <strong>de</strong> ruido a la imag<strong>en</strong>, superposición <strong>de</strong> imag<strong>en</strong> al<br />

vi<strong>de</strong>o, eliminación <strong>de</strong> color, posterizado y <strong>real</strong>ce.


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 3<br />

INDICE<br />

Síntesis ........................................................................................................ 2<br />

Índice .......................................................................................................... 3<br />

Agra<strong>de</strong>cimi<strong>en</strong>tos ......................................................................................... 7<br />

1 Introducción .................................................. 8<br />

1.1 Antece<strong>de</strong>ntes ................................................................................ 8<br />

1.2 Definición <strong>de</strong>l proyecto ............................................................... 10<br />

1.3 Objetivos ...................................................................................... 12<br />

1.4 Panorama g<strong>en</strong>eral ......................................................................... 12<br />

2 Análisis <strong>de</strong> fundam<strong>en</strong>tos ................................ 13<br />

2.1 Estado <strong>de</strong>l arte ............................................................................... 13<br />

2.2 Herrami<strong>en</strong>tas disponibles .............................................................. 15<br />

3 Investigación ................................................... 16<br />

3.1 <strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> imág<strong>en</strong>es ................................................ 16<br />

3.1.1 Relaciones <strong>en</strong>tre pixeles .................................................. 17<br />

3.1.1.1 Distancia ................................................................ 18<br />

3.1.2 Color ................................................................................ 19<br />

3.1.2.1 Espacio RGB .......................................................... 19<br />

3.1.2.2 Espacio HSI ............................................................ 20<br />

3.1.3 Transformaciones matemáticas ....................................... 21<br />

3.1.3.1 Convolución ............................................................ 21<br />

3.1.3.2 Operaciones matemáticas ....................................... 22<br />

3.1.4 Ruido ................................................................................ 24<br />

3.1.5 Detección <strong>de</strong> bor<strong>de</strong>s ......................................................... 24<br />

3.1.5.1 Técnicas basadas <strong>en</strong> el gradi<strong>en</strong>te ..................................... 25<br />

3.2 Hardware ....................................................................................... 27<br />

3.2.1 Monitores ....................................................................... 27<br />

3.2.2 Tarjetas <strong>de</strong> vi<strong>de</strong>o ............................................................ 28<br />

3.2.3 Procesador ..................................................................... 29<br />

3.3 Soporte <strong>de</strong> multimonitor ............................................................... 29<br />

3.4 DirectX .......................................................................................... 29<br />

3.5 El mo<strong>de</strong>lo <strong>de</strong> compon<strong>en</strong>tes COM ................................................. 30<br />

3.5.1 Creación y gestión <strong>de</strong> objetos ......................................... 31<br />

3.5.2 Gestión <strong>de</strong> errores ........................................................... 32<br />

3.6 DirectShow ................................................................................... 32


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 4<br />

3.6.1 Grafico <strong>de</strong> filtros ............................................................. 33<br />

3.6.2 Aplicaciones DirectShow ............................................... 34<br />

3.7 Compon<strong>en</strong>tes <strong>de</strong> DirectShow ......................................................... 34<br />

3.7.1 El grafico <strong>de</strong> filtros y sus compon<strong>en</strong>tes .......................... 35<br />

3.7.2 Filtros .............................................................................. 36<br />

3.7.2.1 Filtros Source ......................................................... 37<br />

3.7.2.2 Filtros Transform ................................................... 37<br />

3.7.2.3 Filtros R<strong>en</strong><strong>de</strong>rer ..................................................... 37<br />

3.7.3 Pins ................................................................................. 37<br />

3.7.4 Muestras multimedia ...................................................... 38<br />

3.7.5 Asignadores .................................................................... 38<br />

3.7.6 Relojes ............................................................................ 39<br />

3.8 Flujo <strong>de</strong> datos <strong>en</strong> el Gráfico <strong>de</strong> filtros .......................................... 39<br />

3.8.1 Samples y Buffers .......................................................... 39<br />

3.8.2 Entrega <strong>de</strong> Muestras ....................................................... 40<br />

3.8.3 Det<strong>en</strong>er, Pausa, y Ejecución ........................................... 41<br />

3.8.4 Notificación <strong>de</strong> ev<strong>en</strong>tos <strong>en</strong> DirectShow ......................... 42<br />

3.8.4.1 Capturando Ev<strong>en</strong>tos ............................................... 42<br />

3.8.4.2 Saber cuando un ev<strong>en</strong>to ocurre .............................. 43<br />

3.8.4.3 Notificación Windows ........................................... 43<br />

3.8.4.4 Manejadores <strong>de</strong> ev<strong>en</strong>tos ......................................... 44<br />

3.9 Hardware <strong>en</strong> el gráfico <strong>de</strong> filtros ................................................... 45<br />

3.9.1 Filtros Envoltura (Wrapper) ........................................... 45<br />

3.9.2 Vi<strong>de</strong>o para dispositivos Windows .................................. 45<br />

3.9.3 Captura <strong>de</strong> Audio y dispositivos Mezcladores ............... 46<br />

4 Diseño .............................................................. 47<br />

4.1 Descripción g<strong>en</strong>eral <strong>de</strong>l sistema .................................................... 47<br />

4.2 Entrada <strong>de</strong> vi<strong>de</strong>o ........................................................................... 47<br />

4.3 Filtro multiprocesami<strong>en</strong>to ............................................................. 48<br />

4.4 Entrega <strong>de</strong> muestras al sistema operativo ..................................... 49<br />

4.5 Aplicación ..................................................................................... 49<br />

5 Implem<strong>en</strong>tación ............................................ 51<br />

5.1 Funcionami<strong>en</strong>to <strong>de</strong> la tarjeta WinTV ........................................... 51<br />

5.1.1 Modo <strong>de</strong> superposición <strong>de</strong> vi<strong>de</strong>o ................................... 51<br />

5.1.2 Modo <strong>de</strong> superficie principal ......................................... 51<br />

5.2 Multiplexado <strong>de</strong> vi<strong>de</strong>o ......................................... ........................ 51<br />

5.2.1 Tarjeta primaria y tarjetas secundarias .......................... 52<br />

5.2.2 Configuración <strong>de</strong> multimonitor ..................................... 52<br />

5.2.3 Pantalla virtual ............................................................... 54<br />

5.3 Instalación <strong>de</strong>l SDK DirectX ........................................................ 55<br />

5.4 Simulación con GraphEdit ........................................................... 57<br />

5.5 Uso <strong>de</strong> GraphEdit ......................................................................... 57


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 5<br />

5.5.1 Construy<strong>en</strong>do un grafico <strong>de</strong> ejecución <strong>de</strong> archivos ...... 58<br />

5.5.2 Construy<strong>en</strong>do un Grafico <strong>de</strong> filtros personalizado ....... 58<br />

5.5.3 Ejecutando el grafico .................................................... 59<br />

5.5.4 Ver paginas propietarias .................................................. 59<br />

5.6 Escritura <strong>de</strong>l filtro ........................................................................ 60<br />

5.6.1 Conexión <strong>de</strong> filtros ........................................................ 60<br />

5.6.2 Negociando los tipos <strong>de</strong> Media ..................................... 61<br />

5.6.3 Negociación <strong>de</strong> Asignadores ......................................... 61<br />

5.6.4 Clase base a utilizar ....................................................... 62<br />

5.6.5 Instanciar el filtro .......................................................... 63<br />

5.6.6 Adición <strong>de</strong> interfaces .................................................... 63<br />

5.6.7 Funciones miembro ....................................................... 64<br />

5.6.7.1 Función miembro Transform ............................... 64<br />

5.6.7.2 Función miembro CheckInputType ..................... 64<br />

5.6.7.3 Función miembro CheckTransform ..................... 64<br />

5.6.7.4 Función miembro Deci<strong>de</strong>BufferSize ................... 64<br />

5.6.7.5 Función miembro GetMediaType ........................ 65<br />

5.6.8 Filtro <strong>de</strong> efectos ............................................................. 65<br />

5.6.9 Programación <strong>de</strong>l filtro <strong>en</strong> C++ ..................................... 66<br />

5.6.10 Algoritmos <strong>de</strong> procesami<strong>en</strong>to ........................................ 69<br />

5.6.10.1 Efecto rojo .................................................... 70<br />

5.6.10.2 Efecto ruido .................................................. 70<br />

5.6.10.3 Efecto imag<strong>en</strong> BMP ..................................... 71<br />

5.6.10.4 Efecto imag<strong>en</strong> BMP diluida ......................... 72<br />

5.6.10.5 Efecto Rayos X ............................................. 72<br />

5.6.10.6 Efecto Poster ................................................ 72<br />

5.6.10.7 Efecto Borroso .............................................. 73<br />

5.6.10.8 Efecto Gris .................................................... 74<br />

5.6.10.9 Efecto Realce ................................................ 75<br />

5.7 Aplicación ..................................................................................... 77<br />

5.7.1 Ejecución <strong>de</strong> un archivo ................................................. 77<br />

5.7.2 Ajuste <strong>de</strong> la v<strong>en</strong>tana <strong>de</strong> vi<strong>de</strong>o ........................................ 79<br />

5.7.3 Despliegue <strong>de</strong> la pagina propietaria ............................... 80<br />

5.7.4 Captura <strong>de</strong> vi<strong>de</strong>o WinTV ............................................... 81<br />

5.7.4.1 Gráfico <strong>de</strong> captura ................................................. 83<br />

5.8 Resultados ..................................................................................... 83<br />

6 Evaluación ........................................................ 85<br />

7 Conclusiones y perspectivas ........................... 88


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 6<br />

Consultas <strong>real</strong>izadas .......................................... 89<br />

Anexos ................................................................. 90<br />

Fu<strong>en</strong>tes <strong>de</strong> internet ...................................................................................... 90<br />

Manual <strong>de</strong> usuario ....................................................................................... 91<br />

Código fu<strong>en</strong>te <strong>de</strong>l filtro ............................................................................... 95<br />

Código fu<strong>en</strong>te <strong>de</strong> la aplicación .................................................................... 111


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 7<br />

AGRADECIMIENTOS<br />

Agra<strong>de</strong>zco a la comunidad pert<strong>en</strong>eci<strong>en</strong>te al grupo <strong>de</strong> noticias <strong>de</strong> Microsoft DirectX<br />

MSDN newsgroup <strong>en</strong> gráficos y multimedia por su valiosa ayuda <strong>en</strong> las múltiples dudas<br />

surgidas durante el <strong>de</strong>sarrollo <strong>de</strong>l software.<br />

Del mismo modo a nuestra institución educativa y <strong>en</strong> particular a la <strong>Maestría</strong> <strong>en</strong><br />

Ci<strong>en</strong>cias <strong>de</strong> la Computación por su labor formativa.<br />

Finalm<strong>en</strong>te reitero mi agra<strong>de</strong>cimi<strong>en</strong>to al Dr. Carlos Avilés Cruz por haber apoyado<br />

mi iniciativa <strong>en</strong> la elaboración <strong>de</strong>l pres<strong>en</strong>te proyecto, y facilitarme los recursos necesarios<br />

<strong>de</strong>l laboratorio multimedia.<br />

Ukranio Coronilla


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 8<br />

Introducción<br />

1.1 Antece<strong>de</strong>ntes<br />

El procesami<strong>en</strong>to <strong>digital</strong> <strong>de</strong> señales y sus aplicaciones <strong>en</strong>vuelv<strong>en</strong> hoy día una gran<br />

cantidad <strong>de</strong> áreas como la medica, espacial, <strong>de</strong> telefonía, comercial, ci<strong>en</strong>tífica e industrial.<br />

Sus oríg<strong>en</strong>es se ubican <strong>en</strong> las décadas <strong>de</strong> los 60´s y 70´s, mom<strong>en</strong>to <strong>en</strong> el cual las<br />

computadoras <strong>digital</strong>es com<strong>en</strong>zaron a estar disponibles. Los <strong>de</strong>sarrollos iniciales se dieron<br />

solo <strong>en</strong> áreas estratégicas como radar y sonar, exploración petrolera y espacial, a<strong>de</strong>más <strong>de</strong><br />

imág<strong>en</strong>es medicas. A partir <strong>de</strong> los 80´s y 90´s la revolución <strong>en</strong> las computadoras com<strong>en</strong>zó a<br />

expandir el campo <strong>de</strong>l procesami<strong>en</strong>to <strong>digital</strong> <strong>de</strong> señales <strong>en</strong> nuevas aplicaciones,<br />

principalm<strong>en</strong>te comerciales como telefonía móvil, reproductores <strong>de</strong> discos compactos, y<br />

vi<strong>de</strong>oconfer<strong>en</strong>cia.<br />

Un área <strong>de</strong> <strong>de</strong>sarrollo relacionada con el pres<strong>en</strong>te trabajo es el procesami<strong>en</strong>to <strong>de</strong><br />

imág<strong>en</strong>es. La manipulación y almac<strong>en</strong>ami<strong>en</strong>to <strong>de</strong> imág<strong>en</strong>es involucra una gran cantidad <strong>de</strong><br />

recursos, por ejemplo para almac<strong>en</strong>ar un segundo <strong>de</strong> vi<strong>de</strong>o se requier<strong>en</strong> mas <strong>de</strong> 10Mb.<br />

Motivo por el cual hasta últimos años ha sido accesible la capacidad <strong>de</strong> procesami<strong>en</strong>to a<br />

costos mo<strong>de</strong>rados. Normalm<strong>en</strong>te el procesami<strong>en</strong>to <strong>digital</strong> se lleva a cabo con dispositivos<br />

<strong>digital</strong>es <strong>de</strong> propósito especifico <strong>de</strong>nominados DSP (Digital Signal Processors). Aunque <strong>en</strong><br />

los últimos años el <strong>de</strong>sarrollo <strong>de</strong> los DSP ha permitido su incorporación <strong>en</strong> diversos<br />

dispositivos electrónicos, actualm<strong>en</strong>te el procesami<strong>en</strong>to <strong>de</strong> vi<strong>de</strong>o a través <strong>de</strong> estos es caro<br />

<strong>de</strong>bido a que el mercado no es muy ext<strong>en</strong>so aun y su <strong>de</strong>manda reducida.<br />

La v<strong>en</strong>taja <strong>de</strong>l uso <strong>de</strong> microprocesadores <strong>de</strong> propósito g<strong>en</strong>eral respecto a los DSP,<br />

radica <strong>en</strong> la celeridad con la que crece su mercado, provocando una disminución <strong>de</strong> costo y<br />

el consigui<strong>en</strong>te aum<strong>en</strong>to <strong>en</strong> los r<strong>en</strong>dimi<strong>en</strong>tos y capacida<strong>de</strong>s <strong>de</strong> procesami<strong>en</strong>to. Las<br />

características <strong>de</strong> hardware paulatinam<strong>en</strong>te van semejando mucho a las <strong>de</strong> un DSP. Baste<br />

como ejemplo citar la tecnología MMX que los procesadores P<strong>en</strong>tium <strong>de</strong> Intel® han<br />

añadido a sus procesadores:<br />

“ Los diseñadores <strong>de</strong> Intel han añadido 57 nuevas y po<strong>de</strong>rosas<br />

instrucciones específicam<strong>en</strong>te diseñadas para manipular y procesar<br />

vi<strong>de</strong>o, audio y datos gráficos <strong>de</strong> manera efici<strong>en</strong>te. Estas instrucciones<br />

están ori<strong>en</strong>tadas a conseguir secu<strong>en</strong>cias altam<strong>en</strong>te paralelas y<br />

repetitivas <strong>en</strong>contradas continuam<strong>en</strong>te <strong>en</strong> operaciones multimedia. “<br />

http://www.intel.com/espanol/in<strong>de</strong>x.htm ( Mayo 2001)<br />

Estas novedosas capacida<strong>de</strong>s son explotadas <strong>en</strong> el pres<strong>en</strong>te trabajo al construirse el<br />

software que permite llevar a cabo procesami<strong>en</strong>to <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> <strong>en</strong> una<br />

computadora personal. Dicho software se apoya <strong>en</strong> el sistema <strong>de</strong> <strong>de</strong>sarrollo SDK <strong>de</strong><br />

DirectX® DirectShow el cual ofrece acceso directo a tarjetas <strong>de</strong> vi<strong>de</strong>o y <strong>de</strong> audio<br />

conectadas <strong>en</strong> la PC.


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 9<br />

El procesami<strong>en</strong>to <strong>de</strong> vi<strong>de</strong>o pue<strong>de</strong> incluir un amplio rango <strong>de</strong> efectos, que van <strong>de</strong>s<strong>de</strong><br />

la eliminación <strong>de</strong> compon<strong>en</strong>tes <strong>de</strong> color hasta los complejos que incluy<strong>en</strong> introducir parte<br />

<strong>de</strong> un vi<strong>de</strong>o(por ejemplo la imag<strong>en</strong> <strong>en</strong> movimi<strong>en</strong>to <strong>de</strong> una persona) <strong>de</strong>ntro <strong>de</strong> otro vi<strong>de</strong>o.<br />

Asimismo se pue<strong>de</strong> <strong>real</strong>izar procesami<strong>en</strong>to sobre vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong>, y<br />

procesami<strong>en</strong>to <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> modo <strong>de</strong> edición cuadro por cuadro sobre cada imag<strong>en</strong>, para su<br />

posterior pres<strong>en</strong>tación. Este ultimo tipo <strong>de</strong> procesami<strong>en</strong>to se <strong>real</strong>iza <strong>en</strong> edición <strong>de</strong> películas<br />

para añadir efectos visuales especiales y requiere costosas estaciones <strong>de</strong> trabajo con mas <strong>de</strong><br />

un procesador si se quiere ahorro <strong>de</strong> <strong>tiempo</strong> aunque una PC lo pue<strong>de</strong> hacer con ciertas<br />

restricciones.<br />

En la actualidad se dispone <strong>en</strong> el mercado <strong>de</strong> software para edición <strong>de</strong> vi<strong>de</strong>o, pero<br />

no <strong>de</strong> software comercial para procesami<strong>en</strong>to <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> para la PC, lo cual<br />

constituye un atractivo alici<strong>en</strong>te para este trabajo. Cabe resaltar que exist<strong>en</strong> sistemas <strong>de</strong><br />

procesami<strong>en</strong>to <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> la PC pero estos incluy<strong>en</strong> tarjetas con procesadores <strong>digital</strong>es <strong>de</strong><br />

señales (DSP) externos.<br />

En este proyecto se <strong>real</strong>iza solo procesami<strong>en</strong>to <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> básico, y<br />

dado que la complejidad permisible <strong>de</strong>l procesami<strong>en</strong>to vi<strong>en</strong>e <strong>de</strong>terminada fuertem<strong>en</strong>te por<br />

el hardware, se experim<strong>en</strong>ta la capacidad <strong>de</strong> procesami<strong>en</strong>to <strong>de</strong> la computadora personal<br />

utilizada para establecer sus limitaciones.<br />

Se elaboraron procesami<strong>en</strong>tos básicos <strong>de</strong> vi<strong>de</strong>o que consist<strong>en</strong> <strong>en</strong> filtrado <strong>de</strong><br />

compon<strong>en</strong>tes <strong>de</strong> color, adición <strong>de</strong> ruido a la imag<strong>en</strong>, superposición <strong>de</strong> imag<strong>en</strong> al vi<strong>de</strong>o,<br />

eliminación <strong>de</strong> color, posterizado y <strong>real</strong>ce. Algunos efectos que requerían mayor capacidad<br />

<strong>de</strong> procesami<strong>en</strong>to no pudieron llevarse acabo, sin embargo el aum<strong>en</strong>to <strong>en</strong> las capacida<strong>de</strong>s<br />

<strong>de</strong>l hardware seguram<strong>en</strong>te solv<strong>en</strong>tara pronto dichas restricciones.<br />

La interacción <strong>en</strong>tre la televisión y las computadoras es uno <strong>de</strong> los campos con<br />

mayor pot<strong>en</strong>cial <strong>de</strong> <strong>de</strong>sarrollo <strong>en</strong> la actualidad. Con las tecnologías reci<strong>en</strong>tes como el DVD<br />

(Digital Vi<strong>de</strong>o Disc) y la HDTV (High-Definition Television), se amplían las perspectivas<br />

<strong>de</strong> éxito <strong>en</strong> la fusión <strong>de</strong> la televisión y la computadora para las próximas décadas.<br />

La versatilidad <strong>de</strong> la computadora y el software actuales <strong>en</strong> la elaboración <strong>de</strong> productos<br />

multimedia interactivos, aunada a las imág<strong>en</strong>es <strong>en</strong> movimi<strong>en</strong>to que pue<strong>de</strong>n g<strong>en</strong>erarse con<br />

algún reproductor <strong>de</strong> vi<strong>de</strong>o <strong>digital</strong> o analógico, permit<strong>en</strong> captar la at<strong>en</strong>ción <strong>de</strong>l televi<strong>de</strong>nte,<br />

brindando así un excel<strong>en</strong>te medio <strong>de</strong> apr<strong>en</strong>dizaje.<br />

Para la <strong>en</strong>señanza <strong>en</strong> aulas escolares es importante a<strong>de</strong>más, la g<strong>en</strong>eración <strong>de</strong> imág<strong>en</strong>es<br />

amplias que facilit<strong>en</strong> a todos los alumnos la percepción clara <strong>de</strong> los <strong>de</strong>talles <strong>en</strong> texto y<br />

esquemas. Esto se logra mediante el uso <strong>de</strong> cañoneras o vi<strong>de</strong>o proyectores, sin embargo<br />

ti<strong>en</strong><strong>en</strong> limitaciones <strong>en</strong> cuanto a la cantidad <strong>de</strong> lúm<strong>en</strong>es que produc<strong>en</strong>, y por <strong>en</strong><strong>de</strong> esta<br />

restringido su uso a lugares con poca iluminación.<br />

Es <strong>en</strong> este contexto que surge el interés por elaborar un dispositivo <strong>de</strong> bajo costo<br />

que permita manipular señales <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> prov<strong>en</strong>i<strong>en</strong>tes <strong>de</strong> una vi<strong>de</strong>o casetera,


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 10<br />

una vi<strong>de</strong>ocámara, un DVD o la computadora personal; y que proporcione una imag<strong>en</strong><br />

ampliada <strong>en</strong> un arreglo cuadrado <strong>de</strong> monitores o televisores para su uso <strong>en</strong> aulas iluminadas<br />

o inclusive al aire libre.<br />

Figura 1.1 Aspecto g<strong>en</strong>eral <strong>de</strong> un vi<strong>de</strong>owall <strong>de</strong> 5x5 monitores<br />

Al arreglo <strong>de</strong> monitores o dispositivos <strong>de</strong> proyección que están conectados a un<br />

procesador <strong>digital</strong> <strong>de</strong> señales vía software, se le <strong>de</strong>nomina comercialm<strong>en</strong>te vi<strong>de</strong>owall. Sus<br />

usos compr<strong>en</strong><strong>de</strong>n anuncios <strong>de</strong> comerciales, pres<strong>en</strong>tación <strong>de</strong> ev<strong>en</strong>tos al aire libre,<br />

pres<strong>en</strong>tación <strong>de</strong> vi<strong>de</strong>os, etc. . El costo <strong>de</strong> un vi<strong>de</strong>owall se increm<strong>en</strong>ta con el numero <strong>de</strong><br />

monitores que es capaz <strong>de</strong> manejar. Como ejemplo la empresa VIDEOWALLSUSA<br />

(www.vwusa.teklab.it) ofrece un procesador vi<strong>de</strong>owall 2x2 (4 monitores) <strong>en</strong> US$2,495. Por<br />

otra parte Minnesota Vi<strong>de</strong>o Productions (www.tccom.com) ofrece la r<strong>en</strong>ta <strong>de</strong> un vi<strong>de</strong>owall<br />

3x3 (9 monitores) por 4 días con algunos servicios adicionales <strong>en</strong> US$5,500.<br />

Finalm<strong>en</strong>te se ha <strong>de</strong> combinar el vi<strong>de</strong>owall con el procesami<strong>en</strong>to <strong>de</strong>l vi<strong>de</strong>o <strong>en</strong><br />

<strong>tiempo</strong> <strong>real</strong> aunque esto aña<strong>de</strong> una gran sobrecarga a la computadora y <strong>en</strong>fr<strong>en</strong>ta no pocos<br />

problemas <strong>de</strong> diseño <strong>de</strong> software.<br />

1.2 Definición <strong>de</strong>l proyecto<br />

La figura 1.3 muestra <strong>en</strong> modo g<strong>en</strong>eral los subsistemas que compr<strong>en</strong><strong>de</strong>n al pres<strong>en</strong>te<br />

dispositivo.<br />

A) G<strong>en</strong>eración <strong>de</strong> la señal <strong>de</strong> vi<strong>de</strong>o.<br />

B) Conversión <strong>de</strong> la señal <strong>de</strong> vi<strong>de</strong>o a un formato <strong>digital</strong>.<br />

C) Sistema para el procesami<strong>en</strong>to <strong>de</strong> vi<strong>de</strong>o, utilizando microprocesadores <strong>de</strong> propósito<br />

g<strong>en</strong>eral.<br />

D) Multiplexor <strong>digital</strong> <strong>en</strong>cargado <strong>de</strong> repartir la señal <strong>de</strong> vi<strong>de</strong>o procesada hacia cada<br />

monitor o televisor<br />

E) Conversión <strong>de</strong> la señal <strong>de</strong> vi<strong>de</strong>o <strong>digital</strong> a un formato analógico o compatible con el<br />

monitor


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 11<br />

Figura 1.2 Diagrama a bloques <strong>de</strong>l proyecto<br />

D<strong>en</strong>tro <strong>de</strong> lo concerni<strong>en</strong>te al bloque B se ti<strong>en</strong>e contemplado el uso <strong>de</strong> una tarjeta <strong>de</strong><br />

adquisición <strong>de</strong> vi<strong>de</strong>o, la cual <strong>real</strong>iza la conversión analógica a <strong>digital</strong> y <strong>en</strong>vía la información<br />

directam<strong>en</strong>te a la memoria <strong>de</strong> vi<strong>de</strong>o <strong>de</strong> la computadora, liberando <strong>de</strong> esta tarea al<br />

microprocesador.<br />

En el bloque C <strong>de</strong> la figura anterior el procesador <strong>de</strong> propósito g<strong>en</strong>eral embebido <strong>en</strong><br />

una computadora personal <strong>real</strong>izará el procesami<strong>en</strong>to <strong>de</strong> vi<strong>de</strong>o auxiliado por dispositivos<br />

para manejo <strong>de</strong> imág<strong>en</strong>es como las tarjetas aceleradoras <strong>de</strong> gráficos AGP.<br />

La programación se llevará a cabo <strong>en</strong> Visual C++ y empleando librerías DirectX, las<br />

cuales permit<strong>en</strong> un acceso <strong>de</strong> bajo nivel al hardware multimedia <strong>de</strong> forma in<strong>de</strong>p<strong>en</strong>di<strong>en</strong>te <strong>de</strong>l<br />

dispositivo y aprovechan los conjuntos <strong>de</strong> instrucciones ampliadas para el manejo <strong>de</strong> audio<br />

y vi<strong>de</strong>o que ofrec<strong>en</strong> los microprocesadores c<strong>en</strong>trales y gráficos.<br />

La manipulación <strong>de</strong> las fu<strong>en</strong>tes audiovisuales pue<strong>de</strong> incluir diversos efectos como la<br />

mejora <strong>en</strong> la calidad <strong>de</strong> la imag<strong>en</strong> ampliada mediante técnicas <strong>de</strong> interpolación, la<br />

superposición <strong>de</strong> imág<strong>en</strong>es y/o subtítulos, el escalami<strong>en</strong>to <strong>de</strong> imág<strong>en</strong>es (aum<strong>en</strong>to o<br />

disminución), y el filtrado <strong>de</strong> compon<strong>en</strong>tes <strong>de</strong> color.<br />

Para el bloque D se ti<strong>en</strong>e p<strong>en</strong>sado elaborar una tarjeta que se inserte <strong>en</strong> un puerto <strong>de</strong><br />

la computadora y <strong>real</strong>ice la función <strong>de</strong> multiplexado para <strong>en</strong>viar la información <strong>digital</strong> <strong>de</strong><br />

vi<strong>de</strong>o, hacia cada una <strong>de</strong> las pantallas <strong>de</strong> televisión.


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 12<br />

En lo que respecta al bloque E se ti<strong>en</strong>e p<strong>en</strong>sado elaborar un sistema <strong>de</strong> conversión<br />

<strong>de</strong> imag<strong>en</strong> por hardware para cada una <strong>de</strong> las pantallas o monitores. La pres<strong>en</strong>tación <strong>de</strong> la<br />

imag<strong>en</strong> se dará <strong>en</strong> un arreglo <strong>de</strong> 2x2 (4 televisores o monitores <strong>de</strong> alta resolución para<br />

computadora), la magnitud <strong>de</strong>l arreglo respon<strong>de</strong> a la necesidad <strong>de</strong> minimizar los recursos <strong>de</strong><br />

la unidad c<strong>en</strong>tral <strong>de</strong> proceso(CPU) que hagan <strong>real</strong>izable el procesami<strong>en</strong>to <strong>de</strong> vi<strong>de</strong>o <strong>en</strong><br />

<strong>tiempo</strong> <strong>real</strong>.<br />

1.3 Objetivos<br />

Objetivo g<strong>en</strong>eral:<br />

Diseñar e implem<strong>en</strong>tar un sistema <strong>digital</strong> para procesami<strong>en</strong>to <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong>, el<br />

cual proporcione una sola imag<strong>en</strong> <strong>en</strong> un arreglo cuadrado <strong>de</strong> televisores.<br />

Objetivos particulares:<br />

- Desarrollar el software y el hardware necesario para la conversión <strong>de</strong> la señal <strong>de</strong><br />

vi<strong>de</strong>o analógico o <strong>digital</strong>, a un formato estándar y manipulable por el<br />

microprocesador <strong>de</strong> propósito g<strong>en</strong>eral.<br />

- Desarrollar el software para el microprocesador que <strong>real</strong>ice efectos diversos con las<br />

señales <strong>de</strong> vi<strong>de</strong>o.<br />

- Desarrollar el software y el hardware necesarios para dividir la imag<strong>en</strong> <strong>digital</strong>,<br />

a<strong>de</strong>más <strong>de</strong> proporcionar señales para cada monitor <strong>en</strong> el arreglo cuadrado.<br />

1.4 Panorama g<strong>en</strong>eral<br />

En el capitulo dos se expon<strong>en</strong> los elem<strong>en</strong>tos que nos llevaron a seleccionar el pres<strong>en</strong>te<br />

proyecto, tomando <strong>en</strong> consi<strong>de</strong>ración el estado <strong>de</strong>l arte y la posibilidad <strong>de</strong>l mismo. El<br />

capitulo tres pres<strong>en</strong>ta los datos relevantes sobre la investigación <strong>real</strong>izada que permite el<br />

<strong>de</strong>sarrollo práctico <strong>de</strong>l sistema, se incluye terminología básica y conceptos clave para la<br />

compr<strong>en</strong>sión <strong>de</strong>l software. Para el capitulo cuatro se tocan los elem<strong>en</strong>tos <strong>de</strong> diseño básicos<br />

que posibilitarán la implem<strong>en</strong>tación <strong>de</strong>l software. En el capitulo cinco se <strong>de</strong>scrib<strong>en</strong> los<br />

pasos <strong>de</strong> <strong>de</strong>sarrollo <strong>en</strong> software, este compr<strong>en</strong><strong>de</strong> la aplicación, el filtro y la interfase con el<br />

sistema operativo. Finalm<strong>en</strong>te se expone una evaluación <strong>de</strong>l proyecto con las conclusiones<br />

obt<strong>en</strong>idas.


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 13<br />

2. Análisis <strong>de</strong> fundam<strong>en</strong>tos<br />

2.1 Estado <strong>de</strong>l arte<br />

A últimos días el procesami<strong>en</strong>to <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> a tomado gran<br />

importancia y sus aplicaciones van <strong>de</strong>s<strong>de</strong> la edición <strong>de</strong> películas, eliminación <strong>de</strong> ruido <strong>en</strong> la<br />

transmisión <strong>de</strong> vi<strong>de</strong>o, compresión <strong>de</strong> vi<strong>de</strong>o y adición <strong>de</strong> efectos especiales <strong>en</strong>tre otras.<br />

Diversas universida<strong>de</strong>s <strong>en</strong> el mundo <strong>real</strong>izan investigación <strong>en</strong> esta área y se pue<strong>de</strong>n<br />

<strong>en</strong>contrar una gran cantidad <strong>de</strong> trabajos que se increm<strong>en</strong>tan día con día.<br />

En la gran mayoría <strong>de</strong> c<strong>en</strong>tros <strong>de</strong> investigación los dispositivos utilizados para el<br />

procesami<strong>en</strong>to <strong>de</strong>l vi<strong>de</strong>o son los procesadores <strong>digital</strong>es <strong>de</strong> señales DSP(Digital Signal<br />

Processors). Estos procesadores <strong>de</strong> propósito especifico cumpl<strong>en</strong> con altas normas <strong>de</strong><br />

r<strong>en</strong>dimi<strong>en</strong>to, sin embargo los costos asociados son relativam<strong>en</strong>te altos.<br />

Uno <strong>de</strong> los c<strong>en</strong>tros con mayor producción <strong>de</strong> trabajos <strong>en</strong> este campo es el<br />

laboratorio <strong>de</strong> procesami<strong>en</strong>to <strong>de</strong> imág<strong>en</strong>es y vi<strong>de</strong>o VIPER (Vi<strong>de</strong>o and Image Processing<br />

Laboratory) <strong>de</strong> la Universidad <strong>de</strong> Purdue. Los trabajos más reci<strong>en</strong>tes se pue<strong>de</strong>n <strong>en</strong>contrar<br />

<strong>en</strong>: http://dynamo.ecn.purdue.edu/~ace/<strong>de</strong>lp-pub.html<br />

Como ejemplo <strong>de</strong> lo m<strong>en</strong>cionado <strong>en</strong>contramos investigaciones sobre compresión <strong>de</strong><br />

vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong>, filtrado y <strong>de</strong>tección <strong>de</strong> contornos utilizando un sistema basado <strong>en</strong> el<br />

microprocesador TMS320C80 <strong>de</strong> la empresa Texas Instrum<strong>en</strong>ts, el cual conti<strong>en</strong>e 5<br />

procesadores programables: Un procesador maestro y cuatro procesadores paralelos. Dicho<br />

trabajo se pue<strong>de</strong> revisar <strong>en</strong>: http://dynamo.ecn.purdue.edu/~ace/c80/c80.html<br />

Figura 2.1 Detección <strong>de</strong> contornos<br />

En este caso el procesador asociado TMS320C80 ti<strong>en</strong>e un costo <strong>de</strong> US$993, pero un<br />

sistema <strong>de</strong> <strong>de</strong>sarrollo completo requiere <strong>de</strong> un kit <strong>de</strong> herrami<strong>en</strong>tas y una computadora<br />

adicional cuyo costo pue<strong>de</strong> asc<strong>en</strong><strong>de</strong>r a los US$4500.<br />

Por otro lado el grupo <strong>de</strong> investigación <strong>de</strong> procesami<strong>en</strong>to <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> el<br />

<strong>de</strong>partam<strong>en</strong>to <strong>de</strong> electrónica e ing<strong>en</strong>iería eléctrica <strong>de</strong> la universidad <strong>de</strong> Dublin<br />

http://wwwdsp.ucd.ie <strong>real</strong>izan el filtrado para eliminar errores <strong>en</strong> la imag<strong>en</strong> producidas


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 14<br />

durante el proceso <strong>de</strong> compresión, <strong>en</strong> todos los casos las pruebas e implem<strong>en</strong>tación se<br />

hac<strong>en</strong> <strong>en</strong> DSP para procesami<strong>en</strong>to <strong>de</strong> vi<strong>de</strong>o.<br />

En el ámbito nacional <strong>de</strong>ntro <strong>de</strong>l IIMAS <strong>en</strong> la UNAM el Dr. Fabián García Nocetti<br />

trabaja <strong>en</strong> la investigación y <strong>de</strong>sarrollo <strong>de</strong> arquitecturas computacionales <strong>de</strong> alto <strong>de</strong>sempeño<br />

y <strong>de</strong> algoritmos efici<strong>en</strong>tes para implem<strong>en</strong>tar sistemas paralelos <strong>en</strong> aplicaciones <strong>de</strong> <strong>tiempo</strong><br />

<strong>real</strong>. En su c<strong>en</strong>tro <strong>de</strong> investigación se <strong>de</strong>sarrollan arquitecturas computacionales<br />

heterogéneas, integradas por procesadores paralelos y procesadores <strong>digital</strong>es <strong>de</strong> señales<br />

(DSPs), lo que permite explotar las características computacionales <strong>de</strong> los procesadores que<br />

la integran, optimizando el mecanismo <strong>de</strong> comunicación <strong>en</strong>tre los mismos y permiti<strong>en</strong>do<br />

una distribución efici<strong>en</strong>te <strong>de</strong> las tareas ejecutadas por los módulos <strong>de</strong> procesami<strong>en</strong>to. El uso<br />

<strong>de</strong> arquitecturas heterogéneas ha resultado <strong>en</strong> un m<strong>en</strong>or <strong>tiempo</strong> <strong>de</strong> ejecución <strong>de</strong> los<br />

algoritmos, a<strong>de</strong>más se ha contribuido <strong>en</strong> la g<strong>en</strong>eración <strong>de</strong> metodologías formales para<br />

automatizar la paralelización <strong>de</strong> las aplicaciones, permiti<strong>en</strong>do integrar sistemas <strong>de</strong><br />

procesami<strong>en</strong>to <strong>de</strong> alto <strong>de</strong>sempeño escalables y reconfigurables. En este caso se da énfasis al<br />

procesami<strong>en</strong>to paralelo para lograr las transformaciones <strong>en</strong> <strong>tiempo</strong> <strong>real</strong>. También se<br />

<strong>de</strong>sarrollan métodos para la utilización <strong>de</strong>l cómputo paralelo <strong>en</strong> la obt<strong>en</strong>ción,<br />

procesami<strong>en</strong>to y <strong>de</strong>spliegue <strong>de</strong> imág<strong>en</strong>es ultrasónicas. Los resultados han permitido<br />

increm<strong>en</strong>tar tanto la velocidad y como la resolución <strong>en</strong> el proceso <strong>de</strong> formación <strong>de</strong> la<br />

imag<strong>en</strong> y aplicar estos <strong>de</strong>sarrollos al área <strong>de</strong> imag<strong>en</strong>ología ultrasónica.<br />

También <strong>de</strong>l IIMAS se <strong>en</strong>cu<strong>en</strong>tra el Dr. Julio Solano González:.<strong>de</strong>dicado al<br />

Estudio y <strong>de</strong>sarrollo <strong>de</strong> arquitecturas y algoritmos efici<strong>en</strong>tes para el Cómputo <strong>de</strong> Alto<br />

Desempeño, utilizando arquitecturas paralelas homogéneas y heterogéneas, combinando<br />

procesadores paralelos con procesadores <strong>digital</strong>es <strong>de</strong> señales (DSP's). Los <strong>de</strong>sarrollos<br />

<strong>de</strong>scritos han sido aplicados directam<strong>en</strong>te a problemas <strong>en</strong> los campos <strong>de</strong>l <strong>Procesami<strong>en</strong>to</strong> <strong>de</strong><br />

Señales e Imág<strong>en</strong>es, específicam<strong>en</strong>te <strong>en</strong> las áreas <strong>de</strong> flujometría Doppler e Imag<strong>en</strong>ología<br />

Ultrasónica.<br />

Una investigación utilizando DirectShow se <strong>en</strong>cu<strong>en</strong>tra disponible <strong>en</strong> internet bajo la<br />

dirección: http://keeper.warhead.org.uk . El titulo es “DirectShow TV display with Real Time<br />

vi<strong>de</strong>o processing” .<br />

El proyecto combina técnicas <strong>de</strong> <strong>tiempo</strong> <strong>real</strong> para la reducción <strong>de</strong> ruido y<br />

<strong>de</strong>s<strong>en</strong>trelazado <strong>de</strong>rivado <strong>de</strong> publicaciones con un carácter puram<strong>en</strong>te teórico. Ambos<br />

procesami<strong>en</strong>tos se <strong>real</strong>izan bajo el marco <strong>de</strong> DirectShow. El filtro <strong>de</strong> procesami<strong>en</strong>to <strong>de</strong><br />

vi<strong>de</strong>o es un compon<strong>en</strong>te COM y pue<strong>de</strong> ser reutilizado sin modificaciones <strong>en</strong> otros<br />

proyectos DirectShow. El filtro implem<strong>en</strong>ta una serie <strong>de</strong> algoritmos <strong>de</strong> reducción <strong>de</strong> ruido y<br />

<strong>de</strong> <strong>de</strong>s<strong>en</strong>trelazado para ser utilizados <strong>en</strong> computadoras personales <strong>de</strong> varias velocida<strong>de</strong>s.<br />

Salvo este último caso no me ha sido posible <strong>en</strong>contrar algún otro proyecto <strong>de</strong><br />

investigación que utilice a DirectShow como herrami<strong>en</strong>ta <strong>de</strong> procesami<strong>en</strong>to <strong>de</strong> vi<strong>de</strong>o <strong>en</strong><br />

<strong>tiempo</strong> <strong>real</strong>. Cabe <strong>de</strong>stacarse que la herrami<strong>en</strong>ta DirectShow tuvo su primera aparición <strong>en</strong> la<br />

versión 8.0a <strong>de</strong> DirectX disponible <strong>en</strong> 1999.


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 15<br />

2.2 Herrami<strong>en</strong>tas disponibles<br />

En el pres<strong>en</strong>te proyecto hemos consi<strong>de</strong>rado el uso <strong>de</strong> una PC con un procesador <strong>de</strong><br />

propósito g<strong>en</strong>eral Intel para el procesami<strong>en</strong>to <strong>de</strong> vi<strong>de</strong>o ejecutando el sistema operativo<br />

Windows 98. La razón principal es la economía, <strong>de</strong>bido a que el costo <strong>de</strong> un<br />

microprocesador <strong>de</strong> propósito g<strong>en</strong>eral es con mucho m<strong>en</strong>or a un DSP, adicionalm<strong>en</strong>te se<br />

ti<strong>en</strong>e una gran cantidad <strong>de</strong> hardware <strong>de</strong> bajo costo con controladores para Windows 98 que<br />

permite a<strong>de</strong>cuar el sistema a nuestras necesida<strong>de</strong>s.<br />

Por otro lado el <strong>de</strong>sarrollo <strong>de</strong> los mo<strong>de</strong>rnos procesadores <strong>de</strong> propósito g<strong>en</strong>eral,<br />

incorporan po<strong>de</strong>rosas funciones. Por ejemplo el “reci<strong>en</strong>te” P<strong>en</strong>tium III <strong>de</strong> Intel, incluye la<br />

característica SIMD (Single Instruction Multiple Data) <strong>en</strong> punto flotante, lo cual<br />

<strong>de</strong>finitivam<strong>en</strong>te increm<strong>en</strong>ta el r<strong>en</strong>dimi<strong>en</strong>to <strong>en</strong> aplicaciones multimedia.<br />

Adicionalm<strong>en</strong>te y hace un par <strong>de</strong> meses se ha añadido<br />

DirectShow como parte <strong>de</strong> DirectX 8.1, software <strong>de</strong> <strong>de</strong>sarrollo<br />

creado por Microsoft disponible gratuitam<strong>en</strong>te y que permite la<br />

manipulación <strong>de</strong> vi<strong>de</strong>o. DirectX proporciona una serie <strong>de</strong> librerías<br />

que permit<strong>en</strong> al <strong>de</strong>sarrollador acce<strong>de</strong>r a las características<br />

avanzadas y <strong>de</strong> alto r<strong>en</strong>dimi<strong>en</strong>to <strong>en</strong> hardware. Es con esta<br />

herrami<strong>en</strong>ta que se pret<strong>en</strong><strong>de</strong> explotar las capacida<strong>de</strong>s novedosas<br />

<strong>de</strong>l procesador <strong>de</strong> propósito g<strong>en</strong>eral para lograr el procesami<strong>en</strong>to<br />

<strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong>. Las limitaciones se <strong>de</strong>sconoc<strong>en</strong> y dada su<br />

<strong>de</strong>p<strong>en</strong><strong>de</strong>ncia directa con el hardware no dudo que al termino <strong>de</strong>l<br />

proyecto sean muy distintas a las actuales. Mi<strong>en</strong>tras tanto se irán<br />

Figura 2.2 DirectX <strong>de</strong>scribi<strong>en</strong>do los limitantes <strong>de</strong> software asociados.


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 16<br />

3. Investigación<br />

3.1 <strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> imág<strong>en</strong>es<br />

El concepto <strong>de</strong> imag<strong>en</strong> está asociado a una función bidim<strong>en</strong>sional f(x,y), cuya<br />

amplitud o valor será el grado <strong>de</strong> iluminación (int<strong>en</strong>sidad <strong>de</strong> la luz) <strong>en</strong> el espacio <strong>de</strong><br />

coor<strong>de</strong>nadas (x,y) <strong>de</strong> la imag<strong>en</strong> para cada punto. El valor <strong>de</strong> esta función <strong>de</strong>p<strong>en</strong><strong>de</strong> <strong>de</strong> la<br />

cantidad <strong>de</strong> luz que inci<strong>de</strong> sobre la esc<strong>en</strong>a vista, asi como <strong>de</strong> la parte que sea reflejada por<br />

los objetos que compon<strong>en</strong> dicha esc<strong>en</strong>a. Estos compon<strong>en</strong>tes son llamados iluminación y<br />

reflexión, si<strong>en</strong>do <strong>de</strong>scritos por i(x,y) y r(x,y) respectivam<strong>en</strong>te. El producto <strong>de</strong> ambas<br />

funciones proporciona la función f(x,y):<br />

Si<strong>en</strong>do el intervalo <strong>de</strong> <strong>de</strong>finición:<br />

Por lo que f(x,y) estará acotada <strong>en</strong>:<br />

f ( x,<br />

y)<br />

= i(<br />

x,<br />

y)<br />

r(<br />

x,<br />

y)<br />

0 < i(<br />

x,<br />

y)<br />

< ∞<br />

0 < r(<br />

x,<br />

y)<br />

< 1<br />

0 < f ( x,<br />

y)<br />

< ∞<br />

La naturaleza <strong>de</strong> la iluminación vi<strong>en</strong>e <strong>de</strong>terminada por la fu<strong>en</strong>te <strong>de</strong> luz, mi<strong>en</strong>tras que<br />

la reflexión <strong>de</strong>p<strong>en</strong><strong>de</strong> <strong>de</strong> las caracteristicas <strong>de</strong>l objeto <strong>en</strong> la esc<strong>en</strong>a.<br />

Dep<strong>en</strong>di<strong>en</strong>do <strong>de</strong> las dim<strong>en</strong>siones, la función pue<strong>de</strong> ser escalar (como las imág<strong>en</strong>es<br />

<strong>en</strong> blanco y negro) o vectorial (como las imág<strong>en</strong>es <strong>en</strong> color que ti<strong>en</strong><strong>en</strong> tres compon<strong>en</strong>tes).<br />

La función <strong>de</strong> imag<strong>en</strong> f(x,y) es <strong>digital</strong>izada <strong>en</strong> la memoria <strong>de</strong> la computadora, tanto<br />

espacialm<strong>en</strong>te como <strong>en</strong> amplitud. Por lo tanto f(x,y) está almac<strong>en</strong>ada <strong>en</strong> una matriz <strong>de</strong><br />

N × M elem<strong>en</strong>tos. Tomaremos el orig<strong>en</strong> <strong>de</strong> coor<strong>de</strong>nadas <strong>de</strong> la imag<strong>en</strong> <strong>en</strong> la esquina<br />

superior izquierda, el eje x el horizontal y el eje y el vertical.<br />

⎡ f ( 0,<br />

0)<br />

⎢<br />

⎢<br />

f ( 0,<br />

1)<br />

f ( x,<br />

y)<br />

= ⎢ �<br />

⎢<br />

⎢ f ( 0,<br />

M − 2)<br />

⎢<br />

⎣ f ( 0,<br />

M −1)<br />

f ( 1,<br />

0)<br />

f ( 1,<br />

1)<br />

�<br />

f ( 1,<br />

M −1)<br />

�<br />

�<br />

�<br />

f ( 1,<br />

M − 2)<br />

�<br />

�<br />

f ( N − 2,<br />

0)<br />

f ( N − 2,<br />

1)<br />

�<br />

f ( N − 2,<br />

M − 2)<br />

f ( N − 2,<br />

M −1)<br />

f ( N −1,<br />

0)<br />

⎤<br />

f ( N −1,<br />

1)<br />

⎥<br />

⎥<br />

� ⎥<br />

⎥<br />

f ( N −1,<br />

M − 2)<br />

⎥<br />

f ( N −1,<br />

M −1)<br />

⎥<br />

⎦<br />

El muestreo es la conversión que sufr<strong>en</strong> las dos dim<strong>en</strong>siones espaciales <strong>de</strong> la señal<br />

analogica, y que g<strong>en</strong>era la noción <strong>de</strong> pixel. La cuantificación es la conversión que sufre la


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 17<br />

amplitud <strong>de</strong> la señal analógica, así se g<strong>en</strong>era el concepto <strong>de</strong> nivel <strong>de</strong> gris o int<strong>en</strong>sidad. Para<br />

el caso <strong>de</strong> t<strong>en</strong>er 256 niveles <strong>de</strong> gris (0–255). El 0 correspon<strong>de</strong> a un objeto no iluminado o<br />

que absorbe todos los rayos luminosos que inci<strong>de</strong>n sobre él (negro), y el nivel 255 a un<br />

objeto muy iluminado o que refleja todos los rayos que inci<strong>de</strong>n sobre el (blanco).<br />

En el proceso <strong>de</strong> <strong>digital</strong>ización es preciso establecer el valor <strong>de</strong> N y M asi como el<br />

numero <strong>de</strong> niveles <strong>de</strong> gris asignados a cada pixel. Es una práctica común <strong>en</strong> el proceso <strong>de</strong><br />

<strong>digital</strong>ización <strong>de</strong> imág<strong>en</strong>es que estas cantida<strong>de</strong>s sean números <strong>en</strong>teros pot<strong>en</strong>cias <strong>de</strong> dos. El<br />

numero <strong>de</strong> bits b requeridos para almac<strong>en</strong>ar la imag<strong>en</strong> <strong>digital</strong>izada vi<strong>en</strong>e dado por el<br />

producto:<br />

si<strong>en</strong>do 2 g el numero <strong>de</strong> niveles <strong>de</strong> gris.<br />

b = NMg<br />

El histograma conti<strong>en</strong>e el numero <strong>de</strong> pixeles que ti<strong>en</strong><strong>en</strong> el mismo nivel <strong>de</strong> gris, y<br />

pue<strong>de</strong> <strong>en</strong>t<strong>en</strong><strong>de</strong>rse como la probabilidad <strong>de</strong> que un velor <strong>de</strong> gris <strong>de</strong>terminado aparezca <strong>en</strong> la<br />

imag<strong>en</strong>.<br />

Un ultimo elem<strong>en</strong>to <strong>de</strong> la imag<strong>en</strong> son los planos <strong>de</strong> bits. Si una imag<strong>en</strong> ti<strong>en</strong>e 256<br />

niveles <strong>de</strong> gris, cada uno <strong>de</strong> los pixeles ocupa un byte (8 bits).<br />

Cada plano <strong>de</strong> bit es una imag<strong>en</strong> formada por un bit <strong>de</strong> una <strong>de</strong>terminada posición<br />

<strong>en</strong> el byte para cada pixel. Los planos <strong>de</strong> bits reflejan bi<strong>en</strong> la influ<strong>en</strong>cia <strong>de</strong>l ruido <strong>en</strong> la<br />

imag<strong>en</strong>. Así pue<strong>de</strong> observarse como para planos <strong>de</strong> bits mas significativos se pue<strong>de</strong>n<br />

distinguir los distintos objetos que forman la imag<strong>en</strong>, pero para bits m<strong>en</strong>os significativos la<br />

impresión que dan es una distribución aleatoria <strong>de</strong> puntos.<br />

3.1.1 Relaciones <strong>en</strong>tre pixeles<br />

Un pixel p <strong>de</strong> coor<strong>de</strong>nadas (x,y) pres<strong>en</strong>ta un total <strong>de</strong> cuatro vecinos <strong>en</strong> el plano<br />

vertical y horizontal, si<strong>en</strong>do sus coor<strong>de</strong>nadas:<br />

x − 1,<br />

y<br />

x , y −1<br />

x, y<br />

x , y + 1<br />

x + 1,<br />

y<br />

Este conjunto <strong>de</strong> pixeles se <strong>de</strong>nomina vecindad <strong>de</strong> tipo 4 <strong>de</strong>l pixel p, y se repres<strong>en</strong>ta<br />

por N4(p). A<strong>de</strong>más se pue<strong>de</strong> consi<strong>de</strong>rar la exist<strong>en</strong>cia <strong>de</strong> otros cuatro vecinos asociados a las<br />

diagonales, cuyas coor<strong>de</strong>nadas son:<br />

x −1, y −1<br />

x, y<br />

x + 1, y −1<br />

x −1 , y + 1<br />

x<br />

+ 1 , y + 1


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 18<br />

Los cuales se repres<strong>en</strong>tan por ND(p). La suma <strong>de</strong> los anteriores <strong>de</strong>fine los ocho vecinos <strong>de</strong>l<br />

pixel, N8(p).<br />

Mediante el concepto <strong>de</strong> conectividad se quiere expresar que dos pixeles pert<strong>en</strong>ec<strong>en</strong><br />

al mismo objeto, por lo que está relacionado con el <strong>de</strong> vecindad. Dos pixeles están<br />

conectados si son adyac<strong>en</strong>tes (vecinos) y si sus niveles <strong>de</strong> gris satisfac<strong>en</strong> algún criterio <strong>de</strong><br />

especificación (por ejemplo ser iguales).<br />

Exist<strong>en</strong> tres tipos:<br />

1. Conectividad-4. Dos pixeles p y q pres<strong>en</strong>tan una conectividad-4 si q pert<strong>en</strong>ece al<br />

N4(p).<br />

2. Conectividad-8. Dos pixeles p y q pres<strong>en</strong>tan una conectividad-8 si q pert<strong>en</strong>ece al<br />

N8(p).<br />

3. Conectividad-m (conectividad mixta). Dos pixeles p y q pres<strong>en</strong>tan una<br />

conectividad-m si:<br />

a) q pert<strong>en</strong>ece a N4(p), o<br />

b) q pert<strong>en</strong>ece a ND(p) y el conjunto N 4( p)<br />

∩ N 4(<br />

q)<br />

es el conjunto vacio.<br />

3.1.1.1 Distancia<br />

Con la distancia se quiere obt<strong>en</strong>er el minimo numero <strong>de</strong> pasos elem<strong>en</strong>tales que se<br />

necesitan para ir <strong>de</strong> un punto a otro. Dados tres pixeles p, q y z, con coor<strong>de</strong>nadas (x,y), (s,t)<br />

y (u,v) respectivam<strong>en</strong>te, se pue<strong>de</strong> <strong>de</strong>finir una función <strong>de</strong> distancia D si cumple:<br />

• D ( p,<br />

q)<br />

≥ 0,<br />

( D(<br />

p,<br />

q)<br />

= 0,<br />

si p = q)<br />

• D ( p,<br />

q)<br />

= D(<br />

q,<br />

p)<br />

• D ( p,<br />

z)<br />

≤ D(<br />

p,<br />

q)<br />

+ D(<br />

q,<br />

z)<br />

Las funciones <strong>de</strong> distancia usadas comunm<strong>en</strong>te son:<br />

La distancia eucli<strong>de</strong>a <strong>en</strong>tre p y q se <strong>de</strong>fine como:<br />

con esta <strong>de</strong>finición, las distancias serán:<br />

2<br />

DE ( p,<br />

q)<br />

= ( x − s)<br />

+ ( y − t<br />

8 5 2 5 8<br />

5 2 1 2 5<br />

2 1 0 1 2<br />

5 2 1 2 5<br />

8 5 2 5 8<br />

Distancia Manhattan. Se toman solam<strong>en</strong>te <strong>en</strong> cu<strong>en</strong>ta los vecinos <strong>de</strong> or<strong>de</strong>n 4.<br />

)<br />

2


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 19<br />

Las distancias serán por tanto:<br />

D = x − s + y − t<br />

4 3 2 3 4<br />

3 2 1 2 3<br />

2 1 0 1 2<br />

3 2 1 2 3<br />

4 3 2 3 4<br />

Con esta <strong>de</strong>finición los vecinos <strong>de</strong>l tipo 4 están a la distancia unidad.<br />

3.1.2 Color<br />

Algunas <strong>de</strong>finiciones básicas para compr<strong>en</strong><strong>de</strong>r los espacios <strong>de</strong> colores son:<br />

• Brillo: s<strong>en</strong>sación que indica si un área está más o m<strong>en</strong>os iluminada.<br />

• Tono: s<strong>en</strong>sación que indica si un área parece similar al rojo, amarillo, ver<strong>de</strong> o azul o<br />

a una proporción <strong>de</strong> dos <strong>de</strong> ellos.<br />

• Coloración: s<strong>en</strong>sación por la que un área ti<strong>en</strong>e un mayor o m<strong>en</strong>or tono.<br />

• Luminosidad: brillo <strong>de</strong> una zona respecto a otra blanca <strong>en</strong> la imag<strong>en</strong>.<br />

• Croma: La coloridad <strong>de</strong> un área respecto al brillo <strong>de</strong> un blanco <strong>de</strong> refer<strong>en</strong>cia.<br />

• Saturación: La relación <strong>en</strong>tre la coloridad y el brillo.<br />

Un espacio <strong>de</strong> color es un método por el que se pue<strong>de</strong> especificar, crear o visualizar<br />

cualquier color. Dep<strong>en</strong>di<strong>en</strong>do <strong>de</strong>l tipo <strong>de</strong> s<strong>en</strong>sor y aplicación se han <strong>de</strong>sarrollado diversos<br />

espacios <strong>de</strong> colores que se utilizan para la adquisición, la transmisión <strong>de</strong> las señales (por<br />

ejemplo para la televisión), y la impresión o los espacios que tratan <strong>de</strong> imitar la percepción<br />

humana.<br />

3.1.2.1 Espacio RGB<br />

El espacio RGB se basa <strong>en</strong> la combinación <strong>de</strong> tres señales <strong>de</strong> luminancia crómatica<br />

distinta: el rojo, el ver<strong>de</strong> y el azul (Red, Gre<strong>en</strong>, Blue). La manera mas s<strong>en</strong>cilla e intuitiva <strong>de</strong><br />

conseguir un color concreto es <strong>de</strong>terminar la cantidad <strong>de</strong> color rojo, ver<strong>de</strong> y azul que se<br />

necesita combinar; para ello se <strong>real</strong>iza la suma aritmética <strong>de</strong> las compon<strong>en</strong>tes:<br />

X = R + G + B<br />

Graficam<strong>en</strong>te se repres<strong>en</strong>ta por un cubo. En la recta que une el orig<strong>en</strong> con el valor<br />

máximo se hayan los grises, ya que las tres compon<strong>en</strong>tes son iguales.


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 20<br />

Cuando una camara adquiere una imag<strong>en</strong> <strong>en</strong> color, para cada pixel <strong>en</strong> color se ti<strong>en</strong><strong>en</strong><br />

<strong>en</strong> <strong>real</strong>idad tres, uno por cada compon<strong>en</strong>te; la ganancia máxima <strong>de</strong> cada uno <strong>de</strong> ellos<br />

correspon<strong>de</strong> a la longitud <strong>de</strong> onda <strong>de</strong> los tres colores básicos antes nombrados (rojo, ver<strong>de</strong> y<br />

azul). Aunque el sistema RGB es el más intuitivo <strong>de</strong> todos y <strong>de</strong> hecho es <strong>en</strong> el que se basan<br />

las cámaras para adquirir imág<strong>en</strong>es <strong>en</strong> color, pres<strong>en</strong>ta un serio inconv<strong>en</strong>i<strong>en</strong>te: <strong>en</strong> sus tres<br />

valores mezcla la información <strong>de</strong>l color (tono y saturación) y la int<strong>en</strong>sidad.<br />

3.1.2.2 Espacio HSI<br />

El espacio <strong>de</strong> color HSI se basa <strong>en</strong> el modo <strong>de</strong> percibir los colores que t<strong>en</strong>emos los<br />

humanos. Dicho sistema caracteriza el color <strong>en</strong> términos <strong>de</strong> tono o tinte(Hue), saturación o<br />

cromatismo (Saturation) y brillo (Int<strong>en</strong>sity); compon<strong>en</strong>tes que se muestran favorables <strong>de</strong><br />

cara a <strong>real</strong>izar segm<strong>en</strong>taciones <strong>de</strong> la imag<strong>en</strong> <strong>en</strong> at<strong>en</strong>ción al tono o tinte <strong>de</strong>l color.<br />

Las transformaciones matemáticas que permit<strong>en</strong> el paso <strong>de</strong>l espacio RGB al HSI<br />

son <strong>real</strong>izadas normalm<strong>en</strong>te mediante hardware especifico. Las ecuaciones son:<br />

En la espresión <strong>de</strong>l tono<br />

R + G + B<br />

I =<br />

3<br />

⎛ 3(<br />

G − B)<br />

⎞<br />

H = arctan⎜<br />

⎟<br />

⎜<br />

⎟<br />

⎝ ( R − G)<br />

+ ( R − B)<br />

⎠<br />

min( R,<br />

G,<br />

B)<br />

S = 1−<br />

I<br />

⎛ x ⎞<br />

H = arctan ⎜ ⎟<br />

⎝ y ⎠<br />

se emplea el signo <strong>de</strong> x e y para establecer el cuadrante al que pert<strong>en</strong>ece el ángulo<br />

resultante. Se pue<strong>de</strong> consi<strong>de</strong>rar que el tono indica el ángulo formado <strong>en</strong>tre el eje <strong>de</strong><br />

refer<strong>en</strong>cia (el correspondi<strong>en</strong>te al color rojo) y el punto que ocuparía el color a analizar.<br />

Asi como el espacio RGB se repres<strong>en</strong>ta para un cubo, el HSI lo forman dos<br />

pirami<strong>de</strong>s unidas por su base. Dep<strong>en</strong>di<strong>en</strong>do <strong>de</strong>l valor <strong>de</strong> la int<strong>en</strong>sidad se t<strong>en</strong>drá un corte con<br />

las pirami<strong>de</strong>s obt<strong>en</strong>i<strong>en</strong>dose un triángulo. D<strong>en</strong>tro <strong>de</strong>l triangulo obt<strong>en</strong>i<strong>en</strong>do la compon<strong>en</strong>te H


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 21<br />

vi<strong>en</strong>e <strong>de</strong>finida por su ori<strong>en</strong>tación (el rojo es 0 o , el ver<strong>de</strong> 120 o y el azul 240 o ) y la saturación<br />

indica la distancia al c<strong>en</strong>tro <strong>de</strong>l triangulo. D<strong>en</strong>tro <strong>de</strong> la circunfer<strong>en</strong>cia obt<strong>en</strong>ida el color<br />

vi<strong>en</strong>e <strong>de</strong>finido por su ori<strong>en</strong>tación (el rojo es 0 o , el ver<strong>de</strong> 120 o y el azul 240 o ) y la<br />

saturación indica la lejanía <strong>de</strong>l c<strong>en</strong>tro <strong>de</strong>l circulo.<br />

3.1.3 Transformaciones matemáticas<br />

Las transformaciones matematicas que se <strong>de</strong>scrib<strong>en</strong> acontinuación , son aquellos<br />

algoritmos <strong>de</strong> los que se obti<strong>en</strong>e una imag<strong>en</strong> g(x,y) a partir <strong>de</strong> la original f(x,y). El fin<br />

perseguido es transformar la imag<strong>en</strong> original. En este proyecto solo llevaremos a cabo<br />

transformaciones <strong>en</strong> el dominio <strong>de</strong>l espacio.<br />

El procesami<strong>en</strong>to espacial lo constituy<strong>en</strong> aquellas técnicas que operan directamete<br />

sobre los valores <strong>de</strong> los píxeles <strong>de</strong> la imag<strong>en</strong>. Serán transformaciones <strong>de</strong>l tipo:<br />

S ( x,<br />

y)<br />

= F(<br />

I(<br />

x,<br />

y))<br />

si<strong>en</strong>do I(x,y) la imag<strong>en</strong> original, S(x,y) la resultante y F la transformación. Estas<br />

transformaciones suel<strong>en</strong> aplicarse a un <strong>en</strong>torno cuadrado <strong>de</strong>l píxel.<br />

3.1.3.1 Convolucion<br />

Para el caso unidim<strong>en</strong>sional, se <strong>de</strong>fine como convolución <strong>de</strong> la función f(x) respecto<br />

a la función h(x) una nueva función g(x) tal que:<br />

i=<br />

∞<br />

∫<br />

i=<br />

−∞<br />

g ( x)<br />

= h(<br />

x)<br />

* f ( x)<br />

= f ( i)<br />

h(<br />

x − i)<br />

di<br />

Si se trata <strong>de</strong>l caso discreto con dos secu<strong>en</strong>cias f(x) y h(x) se obt<strong>en</strong>dría una<br />

secu<strong>en</strong>cia <strong>de</strong> salida g(x):<br />

i=<br />

∞<br />

∫<br />

i=<br />

−∞<br />

g ( x)<br />

= h(<br />

x)<br />

* f ( x)<br />

= f ( i)<br />

h(<br />

x − i)<br />

Para el caso <strong>de</strong> imág<strong>en</strong>es <strong>digital</strong>es se usan convoluciones bidim<strong>en</strong>sionales discretas, cuya<br />

formula es:


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 22<br />

∞ = i j=<br />

∞<br />

∑∑<br />

g ( x,<br />

y)<br />

= h(<br />

x,<br />

y)<br />

* f ( x,<br />

y)<br />

= f ( i,<br />

j)<br />

h(<br />

x − i,<br />

y − j)<br />

i=<br />

−∞ j=<br />

−∞<br />

Lo mas normal es usar convoluciones <strong>de</strong> 3x3 elem<strong>en</strong>tos. Entonces la expresión anterior<br />

pue<strong>de</strong> concretarse <strong>en</strong>:<br />

g ( x,<br />

y)<br />

= h(<br />

x,<br />

y)<br />

* f ( x,<br />

y)<br />

=<br />

que por ejemplo para g(2,2) será:<br />

i 2 j 2 = =<br />

i=<br />

0 j=<br />

0<br />

= i 2 j=<br />

2<br />

∑∑<br />

i=<br />

0 j=<br />

0<br />

g(<br />

2,<br />

2)<br />

= ∑∑ f ( i,<br />

j)<br />

h(<br />

2 − i,<br />

2 − j)<br />

=<br />

f ( i,<br />

j)<br />

h(<br />

x − i,<br />

y − j)<br />

f ( 0,<br />

0)<br />

h(<br />

2,<br />

2)<br />

+ f ( 0,<br />

1)<br />

h(<br />

2,<br />

1)<br />

+ f ( 0,<br />

2)<br />

h(<br />

2,<br />

0)<br />

+<br />

f ( 1,<br />

0)<br />

h(<br />

1,<br />

2)<br />

+ f ( 1,<br />

1)<br />

h(<br />

1,<br />

1)<br />

+ f ( 1,<br />

2)<br />

h(<br />

1,<br />

0)<br />

+<br />

f ( 2,<br />

0)<br />

h(<br />

0,<br />

2)<br />

+ f ( 2,<br />

1)<br />

h(<br />

0,<br />

1)<br />

+ f ( 2,<br />

2)<br />

h(<br />

0,<br />

0)<br />

G<strong>en</strong>eralm<strong>en</strong>te <strong>en</strong> lugar <strong>de</strong> hablar <strong>de</strong> convolucionar la imag<strong>en</strong> f(x,y) con la<br />

transformación h(x,y), se habla <strong>de</strong> convolucionar con una máscara que ti<strong>en</strong>e la forma:<br />

h(-i, -j) es <strong>en</strong>tonces:<br />

h(0,0) h(0,1) h(0,2)<br />

h(1,0) h(1,1) h(1,2)<br />

h(2,0) h(2,1) h(2,2)<br />

h(2,2) h(2,1) h(2,0)<br />

h(1,2) h(1,1) h(1,0)<br />

h(0,2) h(0,1) h(0,0)<br />

La porción inicial <strong>de</strong> la imag<strong>en</strong> correspondi<strong>en</strong>te es:<br />

f(0,0) f(0,1) f(0,2)<br />

f(1,0) f(1,1) f(1,2)<br />

f(2,0) f(2,1) f(2,2)<br />

Gráficam<strong>en</strong>te se trata <strong>de</strong> poner las dos matrices, una <strong>en</strong>cima <strong>de</strong> la otra, multiplicar<br />

cada celda por la inferior y sumar los productos. Para obt<strong>en</strong>er el sigui<strong>en</strong>te valor <strong>de</strong> g(x,y) la<br />

máscara h(x,y) se <strong>de</strong>splaza un elem<strong>en</strong>to a la <strong>de</strong>recha y se repite la operación. Al acabar las<br />

columnas se vuelve al principio a una fila inferior, y asi sucesivam<strong>en</strong>te hasta llegar al<br />

ultimo píxel.<br />

3.1.3.2 Operaciones matemáticas<br />

Suma<br />

Las operaciones aritméticas <strong>en</strong>tre dos píxeles p y q son las sigui<strong>en</strong>tes:


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 23<br />

Resta<br />

Multiplicación<br />

División<br />

Al <strong>real</strong>izar dichas operaciones se pue<strong>de</strong> t<strong>en</strong>er algunos problemas como el efecto<br />

<strong>de</strong>sbordami<strong>en</strong>to <strong>de</strong>l píxel (pixel overflow). Las imág<strong>en</strong>es ti<strong>en</strong><strong>en</strong> una resolución que suele<br />

ser <strong>de</strong> 8 bits por lo que el valor mas alto es <strong>de</strong> 255. Si por una operación se sobrepasa este<br />

máximo, el píxel t<strong>en</strong>drá como nivel <strong>de</strong> gris, el valor m<strong>en</strong>os 255, por eso <strong>de</strong>spués <strong>de</strong> una<br />

operación y antes <strong>de</strong> escribir los valores <strong>en</strong> la imag<strong>en</strong>, hay que normalizar los valores <strong>en</strong>tre<br />

0 y 255(si el tamaño <strong>de</strong> los píxeles es <strong>de</strong> 8 bits).<br />

AND<br />

OR<br />

NOT<br />

Las operaciones lógicas utilizadas son:<br />

Es preciso t<strong>en</strong>er <strong>en</strong> cu<strong>en</strong>ta que las operaciones lógicas sólo se pue<strong>de</strong>n aplicar sobre<br />

imág<strong>en</strong>es binarias, lo cual no ocurre con las operaciones aritméticas.<br />

Las transformaciones geométricas modifican las relaciones espaciales <strong>en</strong>tre los<br />

píxeles. Se necesitan dos tipos distintos <strong>de</strong> algoritmos. El primero es el que <strong>de</strong>termina la<br />

relación <strong>en</strong>tre las coor<strong>de</strong>nadas <strong>de</strong> la imag<strong>en</strong> original y la imag<strong>en</strong> resultante. Como caso<br />

g<strong>en</strong>eral, las transformaciones <strong>de</strong> numeros <strong>en</strong>teros no ti<strong>en</strong><strong>en</strong> por qué dar <strong>en</strong>teros, asi que será<br />

necesario un algoritmo <strong>de</strong> interpolación que <strong>de</strong>termine el nivel <strong>de</strong> gris <strong>de</strong> la imag<strong>en</strong> final a<br />

partir <strong>de</strong> uno o varios píxeles <strong>de</strong> la imag<strong>en</strong> original.<br />

Si se quiere trasladar el orig<strong>en</strong> <strong>de</strong> la imag<strong>en</strong> se aplica la ecuación:<br />

Que <strong>en</strong> coor<strong>de</strong>nadas homogéneas es:<br />

Magnificación<br />

o el equival<strong>en</strong>te<br />

⎡xf<br />

⎤⎡1<br />

⎢ ⎥⎢<br />

⎢<br />

yf<br />

⎥⎢<br />

0<br />

⎢⎣<br />

1 ⎥⎦<br />

⎢⎣<br />

0<br />

xf = xi + xo<br />

yf = yi + yo<br />

0<br />

1<br />

0<br />

xi<br />

xf =<br />

a<br />

yi<br />

yf =<br />

b<br />

xo⎤⎡<br />

xi⎤<br />

yo<br />

⎥⎢<br />

⎥<br />

⎥⎢<br />

yi<br />

⎥<br />

1 ⎥⎦<br />

⎢⎣<br />

1 ⎥⎦


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 24<br />

Rotación respecto al orig<strong>en</strong><br />

⎡xf<br />

⎤⎡1<br />

/ a<br />

⎢ ⎥⎢<br />

⎢<br />

yf<br />

⎥⎢<br />

0<br />

⎢⎣<br />

1 ⎥⎦<br />

⎢⎣<br />

0<br />

0<br />

1/<br />

b<br />

0<br />

⎡xf<br />

⎤⎡cosθ<br />

− s<strong>en</strong>θ<br />

⎢ ⎥⎢<br />

⎢<br />

yf<br />

⎥⎢<br />

s<strong>en</strong>θ<br />

cosθ<br />

⎢⎣<br />

1 ⎥⎦<br />

⎢⎣<br />

0 0<br />

0⎤⎡<br />

xi⎤<br />

0<br />

⎥⎢<br />

⎥<br />

⎥⎢<br />

yi<br />

⎥<br />

1⎥⎦<br />

⎢⎣<br />

1 ⎥⎦<br />

0⎤⎡<br />

xi⎤<br />

0<br />

⎥⎢<br />

⎥<br />

⎥⎢<br />

yi<br />

⎥<br />

1⎥⎦<br />

⎢⎣<br />

1 ⎥⎦<br />

Todas estas transformaciones tomarían mucho <strong>tiempo</strong> si se tuviera que leer cada<br />

píxel, <strong>real</strong>izar la operación matemática, normalizar el valor a 255 y escribirlo <strong>en</strong> una nueva<br />

imag<strong>en</strong>. Para acelerar este proceso exist<strong>en</strong> las tablas <strong>de</strong> consulta (look up tables LUT). Son<br />

tablas <strong>en</strong> las que su índice es el nivel <strong>de</strong> gris antiguo <strong>de</strong>l píxel y su valor el nuevo nivel <strong>de</strong><br />

gris que le correspon<strong>de</strong>. Así todos los calculos se <strong>real</strong>izan <strong>en</strong> la parte <strong>de</strong> inicialización <strong>de</strong>l<br />

algoritmo para po<strong>de</strong>r <strong>de</strong>spués trabajar <strong>en</strong> <strong>tiempo</strong> <strong>real</strong>.<br />

3.1.4 Ruido<br />

Todas las imág<strong>en</strong>es ti<strong>en</strong><strong>en</strong> una cierta cantidad <strong>de</strong> ruido, valores distorsionados, bi<strong>en</strong><br />

<strong>de</strong>bidos al s<strong>en</strong>sor CCD <strong>de</strong> la camara o al medio <strong>de</strong> transmisión <strong>de</strong> la señal. El ruido se<br />

manifiesta g<strong>en</strong>eralm<strong>en</strong>te <strong>en</strong> píxeles aislados que toman un valor <strong>de</strong> gris difer<strong>en</strong>te al <strong>de</strong> sus<br />

vecinos. El ruido pue<strong>de</strong> clasificarse <strong>en</strong> cuatro tipos:<br />

Gausiano. Produce pequeñas variaciones <strong>en</strong> la imag<strong>en</strong> y se <strong>de</strong>be a las difer<strong>en</strong>tes ganancias<br />

<strong>en</strong> el s<strong>en</strong>sor, ruido <strong>de</strong> los <strong>digital</strong>izadores, perturbaciones <strong>en</strong> la transmisión etc. Se consi<strong>de</strong>ra<br />

que el valor final <strong>de</strong>l píxel sería el i<strong>de</strong>al más una cantidad correspondi<strong>en</strong>te al error, que<br />

pue<strong>de</strong> <strong>de</strong>scribirse como una variable gausiana.<br />

Impulsional. El valor que toma el píxel no ti<strong>en</strong>e relación con el valor i<strong>de</strong>al sino con el<br />

valor <strong>de</strong>l ruido que toma valores muy altos o bajos. Se caraceteriza <strong>en</strong>tonces porque el píxel<br />

toma un valor máximo, causado por una saturación <strong>de</strong>l s<strong>en</strong>sor, o minimo si se ha perdido su<br />

señal. También pue<strong>de</strong> <strong>en</strong>contrarse si se trabaja con objetos a altas temperaturas, ya que las<br />

camaras ti<strong>en</strong><strong>en</strong> una ganancia <strong>en</strong> el infrarrojo <strong>de</strong> la que no dispone el ojo humano. Por ello<br />

las partes muy cali<strong>en</strong>tes <strong>de</strong> un objeto pue<strong>de</strong>n llegar a saturar el píxel.<br />

Frecu<strong>en</strong>cial. La imag<strong>en</strong> obt<strong>en</strong>ida es la suma <strong>en</strong>tre imag<strong>en</strong> i<strong>de</strong>al y otra señal, la<br />

interfer<strong>en</strong>cia, caracterizada por ser una s<strong>en</strong>oi<strong>de</strong> <strong>de</strong> frecu<strong>en</strong>cia <strong>de</strong>terminada.<br />

Multiplicativo. La imag<strong>en</strong> obt<strong>en</strong>ida es fruto <strong>de</strong> la multiplicación <strong>de</strong> dos señales.<br />

3.1.5 Deteccion <strong>de</strong> bor<strong>de</strong>s<br />

Una <strong>de</strong> las informaciones más utiles que se <strong>en</strong>cu<strong>en</strong>tran <strong>en</strong> una imag<strong>en</strong> la constituy<strong>en</strong><br />

los bor<strong>de</strong>s ya que al <strong>de</strong>limitar los objetos <strong>de</strong>fin<strong>en</strong> los limites <strong>en</strong>tre ellos y el fondo y <strong>en</strong>tre<br />

los objetos <strong>en</strong>tre si.<br />

Las tecnicas usadas <strong>en</strong> la <strong>de</strong>tección <strong>de</strong> bor<strong>de</strong>s ti<strong>en</strong><strong>en</strong> por objeto la localización <strong>de</strong><br />

los puntos <strong>en</strong> los que se produce una variación <strong>de</strong> int<strong>en</strong>sidad, empleandose para ello


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 25<br />

métodos basados <strong>en</strong> los operadores <strong>de</strong>rivada. Básicam<strong>en</strong>te se ti<strong>en</strong><strong>en</strong> dos posibilida<strong>de</strong>s:<br />

aplicar la primera (gradi<strong>en</strong>te) o la segunda <strong>de</strong>rivada (laplaciana). En el primer caso se<br />

buscarán gran<strong>de</strong>s picos y <strong>en</strong> el segundo, pasos <strong>de</strong> respuesta positiva a negativa o viceversa.<br />

Se supone que el nivel <strong>de</strong> gris <strong>en</strong> el interior <strong>de</strong> los objetos es constante, esta es una<br />

situación que nunca se dará. Es por ello que <strong>de</strong>spués <strong>de</strong> la fase <strong>de</strong> <strong>de</strong>tección <strong>de</strong> bor<strong>de</strong>s vi<strong>en</strong>e<br />

otra que distingue lo que son los bor<strong>de</strong>s <strong>de</strong>l objeto <strong>de</strong> lo que es ruido. Ello llevará a que <strong>en</strong><br />

el caso <strong>de</strong> los métodos basados <strong>en</strong> el gradi<strong>en</strong>te, la respuesta sea bor<strong>de</strong>s <strong>de</strong> anchura mayor <strong>de</strong><br />

un píxel, lo que introduce una incertidumbre <strong>en</strong> la verda<strong>de</strong>ra localización <strong>de</strong> los bor<strong>de</strong>s.<br />

Este inconv<strong>en</strong>i<strong>en</strong>te no se <strong>en</strong>cu<strong>en</strong>tra <strong>en</strong> los métodos que se basan <strong>en</strong> la segunda <strong>de</strong>rivada ya<br />

que los bor<strong>de</strong>s vi<strong>en</strong><strong>en</strong> <strong>de</strong>finidos por el paso por cero.<br />

3.1.5.1 Tecnicas basadas <strong>en</strong> el gradi<strong>en</strong>te<br />

Para po<strong>de</strong>r utilizar operadores <strong>de</strong> este tipo sobre una imag<strong>en</strong> muestreada es<br />

necesario obt<strong>en</strong>er una aproximación <strong>de</strong>l concepto <strong>de</strong> <strong>de</strong>rivada para espacios discretos. La<br />

g<strong>en</strong>eraliación comúnm<strong>en</strong>te usada se basa <strong>en</strong> el cálculo <strong>de</strong> difer<strong>en</strong>cias <strong>en</strong>tre píxeles vecinos.<br />

Estas difer<strong>en</strong>cias, según la relación <strong>en</strong>tre los píxeles consi<strong>de</strong>rados, pue<strong>de</strong>n dar lugar a<br />

<strong>de</strong>rivadas unidim<strong>en</strong>sionales o bidim<strong>en</strong>sionales, asi como aplicarse <strong>en</strong> alguna dirección<br />

<strong>de</strong>terminada <strong>de</strong> la imag<strong>en</strong> o <strong>en</strong> todas las direcciopnes <strong>de</strong> forma global.<br />

Se <strong>de</strong>fine el operador gradi<strong>en</strong>te G aplicado sobre una imag<strong>en</strong> f(x,y) como:<br />

∇f<br />

( x,<br />

y)<br />

= y<br />

⎡∂f<br />

∂f<br />

⎤<br />

[ Gx<br />

, G ] = ⎢ , ⎥<br />

⎣∂x<br />

∂y<br />

⎦<br />

El vector gradi<strong>en</strong>te repres<strong>en</strong>ta la variación máxima <strong>de</strong> int<strong>en</strong>sidad para el punto (x,y). Por<br />

ello es interesante conocer su módulo y dirección que v<strong>en</strong>drán dados por:<br />

∇f<br />

=<br />

G<br />

2<br />

x<br />

+ G<br />

2<br />

y<br />

⎛ G y ⎞<br />

∠∇f<br />

= arctan<br />

⎜<br />

⎟<br />

⎝ Gx<br />

⎠<br />

si<strong>en</strong>do la dirección <strong>de</strong>l gradi<strong>en</strong>te perp<strong>en</strong>dicular al bor<strong>de</strong>.<br />

Debido al coste computacional el módulo a veces se simplifica por:<br />

∇ f = G + G<br />

Como las imág<strong>en</strong>es <strong>digital</strong>es no son señales continuas, la nueva expresión <strong>de</strong>l gradi<strong>en</strong>te<br />

vi<strong>en</strong>e dad por:<br />

∇f<br />

( x,<br />

y)<br />

= y<br />

que se pue<strong>de</strong> repres<strong>en</strong>tar por las mascaras:<br />

x<br />

⎡∆f<br />

∆f<br />

⎤<br />

[ Gx<br />

, G ] = ⎢ ,<br />

∆x<br />

∆y<br />

⎥<br />

⎦<br />

y<br />


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 26<br />

-1 1<br />

-1<br />

1<br />

*f(x,y)<br />

*f(x,y)<br />

G x<br />

G x<br />

∆f<br />

=<br />

∆x<br />

∆f<br />

=<br />

∆x<br />

Sin embargo estas máscaras no suel<strong>en</strong> utilizarse <strong>de</strong>bido a que son muy s<strong>en</strong>sibles al ruido al<br />

t<strong>en</strong>er <strong>en</strong> cuanta solam<strong>en</strong>te la información <strong>de</strong> dos píxeles. Con el <strong>tiempo</strong> han aparecido otros<br />

filtros que a<strong>de</strong>más <strong>de</strong> calcular el gradi<strong>en</strong>te ti<strong>en</strong><strong>en</strong> cierto efecto <strong>de</strong> suavizado, o lo que es lo<br />

mismo, son s<strong>en</strong>sibles al ruido.<br />

Operadores <strong>de</strong> Roberts<br />

0 -1<br />

1 0<br />

Operador <strong>de</strong> Prewitt<br />

Expan<strong>de</strong> la <strong>de</strong>finición <strong>de</strong> gradi<strong>en</strong>te a un <strong>en</strong>torno <strong>de</strong> 3x3 para ser mas inmune al ruido<br />

-1 0 1<br />

-1 0 1<br />

-1 0 1<br />

0 -1<br />

1 0<br />

-1 -1 -1<br />

0 0 0<br />

1 1 1<br />

Operador <strong>de</strong> Sobel<br />

Sobel da mas importancia a los pixeles c<strong>en</strong>trales que el operador <strong>de</strong> Prewitt.<br />

-1 0 1<br />

-2 0 2<br />

-1 0 1<br />

-1 -2 -1<br />

0 0 0<br />

1 2 1<br />

Operador isotrópico<br />

Mi<strong>en</strong>tras que Prewitt <strong>de</strong>tecta mejor los bor<strong>de</strong>s verticales, Sobel lo hace <strong>en</strong> los diagonales.<br />

El operador isotropico int<strong>en</strong>ta llegar a un equilibrio <strong>en</strong>tre ellos.<br />

-1 0 1<br />

− 2 0 − 2<br />

-1 0 1<br />

-1 − 2 -1<br />

0 0 0<br />

1 − 2 1


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 27<br />

Operadores <strong>de</strong> segundo or<strong>de</strong>n<br />

La laplaciana es la segunda <strong>de</strong>rivada <strong>de</strong> una función y repres<strong>en</strong>ta la <strong>de</strong>rivada <strong>de</strong> esta<br />

respecto a todas las direcciones:<br />

2 2<br />

2 ∂ f ∂ f<br />

∇ f ( x,<br />

y)<br />

= + 2 2<br />

∂x<br />

∂y<br />

Las dos <strong>de</strong>finiciones que <strong>de</strong> forma mas frecu<strong>en</strong>te se utilizan para el operador laplaciana<br />

son:<br />

-1 -1 -1<br />

-1 8 -1<br />

-1 -1 -1<br />

0 -1 0<br />

-1 4 -1<br />

0 -1 0<br />

Don<strong>de</strong> el pixel c<strong>en</strong>tral toma el valor negativo <strong>de</strong> la suma <strong>de</strong> todos los que le ro<strong>de</strong>an.<br />

3.2 Hardware<br />

Los elem<strong>en</strong>tos <strong>de</strong> hardware utilizados para la elaboración <strong>de</strong>l vi<strong>de</strong>owall son<br />

básicam<strong>en</strong>te a<strong>de</strong>más <strong>de</strong> la computadora, las tarjetas <strong>de</strong> vi<strong>de</strong>o adicionales y sus respectivos<br />

monitores.<br />

3.2.1 Monitores<br />

Se <strong>real</strong>izó una comparación <strong>en</strong>tre varios monitores <strong>de</strong> computadora cuyos precios<br />

oscilaban <strong>en</strong>tre $1100 y $1600 obt<strong>en</strong>iéndose la sigui<strong>en</strong>te tabla:<br />

Marca BENQ DAEWOO DTS LG SAMSUNG<br />

Mo<strong>de</strong>lo V551 531X 1528 563N 551V<br />

Precio $1,366 $1,238 $1,298 $1,329 $1,206<br />

Tipo CRT color CDT Conv<strong>en</strong>cional CRT color CRT color<br />

Área visible 14” 14” 13.9” 13.8” 13.9”<br />

Tratami<strong>en</strong>to Ninguno Antiestático,<br />

antireflejante<br />

ninguno Anti Glare Anti Glare<br />

Resolución 1024x768 1024x768 1280x1024 1024x768 1024x768<br />

El principal motivo <strong>de</strong> la selección resi<strong>de</strong> <strong>en</strong> la resolución permisible, dado que esto<br />

expone mayor calidad <strong>en</strong> la imag<strong>en</strong>. Los tratami<strong>en</strong>tos efectuados sobre la superficie <strong>de</strong>l<br />

cinescopio influy<strong>en</strong> principalm<strong>en</strong>te <strong>en</strong> los reflejos externos producidos, sin embargo no es


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 28<br />

una característica mas importante que la anterior. Los monitores adquiridos son <strong>en</strong>tonces <strong>de</strong><br />

marca DTS y <strong>de</strong> mo<strong>de</strong>lo 1528.<br />

3.1.2 Tarjetas <strong>de</strong> vi<strong>de</strong>o<br />

Las tarjetas <strong>de</strong> vi<strong>de</strong>o se han escogido <strong>de</strong> difer<strong>en</strong>tes tipos con la int<strong>en</strong>ción <strong>de</strong> obt<strong>en</strong>er<br />

sus respectivos r<strong>en</strong>dimi<strong>en</strong>tos y <strong>real</strong>izar comparaciones. Las mas comunes <strong>en</strong> el mercado<br />

fueron seleccionadas t<strong>en</strong>iéndose solo <strong>en</strong> consi<strong>de</strong>ración que fues<strong>en</strong> 3 tarjetas con puerto PCI<br />

y una tarjeta con puerto AGP.<br />

Marca y mo<strong>de</strong>lo ATI 3D Rage Pro 3Dblaster Savage 4 Voodoo 4 4500 PCI Cirrus Logic<br />

5446PCI<br />

Memoria <strong>de</strong> vi<strong>de</strong>o 4MB 8MB 32M 2M<br />

Bus PCI AGP PCI PCI<br />

Resolución<br />

1600x1200 1600x1200 1600x1200 1024x768<br />

máxima<br />

Características<br />

adicionales<br />

Incluye acelerador<br />

gráfico <strong>de</strong> 64 bits<br />

con soporte <strong>de</strong> 2D,<br />

vi<strong>de</strong>o y 3D<br />

Soporta Directraw<br />

2D y 3D<br />

Acelerador gráfico<br />

<strong>de</strong> 128bits<br />

2D/3D/Vi<strong>de</strong>o<br />

Para la adquisición <strong>de</strong> vi<strong>de</strong>o se ha contemplado el uso <strong>de</strong> la tarjeta WinTV-PCI <strong>de</strong> la<br />

empresa Hauppauge (www.hauppauge.com) con las sigui<strong>en</strong>tes características técnicas:<br />

Figura 3.1 Tarjeta <strong>de</strong> adquisición <strong>de</strong> vi<strong>de</strong>o<br />

• Conectores <strong>de</strong> <strong>en</strong>trada auxiliares <strong>de</strong> audio/vi<strong>de</strong>o para vi<strong>de</strong>o cámaras, VCR u otras<br />

fu<strong>en</strong>tes similares.<br />

• Captura imág<strong>en</strong>es con calidad <strong>de</strong> 24-bits y <strong>digital</strong>ización YUV 4:2:2 <strong>en</strong> un formato<br />

<strong>de</strong> color a 60 frames por segundo. El máximo tamaño <strong>de</strong> imag<strong>en</strong> <strong>digital</strong>izada es <strong>de</strong><br />

640x480 para fu<strong>en</strong>tes <strong>de</strong> vi<strong>de</strong>o NTSC.<br />

• El vi<strong>de</strong>o <strong>digital</strong>izado se <strong>en</strong>vía sobre el bus PCI hacia la memoria <strong>de</strong> la tarjeta <strong>de</strong><br />

pres<strong>en</strong>tación VGA, sin necesidad <strong>de</strong> uso <strong>de</strong>l CPU.


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 29<br />

3.2.3 Procesador<br />

Se ha seleccionado el microprocesador P<strong>en</strong>tium III <strong>de</strong> Intel, a 550MHz, <strong>de</strong>bido a<br />

que <strong>en</strong> el mom<strong>en</strong>to pres<strong>en</strong>te expone las mejores prestaciones y capacidad <strong>de</strong> procesami<strong>en</strong>to<br />

para aplicaciones <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong>. En particular, el P<strong>en</strong>tium III incluye<br />

instrucciones Single Instruction Multiple Data (SIMD) <strong>en</strong> punto flotante, las cuales pue<strong>de</strong>n<br />

increm<strong>en</strong>tar significativam<strong>en</strong>te la velocidad <strong>de</strong> los algoritmos <strong>de</strong> procesami<strong>en</strong>to. Por otro<br />

lado dispone <strong>de</strong> la tecnología MMX (Matrix Math ext<strong>en</strong>sión) la cual es muy similar a las<br />

instrucciones SPARC VIS que <strong>real</strong>izan operaciones con <strong>en</strong>teros <strong>en</strong> vectores <strong>de</strong> palabras <strong>de</strong><br />

8, 16, o 32bits. Esto facilita el procesami<strong>en</strong>to <strong>de</strong> vi<strong>de</strong>o así como la estimación <strong>de</strong><br />

movimi<strong>en</strong>to y la interpolación.<br />

3.3 Soporte <strong>de</strong> multimonitor<br />

La característica multimonitor le permite al sistema operativo controlar mas <strong>de</strong> una<br />

tarjeta <strong>de</strong> vi<strong>de</strong>o conectada <strong>en</strong> la misma tarjeta madre. Esta característica reduce<br />

consi<strong>de</strong>rablem<strong>en</strong>te los costos y complejidad <strong>de</strong>l vi<strong>de</strong>owall, y es soportada por Windows<br />

98/Me/2000, y también por LINUX <strong>en</strong> sus versiones 7.0 <strong>de</strong> la distribución Mandrake y<br />

superiores. En todos los casos las tarjetas <strong>de</strong>b<strong>en</strong> ser PCI o AGP, dado que las anteriores<br />

ISA/EISA/VESA no son soportadas. Se ha escogido Windows 98 <strong>de</strong>bido a que soporta una<br />

mayor cantidad <strong>de</strong> hardware y consi<strong>de</strong>rando la herrami<strong>en</strong>ta <strong>de</strong> <strong>de</strong>sarrollo disponible<br />

DirectX.<br />

Para cada monitor se pue<strong>de</strong> t<strong>en</strong>er su propia resolución y cantidad <strong>de</strong> colores, y<br />

Windows permite especificar la posición <strong>de</strong> cada monitor respecto a cualquier otro. Una<br />

<strong>de</strong>sv<strong>en</strong>taja es que el modo <strong>de</strong> pantalla-completa (que se refiere al modo <strong>de</strong> vi<strong>de</strong>o que se<br />

obt<strong>en</strong>dría <strong>en</strong> una sesión <strong>de</strong> DOS <strong>en</strong> toda la pantalla o <strong>de</strong> una aplicación DirectX que ocupe<br />

toda la pantalla) solo se pue<strong>de</strong> obt<strong>en</strong>er <strong>en</strong> un solo monitor <strong>de</strong>nominado monitor principal.<br />

Este es un problema que se espera resuelvan los <strong>de</strong>sarrolladores <strong>de</strong> DirectX <strong>en</strong> el futuro.<br />

También ocurre que el uso <strong>de</strong> múltiple monitor resulta <strong>en</strong> un m<strong>en</strong>or <strong>de</strong>sempeño <strong>de</strong>l<br />

sistema, <strong>de</strong>p<strong>en</strong>di<strong>en</strong>do <strong>de</strong> lo que se esté <strong>real</strong>izando y es uno <strong>de</strong> los elem<strong>en</strong>tos que queremos<br />

carácterizar.<br />

3.4 DirectX<br />

DirectX® <strong>de</strong> Microsoft® es el software que permitirá manipular el hardware <strong>de</strong>l<br />

sistema a bajo nivel. DirectX ofrece un compon<strong>en</strong>te <strong>de</strong> <strong>de</strong>sarrollo <strong>de</strong>nominado<br />

DirectShow®, el cual implem<strong>en</strong>ta librerías para la manipulación <strong>de</strong> elem<strong>en</strong>tos multimedia.<br />

Desafortunadam<strong>en</strong>te no se dispone actualm<strong>en</strong>te <strong>de</strong> bibliografía para el uso <strong>de</strong> DirectShow,<br />

y toda la información al respecto ha sido obt<strong>en</strong>ida <strong>de</strong>l sitio oficial <strong>de</strong> DirectX:<br />

http://www.microsoft.com/directx<br />

DirectX proporciona acceso <strong>de</strong> bajo nivel al hardware multimedia <strong>de</strong> forma<br />

in<strong>de</strong>p<strong>en</strong>di<strong>en</strong>te <strong>de</strong>l dispositivo, adicionalm<strong>en</strong>te aprovecha los últimos <strong>de</strong>sarrollos <strong>en</strong>


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 30<br />

hardware a medida que se van originando como es el caso <strong>de</strong> la tecnología MMX <strong>de</strong><br />

Intel®. Esto se logra simplem<strong>en</strong>te instalando la ultima versión <strong>de</strong> DirectX.<br />

DirectX incluye varios compon<strong>en</strong>tes (Figura 3.2) <strong>en</strong>tre los que se <strong>en</strong>cu<strong>en</strong>tran:<br />

• DirectDraw®. Este proporciona animación <strong>real</strong>ista usando intercambio <strong>de</strong> paginas<br />

<strong>de</strong> vi<strong>de</strong>o, acceso a coprocesadores gráficos especializados y administración <strong>de</strong> la<br />

memoria <strong>de</strong> vi<strong>de</strong>o. También sirve <strong>de</strong> base para otros compon<strong>en</strong>tes como<br />

DirectShow® y Direct3D®.<br />

• Direct3D®. Proporciona interfaces <strong>de</strong> alto y bajo nivel para g<strong>en</strong>erar polígonos con<br />

texturas <strong>en</strong> 3D por software y por hardware.<br />

• DirectSound®. Proporciona sonido estéreo y 3D con mezcla <strong>de</strong> sonido por<br />

hardware, así como administración <strong>de</strong> la memoria <strong>de</strong> la tarjeta <strong>de</strong> sonido.<br />

• DirectPlay®. Incluye servicios transpar<strong>en</strong>tes <strong>de</strong> m<strong>en</strong>sajeria in<strong>de</strong>p<strong>en</strong>di<strong>en</strong>tes <strong>de</strong>l<br />

medio para crear juegos con varios jugadores, así como las funciones necesarias<br />

para organizar y ejecutar un juego multijugador.<br />

• DirectShow®. Proporciona una interfaz para el manejo <strong>de</strong> flujos multimedia<br />

prov<strong>en</strong>i<strong>en</strong>tes <strong>de</strong> archivos o dispositivos <strong>de</strong> adquisición <strong>de</strong> audio y vi<strong>de</strong>o.<br />

Figura 3.2 Compon<strong>en</strong>tes <strong>de</strong> DirectX<br />

Directshow es la herrami<strong>en</strong>ta a utilizar <strong>en</strong> el pres<strong>en</strong>te trabajo, y para su compr<strong>en</strong>sión es<br />

necesario revisar los conceptos sobre el mo<strong>de</strong>lo <strong>de</strong> objetos compon<strong>en</strong>tes COM <strong>de</strong>sarrollado<br />

por Microsoft.<br />

3.5 El mo<strong>de</strong>lo <strong>de</strong> compon<strong>en</strong>tes COM<br />

COM (Compon<strong>en</strong>t Object Mo<strong>de</strong>l) es un estándar creado por Microsoft que <strong>de</strong>fine a<br />

nivel binario como los objetos se <strong>de</strong>b<strong>en</strong> crear, <strong>de</strong>struir e interactuar <strong>en</strong>tre ellos. El hecho <strong>de</strong><br />

que sea un estándar a nivel binario implica que es in<strong>de</strong>p<strong>en</strong>di<strong>en</strong>te <strong>de</strong>l l<strong>en</strong>guaje que se use<br />

para trabajar con los objetos, siempre y cuando el l<strong>en</strong>guaje <strong>en</strong> cuestión sea capaz <strong>de</strong><br />

manejar apuntadores a funciones.<br />

Los compon<strong>en</strong>tes <strong>de</strong> software COM son in<strong>de</strong>p<strong>en</strong>di<strong>en</strong>tes <strong>de</strong> cualquier aplicación y<br />

residirán <strong>en</strong> el sistema <strong>en</strong> forma <strong>de</strong> DLL(Dynamic Link Library). Cada compon<strong>en</strong>te<br />

dispone <strong>de</strong> un i<strong>de</strong>ntificador global único o GUID(globally unique i<strong>de</strong>ntifier) que lo<br />

caracteriza(este i<strong>de</strong>ntificador consiste <strong>de</strong> un <strong>en</strong>tero <strong>de</strong> 128 bits y se pue<strong>de</strong> g<strong>en</strong>erar mediante<br />

el programa guidg<strong>en</strong>.exe). Si el compon<strong>en</strong>te está registrado <strong>en</strong> el sistema, <strong>en</strong>tonces


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 31<br />

podremos crear un objeto concreto <strong>de</strong> esa clase. Estar registrado <strong>en</strong> el sistema significa que<br />

el sistema operativo conoce don<strong>de</strong> resi<strong>de</strong> "físicam<strong>en</strong>te" la implem<strong>en</strong>tación <strong>de</strong> la clase<br />

i<strong>de</strong>ntificada por el GUID. En el sistema Windows esta información se almac<strong>en</strong>a <strong>en</strong> una<br />

base <strong>de</strong> datos c<strong>en</strong>tralizada llamada registro. Este registro se utiliza para configurar el<br />

software y hardware que se ejecute <strong>en</strong> el ambi<strong>en</strong>te Windows. De esta manera, po<strong>de</strong>mos<br />

disponer <strong>de</strong> toda una librería <strong>de</strong> compon<strong>en</strong>tes que po<strong>de</strong>mos usar librem<strong>en</strong>te, siempre y<br />

cuando estén registrados <strong>en</strong> nuestro sistema.<br />

Una interfase es un conjunto <strong>de</strong> métodos (funciones) y atributos (datos) que ti<strong>en</strong><strong>en</strong><br />

una fuerte relación lógica <strong>en</strong>tre ellos. Un compon<strong>en</strong>te es la implem<strong>en</strong>tación <strong>de</strong> una o más<br />

interfaces y queda <strong>de</strong>finida por las interfaces que implem<strong>en</strong>ta. La her<strong>en</strong>cia <strong>de</strong> un<br />

compon<strong>en</strong>te se concibe a nivel <strong>de</strong> interfaces. Así todas las interfaces <strong>de</strong>rivan <strong>de</strong> la interfase<br />

IUnknown. Esta interfase se <strong>en</strong>carga <strong>de</strong> la gestión <strong>de</strong> memoria <strong>de</strong> los objetos. La gestión<br />

<strong>de</strong> memoria se basa <strong>en</strong> un contador <strong>de</strong> refer<strong>en</strong>cias, y la interfase IUnknown esta formada<br />

por tres métodos AddRef, Release y QueryInterface para controlar este contador. Las dos<br />

primeras permit<strong>en</strong> llevar la cu<strong>en</strong>ta <strong>de</strong> si el compon<strong>en</strong>te está si<strong>en</strong>do utilizado y cuantos<br />

cli<strong>en</strong>tes lo están utilizando; <strong>de</strong> esta forma el sistema pue<strong>de</strong> <strong>de</strong>scargar un compon<strong>en</strong>te<br />

cuando no se esté utilizando. La tercera permite averiguar si el objeto <strong>en</strong> cuestión<br />

implem<strong>en</strong>ta una interfase <strong>en</strong> particular o no, a<strong>de</strong>más <strong>de</strong> obt<strong>en</strong>er un acceso al objeto a través<br />

<strong>de</strong> esa interfase.<br />

3.5.1 Creación y gestión <strong>de</strong> objetos<br />

Los objetos se crean mediante la función CoCreateInstance, y se acce<strong>de</strong>n a través<br />

<strong>de</strong> apuntadores a interfaces. Inicialm<strong>en</strong>te, obt<strong>en</strong>emos un apuntador a una interfase a raíz <strong>de</strong><br />

la creación <strong>de</strong>l propio objeto. Posteriorm<strong>en</strong>te, po<strong>de</strong>mos acce<strong>de</strong>r a las otras interfaces que se<br />

implem<strong>en</strong>t<strong>en</strong> con el método QueryInterface <strong>de</strong> ésta. Por ejemplo, si t<strong>en</strong>emos un<br />

compon<strong>en</strong>te i<strong>de</strong>ntificado por el GUID GUID_MYCOMPONENT, que implem<strong>en</strong>ta las<br />

interfaces InterfaceA e InterfaceB po<strong>de</strong>mos escribir el sigui<strong>en</strong>te código:<br />

InterfaceA *pIA;<br />

InterfaceB *pIB;<br />

CoInitialize(NULL);<br />

CoCreateInstance(GUID_MYCOMPONENT, NULL, CLSCTX_INPROC, GUID_INTERFACEA, (LPVOID *) &pIA);<br />

// Ahora po<strong>de</strong>mos acce<strong>de</strong>r a los métodos y atributos <strong>de</strong> la InterfaceA a través <strong>de</strong> pIA<br />

pIA->QueryInterface(GUID_INTERFACEB, (LPVOID *) &pIB);<br />

// ... Ahora también po<strong>de</strong>mos acce<strong>de</strong>r a la InterfaceB a través <strong>de</strong> pIB<br />

pIA->Release();<br />

// ... Ahora el objeto aún no se ha <strong>de</strong>struido porque aún t<strong>en</strong>emos una interfase activa<br />

pIB->Release();<br />

// ... Ahora sí que se <strong>de</strong>struye el objeto<br />

CoUninitialize();<br />

Po<strong>de</strong>mos <strong>en</strong>tonces com<strong>en</strong>tar que:<br />

• Primero, t<strong>en</strong>emos que comunicar al sistema que nuestra aplicación va a ser cli<strong>en</strong>te<br />

(o usuaria) <strong>de</strong> objetos COM mediante la función CoInitialize, que se <strong>de</strong>berá llamar


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 32<br />

al principio <strong>de</strong>l programa. De la misma manera, hay que comunicar que <strong>de</strong>jamos <strong>de</strong><br />

ser cli<strong>en</strong>tes mediante CoUninitialize.<br />

• Por otro lado, observamos que las interfaces también ti<strong>en</strong><strong>en</strong> un GUID asociado que<br />

las i<strong>de</strong>ntifica <strong>de</strong> forma universalm<strong>en</strong>te única, es <strong>de</strong>cir, no <strong>de</strong>bería existir ninguna<br />

otra interfase que t<strong>en</strong>ga el mismo GUID.<br />

• El parámetro CLSCTX_INPROC especifica el contexto <strong>de</strong> ejecución <strong>de</strong>l objeto,<br />

es <strong>de</strong>cir, si se ejecutará <strong>de</strong>ntro <strong>de</strong>l mismo espacio <strong>de</strong> proceso <strong>de</strong> la aplicación, fuera<br />

<strong>de</strong> éste, etc. En g<strong>en</strong>eral siempre especificamos que se ejecute <strong>de</strong>ntro <strong>de</strong> nuestro<br />

proceso.<br />

• Las refer<strong>en</strong>cias a CoCreateInstance y QueryInterface ya increm<strong>en</strong>tan el contador <strong>de</strong><br />

refer<strong>en</strong>cias, por lo que no es necesario hacerlo explícitam<strong>en</strong>te con AddRef. En<br />

cambio, sí es necesario liberar los apuntadores a interfase llamando a Release.<br />

3.5.2 Gestión <strong>de</strong> errores<br />

En el mo<strong>de</strong>lo COM se ha estandarizado la gestión <strong>de</strong> errores. Todas las funciones<br />

COM y métodos <strong>de</strong> objetos COM <strong>de</strong>vuelv<strong>en</strong> un valor <strong>de</strong> tipo HRESULT con un código <strong>de</strong><br />

error. Si todo ha funcionado correctam<strong>en</strong>te, este valor es S_OK. En cambio, si ha habido<br />

algún error, éste código <strong>de</strong>p<strong>en</strong><strong>de</strong>rá <strong>de</strong> la función o método que sea invocado, ya que cada<br />

una pue<strong>de</strong> g<strong>en</strong>erar tipos difer<strong>en</strong>tes <strong>de</strong> errores. Se <strong>de</strong>be consultar la ayuda si se <strong>de</strong>sea hacer<br />

un tratami<strong>en</strong>to exhaustivo <strong>de</strong> los difer<strong>en</strong>tes tipos <strong>de</strong> errores.<br />

En g<strong>en</strong>eral, habrá que controlar como mínimo el resultado <strong>de</strong> la función<br />

CoCreateInstance y <strong>de</strong>l método IUnknown::QueryInterface, ya que éstos <strong>de</strong>vuelv<strong>en</strong><br />

apuntadores a interfaces COM a través <strong>de</strong> las que acce<strong>de</strong>remos al objeto. Si hay algún error<br />

<strong>en</strong> estos casos, el apuntador a interfase que obt<strong>en</strong>dremos será erróneo, y <strong>en</strong> el mom<strong>en</strong>to <strong>en</strong><br />

que queramos llamar a alguno <strong>de</strong> sus métodos provocaremos un acceso a memoria no<br />

válido.<br />

Explicado el funcionami<strong>en</strong>to <strong>de</strong> COM, com<strong>en</strong>cemos a ver las características <strong>de</strong><br />

DirectShow.<br />

3.6 DirectShow<br />

DirectShow es un paquete para <strong>de</strong>sarrollar software que permite obt<strong>en</strong>er flujos <strong>de</strong><br />

datos <strong>de</strong> vi<strong>de</strong>o y/o audio a partir <strong>de</strong> archivos o <strong>de</strong>s<strong>de</strong> dispositivos <strong>de</strong> hardware como tarjetas<br />

<strong>de</strong> sonido y <strong>de</strong> vi<strong>de</strong>o conectados a la computadora. Este soporta una amplia variedad <strong>de</strong><br />

formatos, incluy<strong>en</strong>do ASF(Advanced Streaming Format), MPEG(Motion Picture Experts<br />

Group), AVI(Audio-Vi<strong>de</strong>o Interleaved), MP3(MPEG Audio Layer-3), y archivos WAV.<br />

También soporta captura <strong>de</strong> vi<strong>de</strong>o utilizando dispositivos WDM(Windows Driver Mo<strong>de</strong>l) o<br />

antiguos dispositivos Vi<strong>de</strong>o para Windows. DirectShow esta integrado junto con otras<br />

tecnologías DirectX. Detecta automáticam<strong>en</strong>te y utiliza el hardware para la aceleración <strong>de</strong><br />

audio y vi<strong>de</strong>o cuando se <strong>en</strong>cu<strong>en</strong>tr<strong>en</strong> disponibles <strong>en</strong> el sistema.


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 33<br />

Adicionalm<strong>en</strong>te permite la elaboración <strong>de</strong> compon<strong>en</strong>tes <strong>de</strong> software que <strong>real</strong>ic<strong>en</strong><br />

algún procesami<strong>en</strong>to (compresión, escalami<strong>en</strong>to, filtrado), sobre dicho flujo <strong>en</strong> <strong>tiempo</strong> <strong>real</strong>.<br />

Las aplicaciones se basan <strong>en</strong> un sistema modular <strong>de</strong> compon<strong>en</strong>tes llamados filtros. El filtro<br />

es un objeto COM y se ubica <strong>en</strong> un arreglo <strong>de</strong>nominado gráfico <strong>de</strong> filtros (filter graph) el<br />

cual proporciona a<strong>de</strong>más una i<strong>de</strong>a global <strong>de</strong>l funcionami<strong>en</strong>to e interacción <strong>en</strong>tre filtros.<br />

3.6.1 Gráfico <strong>de</strong> Filtros<br />

El bloque <strong>de</strong> construcción básico <strong>de</strong> DirectShow es un compon<strong>en</strong>te <strong>de</strong> software llamado<br />

filtro. Un filtro g<strong>en</strong>eralm<strong>en</strong>te <strong>real</strong>iza una sola operación <strong>en</strong> un flujo multimedia. Por<br />

ejemplo, hay filtros que <strong>real</strong>izan las sigui<strong>en</strong>tes tareas:<br />

• Obti<strong>en</strong>e vi<strong>de</strong>o <strong>de</strong>s<strong>de</strong> un dispositivo <strong>de</strong> captura <strong>de</strong> vi<strong>de</strong>o.<br />

• Lee archivos<br />

• Decodifica un formato particular <strong>de</strong>l flujo, como vi<strong>de</strong>o MPEG-1.<br />

• Pasa datos hacia la tarjeta <strong>de</strong> vi<strong>de</strong>o o <strong>de</strong> sonido.<br />

Un filtro recibe <strong>en</strong>trada(input) y produc<strong>en</strong> salida(output). Por ejemplo, si un filtro<br />

<strong>de</strong>codifica vi<strong>de</strong>o MPEG-1, la <strong>en</strong>trada es un flujo MPEG-codificado y el salida es un flujo<br />

<strong>de</strong> vi<strong>de</strong>o RGB no comprimido. Para <strong>real</strong>izar una tarea dada, una aplicación conecta varios<br />

filtros don<strong>de</strong> el salida <strong>de</strong> un filtro es la <strong>en</strong>trada <strong>de</strong> otro. Un conjunto <strong>de</strong> filtros conectados se<br />

<strong>de</strong>nomina gráfico <strong>de</strong> filtros(filter graph). Como una ilustración <strong>de</strong> este concepto, la<br />

figura 3.3 muestra un gráfico <strong>de</strong> filtros para ejecutar un archivo AVI.<br />

Figura 3.3 Gráfico <strong>de</strong> filtros<br />

La aplicación no ti<strong>en</strong>e que manejar los filtros individuales <strong>en</strong> el gráfico <strong>de</strong> filtros.<br />

En lugar <strong>de</strong> eso, DirectShow provee <strong>de</strong> un compon<strong>en</strong>te llamado Manejador <strong>de</strong>l Gráfico <strong>de</strong><br />

filtros(Filter Graph Manager). El Manejador <strong>de</strong>l Gráfico <strong>de</strong> filtros controla el flujo <strong>de</strong><br />

datos <strong>en</strong> el grafico. Una aplicación <strong>de</strong> alto nivel solo <strong>real</strong>iza llamadas tales como “Run”<br />

(para mover los datos <strong>en</strong> el grafico) o “Stop” (para <strong>de</strong>t<strong>en</strong>er el flujo <strong>de</strong> datos). Si se requiere<br />

un control más directo <strong>de</strong> las operaciones sobre el flujo, se pue<strong>de</strong> acce<strong>de</strong>r directam<strong>en</strong>te a<br />

los filtros a través <strong>de</strong> las interfaces COM. El Manejador <strong>de</strong>l gráfico <strong>de</strong> filtros pasa<br />

notificaciones <strong>de</strong> ev<strong>en</strong>tos a la aplicación, <strong>de</strong> modo que la aplicación pue<strong>de</strong> respon<strong>de</strong>r a<br />

ev<strong>en</strong>tos tales como el fin <strong>de</strong> flujo.


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 34<br />

3.6.2 Aplicaciones DirectShow<br />

Una aplicación típica DirectShow <strong>real</strong>iza tres pasos básicos, como ilustra la figura 3.4.<br />

Figura 3.4 Desarrollo <strong>de</strong> una aplicación <strong>en</strong> DirectShow<br />

1. Crea una instancia <strong>de</strong>l Manejador <strong>de</strong>l Gráfico <strong>de</strong> filtros, usando la función<br />

CoCreateInstance.<br />

2. Utiliza el Manejador <strong>de</strong>l gráfico <strong>de</strong> filtros para construir un gráfico <strong>de</strong> filtros.<br />

3. Controla el gráfico <strong>de</strong> filtros y respon<strong>de</strong> a ev<strong>en</strong>tos.<br />

El Manejador <strong>de</strong>l gráfico <strong>de</strong> filtros inspecciona la conexión <strong>de</strong> los filtros <strong>en</strong> el<br />

gráfico <strong>de</strong> filtros y controla el flujo <strong>de</strong> datos. Las aplicaciones <strong>de</strong>l usuario controlan las<br />

activida<strong>de</strong>s <strong>de</strong>l grafico <strong>de</strong> filtros mediante la comunicación con el Manejador <strong>de</strong>l Gráfico<br />

<strong>de</strong> filtros. Para elaborar un filtro se requiere el uso <strong>de</strong> programación COM y utilizar las<br />

clases base <strong>en</strong> las librerías <strong>de</strong> DirectShow implem<strong>en</strong>tadas <strong>en</strong> C++. En el pres<strong>en</strong>te trabajo<br />

será necesaria la construcción <strong>de</strong>l filtro y la construcción <strong>de</strong> la aplicación, pero antes<br />

veamos mas <strong>de</strong>talles sobre el funcionami<strong>en</strong>to <strong>de</strong> DirectShow.<br />

3.7 Compon<strong>en</strong>tes <strong>de</strong> DirectShow<br />

Trabajar con multimedia pres<strong>en</strong>ta varios problemas principales.<br />

• Los flujos multimedia conti<strong>en</strong><strong>en</strong> gran<strong>de</strong>s cantida<strong>de</strong>s <strong>de</strong> datos que <strong>de</strong>b<strong>en</strong> ser<br />

procesados a altas velocida<strong>de</strong>s.<br />

• El audio, vi<strong>de</strong>o y cualquier flujo adicional <strong>de</strong>b<strong>en</strong> estar todos sincronizados para<br />

iniciar y <strong>de</strong>t<strong>en</strong>erse todos al mismo <strong>tiempo</strong> y ejecutarse a la misma rapi<strong>de</strong>z.<br />

• Los flujos pue<strong>de</strong>n v<strong>en</strong>ir <strong>de</strong>s<strong>de</strong> muchas fu<strong>en</strong>tes, incluy<strong>en</strong>do archivos multimedia<br />

locales, tarjetas <strong>de</strong> adquisición <strong>de</strong> vi<strong>de</strong>o/audio, vi<strong>de</strong>ocámaras y otros dispositivos.<br />

• Los flujos vi<strong>en</strong><strong>en</strong> <strong>en</strong> una variedad <strong>de</strong> formatos, tales como AVI (Audio-Vi<strong>de</strong>o<br />

Interleaved), ASF(Advanced Streaming Format), MPEG(Motion Picture Experts<br />

Group), (DV)Digital Vi<strong>de</strong>o, y MJPEG(Motion JPEG).


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 35<br />

Para llevar a cabo la tarea <strong>de</strong> proveer flujos <strong>de</strong> vi<strong>de</strong>o y audio <strong>de</strong> manera efici<strong>en</strong>te hacia<br />

las tarjetas graficas y <strong>de</strong> sonido, DirectShow utiliza DirectDraw® y DirectSound®. La<br />

sincronización se lleva a cabo <strong>en</strong>capsulando los datos multimedia <strong>en</strong> muestras con<br />

información temporal. Para manejar la variedad <strong>de</strong> fu<strong>en</strong>tes, formatos, y dispositivos <strong>de</strong><br />

hardware, DirectShow utiliza una arquitectura modular <strong>en</strong> la cual compon<strong>en</strong>tes llamados<br />

filtros, pue<strong>de</strong>n ser mezclados y acoplados para <strong>real</strong>izar tareas distintas.<br />

DirectShow incluye filtros que soportan captura <strong>de</strong> multimedia y dispositivos<br />

sintonizadores basados <strong>en</strong> Windows Driver Mo<strong>de</strong>l (WDM) así como también filtros que<br />

soportan Vi<strong>de</strong>o for Windows (VfW). LA figura 3.5 muestra la relación <strong>en</strong>tre una<br />

aplicación, los compon<strong>en</strong>tes DirectShow, y algunos <strong>de</strong> los compon<strong>en</strong>tes hardware y<br />

software que DirectShow soporta.<br />

Figura 3.5 Esquema global <strong>de</strong> DirectShow<br />

DirectShow proporciona filtros para ejecutar archivos y flujos prov<strong>en</strong>i<strong>en</strong>tes <strong>de</strong><br />

varias fu<strong>en</strong>tes, incluy<strong>en</strong>do archivos locales, CD, Internet, dispositivos DVD, sintonizadores<br />

<strong>de</strong> TV y tarjetas <strong>de</strong> captura <strong>de</strong> vi<strong>de</strong>o. DirectShow ti<strong>en</strong>e compresores nativos,<br />

<strong>de</strong>scompresores para algunos formatos <strong>de</strong> archivos, y muchos <strong>de</strong>codificadores <strong>de</strong> hardware<br />

y software compatibles con DirectShow. La reproducción hace completo uso <strong>de</strong> las<br />

capacida<strong>de</strong>s <strong>de</strong> aceleración <strong>en</strong> hardware cuando este lo soporta.<br />

3.7.1 El grafico <strong>de</strong> filtros y sus compon<strong>en</strong>tes<br />

El Manejador <strong>de</strong>l Gráfico <strong>de</strong> filtros provee un conjunto <strong>de</strong> interfaces COM para que<br />

las aplicaciones puedan acce<strong>de</strong>r al gráfico <strong>de</strong> filtros. Así las aplicaciones pue<strong>de</strong>n llamar a<br />

las interfaces <strong>de</strong>l Manejador <strong>de</strong>l Gráfico <strong>de</strong> filtros para controlar los flujos.


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 36<br />

Un gráfico <strong>de</strong> filtros se compone <strong>de</strong> 3 tipos distintos <strong>de</strong> filtros:<br />

- Filtros Source, toman datos prov<strong>en</strong>i<strong>en</strong>tes <strong>de</strong> una fu<strong>en</strong>te y los introduc<strong>en</strong> a un gráfico <strong>de</strong><br />

filtros.<br />

- Filtros Transform, toma datos, los procesa y los <strong>en</strong>vía.<br />

- Filtros R<strong>en</strong><strong>de</strong>ring, proporciona los datos, a un dispositivo hardware para su pres<strong>en</strong>tación<br />

al usuario, pero pue<strong>de</strong> <strong>en</strong>viarlos hacia cualquier localidad que acepte datos multimedia<br />

como memoria o disco.<br />

Para que el gráfico <strong>de</strong> filtros trabaje, los filtros <strong>de</strong>b<strong>en</strong> ser conectados <strong>en</strong> el or<strong>de</strong>n<br />

apropiado y el flujo <strong>de</strong> datos com<strong>en</strong>zar y parar <strong>en</strong> dicho or<strong>de</strong>n.<br />

Controlar el flujo significa iniciar, pausar o <strong>de</strong>t<strong>en</strong>er el flujo multimedia. El<br />

Manejador <strong>de</strong>l gráfico <strong>de</strong> filtros permite a la aplicación especificar estas activida<strong>de</strong>s y<br />

llama a los métodos apropiados <strong>en</strong> los filtros. También la aplicación pue<strong>de</strong> obt<strong>en</strong>er el<br />

estado actual <strong>de</strong> los filtros, esta relación se pue<strong>de</strong> apreciar <strong>en</strong> la figura 3.6 .<br />

Figura 3.6 Interacción <strong>de</strong>l gráfico <strong>de</strong> filtros con la aplicación<br />

Un filtro es un objeto COM que <strong>real</strong>iza una tarea especifica. Para cada flujo se ti<strong>en</strong>e<br />

al m<strong>en</strong>os un pin. Un pin es un objeto COM creado por el filtro, que repres<strong>en</strong>ta un punto <strong>de</strong><br />

conexión para un flujo unidireccional <strong>de</strong> datos <strong>en</strong> el filtro.<br />

3.7.2 Filtros<br />

Los filtros son los bloques básicos <strong>de</strong> construcción <strong>en</strong> DirectShow. DirectShow<br />

separa el procesami<strong>en</strong>to <strong>de</strong> datos multimedia <strong>en</strong> una serie discreta <strong>de</strong> pasos, y un filtro<br />

repres<strong>en</strong>ta un (o algunas veces mas <strong>de</strong> uno) paso <strong>de</strong> procesami<strong>en</strong>to. Esto permite a las<br />

aplicaciones “mezclar y acoplar” filtros para <strong>real</strong>izar distintos tipos <strong>de</strong> operaciones <strong>en</strong><br />

difer<strong>en</strong>tes formatos multimedia y utilizando diversos dispositivos <strong>de</strong> hardware y software.<br />

Por ejemplo el filtro Async File Source (Archivo fu<strong>en</strong>te asíncrono) lee un archivo <strong>de</strong> un<br />

disco, el filtro TV Tuner (Sintonizador <strong>de</strong> TV) cambia el canal <strong>en</strong> una tarjeta <strong>de</strong> captura <strong>de</strong>


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 37<br />

TV, y el filtro MPEG-2 Splitter (Bifurcador MPEG-2) parsea 1 los datos <strong>de</strong> audio y vi<strong>de</strong>o<br />

<strong>en</strong> un flujo MPEG, así estos pue<strong>de</strong>n ser <strong>de</strong>codificados. Aunque cada uno <strong>de</strong> estos filtros<br />

hace algo único internam<strong>en</strong>te, <strong>de</strong>s<strong>de</strong> el punto <strong>de</strong> vista <strong>de</strong> una aplicación, cada uno es solo<br />

un filtro DirectShow con ciertas características estándar, a saber: soporte para la interfaz<br />

IBaseFilter y uno o más pins <strong>de</strong> <strong>en</strong>trada y/o pins <strong>de</strong> salida que repres<strong>en</strong>tan las conexiones a<br />

uno o más filtros DirectShow.<br />

Todos los filtros ca<strong>en</strong> <strong>en</strong> una <strong>de</strong> estas tres categorías: filtros source, filtros<br />

transform, y filtros r<strong>en</strong><strong>de</strong>rer. Veamos las características <strong>de</strong> cada uno <strong>de</strong> ellos.<br />

3.7.2.1 Filtros Source<br />

Los filtros source pres<strong>en</strong>tan los datos multimedia crudos 2 para procesami<strong>en</strong>to. Ellos<br />

pue<strong>de</strong>n obt<strong>en</strong>erlos <strong>de</strong> un archivo <strong>en</strong> un disco duro, o <strong>de</strong>s<strong>de</strong> un CD o DVD, también pue<strong>de</strong>n<br />

obt<strong>en</strong>erse <strong>de</strong>s<strong>de</strong> una fu<strong>en</strong>te “live” tal como una tarjeta receptora <strong>de</strong> televisión o una tarjeta<br />

<strong>de</strong> captura conectada a una cámara <strong>digital</strong>. Algunos filtros source simplem<strong>en</strong>te pasan los<br />

datos crudos hacia un filtro parseador o un filtro splitter, mi<strong>en</strong>tras otros filtros también<br />

<strong>real</strong>izan el parseo.<br />

3.7.2.2 Filtros Transform<br />

Los filtros transform aceptan datos crudos o datos parcialm<strong>en</strong>te procesados y<br />

<strong>real</strong>izan un procesami<strong>en</strong>to <strong>de</strong> dichos datos. Hay muchos tipos <strong>de</strong> filtros transform<br />

incluy<strong>en</strong>do parseadores que divi<strong>de</strong>n los flujos <strong>de</strong> datos crudos <strong>en</strong> muestras o frames 3 , filtros<br />

compresores, <strong>de</strong>scompresores, y convertidores <strong>de</strong> formato.<br />

3.7.2.3 Filtros R<strong>en</strong><strong>de</strong>rer<br />

Los filtros r<strong>en</strong><strong>de</strong>rer g<strong>en</strong>eralm<strong>en</strong>te aceptan datos completam<strong>en</strong>te procesados y<br />

ejecutan estos <strong>en</strong> el monitor o a través <strong>de</strong> las bocinas, o posiblem<strong>en</strong>te a través <strong>de</strong> algún<br />

dispositivo externo. En esta categoría están incluidos los filtros “file-writer” que salvan<br />

datos a disco u otro elem<strong>en</strong>to <strong>de</strong> almac<strong>en</strong>ami<strong>en</strong>to. Los filtros r<strong>en</strong><strong>de</strong>rer <strong>de</strong> vi<strong>de</strong>o usan<br />

DirectDraw para <strong>de</strong>splegar vi<strong>de</strong>o y el filtro r<strong>en</strong><strong>de</strong>rer <strong>de</strong> audio usa DirectSound para ejecutar<br />

audio.<br />

3.7.3 Pins<br />

Los pins son responsables <strong>de</strong> proveer interfaces para conectarse con otros pins y para<br />

transportar los datos. Las interfaces <strong>de</strong> los pins soportan:<br />

1<br />

Término que se <strong>en</strong>ti<strong>en</strong><strong>de</strong> como la división <strong>de</strong> la <strong>en</strong>trada <strong>en</strong> partes pequeñas mas faciles <strong>de</strong> procesar y/o<br />

analizar.<br />

2<br />

Traducción <strong>de</strong> raw. En este contexto se <strong>en</strong>ti<strong>en</strong><strong>de</strong> como datos sin procesami<strong>en</strong>to alguno prov<strong>en</strong>i<strong>en</strong>tes quizas<br />

<strong>de</strong> un convertidor A/D con un formato <strong>de</strong> bytes sin codofocar.<br />

3<br />

Ent<strong>en</strong><strong>de</strong>mos por frame una imag<strong>en</strong> <strong>digital</strong>izada compuesta por un arreglo cuadrado n x m <strong>de</strong> pixeles


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 38<br />

• La transfer<strong>en</strong>cia <strong>de</strong> datos <strong>en</strong>tre filtros usando memoria compartida u otro método.<br />

• La negociación <strong>de</strong>l formato <strong>de</strong> datos para cada conexión pin a pin.<br />

• La manipulación <strong>de</strong>l buffer y negociación <strong>de</strong> su localización, con la int<strong>en</strong>ción <strong>de</strong><br />

minimizar la copia <strong>de</strong> datos y maximizar su transfer<strong>en</strong>cia.<br />

Las interfaces pin difier<strong>en</strong> poco <strong>de</strong>p<strong>en</strong>di<strong>en</strong>do si son <strong>de</strong> <strong>en</strong>trada o salida.<br />

3.7.4 Muestras multimedia<br />

Figura 3.7 Conexión <strong>de</strong> pins<br />

Después que los datos crudos han sido colocados <strong>en</strong> el grafico, prov<strong>en</strong>i<strong>en</strong>tes <strong>de</strong> un<br />

archivo local o <strong>de</strong> una tarjeta <strong>de</strong> captura, los bytes <strong>de</strong>b<strong>en</strong> ser codificados <strong>en</strong> unida<strong>de</strong>s<br />

básicas llamadas muestras multimedia(media samples). Algunas veces el filtro source hace<br />

la codificación y a veces un filtro aparte <strong>real</strong>iza dicha tarea. Una muestra multimedia es<br />

cont<strong>en</strong>ida por un objeto COM que implem<strong>en</strong>ta IMediaSample2. Adicionalm<strong>en</strong>te a los datos<br />

multimedia actuales, el objeto conti<strong>en</strong>e información incluy<strong>en</strong>do el tipo <strong>de</strong> media especifico<br />

y los <strong>tiempo</strong>s <strong>de</strong> sincronización. Un objeto muestra multimedia que cont<strong>en</strong>ga datos <strong>de</strong><br />

vi<strong>de</strong>o, mant<strong>en</strong>drá los datos para un frame <strong>de</strong> vi<strong>de</strong>o. Para audio, conti<strong>en</strong>e los datos <strong>de</strong> varias<br />

muestras <strong>de</strong> sonido. En cualquier caso, cuando los datos se muev<strong>en</strong> <strong>de</strong>s<strong>de</strong> el filtro source<br />

hacia el r<strong>en</strong><strong>de</strong>r (downstream 4 ) a través <strong>de</strong> un gráfico, se hace <strong>en</strong> la forma <strong>de</strong> objetos media<br />

sample.<br />

3.7.5 Asignadores<br />

Cuando dos filtros se conectan, sus pins <strong>de</strong>b<strong>en</strong> ponerse <strong>de</strong> acuerdo <strong>en</strong> los <strong>de</strong>talles <strong>de</strong><br />

cómo los objetos media sample serán transportados <strong>de</strong>s<strong>de</strong> el filtro upstream 5 hacia el filtro<br />

downstream. En este contexto “conectar” significa <strong>de</strong>terminar el tamaño, localización y<br />

numero <strong>de</strong> muestras que serán utilizadas. El tamaño <strong>de</strong> las muestras <strong>de</strong>p<strong>en</strong><strong>de</strong>rá <strong>de</strong>l tipo <strong>de</strong><br />

media y el formato, la localización <strong>de</strong>l buffer pue<strong>de</strong> estar <strong>en</strong> memoria principal o <strong>en</strong> el<br />

dispositivo hardware tal como una tarjeta <strong>de</strong> captura <strong>de</strong> vi<strong>de</strong>o. La creación y manipulación<br />

<strong>de</strong> las muestras se <strong>real</strong>iza por un asignador, este es un objeto COM usualm<strong>en</strong>te creado por<br />

el pin <strong>de</strong> <strong>en</strong>trada <strong>en</strong> el filtro downstream. Para la mayoría <strong>de</strong> los casos, los <strong>de</strong>talles <strong>de</strong> la<br />

localización <strong>de</strong> los buffers serán completam<strong>en</strong>te transpar<strong>en</strong>tes a las aplicaciones. Debe<br />

aclararse que el “movimi<strong>en</strong>to” <strong>de</strong> datos <strong>en</strong> un gráfico <strong>de</strong> filtros no siempre involucra una<br />

operación <strong>de</strong> copia.<br />

4 Usaremos downstream para indicar un flujo <strong>de</strong> datos “normal” <strong>de</strong>s<strong>de</strong> el filtro que hace la adquisición <strong>de</strong><br />

datos hacia el filtro que hace la pres<strong>en</strong>tación o almac<strong>en</strong>ami<strong>en</strong>to <strong>de</strong> los mismos. En algunas ocasiones también<br />

lo <strong>en</strong>t<strong>en</strong><strong>de</strong>remos como el filtro adyac<strong>en</strong>te hacia el cual se dirige el flujo <strong>de</strong> datos<br />

5 El término upstream indica un flujo <strong>de</strong> datos opuesto al downstream.


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 39<br />

3.7.6 Relojes<br />

En cualquier operación relacionada con multimedia, es vital sincronizar las<br />

muestras, así los frames <strong>de</strong> vi<strong>de</strong>o serán <strong>de</strong>splegadas a la razón apropiada, <strong>de</strong> modo que el<br />

flujo <strong>de</strong> audio no se a<strong>de</strong>lantará al vi<strong>de</strong>o ni lo opuesto. Un gráfico <strong>de</strong> filtros DirectShow<br />

cont<strong>en</strong>drá exactam<strong>en</strong>te un reloj que todos los filtros utilizarán como su base <strong>de</strong> <strong>tiempo</strong>. El<br />

Manejador <strong>de</strong>l gráfico <strong>de</strong> filtros selecciona un reloj (o provee uno si es necesario) e informa<br />

a todos los filtros para que utilic<strong>en</strong> este reloj como fu<strong>en</strong>te <strong>de</strong> sincronización.<br />

3.8 Flujo <strong>de</strong> datos <strong>en</strong> el Gráfico <strong>de</strong> filtros<br />

3.8.1 Samples y Buffers<br />

Cuando dos pins se conectan, los datos pue<strong>de</strong>n moverse <strong>de</strong>s<strong>de</strong> el salida pin hacia el<br />

pin <strong>en</strong>trada. El pin salida <strong>en</strong>trega datos, mi<strong>en</strong>tras el pin <strong>en</strong>trada recibe datos. La dirección<br />

<strong>de</strong>l flujo <strong>de</strong> datos, <strong>de</strong>s<strong>de</strong> el pin salida hacia el pin <strong>en</strong>trada se <strong>de</strong>nomina downstream, y la<br />

dirección opuesta es llamada upstream.<br />

El tipo <strong>de</strong> los datos que se <strong>de</strong>splazan <strong>en</strong>tre dos pines <strong>de</strong>p<strong>en</strong><strong>de</strong> <strong>de</strong> la<br />

implem<strong>en</strong>tación <strong>de</strong> los pines. En la mayoría <strong>de</strong> los casos, los pines trabajan con datos<br />

multimedia que se <strong>en</strong>cu<strong>en</strong>tran <strong>en</strong> la memoria principal. Sin embargo son posibles otras<br />

configuraciones. Por ejemplo, si dos filtros controlan una parte <strong>de</strong>l hardware <strong>de</strong> vi<strong>de</strong>o, el<br />

hardware quizás se <strong>en</strong>cargue <strong>de</strong> los datos <strong>de</strong> vi<strong>de</strong>o, con los pins intercambiando<br />

información <strong>de</strong> control. El tipo <strong>de</strong> datos, y como se muev<strong>en</strong> estos <strong>en</strong>tre los pines, se<br />

<strong>de</strong>nomina transporte(transport). Esta sección se avoca al caso don<strong>de</strong> los datos multimedia<br />

son cont<strong>en</strong>idos <strong>en</strong> la memoria principal, llamada memoria local <strong>de</strong> transporte (local<br />

memory transport).<br />

En la memoria local <strong>de</strong> transporte, los datos son empacados <strong>en</strong> objetos discretos<br />

llamados muestras multimedia(media samples). Una muestra multimedia es un objeto COM<br />

que manti<strong>en</strong>e un apuntador a un buffer <strong>de</strong> memoria. Una muestra multimedia soporta la<br />

interfaz ImediaSample.<br />

Otro objeto COM es el asignador <strong>de</strong> memoria (memory asignator), responsable <strong>de</strong><br />

ubicar buffers y crear muestras multimedia. En el <strong>tiempo</strong> <strong>de</strong> conexión, el asignador reserva<br />

memoria para los buffers. El asignador también crea un conjunto <strong>de</strong> muestras multimedia, y<br />

da a cada muestra multimedia un apuntador a una dirección <strong>de</strong>ntro <strong>de</strong>l bloque <strong>de</strong> memoria.<br />

Mi<strong>en</strong>tras el buffer no sea liberado, el asignador manti<strong>en</strong>e una lista <strong>de</strong> cuales muestras están<br />

disponibles. Cualquier filtro que necesite una muestra nueva, la solicita al asignador.<br />

Después <strong>de</strong> que la muestra es procesada, la muestra regresa a la lista.<br />

Este mecanismo reduce la cantidad <strong>de</strong> memoria, <strong>de</strong>bido a que los filtros re-utilizan<br />

los mismos buffers. Esto también previ<strong>en</strong>e a los filtros <strong>de</strong> la escritura acci<strong>de</strong>ntal sobre los


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 40<br />

datos que no han sido procesados, <strong>de</strong>bido a que el asignador manti<strong>en</strong>e la lista <strong>de</strong> las<br />

muestras disponibles. Finalm<strong>en</strong>te este provee una manera efici<strong>en</strong>te <strong>de</strong> mover datos a través<br />

<strong>de</strong>l grafico: Cuando un pin salida <strong>en</strong>trega una muestra, este pasa un apuntador a la interfaz<br />

IMediaSample <strong>de</strong> la muestra. Esto provoca que no t<strong>en</strong>ga que copiar ningún dato.<br />

y el filtro.<br />

La figura 3.8 muestra la relación <strong>en</strong>tre el asignador, las muestras multimedia,<br />

Figura 3.8 Función <strong>de</strong>l asignador<br />

Los pins conectados compart<strong>en</strong> un asignador <strong>de</strong> memoria. Un filtro pue<strong>de</strong> usar<br />

difer<strong>en</strong>tes asignadores para sus <strong>en</strong>tradas y salidas. Esto es típico cuando el filtro expan<strong>de</strong><br />

los datos, como <strong>en</strong> el caso <strong>de</strong> un filtro <strong>de</strong>scompresor. Si las salidas no son mayores que las<br />

<strong>en</strong>tradas, el filtro pue<strong>de</strong> procesar los datos <strong>en</strong> el mismo lugar, sin moverlos hacia un nuevo<br />

buffer. En este caso, dos o más conexiones <strong>de</strong> pines pue<strong>de</strong>n compartir el mismo asignador.<br />

3.8.2 Entrega <strong>de</strong> Muestras<br />

Los pins <strong>en</strong>trada que soportan memoria local <strong>de</strong> transporte expon<strong>en</strong> la interfaz<br />

ImemInputPin. El pin salida <strong>en</strong>trega una muestra al llamar el método<br />

ImemInputPin::Receive <strong>en</strong> el pin <strong>en</strong>trada. El pin <strong>en</strong>trada <strong>real</strong>iza una <strong>de</strong> las sigui<strong>en</strong>tes<br />

funciones:<br />

• Rechaza la muestra<br />

• Se bloquea hasta que se finaliza el procesami<strong>en</strong>to <strong>de</strong> una muestra.<br />

• Regresa inmediatam<strong>en</strong>te y procesa la muestra <strong>en</strong> otro hilo(thread).<br />

El método ImemInputPin::ReceiveCanBlock <strong>de</strong>termina si el pin <strong>en</strong>trada pue<strong>de</strong><br />

bloquearse <strong>en</strong> la llamada a Recibe. El pin salida pue<strong>de</strong> llamar a este método para<br />

<strong>de</strong>terminar una estrategia apropiada <strong>de</strong> hilado(threading). Algunos filtros crean un hilo <strong>de</strong><br />

ejecución, así que ellos pue<strong>de</strong>n <strong>en</strong>tregar muestras <strong>en</strong> segundo plano mi<strong>en</strong>tras están<br />

haci<strong>en</strong>do otro trabajo. Otros filtros simplem<strong>en</strong>te se bloquean hasta que el filtro downstream<br />

esta listo para aceptar otra muestra.


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 41<br />

Hay también un método para <strong>en</strong>tregar mas <strong>de</strong> una muestra a un <strong>tiempo</strong>,<br />

ImemInputPin::ReceiveMultiple. Este trabaja como Receive, pero con un arreglo <strong>de</strong><br />

muestras.<br />

3.8.3 Det<strong>en</strong>er, Pausa, y Ejecución<br />

Los filtros ti<strong>en</strong><strong>en</strong> tres estados: <strong>de</strong>t<strong>en</strong>ido, pausado y ejecutándose. Para muchos<br />

filtros, pausado y ejecutándose son equival<strong>en</strong>tes. Cuando un filtro esta <strong>de</strong>t<strong>en</strong>ido, no se<br />

procesan muestras y se rechaza cualquier muestra <strong>de</strong> filtros upstream.<br />

Cuando un filtro es pausado o esta ejecutándose, este acepta muestras y las procesa.<br />

Si este es un filtro source, g<strong>en</strong>era nuevas muestras y las <strong>en</strong>trega downstream. Los filtros<br />

r<strong>en</strong><strong>de</strong>rer son una excepción. Cuando un filtro r<strong>en</strong><strong>de</strong>rer va <strong>de</strong> <strong>de</strong>t<strong>en</strong>ido a pausado, no se<br />

completa la transición sino hasta que reciba muestras media. En este punto, el filtro<br />

manti<strong>en</strong>e la muestra y se bloquea <strong>en</strong> la llamada a Receive. Los r<strong>en</strong><strong>de</strong>rers <strong>de</strong> vi<strong>de</strong>o dibujan<br />

la muestra como un frame fijo. Los r<strong>en</strong><strong>de</strong>rers <strong>de</strong> audio no pres<strong>en</strong>tan la muestra hasta que<br />

ellos estén ejecutándose. En cualquier caso, el r<strong>en</strong><strong>de</strong>rer no acepta mas muestras hasta que<br />

pase <strong>de</strong> pausado a ejecutándose.<br />

El Manejador <strong>de</strong>l gráfico <strong>de</strong> filtros controla el estado <strong>de</strong>l gráfico <strong>de</strong> filtros como un<br />

conjunto. Las transiciones <strong>de</strong> estados validas son <strong>en</strong>tre <strong>de</strong>t<strong>en</strong>ido y pausado, y <strong>en</strong>tre pausado<br />

y ejecutándose. Transiciones <strong>en</strong>tre <strong>de</strong>t<strong>en</strong>ido y ejecutándose <strong>de</strong>b<strong>en</strong> ser a través <strong>de</strong> pausado<br />

(Si se llama a ImediaControl::Run <strong>en</strong> un grafico <strong>de</strong>t<strong>en</strong>ido, o ImediaControl::Stop <strong>en</strong> un<br />

filtro ejecutándose, el Manejador <strong>de</strong>l gráfico <strong>de</strong> filtros pausa primero el grafico).<br />

Cuando el grafico <strong>de</strong>l filtro va <strong>de</strong> <strong>de</strong>t<strong>en</strong>ido a pausado, ocurre la sigui<strong>en</strong>te secu<strong>en</strong>cia:<br />

El Manejador <strong>de</strong>l gráfico <strong>de</strong> filtros llama a ImediaFilter::Pause <strong>en</strong> cada filtro,<br />

iniciando <strong>de</strong>s<strong>de</strong> el filtro r<strong>en</strong><strong>de</strong>rer y continuando upstream.<br />

Como cada filtro conmuta a pausado, un filtro se <strong>en</strong>cu<strong>en</strong>tra listo para aceptar<br />

muestras <strong>de</strong>s<strong>de</strong> su upstream más cercano. Este pue<strong>de</strong> <strong>en</strong>tregar muestras downstream con<br />

seguridad, <strong>de</strong>bido a que los filtros downstream también están pausados.<br />

El filtro source es el último <strong>en</strong> ser pausado. En este punto, el filtro inicia <strong>en</strong>tregando<br />

muestras. Como las muestras se muev<strong>en</strong> downstream, los filtros intermedios las procesan.<br />

Cuando las primeras muestras alcanzan al r<strong>en</strong><strong>de</strong>rer, el r<strong>en</strong><strong>de</strong>rer completa su estado<br />

<strong>de</strong> transición y se bloquea.<br />

Estos ev<strong>en</strong>tos pue<strong>de</strong>n tomar una cantidad arbitraria <strong>de</strong> <strong>tiempo</strong> para completarse<br />

(usualm<strong>en</strong>te no mucho, pero el retardo podría ser significativo, especialm<strong>en</strong>te si la fu<strong>en</strong>te<br />

requiere <strong>de</strong>scompresión). Al <strong>tiempo</strong> que el gráfico ha terminado <strong>de</strong> pausarse, estará apto<br />

para iniciar la pres<strong>en</strong>tación <strong>de</strong> datos inmediatam<strong>en</strong>te. Una aplicación pue<strong>de</strong> hacer esto<br />

a<strong>de</strong>lantándose <strong>en</strong> <strong>tiempo</strong>, y <strong>en</strong>tonces rápidam<strong>en</strong>te conmutar el grafico a ejecutándose, <strong>en</strong><br />

respuesta a un comando <strong>de</strong>l usuario.


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 42<br />

3.8.4 Notificación <strong>de</strong> ev<strong>en</strong>tos <strong>en</strong> DirectShow<br />

Un filtro notifica al Manejador <strong>de</strong>l gráfico <strong>de</strong> filtros acerca <strong>de</strong> un ev<strong>en</strong>to mediante el<br />

<strong>en</strong>vío <strong>de</strong> una notificación <strong>de</strong> ev<strong>en</strong>to. El ev<strong>en</strong>to pue<strong>de</strong> ser algunas veces previsto, tal como el<br />

fin <strong>de</strong> un flujo, o este podría repres<strong>en</strong>tar un error, tal como una falla al pres<strong>en</strong>tar un flujo. El<br />

Manejador <strong>de</strong>l gráfico <strong>de</strong> filtros maneja algunos ev<strong>en</strong>tos <strong>de</strong> los filtros y <strong>de</strong>ja otros ev<strong>en</strong>tos<br />

para que los maneje la aplicación. Si el Manejador <strong>de</strong>l gráfico <strong>de</strong> filtros no maneja el<br />

ev<strong>en</strong>to <strong>de</strong>l filtro, este coloca la notificación <strong>de</strong>l ev<strong>en</strong>to <strong>en</strong> una cola. El Gráfico <strong>de</strong> filtros<br />

pue<strong>de</strong> también <strong>en</strong>colar sus propias notificaciones <strong>de</strong> ev<strong>en</strong>tos para la aplicación.<br />

Una aplicación obti<strong>en</strong>e ev<strong>en</strong>tos <strong>de</strong> la cola y respon<strong>de</strong> a ellos basado <strong>en</strong> el tipo <strong>de</strong><br />

ev<strong>en</strong>to. La notificación <strong>de</strong> ev<strong>en</strong>tos <strong>en</strong> DirectShow es similar al esquema <strong>de</strong> <strong>en</strong>colado <strong>de</strong><br />

m<strong>en</strong>sajes <strong>de</strong> Windows. Una aplicación pue<strong>de</strong> también cancelar el comportami<strong>en</strong>to por<br />

<strong>de</strong>fault <strong>de</strong>l Manejador <strong>de</strong>l gráfico <strong>de</strong> filtros para un tipo <strong>de</strong> ev<strong>en</strong>to dado. El Manejador <strong>de</strong>l<br />

gráfico <strong>de</strong> filtros <strong>en</strong>tonces mete estos ev<strong>en</strong>tos directam<strong>en</strong>te <strong>en</strong> la cola para que la aplicación<br />

las maneje.<br />

Este mecanismo permite:<br />

• Al Manejador <strong>de</strong>l gráfico <strong>de</strong> filtros comunicarse con la aplicación.<br />

• A los filtros comunicarse con la aplicación y con el Manejador <strong>de</strong>l Gráfico <strong>de</strong><br />

filtros.<br />

• A la aplicación <strong>de</strong>terminar su grado <strong>de</strong> involucrami<strong>en</strong>to <strong>en</strong> el manejo <strong>de</strong> ev<strong>en</strong>tos.<br />

3.8.4.1 Capturando Ev<strong>en</strong>tos<br />

El Manejador <strong>de</strong>l gráfico <strong>de</strong> filtros expone tres interfaces que soportan la<br />

notificación <strong>de</strong> ev<strong>en</strong>tos.<br />

IMediaEv<strong>en</strong>tSink conti<strong>en</strong>e los métodos para que los filtros <strong>en</strong>ví<strong>en</strong> ev<strong>en</strong>tos.<br />

IMediaEv<strong>en</strong>t conti<strong>en</strong>e métodos para que las aplicaciones captur<strong>en</strong> ev<strong>en</strong>tos.<br />

IMediaEv<strong>en</strong>tEx hereda <strong>de</strong>s<strong>de</strong> y exti<strong>en</strong><strong>de</strong> la interfaz IMediaEv<strong>en</strong>t.<br />

Los filtros <strong>en</strong>vían notificaciones <strong>de</strong> ev<strong>en</strong>tos mediante la llamada al método<br />

IMediaEv<strong>en</strong>tSink::Notify <strong>en</strong> el Manejador <strong>de</strong>l Gráfico <strong>de</strong> filtros, y dos parámetros<br />

DWORD que dan información adicional. Dep<strong>en</strong>di<strong>en</strong>do <strong>de</strong>l código <strong>de</strong>l ev<strong>en</strong>to, los<br />

parámetros pue<strong>de</strong>n cont<strong>en</strong>er apuntadores, regresar códigos, <strong>tiempo</strong>s <strong>de</strong> refer<strong>en</strong>cia, u otra<br />

información.<br />

Para obt<strong>en</strong>er un ev<strong>en</strong>to <strong>de</strong> una cola la aplicación llama al método<br />

IMediaEv<strong>en</strong>t::GetEv<strong>en</strong>t <strong>en</strong> el Manejador <strong>de</strong>l Gráfico <strong>de</strong> filtros. Este método se bloquea<br />

hasta que regrese un ev<strong>en</strong>to o hasta que pase un lapso <strong>de</strong> <strong>tiempo</strong> especificado. Asumi<strong>en</strong>do<br />

que hay un ev<strong>en</strong>to <strong>en</strong>colado, el método regresa con el código <strong>de</strong>l ev<strong>en</strong>to y los dos<br />

parámetros <strong>de</strong>l ev<strong>en</strong>to. Después <strong>de</strong> llamar a GetEv<strong>en</strong>t, una aplicación <strong>de</strong>be siempre llamar<br />

al método IMediaEv<strong>en</strong>t::FreeEv<strong>en</strong>tParams para actualizar cualquier recurso asociado


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 43<br />

con los parámetros <strong>de</strong>l ev<strong>en</strong>to. Por ejemplo, un parámetro podría ser un valor BSTR que<br />

fuese localizado por el Gráfico <strong>de</strong> filtros.<br />

El sigui<strong>en</strong>te código provee una guía <strong>de</strong> cómo obt<strong>en</strong>er ev<strong>en</strong>tos <strong>de</strong> una cola.<br />

long evCo<strong>de</strong>, param1, param2;<br />

HRESULT hr;<br />

while (hr = pEv<strong>en</strong>t->GetEv<strong>en</strong>t(&evCo<strong>de</strong>, &param1, &param2, 0), SUCCEEDED(hr))<br />

{<br />

switch(evCo<strong>de</strong>)<br />

{<br />

// Llama a funciones <strong>de</strong>finidas <strong>en</strong> la aplicación para cada<br />

// tipo <strong>de</strong> ev<strong>en</strong>to que se quiera manejar.<br />

}<br />

}<br />

hr = pEv<strong>en</strong>t->FreeEv<strong>en</strong>tParams(evCo<strong>de</strong>, param1, param2);<br />

Para sobrescribir el manejador por <strong>de</strong>fault <strong>de</strong>l Manejador <strong>de</strong>l Gráfico <strong>de</strong> filtros, se<br />

<strong>de</strong>be llamar al método IMediaEv<strong>en</strong>t::CancelDefaultHandling con el código <strong>de</strong>l ev<strong>en</strong>to<br />

como un parámetro. Se pue<strong>de</strong> volver a crear una instancia <strong>de</strong>l manejador por <strong>de</strong>fault<br />

llamando al método IMediaEv<strong>en</strong>t::RestoreDefaultHandling.<br />

3.8.4.2 Saber cuando un ev<strong>en</strong>to ocurre<br />

Adicionalm<strong>en</strong>te a lo <strong>de</strong>scrito, una aplicación necesita una manera <strong>de</strong> saber cuando<br />

los ev<strong>en</strong>tos están esperando <strong>en</strong> la cola. El Manejador <strong>de</strong>l gráfico <strong>de</strong> filtros provee dos<br />

formas <strong>de</strong> hacer esto.<br />

• Usando notificaciones Windows, el Manejador <strong>de</strong>l gráfico <strong>de</strong> filtros <strong>en</strong>vía un<br />

m<strong>en</strong>saje tipo Windows a una v<strong>en</strong>tana <strong>de</strong> aplicación <strong>en</strong> cualquier mom<strong>en</strong>to que<br />

exista un nuevo ev<strong>en</strong>to.<br />

• Usando manejadores <strong>de</strong> ev<strong>en</strong>tos, la aplicación obti<strong>en</strong>e un manejador a un ev<strong>en</strong>to<br />

Windows manual-reset 6 . El Manejador <strong>de</strong>l gráfico <strong>de</strong> filtros señala el ev<strong>en</strong>to<br />

manual-reset cuando haya notificaciones <strong>de</strong> ev<strong>en</strong>tos <strong>en</strong> la cola y reinicializa esta<br />

cuando la cola está vacía.<br />

Veamos cada una <strong>de</strong> las dos opciones.<br />

3.8.4.3 Notificación Windows<br />

Para utilizar una notificación windows, se <strong>de</strong>be llamar al método<br />

IMediaEv<strong>en</strong>tEx::SetNotifyWindow y especificar un m<strong>en</strong>saje privado. Las aplicaciones<br />

pue<strong>de</strong>n usar números <strong>de</strong> m<strong>en</strong>sajes <strong>en</strong> el rango <strong>de</strong> WM_APP hasta 0xBFFF como m<strong>en</strong>sajes<br />

privados. En cualquier mom<strong>en</strong>to el Manejador <strong>de</strong>l gráfico <strong>de</strong> filtros coloca una nueva<br />

notificación <strong>de</strong> ev<strong>en</strong>to <strong>en</strong> la cola, este <strong>en</strong>vía este m<strong>en</strong>saje a la v<strong>en</strong>tana <strong>de</strong>stino. La<br />

aplicación respon<strong>de</strong> al m<strong>en</strong>saje <strong>de</strong>s<strong>de</strong> el lazo(loop) <strong>de</strong> m<strong>en</strong>sajes <strong>de</strong> la v<strong>en</strong>tana.<br />

El sigui<strong>en</strong>te código ejemplifica como ajustar la notificación window.<br />

6 El ev<strong>en</strong>to manual-reset es un tipo <strong>de</strong> ev<strong>en</strong>to creado por la función Windows CreateEv<strong>en</strong>t; esta no ti<strong>en</strong>e<br />

nada que ver con las notificaciones <strong>de</strong> ev<strong>en</strong>tos <strong>de</strong>finidas por DirectShow.


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 44<br />

#<strong>de</strong>fine WM_GRAPHNOTIFY WM_APP + 1 // M<strong>en</strong>saje privado.<br />

pEv<strong>en</strong>t->SetNotifyWindow((OAHWND)g_hwnd, WM_GRAPHNOTIFY, 0);<br />

Este m<strong>en</strong>saje es un m<strong>en</strong>saje ordinario Windows, y es <strong>en</strong>viado separadam<strong>en</strong>te <strong>de</strong> la<br />

cola <strong>de</strong> notificación <strong>de</strong> ev<strong>en</strong>tos DirectShow. La v<strong>en</strong>taja <strong>de</strong> esta aproximación es que<br />

muchas aplicaciones ya ti<strong>en</strong><strong>en</strong> implem<strong>en</strong>tado un lazo <strong>de</strong> m<strong>en</strong>sajes. Así mismo pue<strong>de</strong><br />

incorporar un manejador <strong>de</strong> ev<strong>en</strong>tos DirectShow sin mucho trabajo adicional.<br />

El sigui<strong>en</strong>te código muestra como respon<strong>de</strong>r al m<strong>en</strong>saje <strong>de</strong> notificación.<br />

LRESULT CALLBACK WindowProc( HWND hwnd, UINT msg, UINT wParam, LONG lParam)<br />

{<br />

switch (msg)<br />

{<br />

case WM_GRAPHNOTIFY:<br />

HandleEv<strong>en</strong>t(); // Función <strong>de</strong>finida <strong>en</strong> la aplicación.<br />

break;<br />

}<br />

// Maneja otros m<strong>en</strong>sajes <strong>de</strong> Windows aquí también.<br />

}<br />

return (DefWindowProc(hwnd, msg, wParam, lParam));<br />

Debido a que la notificación <strong>de</strong> ev<strong>en</strong>tos, y el lazo <strong>de</strong> m<strong>en</strong>sajes son ambos<br />

asíncronos, la cola pue<strong>de</strong> cont<strong>en</strong>er mas <strong>de</strong> un ev<strong>en</strong>to para el <strong>tiempo</strong> que su aplicación<br />

responda al m<strong>en</strong>saje. También, los ev<strong>en</strong>tos pue<strong>de</strong>n algunas veces ser quitados <strong>de</strong> la cola si<br />

ellos fues<strong>en</strong> inválidos. Así mismo, <strong>en</strong> el código manejador <strong>de</strong>l ev<strong>en</strong>to, hay que llamar a<br />

GetEv<strong>en</strong>t hasta que este regrese un código <strong>de</strong> falla, indicando que la cola está vacía.<br />

3.8.4.4 Manejadores <strong>de</strong> ev<strong>en</strong>tos<br />

El gráfico <strong>de</strong> filtros guarda un ev<strong>en</strong>to manual-reset que refleja el estado <strong>de</strong> la cola<br />

<strong>de</strong> ev<strong>en</strong>tos. Si la cola conti<strong>en</strong>e notificaciones <strong>de</strong> ev<strong>en</strong>tos p<strong>en</strong>di<strong>en</strong>tes, el gráfico <strong>de</strong> filtros<br />

señala los ev<strong>en</strong>tos manual-reset. Si la cola está vacía, una llamada al método<br />

IMediaEv<strong>en</strong>t::GetEv<strong>en</strong>t reinicializa el ev<strong>en</strong>to. Una aplicación pue<strong>de</strong> usar este ev<strong>en</strong>to para<br />

<strong>de</strong>terminar el estado <strong>de</strong> la cola.<br />

El método IMediaEv<strong>en</strong>t::GetEv<strong>en</strong>tHandle obti<strong>en</strong>e un manejador a el ev<strong>en</strong>to<br />

manual-reset. Espera para que el ev<strong>en</strong>to sea señalado mediante un llamado a una función tal<br />

como WaitForMultipleObjects. Al mismo <strong>tiempo</strong> que el ev<strong>en</strong>to es señalado, la llamada al<br />

ev<strong>en</strong>to IMediaEv<strong>en</strong>t::GetEv<strong>en</strong>t obti<strong>en</strong>e la notificación <strong>de</strong>l ev<strong>en</strong>to.<br />

El sigui<strong>en</strong>te código <strong>de</strong> ejemplo ilustra este método. Este obti<strong>en</strong>e el manejador <strong>de</strong><br />

ev<strong>en</strong>to, <strong>en</strong>tonces espera <strong>en</strong> intervalos <strong>de</strong> 100 milisegundos para ser señalado. Si el ev<strong>en</strong>to es<br />

señalado, este llama a GetEv<strong>en</strong>t e imprime el código <strong>de</strong> ev<strong>en</strong>to y los parámetros <strong>de</strong>l ev<strong>en</strong>to<br />

a la v<strong>en</strong>tana. El lazo termina cuando ocurre el ev<strong>en</strong>to EC_COMPLETE.<br />

HANDLE hEv<strong>en</strong>t;<br />

long evCo<strong>de</strong>, param1, param2;<br />

BOOLEAN bDone = FALSE;<br />

HRESULT hr = S_OK;<br />

hr = pEv<strong>en</strong>t->GetEv<strong>en</strong>tHandle((OAEVENT*)&hEv);<br />

while(!bDone)<br />

{


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 45<br />

}<br />

if (WAIT_OBJECT_0 == WaitForSingleObject(hEv<strong>en</strong>t, 100))<br />

{<br />

while (hr = pEv<strong>en</strong>t->GetEv<strong>en</strong>t(&evCo<strong>de</strong>, &param1, &param2, 0), SUCCEEDED(hr))<br />

{<br />

printf("Ev<strong>en</strong>t co<strong>de</strong>: %#04x\n Params: %d, %d\n", evCo<strong>de</strong>, param1, param2);<br />

hr = pEv<strong>en</strong>t->FreeEv<strong>en</strong>tParams(evCo<strong>de</strong>, param1, param2);<br />

bDone = (EC_COMPLETE == evCo<strong>de</strong>);<br />

}<br />

}<br />

Debido a que el gráfico <strong>de</strong> filtros automáticam<strong>en</strong>te ajusta o reinicialaza el ev<strong>en</strong>to<br />

cuando sea apropiado, la aplicación no <strong>de</strong>bería hacerlo. También, cuando se actualiza el<br />

gráfico <strong>de</strong> filtros, el gráfico <strong>de</strong> filtros cierra el manejador <strong>de</strong> ev<strong>en</strong>tos, así no hace uso <strong>de</strong>l<br />

manejador <strong>de</strong> ev<strong>en</strong>tos <strong>de</strong>spués <strong>de</strong> este punto.<br />

3.9 Hardware <strong>en</strong> el gráfico <strong>de</strong> filtros<br />

3.9.1 Filtros Envoltura (Wrapper)<br />

Todos los filtros DirectShow son compon<strong>en</strong>tes <strong>de</strong> software <strong>en</strong> el modo usuario. Para<br />

que un dispositivo hardware <strong>en</strong> el modo kernel como una tarjeta <strong>de</strong> captura <strong>de</strong> vi<strong>de</strong>o/sonido<br />

se añada al gráfico <strong>de</strong> filtros <strong>de</strong> DirectShow, el dispositivo <strong>de</strong>be ser repres<strong>en</strong>tado como un<br />

filtro <strong>en</strong> el modo usuario <strong>de</strong>ntro <strong>de</strong>l gráfico <strong>de</strong> filtros. Esta función se lleva a cabo para<br />

varios tipos <strong>de</strong> dispositivos por filtros especializados llamados filtros <strong>en</strong>voltura(wrapper<br />

filters), provistos con DirectShow.<br />

Los filtros <strong>en</strong>voltura trabajan soportando las interfaces COM que repres<strong>en</strong>tan las<br />

capacida<strong>de</strong>s esperadas <strong>de</strong>l dispositivo. La aplicación usa estas interfaces para pasar<br />

información hacia y <strong>de</strong>s<strong>de</strong> el filtro, el filtro traduce las llamadas a la interfase <strong>en</strong><br />

información que el controlador <strong>de</strong>l dispositivo pueda compr<strong>en</strong><strong>de</strong>r, y <strong>en</strong>tonces el filtro pasa<br />

esta información hacia y <strong>de</strong>s<strong>de</strong> el controlador <strong>en</strong> el modo kernel.<br />

Para los <strong>de</strong>sarrolladores <strong>de</strong> aplicaciones, el principio <strong>de</strong> <strong>en</strong>volver dispositivos <strong>de</strong><br />

hardware como filtros <strong>en</strong> modo usuario significa que las aplicaciones controlan dispositivos<br />

<strong>de</strong> la misma forma que ellos controlan cualquier otro filtro DirectShow. No se requiere una<br />

programación especial <strong>en</strong> la parte <strong>de</strong> la aplicación; todos los <strong>de</strong>talles involucrados <strong>en</strong> la<br />

comunicación con el dispositivo <strong>en</strong> el modo kernel son <strong>en</strong>capsulados <strong>de</strong>ntro <strong>de</strong>l filtro<br />

mismo.<br />

3.9.2 Vi<strong>de</strong>o para dispositivos Windows<br />

Para soportar las ultimas tarjetas <strong>de</strong> captura Vi<strong>de</strong>o for Windows (VfW), DirectShow<br />

provee el filtro <strong>de</strong> captura VFW. Cuando una tarjeta VfW esta pres<strong>en</strong>te <strong>en</strong> el sistema, esta<br />

pue<strong>de</strong> ser <strong>de</strong>scubierta usando el System Device Enumerator 7 . El Enumerator se utiliza<br />

también para añadir el filtro <strong>de</strong> captura VfW al grafico y asociar este con la tarjeta que fue<br />

7 Aplicación cont<strong>en</strong>ida <strong>en</strong> DirectX 8.0


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 46<br />

<strong>en</strong>contrada. El resto <strong>de</strong>l gráfico <strong>de</strong> filtros pue<strong>de</strong> <strong>en</strong>tonces ser construido <strong>de</strong> la manera<br />

usual..<br />

3.9.3 Captura <strong>de</strong> Audio y dispositivos Mezcladores<br />

Las tarjetas <strong>de</strong> sonido mo<strong>de</strong>rnas ti<strong>en</strong><strong>en</strong> conectores <strong>de</strong> <strong>en</strong>trada para micrófonos y otro<br />

tipo <strong>de</strong> dispositivos. Estas tarjetas también ti<strong>en</strong><strong>en</strong> capacida<strong>de</strong>s <strong>de</strong> mezclado para controlar<br />

el volum<strong>en</strong>, graves y agudos <strong>de</strong> cada <strong>en</strong>trada individualm<strong>en</strong>te. En DirectShow, las <strong>en</strong>tradas<br />

<strong>de</strong> las tarjetas <strong>de</strong> sonido y mezcladoras son <strong>en</strong>vueltas <strong>en</strong> el filtro <strong>de</strong> captura <strong>de</strong> audio (Audio<br />

Capture filter). Cada tarjeta <strong>de</strong> sonido <strong>en</strong> el sistema local pue<strong>de</strong> ser <strong>de</strong>scubierta con el<br />

system <strong>de</strong>vice <strong>en</strong>umerator. Para visualizar las tarjetas <strong>de</strong> sonido <strong>en</strong> su sistema basta abrir el<br />

programa GraphEdit que se instala con el SDK y seleccionar <strong>de</strong> la categoría Audio Capture<br />

Sources. Cada filtro repres<strong>en</strong>tado aquí es una instancia separada <strong>de</strong>l Audio Capture filter.


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 47<br />

4 Diseño<br />

4.1 Descripción g<strong>en</strong>eral <strong>de</strong>l sistema<br />

El proyecto se va a dividir <strong>en</strong> dos subsistemas, uno es el que concierne a la<br />

construcción <strong>de</strong>l vi<strong>de</strong>owall, el cual se llevará a cabo via hardware y utilizando las<br />

capacida<strong>de</strong>s <strong>de</strong>l sistema operativo. El otro subsistema consiste <strong>en</strong> la elaboración <strong>de</strong>l<br />

software que permitirá hacer uso <strong>de</strong> todas las pantallas y <strong>real</strong>izar el procesami<strong>en</strong>to <strong>de</strong> vi<strong>de</strong>o<br />

<strong>en</strong> <strong>tiempo</strong> <strong>real</strong>.<br />

En la figura 4.1 se muestra un diagrama <strong>de</strong> flujo <strong>de</strong> datos. El filtro <strong>de</strong> gráficos<br />

DirectShow se muestra <strong>en</strong> gris. Los datos <strong>de</strong> vi<strong>de</strong>o se <strong>de</strong>splazan downstream <strong>de</strong>s<strong>de</strong> la<br />

fu<strong>en</strong>te <strong>de</strong> vi<strong>de</strong>o, ya sea la tarjeta <strong>de</strong> TV o un archivo <strong>de</strong> vi<strong>de</strong>o ubicado <strong>en</strong> el disco duro. La<br />

aplicación controla el filtro <strong>de</strong> procesami<strong>en</strong>to múltiple <strong>de</strong> vi<strong>de</strong>o, y <strong>en</strong>tonces es posible que<br />

el usuario a través <strong>de</strong> la aplicación y mediante una GUI(interfaz Gráfica <strong>de</strong> usuario)<br />

seleccione el procesami<strong>en</strong>to <strong>de</strong> vi<strong>de</strong>o <strong>de</strong> su interés. Finalm<strong>en</strong>te un filtro r<strong>en</strong><strong>de</strong>rer se ocupa<br />

<strong>de</strong> <strong>en</strong>viar el vi<strong>de</strong>o <strong>de</strong> salida hacia el sistema operativo, qui<strong>en</strong> se <strong>en</strong>carga <strong>de</strong> distribuir dicha<br />

imag<strong>en</strong> hacia las cuatro tarjetas <strong>de</strong> vi<strong>de</strong>o conectadas <strong>en</strong> la PC. En el gráfico no se muestran<br />

los datos <strong>de</strong> control <strong>de</strong> calidad(quality control) utilizados por Directshow y que se<br />

<strong>de</strong>splazan upstream.<br />

Figura 4.1 Diagrama g<strong>en</strong>eral <strong>de</strong>l proyecto<br />

El proyecto esta elaborado con Microsoft Visual C++ 6.0, y haci<strong>en</strong>do uso <strong>de</strong> las<br />

librerías <strong>de</strong> DirectShow incluidas <strong>en</strong> DirectX 8.1.<br />

4.2 Entrada <strong>de</strong> vi<strong>de</strong>o<br />

Se seleccionó la tarjeta <strong>de</strong> vi<strong>de</strong>o Hauppauge WinTV, <strong>de</strong>bido al soporte <strong>de</strong><br />

controladores que brindan a través <strong>de</strong> su pagina web. Adicionalm<strong>en</strong>te <strong>en</strong> la web se


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 48<br />

<strong>en</strong>contraron multiples soportes <strong>de</strong> información para dicha tarjeta y finalm<strong>en</strong>te Hauppauge<br />

repres<strong>en</strong>ta cerca <strong>de</strong>l 80% <strong>de</strong> v<strong>en</strong>tas <strong>de</strong> tarjetas <strong>de</strong> TV <strong>en</strong> Europa , garantizando así su<br />

actualización constante.<br />

El acceso a la tarjeta Hauppauge WinTV se logra a través <strong>de</strong> un filtro wrapper<br />

provisto por DirectShow. Se ti<strong>en</strong>e <strong>de</strong>spués que conectar un filtro que convierta el formato<br />

<strong>de</strong> vi<strong>de</strong>o provisto por la tarjeta WinTV a un formato que pueda ser procesado, <strong>en</strong> nuestro<br />

caso a RGB24. Para el caso <strong>de</strong> un archivo <strong>en</strong> Disco duro se han contemplado solo tres<br />

formatos <strong>de</strong> vi<strong>de</strong>o <strong>de</strong> <strong>en</strong>trada *.mov, *.mpg y *.avi, por ser estos <strong>de</strong> mayor uso.<br />

4.3 Filtro multiprocesami<strong>en</strong>to<br />

Se tomó la <strong>de</strong>cisión <strong>de</strong> elaborar un filtro <strong>en</strong> lugar <strong>de</strong> varios filtros, <strong>de</strong>bido a que la<br />

conexión dinámica <strong>de</strong>l grafico <strong>de</strong> filtros pue<strong>de</strong> llevar a discontinuida<strong>de</strong>s <strong>en</strong> la pres<strong>en</strong>tación<br />

<strong>de</strong>l vi<strong>de</strong>o. La int<strong>en</strong>ción es po<strong>de</strong>r <strong>real</strong>izar el intercambio <strong>de</strong> filtros sin afectar la velocidad <strong>de</strong><br />

reproducción <strong>de</strong>l vi<strong>de</strong>o. Adicionalm<strong>en</strong>te por facilidad <strong>de</strong> procesami<strong>en</strong>to se p<strong>en</strong>só utilizar el<br />

formato <strong>de</strong> vi<strong>de</strong>o RGB 24 don<strong>de</strong> cada byte repres<strong>en</strong>ta una compon<strong>en</strong>te <strong>de</strong> color. El filtro <strong>de</strong><br />

procesami<strong>en</strong>to múltiple <strong>de</strong> vi<strong>de</strong>o incluirá los distintos procesami<strong>en</strong>tos y permitirá su<br />

selección a través <strong>de</strong> la aplicación mediante una interfaz. El filtro será <strong>de</strong>l tipo in-place,<br />

<strong>de</strong>bido a que no se ti<strong>en</strong>e contemplado hacer algún tipo <strong>de</strong> compresión sobre el vi<strong>de</strong>o, <strong>de</strong> tal<br />

modo que los efectos <strong>de</strong> vi<strong>de</strong>o solo manipularán las muestras sin afectar la longitud <strong>de</strong> las<br />

mismas. La figura 4.2 muestra un diagrama <strong>de</strong> la construcción <strong>de</strong>l filtro.<br />

Creación <strong>de</strong>l Objeto Filtro<br />

Adición <strong>de</strong> interfaces COM<br />

Función para <strong>de</strong>tección <strong>de</strong>l<br />

Tipo <strong>de</strong> datos Multimedia<br />

Función para transformación<br />

Del vi<strong>de</strong>o Transform ( )<br />

Interfaz para la selección <strong>de</strong>l<br />

efecto<br />

Figura 4.2 Diagrama <strong>de</strong>l filtro


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 49<br />

El filtro <strong>de</strong>be partir <strong>de</strong> la clase base CTransformFilter, la cual no <strong>real</strong>iza operaciones<br />

<strong>de</strong> copia sobre las muestras, esto permitirá ahorrar recursos <strong>de</strong> CPU.<br />

Para las pruebas <strong>en</strong> el filtro se utilizará la herrami<strong>en</strong>ta provista por DirectX<br />

GraphEdit. Después <strong>de</strong> elaborar el filtro se iniciará el <strong>de</strong>sarrollo <strong>de</strong> la aplicación. Cabe<br />

aclarar que por lo investigado, DirectShow no dispone <strong>de</strong> un control directo sobre las<br />

muestras multimedia. En el proyecto se irán experim<strong>en</strong>tando las capacida<strong>de</strong>s y limitaciones<br />

al respecto.<br />

Sobre el diseño <strong>de</strong> los algoritmos a utilizar <strong>en</strong> cada procesami<strong>en</strong>to, se requiere<br />

conocer las características <strong>de</strong> DirectShow, para po<strong>de</strong>r implem<strong>en</strong>tar las que t<strong>en</strong>gan el mejor<br />

r<strong>en</strong>dimi<strong>en</strong>to.<br />

4.4 Entrega <strong>de</strong> muestras al sistema operativo<br />

La <strong>en</strong>trega <strong>de</strong> las muestras multimedia hacia el sistema operativo requiere elaborar<br />

un filtro r<strong>en</strong><strong>de</strong>rer que se ocupe <strong>de</strong> mant<strong>en</strong>er un buffer para almac<strong>en</strong>ar las muestras y<br />

<strong>en</strong>tregarlas hacia el sistema operativo. T<strong>en</strong>i<strong>en</strong>do <strong>en</strong> consi<strong>de</strong>ración que por limitantes<br />

propias <strong>de</strong> DirectX, la pres<strong>en</strong>tación <strong>de</strong>l vi<strong>de</strong>o no será a pantalla completa. Por tal motivo se<br />

implem<strong>en</strong>tara un manejo <strong>de</strong> v<strong>en</strong>tanas típico <strong>de</strong> cuyo <strong>de</strong>spliegue se <strong>en</strong>carga el sistema<br />

operativo.<br />

4.5 Aplicación<br />

La aplicación será responsable <strong>de</strong> la construcción <strong>de</strong>l gráfico <strong>de</strong> filtros, esta se<br />

estructura <strong>en</strong> función <strong>de</strong> la fu<strong>en</strong>te <strong>de</strong> vi<strong>de</strong>o elegida por el usuario (tarjeta <strong>de</strong> TV o un<br />

archivo multimedia). Así la construcción <strong>de</strong>l gráfico <strong>de</strong> filtros <strong>de</strong>berá hacerse<br />

automáticam<strong>en</strong>te <strong>de</strong>p<strong>en</strong>di<strong>en</strong>do <strong>de</strong> si el archivo <strong>de</strong> <strong>en</strong>trada se <strong>en</strong>cu<strong>en</strong>tra <strong>en</strong> formato AVI o<br />

MPEG. Posteriorm<strong>en</strong>te se requiere <strong>de</strong>sconectar el grafico <strong>de</strong> filtros e insertar el filtro<br />

multiprocesami<strong>en</strong>to, lo cual <strong>de</strong>be consi<strong>de</strong>rar los tipos <strong>de</strong> datos que se manejan <strong>en</strong> dicho<br />

punto <strong>de</strong> flujo. Será importante <strong>real</strong>izar una función <strong>de</strong> chequeo sobre el tipo <strong>de</strong> datos<br />

multimedia para asegurar que se pue<strong>de</strong> proporcionar a nuestro filtro un formato RGB24 sin<br />

problema alguno. Finalm<strong>en</strong>te se reconstruye el gráfico <strong>de</strong> filtros incluyéndose el filtro<br />

r<strong>en</strong><strong>de</strong>rer que proporcione la imag<strong>en</strong> <strong>de</strong> vi<strong>de</strong>o final hacia el sistema operativo para su<br />

pres<strong>en</strong>tación <strong>en</strong> múltiples pantallas.<br />

La interfaz grafica al usuario consistirá <strong>en</strong> una v<strong>en</strong>tana con m<strong>en</strong>ú para seleccionar la<br />

fu<strong>en</strong>te <strong>de</strong> vi<strong>de</strong>o, <strong>de</strong>l mismo modo se seleccionará el tamaño <strong>de</strong> la v<strong>en</strong>tana, ya sea que ocupe<br />

un monitor o todos los monitores.<br />

Se <strong>de</strong>be también incorporar una v<strong>en</strong>tana que permita la selección <strong>de</strong> el efecto <strong>de</strong><br />

vi<strong>de</strong>o <strong>de</strong>seado. Esta v<strong>en</strong>tana <strong>de</strong>be aparecer solo cuando sea solicitada por el usuario. La<br />

figura 4.3 muestra un diagrama <strong>de</strong> la construcción <strong>de</strong> la aplicaciòn.


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 50<br />

Selección <strong>de</strong>l tamaño <strong>de</strong> v<strong>en</strong>tana:<br />

Vi<strong>de</strong>owall o v<strong>en</strong>tana simple<br />

Selección <strong>de</strong> la fu<strong>en</strong>te <strong>de</strong> vi<strong>de</strong>o<br />

Construcción automática <strong>de</strong>l<br />

Gráfico <strong>de</strong> filtros<br />

Inserción <strong>de</strong>l filtro multiefectos<br />

Inserción <strong>de</strong>l filtro r<strong>en</strong><strong>de</strong>rer<br />

Despliegue <strong>de</strong> vi<strong>de</strong>o<br />

Figura 4.3 Diagrama <strong>de</strong> la aplicación<br />

Selección <strong>de</strong>l filtro <strong>de</strong> vi<strong>de</strong>o


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 51<br />

5. Implem<strong>en</strong>tación<br />

5.1 Funcionami<strong>en</strong>to <strong>de</strong> la tarjeta WinTV<br />

Para visualizar el vi<strong>de</strong>o, la tarjeta utiliza una técnica <strong>de</strong>nominada PCI Push. Con<br />

esta técnica, la tarjeta WinTV <strong>digital</strong>iza el vi<strong>de</strong>o y a continuación se lleva a través <strong>de</strong>l bus<br />

PCI hacia la memoria <strong>de</strong> la tarjeta VGA sin necesidad <strong>de</strong> que el procesador <strong>real</strong>ice trabajo<br />

alguno y por <strong>en</strong><strong>de</strong> no se reduzca la velocidad <strong>de</strong> la PC. La conversión a vi<strong>de</strong>o <strong>digital</strong> se<br />

logra con el chip Bt848, don<strong>de</strong> se <strong>real</strong>iza un muestreo 4:2:2 YUV con una resolución<br />

equival<strong>en</strong>te a 24 bits RGB por píxel <strong>de</strong> vi<strong>de</strong>o.<br />

5.1.1 Modo <strong>de</strong> superposición <strong>de</strong> vi<strong>de</strong>o<br />

La imag<strong>en</strong> <strong>de</strong> vi<strong>de</strong>o se visualiza <strong>en</strong> la pantalla ya sea utilizando el modo <strong>de</strong><br />

superposición <strong>de</strong> vi<strong>de</strong>o o el modo Superficie principal. El modo que se utiliza <strong>de</strong>p<strong>en</strong><strong>de</strong> <strong>de</strong>l<br />

hardware y software <strong>de</strong> la PC.<br />

Si la tarjeta VGA ti<strong>en</strong>e compatibilidad con DirectDraw 2 y dispone <strong>de</strong> sufici<strong>en</strong>te<br />

memoria <strong>de</strong> pantalla para mant<strong>en</strong>er la imag<strong>en</strong> <strong>de</strong> vi<strong>de</strong>o <strong>digital</strong>izada, y adicionalm<strong>en</strong>te ti<strong>en</strong>e<br />

un puerto <strong>de</strong> vi<strong>de</strong>o diseñado para aceptar vi<strong>de</strong>o <strong>digital</strong>, <strong>en</strong>tonces <strong>real</strong>izara un<br />

almac<strong>en</strong>ami<strong>en</strong>to temporal hacia una parte <strong>de</strong> la memoria VGA fuera <strong>de</strong> la pantalla<br />

<strong>de</strong>nominada Superficie Secundaria. Este método se <strong>de</strong>nomina Superposición <strong>de</strong> vi<strong>de</strong>o. A<br />

continuación el adaptador VGA convertirá la imag<strong>en</strong> <strong>de</strong> vi<strong>de</strong>o <strong>de</strong> YUV 4:2:2 a vi<strong>de</strong>o RGB<br />

y superpondrá continuam<strong>en</strong>te la imag<strong>en</strong> <strong>de</strong> vi<strong>de</strong>o sobre la pantalla VGA.<br />

5.1.2 Modo <strong>de</strong> superficie principal<br />

Si la tarjeta VGA ti<strong>en</strong>e compatibilidad con DirectDraw pero no ti<strong>en</strong>e un puerto <strong>de</strong><br />

vi<strong>de</strong>o o no dispone <strong>de</strong> sufici<strong>en</strong>te memoria para mant<strong>en</strong>er la imag<strong>en</strong> <strong>de</strong> vi<strong>de</strong>o fuera <strong>de</strong> la<br />

pantalla, <strong>en</strong>tonces la tarjeta <strong>de</strong> vi<strong>de</strong>o convierte los pixels <strong>de</strong> vi<strong>de</strong>o 4:2:2 YUV <strong>en</strong> un formato<br />

RGB que es compatible con el modo <strong>de</strong> funcionami<strong>en</strong>to <strong>de</strong> la tarjeta VGA (8 bits por píxel,<br />

16 bits por píxel o 24 bits por píxel) y continuación lleva los pixels directam<strong>en</strong>te hacia la<br />

memoria <strong>de</strong> pantalla o superficie principal <strong>de</strong> la VGA.<br />

5.2 Multiplexado <strong>de</strong> vi<strong>de</strong>o<br />

La multiplexación <strong>de</strong> vi<strong>de</strong>o se ha logrado haci<strong>en</strong>do uso <strong>de</strong> las capacida<strong>de</strong>s <strong>de</strong>l<br />

sistema operativo. Dicha característica se <strong>de</strong>nomina soporte <strong>de</strong> múltiple monitor, y es<br />

ofrecida <strong>en</strong> la actualidad por Windows 98 y superiores a<strong>de</strong>más <strong>de</strong> LINUX.<br />

2 Compon<strong>en</strong>te <strong>de</strong> DirectX


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 52<br />

La <strong>de</strong>cisión <strong>de</strong> trabajar con Windows 98 es la facilidad con la que soporta el nuevo<br />

hardware económico y el bajo consumo <strong>de</strong> recursos, a<strong>de</strong>más <strong>de</strong> la viabilidad para trabajar<br />

con el software DirectX. A la fecha LINUX contaba con muy poca información sobre<br />

librerías para manipulación <strong>de</strong> vi<strong>de</strong>o y la escasa se <strong>en</strong>contraba <strong>en</strong> etapa experim<strong>en</strong>tal.<br />

La característica <strong>de</strong> múltiple monitor permite al sistema operativo manejar hasta 9<br />

monitores conectados a la misma tarjeta madre. Las tarjetas <strong>de</strong>berán ser PCI o AGP,<br />

aunque <strong>en</strong> g<strong>en</strong>eral solo se dispone <strong>de</strong> 6 slots PCI <strong>en</strong> una tarjeta <strong>de</strong> uso común pue<strong>de</strong><br />

conseguirse dispositivos para ampliar el numero <strong>de</strong> slots. Es importante recalcar que la<br />

adición <strong>de</strong> cada tarjeta provocará una sobrecarga <strong>en</strong> el procesador, lo que disminuirá el<br />

r<strong>en</strong>dimi<strong>en</strong>to <strong>de</strong>l sistema <strong>en</strong> su conjunto.<br />

5.2.1 Tarjeta primaria y tarjetas secundarias<br />

Una <strong>de</strong> todas las tarjetas <strong>de</strong> vi<strong>de</strong>o será la tarjeta primaria. Esta es la tarjeta que por<br />

omisión albergará las cajas <strong>de</strong> dialogo, dado que muchas aplicaciones iniciarán ahí, y<br />

básicam<strong>en</strong>te todos los programas que hagan uso <strong>de</strong> pantalla completa se ejecutarán aquí.<br />

Windows 98 no <strong>de</strong>termina cual es la tarjeta primaria. Esta es <strong>de</strong>terminada por el<br />

BIOS <strong>de</strong> la computadora. Esto significa que la primer tarjeta <strong>de</strong> vi<strong>de</strong>o que la computadora<br />

<strong>de</strong>tecte durante el proceso <strong>de</strong> arranque será la primaria. Se pudo observar que la<br />

computadora siempre <strong>de</strong>tecta la misma tarjeta <strong>de</strong> vi<strong>de</strong>o como la primaria, y lo que es mas,<br />

siempre arranca con la tarjeta que se ubica <strong>en</strong> el mismo puerto PCI. Se ti<strong>en</strong>e que solo un<br />

<strong>de</strong>terminado numero <strong>de</strong> tarjetas <strong>de</strong> vi<strong>de</strong>o soportan múltiple monitor y se <strong>de</strong>be <strong>en</strong>tonces<br />

revisar la lista <strong>de</strong> Microsoft para <strong>de</strong>terminar la compatibilidad.<br />

Por lo g<strong>en</strong>eral la tarjeta madre dispone <strong>de</strong> un puerto AGP y <strong>de</strong> varios PCI, <strong>en</strong> estos<br />

casos la PC siempre <strong>de</strong>termina la tarjeta PCI como la primaria, <strong>de</strong>bido a que el BIOS<br />

inicializa el bus PCI antes <strong>de</strong> inicializar el bus AGP.<br />

5.2.2 Configuración <strong>de</strong> multimonitor<br />

Suponi<strong>en</strong>do que se ti<strong>en</strong>e una tarjeta <strong>de</strong> vi<strong>de</strong>o instalada, se aña<strong>de</strong> la sigui<strong>en</strong>te tarjeta<br />

con el equipo apagado y al reiniciar, el sistema <strong>de</strong>berá reconocer la nueva tarjeta. Si todo va<br />

bi<strong>en</strong> solo se <strong>de</strong>be ir hacia Display Properties: Se da clic <strong>en</strong> Start, Settings, Control Panel,<br />

Display, y finalm<strong>en</strong>te <strong>en</strong>, Settings.<br />

Para habilitar el nuevo dispositivo, simplem<strong>en</strong>te se da clic sobre el nuevo monitor, y<br />

<strong>en</strong>tonces se selecciona "Ext<strong>en</strong>d my Windows <strong>de</strong>sktop onto this monitor."


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 53<br />

Figura 5.1 Ext<strong>en</strong>sión <strong>de</strong>l escritorio<br />

En el caso <strong>de</strong> que se t<strong>en</strong>ga problemas <strong>en</strong> saber cual monitor es cual, sobre todo<br />

cuando se ti<strong>en</strong><strong>en</strong> 4 monitores o más, solo se da click con el botón <strong>de</strong>recho sobre el monitor<br />

y se selecciona I<strong>de</strong>ntify. Entonces aparecerá el numero correspondi<strong>en</strong>te al monitor actual, el<br />

monitor principal ti<strong>en</strong>e el numero 1 por <strong>de</strong>fault.<br />

Figura 5.2 Activación <strong>de</strong>l monitor secundario<br />

No es necesario usar la misma resolución <strong>en</strong> cada monitor. Abajo se muestra un<br />

ejemplo con el monitor primario a 1024 x 768 y el secundario a 800 x 600.<br />

Figura 5.3 Resoluciones distintas


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 54<br />

Los monitores pue<strong>de</strong>n ser colocados virtualm<strong>en</strong>te uno al lado <strong>de</strong> otro, uno <strong>en</strong>cima<br />

<strong>de</strong> otro, con las esquinas conectadas o un poco separados. Igualm<strong>en</strong>te se pue<strong>de</strong> configurar<br />

la resolución y numero <strong>de</strong> colores para cada uno <strong>de</strong> los monitores.<br />

5.2.3 Pantalla virtual<br />

Figura 5.4 Configuraciones distintas<br />

Windows utiliza un sistema <strong>de</strong> coor<strong>de</strong>nadas para refer<strong>en</strong>ciar cualquier elem<strong>en</strong>to<br />

sobre la pantalla. La esquina superior izquierda <strong>en</strong> una pantalla con resolución 800x600 es<br />

la coor<strong>de</strong>nada 0,0. La coor<strong>de</strong>nada <strong>de</strong> la esquina inferior <strong>de</strong>recha es 800, 600.<br />

En el caso <strong>de</strong> múltiple monitor, la esquina superior izquierda <strong>de</strong>l monitor primario<br />

ti<strong>en</strong>e la coor<strong>de</strong>nada 0,0. Si t<strong>en</strong>emos un sistema con 2 monitores a 1024x768, con el<br />

secundario colocado al lado <strong>de</strong>recho <strong>de</strong>l primario. Entonces la esquina inferior <strong>de</strong>recha <strong>de</strong><br />

la pantalla virtual será 2048x768.<br />

Para evitar inconsist<strong>en</strong>cias con coor<strong>de</strong>nadas <strong>de</strong> números negativos (algunas<br />

aplicaciones no pue<strong>de</strong>n ser arrastradas hacia los monitores con coor<strong>de</strong>nadas negativas ) se<br />

ha <strong>real</strong>izado la sigui<strong>en</strong>te configuración <strong>de</strong> monitores <strong>en</strong> el pres<strong>en</strong>te proyecto.<br />

Figura 5.5 Pantalla virtual <strong>de</strong>l vi<strong>de</strong>owall<br />

Se han instalado las sigui<strong>en</strong>tes tarjetas <strong>de</strong> vi<strong>de</strong>o VGA sin conflicto con la<br />

configuración multimonitor:


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 55<br />

1.- ATI 3D Rage Pro<br />

2.- 3Dblaster Savage 4<br />

3.- ATI 3D Rage Pro<br />

4.- Cirrus Logic 5446PCI<br />

En alguna bibliografía e información <strong>de</strong> internet se especificaba no colocar tarjetas<br />

<strong>de</strong> vi<strong>de</strong>o idénticas, sin embargo se utilizaron 2 tarjetas ATI sin problemas. En la figura 5.6<br />

se observan las tarjetas ya instaladas <strong>en</strong> la tarjeta principlal <strong>de</strong> la PC.<br />

Figura 5.6 Tarjetas VGA y WinTV instaladas<br />

5.3 Instalación <strong>de</strong>l SDK DirectX<br />

El software SDK(System Developm<strong>en</strong>t Kit) <strong>de</strong> DirectX conti<strong>en</strong>e las herrami<strong>en</strong>tas<br />

necesarias para construir aplicaciones graficas y <strong>de</strong> multimedia. Esta incluye el runtime,<br />

hea<strong>de</strong>rs y libs, ejemplos <strong>de</strong> ejecutables, ejemplos <strong>en</strong> código fu<strong>en</strong>te, docum<strong>en</strong>tación,<br />

utilida<strong>de</strong>s, y soporte para <strong>de</strong>sarrollo <strong>en</strong> C++ y Visual Basic.<br />

El usuario que <strong>de</strong>sea incorporar el soporte <strong>de</strong> DirectX solo requiere el runtime. El<br />

SDK pue<strong>de</strong> obt<strong>en</strong>erse <strong>de</strong>s<strong>de</strong> el sitio <strong>de</strong> Microsoft:<br />

http://www.microsoft.com/windows/directx/<strong>de</strong>fault.asp<br />

El tamaño <strong>de</strong>l archivo es <strong>de</strong> 175MB, y solo requiere ejecutarse para com<strong>en</strong>zar la instalación<br />

<strong>de</strong> todo el sistema <strong>de</strong> <strong>de</strong>sarrollo.<br />

Para verificar la correcta instalación <strong>de</strong>l SDK, se comi<strong>en</strong>za por compilar alguno <strong>de</strong><br />

los ejemplos, <strong>en</strong> este caso compilaremos el ejemplo PlayWnd (reproductor multimedia<br />

s<strong>en</strong>cillo). En el pres<strong>en</strong>te trabajo se utilizó el compilador Microsoft Visual C++ 6.0 pero los<br />

procedimi<strong>en</strong>tos son validos también para la versión 5.0.<br />

El código fu<strong>en</strong>te <strong>de</strong>l ejemplo se ubica <strong>en</strong> la sigui<strong>en</strong>te ruta:


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 56<br />

(SDK root)\Samples\Multimedia\DirectShow\Players\PlayWnd<br />

Se dispone <strong>de</strong> dos modos <strong>de</strong> compilación, el modo Debug y el modo Release. En el<br />

modo Debug al compilarse se incluye código adicional que permite obt<strong>en</strong>er texto sobre los<br />

errores <strong>en</strong> el proceso <strong>de</strong> compilación. En el modo Release esto no suce<strong>de</strong> pero el código<br />

ejecutable es significativam<strong>en</strong>te m<strong>en</strong>or.<br />

La selección <strong>de</strong>l modo se <strong>real</strong>iza <strong>en</strong> la barra <strong>de</strong> m<strong>en</strong>ús <strong>de</strong> Visual C++. Se da clic <strong>en</strong> Build<br />

<strong>de</strong>spués <strong>en</strong> Set Active Configuration y finalm<strong>en</strong>te se selecciona el modo <strong>de</strong>seado.<br />

Las aplicaciones <strong>de</strong> DirectShow requier<strong>en</strong> para su compilación <strong>de</strong> las librerías<br />

strmbasd.lib <strong>en</strong> el caso <strong>de</strong>l modo Debug y <strong>de</strong> STRMBASE.lib <strong>en</strong> el caso <strong>de</strong> Release. Estas<br />

librerías <strong>de</strong>b<strong>en</strong> crearse, por lo tanto se <strong>de</strong>be abrir el proyecto<br />

(SDK root)\Samples\Multimedia\DirectShow\BaseClasses\baseclasses.dsw<br />

posteriorm<strong>en</strong>te <strong>de</strong>be compilarse <strong>en</strong> los modos Debug y Release para que se cre<strong>en</strong> las<br />

librerías correspondi<strong>en</strong>tes. La int<strong>en</strong>ción <strong>de</strong> esto es que el <strong>de</strong>sarrollador pueda modificar<br />

dichas librerías.<br />

A continuación se <strong>de</strong>b<strong>en</strong> añadir las rutas <strong>de</strong> las librerías y hea<strong>de</strong>rs <strong>de</strong> DirectX,<br />

ambas <strong>de</strong>b<strong>en</strong> ubicarse <strong>en</strong> el primer lugar <strong>de</strong> búsqueda para que el compilador no escoja una<br />

librería antigua. Esto se <strong>real</strong>iza mediante la inclusión <strong>de</strong> las rutas<br />

(SDK root)\inclu<strong>de</strong><br />

(SDK root)\lib<br />

En el m<strong>en</strong>ú Tools se da click <strong>en</strong> Options y se selecciona la pestaña Directories. Se<br />

ajusta la caja <strong>de</strong> dialogo para que se visualice como sigue <strong>en</strong> el caso <strong>de</strong> inclu<strong>de</strong>:<br />

Figura 5.7 Configuración <strong>de</strong> directorios <strong>en</strong> Visual C++


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 57<br />

Hecho lo anterior <strong>en</strong>tonces po<strong>de</strong>mos abrir el proyecto<br />

(SDK root)\Samples\Multimedia\DirectShow\Players\PlayWnd\PlayWnd.dsw<br />

y su compilación no <strong>de</strong>be t<strong>en</strong>er problema adicional. Antes <strong>de</strong> la introducción con<br />

DirectShow es necesario revisar el mo<strong>de</strong>lo <strong>de</strong> objetos compon<strong>en</strong>tes COM con el que se<br />

basan todas las aplicaciones DirectX.<br />

Iniciamos la construcción <strong>de</strong>l filtro <strong>de</strong> procesami<strong>en</strong>to múltiple, pero como se<br />

com<strong>en</strong>taba <strong>en</strong> el capitulo anterior utilizaremos la herrami<strong>en</strong>ta GraphEdit para <strong>real</strong>izar las<br />

pruebas con el.<br />

5.4 Simulación con GraphEdit<br />

El SDK <strong>de</strong> Microsoft® DirectX® provee una utilidad <strong>de</strong> <strong>de</strong>puración llamada<br />

GraphEdit, la cual se pue<strong>de</strong> usar para crear y probar un grafico <strong>de</strong> filtros.<br />

GraphEdit es una herrami<strong>en</strong>ta visual para construir un grafico <strong>de</strong> filtros. Utilizando<br />

GraphEdit, se pue<strong>de</strong> experim<strong>en</strong>tar con un grafico <strong>de</strong> filtros antes <strong>de</strong> escribir el código <strong>de</strong> la<br />

aplicación. Se pue<strong>de</strong> también cargar un grafico <strong>de</strong> filtros que la aplicación creó, para<br />

verificar que la aplicación está construy<strong>en</strong>do el grafico correcto. Si se <strong>de</strong>sarrolla un filtro<br />

personalizado, GraphEdit permite hacer pruebas con él int<strong>en</strong>tando correr un gráfico.<br />

La figura 5.8 muestra como GraphEdit repres<strong>en</strong>ta un grafico <strong>de</strong> filtros simple.<br />

Figura 5.8 Grafico <strong>de</strong> filtros s<strong>en</strong>cillo<br />

Cada filtro es repres<strong>en</strong>tado como un rectángulo. Los pequeños cuadros cerca <strong>de</strong> las<br />

esquinas <strong>de</strong> los filtros repres<strong>en</strong>tan los pins. Los pins <strong>en</strong>trada están <strong>en</strong> el lado izquierdo <strong>de</strong>l<br />

filtro, y los salida pins <strong>en</strong> el lado <strong>de</strong>recho. Las flechas repres<strong>en</strong>tan la conexión <strong>en</strong>tre pins.<br />

5.5 Uso <strong>de</strong> GraphEdit<br />

Cuando se instala el DirectX SDK 8.0, GraphEdit aparece <strong>en</strong> el m<strong>en</strong>ú Start bajo<br />

Microsoft DirectX 8 SDK, <strong>en</strong> el subm<strong>en</strong>ú DX Utilities. El archivo ejecutable es<br />

GraphEdit.exe. Por <strong>de</strong>fault, este es instalado <strong>en</strong> el fól<strong>de</strong>r Mssdk\Bin\DXUtils.<br />

A continuación hay una breve <strong>de</strong>scripción <strong>de</strong> algunas cosas que se pue<strong>de</strong>n hacer<br />

usando GraphEdit.


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 58<br />

5.5.1 Construcción <strong>de</strong> un grafico <strong>de</strong> ejecución <strong>de</strong> archivos<br />

GraphEdit pue<strong>de</strong> construir un grafico <strong>de</strong> filtros para ejecutar un archivo. Esta<br />

característica es equival<strong>en</strong>te a hacer una llamada al método IGraphBuil<strong>de</strong>r::R<strong>en</strong><strong>de</strong>rFile<br />

<strong>en</strong> una aplicación. Des<strong>de</strong> el m<strong>en</strong>ú File, hacer clic <strong>en</strong> R<strong>en</strong><strong>de</strong>r Media File. GraphEdit<br />

<strong>de</strong>spliega una caja <strong>de</strong> dialogo Op<strong>en</strong> File. Se selecciona un archivo multimedia y se da clic<br />

<strong>en</strong> Op<strong>en</strong>. GraphEdit construye un grafico <strong>de</strong> filtros para ejecutar el archivo que se ha<br />

seleccionado.<br />

5.5.2 Construcción <strong>de</strong> un Grafico <strong>de</strong> filtros personalizado<br />

GraphEdit pue<strong>de</strong> construir un grafico <strong>de</strong> filtros personalizado, usando cualquiera <strong>de</strong><br />

los filtros registrados <strong>en</strong> su sistema. Des<strong>de</strong> el m<strong>en</strong>ú Graph, hay que dar clic <strong>en</strong> Insert<br />

Filters. Una caja <strong>de</strong> dialogo aparece con una lista <strong>de</strong> los filtros <strong>en</strong> el sistema, organizados<br />

por categoría <strong>de</strong> filtros. GraphEdit construye esta lista a partir <strong>de</strong> información <strong>en</strong> el registro.<br />

La sigui<strong>en</strong>te ilustración muestra la caja <strong>de</strong> dialogo.<br />

Figura 5.9 Selección <strong>de</strong>l filtro a insertar<br />

Para añadir un filtro al grafico, se selecciona el nombre <strong>de</strong>l filtro y se da clic <strong>en</strong> el<br />

botón Insert Filters, o doble clic <strong>en</strong> el nombre <strong>de</strong>l filtro. Después <strong>de</strong> que se han añadido<br />

los filtros, se pue<strong>de</strong>n conectar dos filtros arrastrando el mouse <strong>de</strong>s<strong>de</strong> el salida pin <strong>de</strong>l filtro<br />

hacia el pin <strong>en</strong>trada <strong>de</strong> otro filtro. Si los pins aceptan la conexión, GraphEdit dibuja una<br />

flecha conectándolos.


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 59<br />

5.5.3 Ejecución <strong>de</strong>l grafico<br />

Figura 5.10 Conexión <strong>de</strong> dos filtros<br />

En el mom<strong>en</strong>to que se ha construido un grafico <strong>de</strong> filtros <strong>en</strong> Graph Edit, se pue<strong>de</strong><br />

correr el grafico para ver si este trabaja como se esperaba. El m<strong>en</strong>ú Graph conti<strong>en</strong>e los<br />

m<strong>en</strong>ús <strong>de</strong> comando Play, Pause, y Stop. Estos comandos invocan a los métodos<br />

IMediaControl Run, Pause, y Stop, respectivam<strong>en</strong>te. La barra <strong>de</strong> herrami<strong>en</strong>tas <strong>de</strong><br />

GraphEdit ti<strong>en</strong>e botones para estos comandos como se muestra:<br />

Figura 5.11 Controles <strong>de</strong> ejecución<br />

Nota El comando Stop primero pausa el grafico y se recorre al <strong>tiempo</strong> cero. Para archivos<br />

<strong>de</strong> vi<strong>de</strong>o se restaura la v<strong>en</strong>tana <strong>de</strong> vi<strong>de</strong>o con el primer cuadro. Entonces GraphEdit llama a<br />

IMediaControl::Stop.<br />

Si el grafico es rebobinable, se pue<strong>de</strong> bobinar arrastrando la barra <strong>de</strong>slizable que<br />

aparece <strong>de</strong>bajo <strong>de</strong> la caja <strong>de</strong> herrami<strong>en</strong>tas. Arrastrar la barra <strong>de</strong>slizable invoca al método<br />

IMediaSeeking::SetPositions.<br />

5.5.4 Ver paginas propietarias<br />

Algunos filtros soportan paginas propietarias personalizadas, el cual provee una<br />

interfaz <strong>de</strong> usuario para ajustar las propieda<strong>de</strong>s <strong>en</strong> el filtro. Para ver las paginas propietarias<br />

<strong>de</strong>l filtro, hacer clic con el botón <strong>de</strong>recho <strong>en</strong> el filtro y seleccionar Properties <strong>de</strong> la v<strong>en</strong>tana<br />

que aparezca. GraphEdit <strong>de</strong>spliega una pagina propietaria que conti<strong>en</strong>e las hojas <strong>de</strong>finidas<br />

para el filtro (si hay alguna). Adicionalm<strong>en</strong>te, GraphEdit incluye hojas para cada pin <strong>en</strong> el<br />

filtro. Las hojas <strong>de</strong>l pin son <strong>de</strong>finidas por GraphEdit, no por el filtro. Si el pin esta<br />

conectado, la hoja <strong>de</strong>l pin <strong>de</strong>spliega el tipo <strong>de</strong> media para la conexión, <strong>de</strong> lo contrario, esta<br />

lista los tipos <strong>de</strong> media preferidos <strong>de</strong>l pin.<br />

En la figura 5.12 se muestra un ejemplo típico <strong>de</strong> pagina propietaria, es la<br />

mezcladora <strong>de</strong> sonidos disponible <strong>en</strong> todo sistema Windows.


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 60<br />

Figura 5.12 Pagina propietaria <strong>de</strong>l dispositivo <strong>de</strong> grabación <strong>en</strong> Windows<br />

5.6 Escritura <strong>de</strong>l filtro<br />

Como se m<strong>en</strong>cionó arriba la aplicación será <strong>en</strong>cargada <strong>de</strong> construir el gráfico <strong>de</strong><br />

filtros que incorporará nuestro filtro multiprocesami<strong>en</strong>to. Es necesario <strong>en</strong>tonces estudiar<br />

como funcionan internam<strong>en</strong>te los filtros y como interaccionan <strong>en</strong>tre ellos.<br />

Para que un filtro interactúe con otros filtros se requiere que se puedan conectar lo<br />

cual requiere <strong>de</strong> un acuerdo para intercambiar un tipo <strong>de</strong> datos coher<strong>en</strong>te.<br />

5.6.1 Conexión <strong>de</strong> filtros<br />

Los filtros se conectan a través <strong>de</strong> sus pines, haci<strong>en</strong>do uso <strong>de</strong> la interfaz IPin. Los<br />

pins salida se conectan a los pins <strong>en</strong>trada. Cada conexión <strong>de</strong> pin ti<strong>en</strong>e un tipo <strong>de</strong> media,<br />

<strong>de</strong>scrito por la estructura AM_MEDIA_TYPE.<br />

Una aplicación conecta filtros mediante llamadas a métodos <strong>en</strong> el Manejador <strong>de</strong>l<br />

Gráfico <strong>de</strong> filtros, nunca por llamadas a métodos <strong>en</strong> los filtros o <strong>en</strong> los pins mismos. La<br />

aplicación pue<strong>de</strong> directam<strong>en</strong>te especificar el filtro a conectar, llamando al método<br />

IGraphBuil<strong>de</strong>r::Connect. También pue<strong>de</strong> conectar filtros indirectam<strong>en</strong>te con uno <strong>de</strong> los<br />

métodos <strong>de</strong> construcción <strong>de</strong> gráficos <strong>de</strong> filtros, tal como IGraphBuil<strong>de</strong>r::R<strong>en</strong><strong>de</strong>rFile.<br />

Para que la conexión sea exitosa, ambos filtros <strong>de</strong>b<strong>en</strong> estar <strong>en</strong> el grafico <strong>de</strong> filtros.<br />

La aplicación pue<strong>de</strong> añadir un filtro al grafico llamando al método<br />

IFilterGraph::AddFilter.<br />

El bosquejo g<strong>en</strong>eral <strong>de</strong>l proceso <strong>de</strong> conexión es el sigui<strong>en</strong>te:<br />

1. El Manejador <strong>de</strong>l gráfico <strong>de</strong> filtros llama a IPin::Connect <strong>en</strong> el pin salida,<br />

pasándole un apuntador al pin <strong>en</strong>trada.


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 61<br />

2. Si el pin salida acepta la conexión, este llama a IPin::ReceiveConnection <strong>en</strong> el pin<br />

<strong>en</strong>trada.<br />

3. Si el pin <strong>en</strong>trada también acepta la conexión, la conexión int<strong>en</strong>ta llevarse a cabo y<br />

los pins serán conectados.<br />

Algunos pins pue<strong>de</strong>n ser <strong>de</strong>sconectados y conectados mi<strong>en</strong>tras el filtro esta activo. Este<br />

tipo <strong>de</strong> reconexión se <strong>de</strong>nomina reconexión dinámica. Sin embargo, la mayoría <strong>de</strong> los<br />

filtros no soportan la reconexión dinámica. De hecho no fue posible <strong>real</strong>izar una reconexión<br />

dinámica con filtros que manipulas<strong>en</strong> vi<strong>de</strong>o y audio al mismo <strong>tiempo</strong>.<br />

Los filtros son usualm<strong>en</strong>te conectados <strong>en</strong> or<strong>de</strong>n downstream ( <strong>en</strong> otras palabras, los pins<br />

<strong>en</strong>trada <strong>de</strong> los filtros son conectados antes <strong>de</strong> sus pins salida). Un filtro siempre <strong>de</strong>be<br />

soportar este or<strong>de</strong>n <strong>de</strong> conexión..<br />

5.6.2 Negociando los tipos <strong>de</strong> Media<br />

Cuando el Manejador <strong>de</strong>l gráfico <strong>de</strong> filtros llama al método IPin::Connect, este ti<strong>en</strong>e<br />

varias opciones para especificar un tipo <strong>de</strong> media:<br />

• Tipo completo: Si el tipo <strong>de</strong> media esta completam<strong>en</strong>te especificado, los pins<br />

int<strong>en</strong>tan conectarse con este tipo. Si no son <strong>de</strong>l mismo, el int<strong>en</strong>to <strong>de</strong> conexión falla.<br />

• Tipo <strong>de</strong> media parcial: Un tipo <strong>de</strong> media es parcial si el tipo principal, subtipo, o<br />

tipo <strong>de</strong> formato es GUID_NULL. El valor GUID_NULL actúa como un "comodín",<br />

indicando que cualquier valor es aceptable. El pin negocia un tipo que es consist<strong>en</strong>te<br />

con el tipo parcial.<br />

• Sin tipo <strong>de</strong> media: Si el Manejador <strong>de</strong>l Grafico <strong>de</strong> filtros pasa un apuntador NULL,<br />

el pin pue<strong>de</strong> aceptar cualquier tipo <strong>de</strong> media que sea compatible a ambos pins.<br />

Si los pins se conectan, la conexión siempre ti<strong>en</strong>e un tipo <strong>de</strong> media completo. El<br />

propósito <strong>de</strong>l tipo <strong>de</strong> media <strong>de</strong>terminado por el Manejador <strong>de</strong>l gráfico <strong>de</strong> filtros es limitar<br />

los posibles tipos <strong>de</strong> conexión.<br />

Durante el proceso <strong>de</strong> negociación, el salida pin propone un tipo <strong>de</strong> media, llamando al<br />

método IPin::ReceiveConnection <strong>de</strong>l pin <strong>en</strong>trada. El pin <strong>en</strong>trada pue<strong>de</strong> aceptar o rechazar<br />

el tipo propuesto. Este proceso se repite hasta que el pin <strong>en</strong>trada acepta el tipo, o el salida<br />

pin recorre todos los tipos y la conexión falla.<br />

5.6.3 Negociación <strong>de</strong> Asignadores<br />

Cuando dos pins se conectan, ellos necesitan un mecanismo para intercambiar datos<br />

multimedia. El mecanismo es <strong>de</strong>nominado transporte. En g<strong>en</strong>eral, la arquitectura<br />

DirectShow es neutral <strong>en</strong> relación con los transportes. Dos filtros pue<strong>de</strong>n acordar<br />

conectarse utilizando cualquier transporte que ambos soport<strong>en</strong>.<br />

El transporte más común es el <strong>de</strong> memoria local. Con este transporte, los datos<br />

media se manti<strong>en</strong><strong>en</strong> <strong>en</strong> la memoria principal. Un objeto llamado un asignador es


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 62<br />

responsable por asignar buffers <strong>de</strong> memoria. El asignador soporta la interfaz<br />

ImemAsignador. Los pins <strong>en</strong>trada soportan transporte <strong>de</strong> memoria local mediante la<br />

exposición <strong>de</strong> la interfaz ImemInputPin. El pin salida consulta por la interfaz durante el<br />

proceso <strong>de</strong> conexión.<br />

Ambos pins compart<strong>en</strong> el mismo asignador. Cuando ellos se conectan, los pins<br />

negocian cual pin proveerá el asignador, como sigue:<br />

1. Opcionalm<strong>en</strong>te, el pin salida llama IMemInputPin::GetAsignadorRequirem<strong>en</strong>ts.<br />

Este método obti<strong>en</strong>e los requerimi<strong>en</strong>tos <strong>de</strong> buffer <strong>de</strong>l pin <strong>en</strong>trada, tales como la<br />

alineación <strong>de</strong> memoria. En g<strong>en</strong>eral, el pin salida <strong>de</strong>be correspon<strong>de</strong>r a la petición <strong>de</strong>l<br />

pin <strong>en</strong>trada, hasta que no exista una bu<strong>en</strong>a razón para no hacerlo.<br />

2. Opcionalm<strong>en</strong>te, el pin salida llama a IMemInputPin::GetAsignador. Este método<br />

requiere un asignador <strong>de</strong>l pin <strong>en</strong>trada. El pin <strong>en</strong>trada provee uno, o retorna un<br />

código <strong>de</strong> error.<br />

3. El pin salida selecciona un asignador. Este pue<strong>de</strong> usar uno provisto por el pin<br />

<strong>en</strong>trada, o proveer uno el mismo. El pin salida llama a<br />

IMemInputPin::NotifyAsignador para informar al pin <strong>en</strong>trada <strong>de</strong> la selección.<br />

Si un filtro selecciona un asignador <strong>de</strong>l pin <strong>en</strong>trada downstream, el filtro <strong>de</strong>be usar un<br />

asignador solo para <strong>en</strong>tregar muestras al pin <strong>en</strong>trada. Este no <strong>de</strong>be usar el asignador para<br />

<strong>en</strong>tregar muestras a otros pins.<br />

5.6.4 Clase base a utilizar<br />

Dado que <strong>en</strong> este proyecto el filtro <strong>real</strong>izará el procesami<strong>en</strong>to in-place, <strong>de</strong>rivamos<br />

nuestro filtro <strong>de</strong> la clase CTransformFilter . Esto implica que no se <strong>real</strong>izarán copias <strong>de</strong><br />

muestras. Debido a que las operaciones <strong>de</strong> copia utilizan una gran cantidad <strong>de</strong> recursos <strong>en</strong><br />

la CPU, las tratamos <strong>de</strong> evitar.<br />

Figura 5.13 Derivación <strong>de</strong> la clase CTransformFilter


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 63<br />

5.6.5 Instanciar el filtro<br />

Todos los filtros <strong>de</strong>b<strong>en</strong> añadir código para permitir a la clase base instanciar el<br />

filtro. Para instanciar un filtro, se <strong>de</strong>b<strong>en</strong> incluir dos piezas <strong>de</strong> código <strong>en</strong> el filtro: una<br />

función miembro estática CreateInstance <strong>en</strong> la clase CtransformFilter y un medio para<br />

informar a la class factory <strong>de</strong> como acce<strong>de</strong>r a esta función.<br />

Típicam<strong>en</strong>te, la función miembro CreateInstance llama al constructor para la clase<br />

filtro <strong>de</strong>rivada. A continuación se muestra como implem<strong>en</strong>tar la función miembro<br />

CreateInstance:<br />

CUnknown *CGargle::CreateInstance(LPUNKNOWN punk, HRESULT *phr) {<br />

CGargle *pNewObject = new CGargle(NAME("Gargle Filter"), punk, phr);<br />

if (pNewObject == NULL) {<br />

*phr = E_OUTOFMEMORY;<br />

}<br />

return pNewObject;<br />

} // CreateInstance<br />

Para comunicarse con la class factory, se <strong>de</strong>clara un arreglo global<br />

CfactoryTemplate y se provee el nombre <strong>de</strong>l filtro, el i<strong>de</strong>ntificador <strong>de</strong> la clase (CLSID) <strong>de</strong>l<br />

filtro, y un apuntador a la función miembro estática CocreateInstance que crea nuestro<br />

objeto filtro.<br />

// Necesario para el mecanismo CreateInstance<br />

CFactoryTemplate g_Templates[2]=<br />

{ { L"Gargle filter" , &CLSID_Gargle , CGargle::CreateInstance }<br />

, { L"Gargle filter Property Page", &CLSID_GargProp, CGargleProperties::CreateInstance}<br />

};<br />

int g_cTemplates = sizeof(g_Templates)/sizeof(g_Templates[0]);<br />

Finalm<strong>en</strong>te, se <strong>en</strong>ca<strong>de</strong>na el filtro a Strmbase.lib y exporta DllGetClassObject y<br />

DllCanUnloadNow utilizando un archivo .<strong>de</strong>f .<br />

5.6.6 Adición <strong>de</strong> interfaces<br />

En nuestro proyecto se añadirá una interfaz para po<strong>de</strong>r crear una pagina propietaria<br />

y así el usuario modifique las propieda<strong>de</strong>s <strong>de</strong>l filtro. DirectShow <strong>de</strong>fine una clase especial<br />

llamada INonDelegatingUnknown cuyos métodos hac<strong>en</strong> las mismas cosas que IUnknow.<br />

El método NonDelegatingQueryInterface será llamado por cualquier objeto o aplicación<br />

que quiera consultar un pin o un filtro por alguna interfaz que este implem<strong>en</strong>te. El sigui<strong>en</strong>te<br />

código ejemplo sobrescribe la función miembro que distribuye refer<strong>en</strong>cias a las interfaces<br />

ISpecifyPropertyPages y IPersistFlujo:<br />

// Muestra las interfaces persist<strong>en</strong>t flujo, property pages y Igargle.<br />

STDMETHODIMP CGargle::NonDelegatingQueryInterface(REFIID riid, void **ppv) {<br />

if (riid == IID_IGargle) {<br />

return GetInterface((IGargle *) this, ppv);<br />

} else if (riid == IID_ISpecifyPropertyPages) {<br />

return GetInterface((ISpecifyPropertyPages *) this, ppv);<br />

} else if (riid == IID_IPersistFlujo) {<br />

AddRef(); // add a refer<strong>en</strong>ce count to ourselves


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 64<br />

*ppv = (void *)(IPersistFlujo *)this;<br />

return NOERROR;<br />

} else {<br />

return CTransInPlaceFilter::NonDelegatingQueryInterface(riid, ppv);<br />

}<br />

} // NonDelegatingQueryInterface<br />

5.6.7 Funciones miembro<br />

Se <strong>de</strong>b<strong>en</strong> escribir algunas funciones miembro necesarias para el proceso <strong>de</strong><br />

conexión, tales como ajustar el tamaño <strong>de</strong>l asignador o proveer los tipos <strong>de</strong> media que se<br />

utilizarán.<br />

5.6.7.1 Función miembro Transform<br />

La función miembro Transform <strong>de</strong> nuestra clase <strong>de</strong>rivada se llama cada vez que el<br />

método IMemInputPin::Receive <strong>en</strong> el pin <strong>en</strong>trada <strong>de</strong>l filtro es llamado para transferir otra<br />

muestra. Aquí se coloca el código o <strong>de</strong>s<strong>de</strong> aquí se llaman las funciones que <strong>real</strong>izan las<br />

transformaciones requeridas, <strong>en</strong> nuestro caso los distintos procesami<strong>en</strong>tos sobre el vi<strong>de</strong>o.<br />

5.6.7.2 Función miembro CheckInputType<br />

Durante la conexión <strong>de</strong>l pin, la función miembro CheckMediaType <strong>de</strong>l pin <strong>en</strong>trada<br />

es llamada para <strong>de</strong>terminar cual <strong>de</strong> los tipos <strong>de</strong> media propuestos es aceptable. La función<br />

miembro CTransformInputPin::CheckMediaType es implem<strong>en</strong>tada para llamar a la<br />

función miembro CheckInputType <strong>de</strong> la clase filtro <strong>de</strong>rivada con el tipo <strong>de</strong> media. Se <strong>de</strong>be<br />

implem<strong>en</strong>tar para acomodar los tipos <strong>de</strong> media que nuestro filtro pue<strong>de</strong> manejar. El<br />

sigui<strong>en</strong>te código muestra parte <strong>de</strong> la función miembro Cgargle::CheckInputType, la cual<br />

rechaza cualquier tipo <strong>de</strong> media que no sea MEDIATYPE_Audio:<br />

HRESULT CGargle::CheckInputType(const CMediaType *pmt) {<br />

...<br />

// Reject non-Audio type<br />

if (pmt->majortype != MEDIATYPE_Audio) {<br />

return E_INVALIDARG;<br />

}<br />

5.6.7.3 Función miembro CheckTransform<br />

Los filtros transform pue<strong>de</strong>n modificar el tipo <strong>de</strong> media que va <strong>de</strong>l pin <strong>en</strong>trada hacia<br />

el pin salida. Entonces es necesario revisar con la función miembro CheckTransform para<br />

verificar que la transformación <strong>de</strong>s<strong>de</strong> el pin <strong>en</strong>trada hacia el pin salida es valida.<br />

5.6.7.4 Función miembro Deci<strong>de</strong>BufferSize<br />

Los filtros <strong>de</strong> transformación pue<strong>de</strong>n requerir el ajuste <strong>de</strong> las propieda<strong>de</strong>s <strong>de</strong>l<br />

asignador hacia el cual ellos <strong>real</strong>izarán la copia. En este caso, la función miembro<br />

CBaseSalidaPin::Deci<strong>de</strong>BufferSize es llamada <strong>de</strong>s<strong>de</strong> la función miembro<br />

CBaseSalidaPin::Deci<strong>de</strong>Allocator, y la clase <strong>de</strong>rivada ajusta los requerimi<strong>en</strong>tos para el


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 65<br />

buffer mediante la llamada al método IMemAllocator::SetProperties <strong>en</strong> el objeto<br />

asignador para el cual este ti<strong>en</strong>e una refer<strong>en</strong>cia.<br />

5.6.7.5 Función miembro GetMediaType<br />

Los pins prove<strong>en</strong> <strong>en</strong>umeradores para permitir a otros objetos <strong>de</strong>terminar el tipo <strong>de</strong><br />

media <strong>de</strong>l pin. Un pin provee el <strong>en</strong>umerador <strong>de</strong>l tipo <strong>de</strong> media(la interfaz<br />

I<strong>en</strong>umMediaTypes), cuya clase base implem<strong>en</strong>ta para llamar a la función miembro<br />

GetMediaType. Nuestra clase <strong>de</strong>rivada <strong>de</strong>be implem<strong>en</strong>tar esta función miembro para<br />

proveer una lista <strong>de</strong> cada media soportada.<br />

5.6.8 Filtro <strong>de</strong> efectos<br />

En DirectShow los filtros <strong>de</strong> efectos se <strong>de</strong>fin<strong>en</strong> como aquellos que aplican algún<br />

efecto a los datos multimedia, pero que no cambian el tipo <strong>de</strong> los datos.<br />

Dado que los formatos <strong>de</strong> <strong>en</strong>trada y salida son los mismos, y los efectos aplicados<br />

no pue<strong>de</strong>n cambiar el formato, estos filtros conti<strong>en</strong><strong>en</strong> un código que checa continuam<strong>en</strong>te el<br />

formato <strong>de</strong> los datos. Como utilizamos la clase CtransformFilter se <strong>de</strong>b<strong>en</strong> utilizar los<br />

métodos CheckMediaType, CTransformFilter::CheckInputType, y CheckTransform.<br />

El filtro <strong>de</strong> efectos <strong>de</strong>be implem<strong>en</strong>tar la interfaz IPersistStream si se quiere salvar<br />

el estado <strong>de</strong> los efectos <strong>en</strong> GraphEdit. Esto pue<strong>de</strong> ser <strong>de</strong> mucha ayuda durante el diseño, y<br />

lo hemos implem<strong>en</strong>tado para regresar al estado inicial <strong>de</strong>l filtro cuando se cierre el<br />

simulador GraphEdit.<br />

Si se quiere po<strong>de</strong>r manipular el efecto, se <strong>de</strong>be crear y <strong>de</strong>splegar su pagina<br />

propietaria y proveer un mecanismo para retornar las <strong>en</strong>tradas <strong>de</strong>l usuario hacia el filtro.<br />

Para lograrlo se implem<strong>en</strong>ta la clase ISpecifyPropertyPages, y se personaliza la interfaz<br />

que cambia los valores <strong>de</strong> la pagina propietaria. Se <strong>de</strong>be proveer también <strong>de</strong> los archivos<br />

fu<strong>en</strong>te que <strong>de</strong>spliegan los controles <strong>en</strong> la pagina propietaria.<br />

Para implem<strong>en</strong>tar la clase <strong>de</strong> la pagina propietaria, se crea una clase que <strong>de</strong>riva <strong>de</strong><br />

CBasePropertyPage y se implem<strong>en</strong>ta el método OnReceiveMessage, el método<br />

CPersistStream::SetDirty, y un dato miembro para cada parámetro <strong>de</strong> un efecto. Para<br />

acce<strong>de</strong>r a las dos interfaces, se <strong>de</strong>riva la clase <strong>de</strong>l filtro <strong>de</strong> efectos <strong>de</strong><br />

IspecifyPropertyPages y la interfaz personalizada. Se pue<strong>de</strong> consultar por las interfaces<br />

que se necesit<strong>en</strong> al sobrescribir el método NonDelegatingQueryInterface como se muestra<br />

<strong>en</strong> el sigui<strong>en</strong>te ejemplo.<br />

STDMETHODIMP CGargle::NonDelegatingQueryInterface(REFIID riid, void **ppv)<br />

{<br />

CheckPointer(ppv,E_POINTER);<br />

if (riid == IID_IGargle) {<br />

return GetInterface((IGargle *) this, ppv);<br />

} else if (riid == IID_ISpecifyPropertyPages) {<br />

return GetInterface((ISpecifyPropertyPages *) this, ppv);<br />

} else if (riid == IID_IPersistFlujo) {<br />

return GetInterface((IPersistFlujo *) this, ppv);


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 66<br />

}<br />

} else {<br />

return CTransInPlaceFilter::NonDelegatingQueryInterface(riid, ppv);<br />

}<br />

La interfaz personalizada <strong>de</strong>l filtro <strong>de</strong> efectos típicam<strong>en</strong>te provee un método put y<br />

uno get para cada parámetro <strong>de</strong>l efecto. Por ejemplo la interfaz IGargle provee los métodos<br />

put_GargleRate y get_GargleRate. Cuando el usuario accesa a uno <strong>de</strong> los controles <strong>en</strong> la<br />

pagina propietaria, la página g<strong>en</strong>era un m<strong>en</strong>saje <strong>de</strong> la v<strong>en</strong>tana. La función miembro<br />

OnReceiveMessage <strong>de</strong> la página propietaria maneja este m<strong>en</strong>saje. El sigui<strong>en</strong>te código<br />

<strong>de</strong>muestra la g<strong>en</strong>eración <strong>de</strong>l m<strong>en</strong>saje y su manejo. IDB_DEFAULT es el ID <strong>de</strong>l botón<br />

Default. El usuario da clic <strong>en</strong> este botón para ajustar el contraste <strong>de</strong>l vi<strong>de</strong>o a un estado<br />

<strong>de</strong>fault. La clase CContrastPropierties implem<strong>en</strong>ta la pagina propietaria y el método<br />

IContrast::put_DefaultContrastLevel ajusta el nivel <strong>de</strong> contraste a su valor por <strong>de</strong>fault.<br />

BOOL CContrastProperties::OnReceiveMessage(HWND hwnd, UINT uMsg,<br />

WPARAM wParam, LPARAM lParam)<br />

{<br />

switch (uMsg)<br />

{<br />

case WM_COMMAND:<br />

{<br />

if (LOWORD(wParam) == IDB_DEFAULT)<br />

{<br />

pIContrast()->put_DefaultContrastLevel();<br />

S<strong>en</strong>dMessage(m_hwndSli<strong>de</strong>r, TBM_SETPOS, TRUE, 0L);<br />

SetDirty();<br />

}<br />

return (LRESULT) 1;<br />

}<br />

...<br />

Los filtros <strong>de</strong> efectos usan secciones criticas internas para proteger el estado global<br />

<strong>de</strong>l filtro. Los filtros <strong>de</strong> efectos pue<strong>de</strong>n cerrar una sección critica para asegurar que el flujo<br />

<strong>de</strong> datos a través <strong>de</strong>l gráfico <strong>de</strong> filtros es serializado y que el estado global <strong>de</strong>l filtro no<br />

cambie mi<strong>en</strong>tras el efecto está ocurri<strong>en</strong>do. DirectShow cierra una sección critica al <strong>de</strong>clarar<br />

un objeto <strong>de</strong> la clase CAutoLock . Típicam<strong>en</strong>te los filtros <strong>de</strong> efectos cierran la región critica<br />

tan pronto como ellos <strong>en</strong>tran a la función que aplica el efecto. En el sigui<strong>en</strong>te fragm<strong>en</strong>to, la<br />

función que aplica el efecto es MessItAbout:<br />

// Declare the critical section data member in<br />

// the effect filter class <strong>de</strong>finition.<br />

CCritSec m_GargleLock;<br />

void CGargle::MessItAbout(PBYTE pb, int cb)<br />

{<br />

CAutoLock foo(&m_GargleLock);<br />

Los métodos put y get <strong>de</strong> las propieda<strong>de</strong>s <strong>de</strong> los efectos cierran las secciones criticas<br />

así los valores <strong>de</strong> los efectos no cambian a la mitad <strong>de</strong> una actualización.<br />

5.6.9 Programación <strong>de</strong>l filtro <strong>en</strong> C++<br />

Como lo m<strong>en</strong>cionamos arriba <strong>de</strong>rivaremos nuestro filtro <strong>de</strong> la clase<br />

CtransformFilter.<br />

class CEZrgb24 : public CtransformFilter


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 67<br />

Implem<strong>en</strong>tamos la interfaz IUnknown, <strong>en</strong> la sección public <strong>de</strong> la <strong>de</strong>finición <strong>de</strong> nuestra clase<br />

filtro creamos una instancia <strong>de</strong> CUnknown, y <strong>en</strong>tonces llamamos la macro<br />

DECLER_IUNKNOWN.<br />

public:<br />

DECLARE_IUNKNOWN;<br />

static CUnknown * WINAPI CreateInstance(LPUNKNOWN punk, HRESULT *phr);<br />

Definimos el constructor <strong>en</strong> la sección private <strong>de</strong> la clase filtro.<br />

private:<br />

// Constructor<br />

CEZrgb24(TCHAR *tszName, LPUNKNOWN punk, HRESULT *phr);<br />

Añadimos el código para <strong>real</strong>izar las funciones transform y chequeo <strong>de</strong>l InputType.<br />

// Transform<br />

// Copia la muestra <strong>de</strong> <strong>en</strong>trada hacia la muestra <strong>de</strong> salida - <strong>en</strong>tonces transforma<br />

// la muestra <strong>de</strong> salida 'in place'.<br />

HRESULT CEZrgb24::Transform(IMediaSample *pIn, IMediaSample *pOut)<br />

{<br />

// Copia las propieda<strong>de</strong>s<br />

HRESULT hr = Copy(pIn, pOut);<br />

if (FAILED(hr)) {<br />

return hr;<br />

}<br />

// Checa para ver si es <strong>tiempo</strong> <strong>de</strong> hacer la muestra<br />

CRefTime tStart, tStop ;<br />

pIn->GetTime((REFERENCE_TIME *) &tStart, (REFERENCE_TIME *) &tStop);<br />

if (tStart >= m_effectStartTime) {<br />

if (tStop FormatType() != FORMAT_Vi<strong>de</strong>oInfo) {<br />

return E_INVALIDARG;<br />

}<br />

}<br />

// Se pue<strong>de</strong> transformar este tipo?<br />

if (CanPerformEZrgb24(mtIn)) {<br />

return NOERROR;<br />

}<br />

return E_FAIL;<br />

La estructura VIDEOINFOHEADER <strong>de</strong>scribe el mapa <strong>de</strong> bits e información <strong>de</strong> la<br />

imag<strong>en</strong> <strong>de</strong> vi<strong>de</strong>o.<br />

Se implem<strong>en</strong>ta CreateInstance para nuestro objeto filtro.<br />

// CreateInstance<br />

//<br />

// Usada por las clases base <strong>de</strong> DirectShow para crear instancias<br />

//<br />

CUnknown *CEZrgb24Properties::CreateInstance(LPUNKNOWN lpunk, HRESULT *phr)<br />

{<br />

CUnknown *punk = new CEZrgb24Properties(lpunk, phr);<br />

if (punk == NULL) {<br />

*phr = E_OUTOFMEMORY;<br />

}<br />

return punk;<br />

} // CreateInstance


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 68<br />

Se <strong>de</strong>clara un arreglo global g_Templates objeto CFactoryTemplate para informar a<br />

la clase factory como acce<strong>de</strong>r a la función CreateInstance:<br />

// La clase factory llamará a CreateInstance<br />

CFactoryTemplate g_Templates[] = {<br />

{ L"Image Effects"<br />

, &CLSID_EZrgb24<br />

, CEZrgb24::CreateInstance<br />

, NULL<br />

, &sudEZrgb24 }<br />

,<br />

{ L"Special Effects"<br />

, &CLSID_EZrgb24PropertyPage<br />

, CEZrgb24Properties::CreateInstance }<br />

};<br />

Observe que se ha añadido parámetros para la pagina propietaria que manejará el filtro.<br />

Se g<strong>en</strong>era un GUID par el objeto filtro, este i<strong>de</strong>ntificador, permite que nuestro filtro<br />

t<strong>en</strong>ga un numero único <strong>en</strong> todo el mundo, y así su posible uso <strong>en</strong> ambi<strong>en</strong>tes distribuidos.<br />

Para g<strong>en</strong>erar un GUID, se ejecuta el programa g<strong>en</strong>erador uuidg<strong>en</strong>.exe ubicado <strong>en</strong> el<br />

subdirectorio bin <strong>de</strong> directX. Finalm<strong>en</strong>te se agrega el GUID para nuestro filtro quedando<br />

como sigue:<br />

DEFINE_GUID(CLSID_EZrgb24,<br />

0x8b498501, 0x1218, 0x11cf, 0xad, 0xc4, 0x0, 0xa0, 0xd1, 0x0, 0x4, 0x1b);<br />

Dado que nuestro filtro implem<strong>en</strong>ta una interfaz que no se <strong>en</strong>cu<strong>en</strong>tra hecha <strong>en</strong> la<br />

clase base, nos referimos a la clase propietaria, <strong>en</strong>tonces <strong>de</strong>bemos escribir la función<br />

NonDelegatingQueryInterface y regresar apuntadores a la interfaz implem<strong>en</strong>tada. La<br />

función se coloca <strong>en</strong> la sección public <strong>de</strong> la <strong>de</strong>finición <strong>de</strong> nuestra clase filtro.<br />

// NonDelegatingQueryInterface<br />

//<br />

// Pres<strong>en</strong>ta las paginas propietarias IIPEffect y ISpecifyPropertyPages<br />

//<br />

STDMETHODIMP CEZrgb24::NonDelegatingQueryInterface(REFIID riid, void **ppv)<br />

{<br />

CheckPointer(ppv,E_POINTER);<br />

if (riid == IID_IIPEffect) {<br />

return GetInterface((IIPEffect *) this, ppv);<br />

} else if (riid == IID_ISpecifyPropertyPages) {<br />

return GetInterface((ISpecifyPropertyPages *) this, ppv);<br />

} else {<br />

return CTransformFilter::NonDelegatingQueryInterface(riid, ppv);<br />

}<br />

} // NonDelegatingQueryInterface<br />

El Manejador <strong>de</strong>l gráfico <strong>de</strong> filtros utiliza las <strong>en</strong>tradas <strong>de</strong> registro <strong>de</strong> nuestro filtro<br />

para configurarlo asi como a sus conexiones. Nosotros proveemos la información <strong>de</strong><br />

registro <strong>de</strong> nuestro filtro <strong>en</strong> las estructuras AMOVIESETUP_MEDIATYPE,<br />

AMOVIESETUP_PIN, y AMOVIESETUP_FILTER.<br />

La estructura AMOVIESETUP_MEDIATYPE manti<strong>en</strong>e información <strong>de</strong> registro<br />

acerca <strong>de</strong> los tipos <strong>de</strong> media que nuestro filtro soporta.<br />

// Información <strong>de</strong> Setup<br />

const AMOVIESETUP_MEDIATYPE sudPinTypes =


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 69<br />

{<br />

};<br />

&MEDIATYPE_Vi<strong>de</strong>o, // tipo Major<br />

&MEDIASUBTYPE_NULL // tipo Minor<br />

Incorporamos la estructura AMOVIESETUP_PIN que manti<strong>en</strong>e un registro sobre<br />

los pines que nuestro filtro soporta.<br />

const AMOVIESETUP_PIN sudpPins[] =<br />

{<br />

{ L"Input", // Nombre <strong>de</strong> Pins<br />

FALSE, // Será r<strong>en</strong><strong>de</strong>red<br />

FALSE, // Este no es un salida<br />

FALSE, // No estamos permiti<strong>en</strong>do ninguno<br />

FALSE, // Permitimos muchos<br />

&CLSID_NULL, // Conexiones al filtro<br />

NULL, // Conexion al pin<br />

1, // Numero <strong>de</strong> tipos<br />

&sudPinTypes // Informacion <strong>de</strong>l Pin<br />

},<br />

{ L"Salida", // Nombre <strong>de</strong>l Pin<br />

FALSE, // Sera r<strong>en</strong><strong>de</strong>red<br />

TRUE, // Este es un salida<br />

FALSE, // No permitimos ninguno<br />

FALSE, // Y soportamos muchos<br />

&CLSID_NULL, // Conexiones al filtro<br />

NULL, // Conexion al pin<br />

1, // Numero <strong>de</strong> tipos<br />

&sudPinTypes // Informacion <strong>de</strong>l pin<br />

}<br />

};<br />

Proveemos la estructura AMOVIESETUP_FILTER que manti<strong>en</strong>e información <strong>de</strong><br />

nuestro objeto filtro, a saber: su CLSID, <strong>de</strong>scripción, numero <strong>de</strong> pins, el nombre <strong>de</strong> la<br />

estructura <strong>de</strong>l pin, y el merito <strong>de</strong>l filtro. El merito controla el or<strong>de</strong>n <strong>en</strong> el cual el Manejador<br />

<strong>de</strong>l gráfico <strong>de</strong> filtros accesa a nuestro filtro.<br />

const AMOVIESETUP_FILTER sudEZrgb24 =<br />

{<br />

&CLSID_EZrgb24, // CLSID <strong>de</strong>l filtro<br />

L"Image Effects", // nombre<br />

MERIT_DO_NOT_USE, // Merito <strong>de</strong>l filtro<br />

2, // Numero <strong>de</strong> pins<br />

sudpPins // Informacion <strong>de</strong>l Pin<br />

};<br />

Solo queda <strong>en</strong>tonces incluir un archivo <strong>de</strong> <strong>de</strong>finición (.<strong>de</strong>f) que exporta las<br />

funciones DLL, <strong>en</strong> nuestro caso:<br />

LIBRARY EZrgb24.ax<br />

EXPORTS<br />

DllGetClassObject PRIVATE<br />

DllCanUnloadNow PRIVATE<br />

DllRegisterServer PRIVATE<br />

DllUnregisterServer PRIVATE<br />

5.6.10 Algoritmos <strong>de</strong> procesami<strong>en</strong>to<br />

Se han elaborado nueve procesami<strong>en</strong>tos distintos sobre la imag<strong>en</strong>, todos incluidos<br />

<strong>de</strong>ntro <strong>de</strong> la función Transform. Se explica cada uno <strong>de</strong> ellos junto con las limitaciones<br />

<strong>en</strong>contradas. Consi<strong>de</strong>rese <strong>en</strong> todos los casos a F ( x,<br />

y)<br />

como la función vectorial <strong>de</strong> imag<strong>en</strong>


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 70<br />

original con tres compon<strong>en</strong>tes R, G y B para cada color <strong>de</strong>l espacio RGB y G ( x,<br />

y)<br />

como la<br />

imag<strong>en</strong> resultado <strong>de</strong> la transformación.<br />

5.6.10.1 Efecto rojo<br />

Este es un filtro s<strong>en</strong>cillo que elimina las compon<strong>en</strong>tes <strong>de</strong> color ver<strong>de</strong> y azul <strong>de</strong>l<br />

espacio <strong>de</strong> color RGB.<br />

( x,<br />

y)<br />

= F(<br />

x,<br />

y)<br />

− f ( x,<br />

y)<br />

+ f ( x,<br />

y)<br />

( )<br />

g R<br />

G<br />

B<br />

Lo único que se hace es igualar las compon<strong>en</strong>tes no <strong>de</strong>seadas a cero y esto resulta<br />

bastante s<strong>en</strong>cillo dado que se ti<strong>en</strong><strong>en</strong> un formato <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> píxeles RGB. La estructura<br />

RGBTRIPLE manti<strong>en</strong>e un miembro para cada compon<strong>en</strong>te <strong>de</strong> color. numPixels es el<br />

numero total <strong>de</strong> píxeles <strong>en</strong> la v<strong>en</strong>tana <strong>de</strong> vi<strong>de</strong>o. Prgb manti<strong>en</strong>e un apuntador al píxel actual.<br />

prgb = (RGBTRIPLE*) pData;<br />

for (iPixel=0; iPixel < numPixels; iPixel++, prgb++) {<br />

prgb->rgbtGre<strong>en</strong> = 0;<br />

prgb->rgbtBlue = 0;<br />

}<br />

5.6.10.2 Efecto ruido<br />

Figura 5.14 Filtro rojo<br />

Se agrega ruido Gausiano a la imag<strong>en</strong> usando la función <strong>de</strong> g<strong>en</strong>eración <strong>de</strong><br />

numeros aleatorios rand(), por lo tanto:<br />

2<br />

G ( x,<br />

y)<br />

= F(<br />

x,<br />

y)<br />

con una probabilidad p =<br />

3<br />

1<br />

y G ( x,<br />

y)<br />

= 255 con una probabilidad p =<br />

3<br />

Dado que se ti<strong>en</strong>e 1 byte por cada color, <strong>en</strong> <strong>de</strong>cimal el máximo valor es 255 para<br />

cada compon<strong>en</strong>te. Igualando todas las compon<strong>en</strong>tes a 255 obt<strong>en</strong>emos el blanco y esto lo<br />

hacemos <strong>de</strong> manera aleatoria <strong>en</strong> cada píxel produciéndose un efecto <strong>de</strong> ruido <strong>en</strong> la<br />

proporción <strong>de</strong>seada. Dado que rand() % 3 produce números <strong>en</strong>tre 0 y 2 <strong>en</strong>tonces la tercera<br />

parte <strong>de</strong> los píxeles <strong>en</strong> la pantalla serán blancos.<br />

prgb = (RGBTRIPLE*) pData;


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 71<br />

for (iPixel=0; iPixel < numPixels; iPixel++, prgb++) {<br />

if(!(rand() % 3)) {<br />

prgb->rgbtGre<strong>en</strong> = 255;<br />

prgb->rgbtBlue = 255;<br />

prgb->rgbtRed = 255;<br />

}<br />

}<br />

5.6.10.3 Efecto imag<strong>en</strong> BMP<br />

Figura 5.15 Adición <strong>de</strong> ruido<br />

Aquí se superpone una imag<strong>en</strong> previam<strong>en</strong>te almac<strong>en</strong>ada <strong>en</strong> un archivo <strong>de</strong>l disco<br />

duro con formato BMP. La imag<strong>en</strong> se carga <strong>en</strong> un arreglo temporal, sin embargo esta<br />

imag<strong>en</strong> no pue<strong>de</strong> cont<strong>en</strong>er un numero <strong>de</strong> píxeles mayor a 5000, porque el sistema se cae,<br />

consi<strong>de</strong>ro que el motivo se <strong>de</strong>be a una cantidad <strong>de</strong> memoria preasignada al filtro y<br />

sobrepasarla la colapsa. Se p<strong>en</strong>só que el apuntador al píxel actual prgb siempre se<br />

<strong>en</strong>contraba <strong>en</strong> la esquina superior <strong>de</strong>recha <strong>de</strong> la v<strong>en</strong>tana <strong>de</strong> vi<strong>de</strong>o, sin embargo <strong>de</strong>p<strong>en</strong>di<strong>en</strong>do<br />

<strong>de</strong> las características <strong>de</strong> la computadora y el tipo <strong>de</strong> procesami<strong>en</strong>to el orig<strong>en</strong> se pue<strong>de</strong><br />

ubicar a <strong>en</strong> la izquierda y a la mitad <strong>de</strong>l alto <strong>de</strong> la v<strong>en</strong>tana <strong>de</strong> vi<strong>de</strong>o. En nuestro caso se<br />

ubicó <strong>en</strong> la esquina inferior izquierda y el conteo <strong>de</strong> píxeles es hacia arriba y hacia la<br />

<strong>de</strong>recha. Es por ese motivo que la imag<strong>en</strong> BMP se <strong>de</strong>be almac<strong>en</strong>ar invertida(<strong>de</strong> cabeza)<br />

para evitar un procesami<strong>en</strong>to adicional. La imag<strong>en</strong> se almac<strong>en</strong>ó <strong>en</strong> el arreglo bidim<strong>en</strong>sional<br />

bmiColors. El color ver<strong>de</strong> puro se utilizó como un color transpar<strong>en</strong>te dado que nuestra<br />

imag<strong>en</strong> no lo cont<strong>en</strong>ía. Los for adicionales son para posicionar la imag<strong>en</strong> <strong>en</strong> la pantalla.<br />

prgb = (RGBTRIPLE*) pData;<br />

//offset <strong>de</strong> la imag<strong>en</strong> superpuesta<br />

for(i = 0; i < (int)((cyImage/25)*(1 + cxImage)); i++, prgb++);<br />

for(iPixel = 0; iPixel < 60; iPixel++) {<br />

for(jPixel = 0; jPixel < 98; jPixel++, prgb++){<br />

if(bmiColors[iPixel][jPixel].rgbGre<strong>en</strong> != 255) {<br />

prgb->rgbtRed = bmiColors[iPixel][jPixel].rgbRed;<br />

prgb->rgbtGre<strong>en</strong> = bmiColors[iPixel][jPixel].rgbGre<strong>en</strong>;<br />

prgb->rgbtBlue = bmiColors[iPixel][jPixel].rgbBlue;<br />

}<br />

}<br />

for(jPixel = 98; jPixel < cxImage; jPixel++, prgb++);<br />

` }


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 72<br />

5.6.10.4 Efecto imag<strong>en</strong> BMP diluida<br />

Figura 5.16 Superposición <strong>de</strong> imag<strong>en</strong> BMP<br />

En este efecto se diluye la imag<strong>en</strong> con el vi<strong>de</strong>o, promediando los valores <strong>de</strong> la<br />

imag<strong>en</strong> y <strong>de</strong>l vi<strong>de</strong>o obt<strong>en</strong>iéndose un 50% <strong>de</strong> cada una. Se pue<strong>de</strong> obt<strong>en</strong>er cualquier<br />

proporción <strong>de</strong> mezcla sin mayor problema. Asi <strong>en</strong>tonces solo para la imag<strong>en</strong> BMP:<br />

F(<br />

x,<br />

y)<br />

+ F<br />

G(<br />

x,<br />

y)<br />

=<br />

2<br />

BMP<br />

( x,<br />

y)<br />

for(i = 0; i < (int)((cyImage/25)*(1 + cxImage)); i++, prgb++);<br />

for(iPixel = 0; iPixel < 60; iPixel++) {<br />

for(jPixel = 0; jPixel < 98; jPixel++, prgb++){<br />

if(bmiColors[iPixel][jPixel].rgbGre<strong>en</strong> != 255) {<br />

prgb->rgbtRed = (prgb->rgbtRed + bmiColors[iPixel][jPixel].rgbRed)/2;<br />

prgb->rgbtGre<strong>en</strong> = (prgb->rgbtGre<strong>en</strong> + bmiColors[iPixel][jPixel].rgbGre<strong>en</strong>)/2;<br />

prgb->rgbtBlue = (prgb->rgbtBlue + bmiColors[iPixel][jPixel].rgbBlue)/2;<br />

}<br />

}<br />

for(jPixel = 98; jPixel < cxImage; jPixel++, prgb++);<br />

}<br />

5.6.10.5 Efecto Rayos X<br />

Figura 5.17 Mezcla <strong>de</strong> imag<strong>en</strong> BMP con el vi<strong>de</strong>o<br />

Este es un efecto que produce el negativo <strong>de</strong> la imag<strong>en</strong>, aqui se inviert<strong>en</strong> los bits, 1<br />

por 0 y viceversa <strong>en</strong> la imag<strong>en</strong> <strong>digital</strong>izada.


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 73<br />

( F(<br />

x,<br />

) )<br />

G ( x,<br />

y)<br />

= NOT y<br />

prgb = (RGBTRIPLE*) pData;<br />

for (iPixel=0; iPixel < numPixels; iPixel++, prgb++) {<br />

prgb->rgbtRed = (BYTE) (~prgb->rgbtRed);<br />

prgb->rgbtGre<strong>en</strong> = (BYTE) (~prgb->rgbtGre<strong>en</strong>);<br />

prgb->rgbtBlue = (BYTE) (~prgb->rgbtBlue);<br />

}<br />

5.6.10.6 Efecto Poster<br />

Figura 5.18 Efecto <strong>de</strong> inversión <strong>de</strong> bits<br />

Se obti<strong>en</strong>e un plano <strong>de</strong> bit correspondi<strong>en</strong>te a los tres bits mas significativos, esto es,<br />

se hac<strong>en</strong> cero los 5 bits m<strong>en</strong>os significativos para cada compon<strong>en</strong>te <strong>de</strong> color, esto logra que<br />

las variaciones ligeras <strong>de</strong> color sean ignoradas y se t<strong>en</strong>gan pocos colores <strong>en</strong> la imag<strong>en</strong>.<br />

Obsérvese que se logra haci<strong>en</strong>do una operación AND a nivel <strong>de</strong> bits <strong>de</strong>l píxel con el byte<br />

11100000 .<br />

G ( x,<br />

y)<br />

= F(<br />

x,<br />

y)<br />

AND(<br />

11100000)<br />

prgb = (RGBTRIPLE*) pData;<br />

for (iPixel=0; iPixel < numPixels; iPixel++, prgb++) {<br />

prgb->rgbtRed = (BYTE) (prgb->rgbtRed & 0xe0);<br />

prgb->rgbtGre<strong>en</strong> = (BYTE) (prgb->rgbtGre<strong>en</strong> & 0xe0);<br />

prgb->rgbtBlue = (BYTE) (prgb->rgbtBlue & 0xe0);<br />

}<br />

Figura 5.19 Efecto <strong>de</strong> poster


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 74<br />

5.6.10.7 Efecto Borroso<br />

Para cada píxel se toma un píxel y el sigui<strong>en</strong>te a dos píxeles a su <strong>de</strong>recha, los<br />

promedia y lo sobrescribe, lográndose así un efecto <strong>de</strong> imag<strong>en</strong> borrosa.<br />

F(<br />

x + 1,<br />

y)<br />

+ F(<br />

x + 2,<br />

y)<br />

G(<br />

x,<br />

y)<br />

=<br />

2<br />

prgb = (RGBTRIPLE*) pData;<br />

for (y = 0 ; y < pvi->bmiHea<strong>de</strong>r.biHeight; y++) {<br />

for (x = 2 ; x < pvi->bmiHea<strong>de</strong>r.biWidth; x++, prgb++) {<br />

prgb->rgbtRed = (BYTE) ((prgb->rgbtRed + prgb[2].rgbtRed) >> 1);<br />

prgb->rgbtGre<strong>en</strong> = (BYTE) ((prgb->rgbtGre<strong>en</strong> + prgb[2].rgbtGre<strong>en</strong>) >> 1);<br />

prgb->rgbtBlue = (BYTE) ((prgb->rgbtBlue + prgb[2].rgbtBlue) >> 1);<br />

}<br />

prgb +=2;<br />

}<br />

Obsérvese la operación <strong>de</strong> bits que también podía ser aplicada al efecto BMP<br />

diluida, sin embargo dificultaría otras proporciones <strong>de</strong> la imág<strong>en</strong>.<br />

5.6.10.8 Efecto Gris<br />

Figura 5.20 Efecto <strong>de</strong> imag<strong>en</strong> borrosa<br />

En este efecto se cambia la imag<strong>en</strong> a una escala <strong>de</strong> grises. Un calculo estándar <strong>en</strong><br />

base a las compon<strong>en</strong>tes RGB es el sigui<strong>en</strong>te:<br />

30 f<br />

g(<br />

x,<br />

y)<br />

=<br />

R<br />

( x,<br />

y)<br />

+ 59 f G ( x,<br />

y)<br />

+ 11 f<br />

100<br />

Una mayor velocidad se obti<strong>en</strong>e con la sigui<strong>en</strong>te simplificación:<br />

f R ( x,<br />

y)<br />

+ f G ( x,<br />

y)<br />

g(<br />

x,<br />

y)<br />

=<br />

2<br />

prgb = (RGBTRIPLE*) pData;<br />

for (iPixel=0; iPixel < numPixels ; iPixel++, prgb++) {<br />

grey = (prgb->rgbtRed + prgb->rgbtGre<strong>en</strong>) >> 1;<br />

prgb->rgbtRed = prgb->rgbtGre<strong>en</strong> = prgb->rgbtBlue = (BYTE) grey;<br />

}<br />

B<br />

( x,<br />

y)


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 75<br />

5.6.10.9 Efecto Realce<br />

Figura 5.20 Vi<strong>de</strong>o <strong>en</strong> escala <strong>de</strong> grises<br />

En este caso hacemos una <strong>de</strong>tección <strong>de</strong> bor<strong>de</strong> aplicando el gradi<strong>en</strong>te a la función<br />

imag<strong>en</strong>.<br />

⎡∆f<br />

∆f<br />

⎤<br />

∇f<br />

( x,<br />

y)<br />

= [ Gx<br />

, G y ] = ⎢ , ⎥<br />

⎣ ∆x<br />

∆y<br />

⎦<br />

repres<strong>en</strong>tada por las mascaras:<br />

∆f<br />

Gx =<br />

∆x<br />

-1 1<br />

-1<br />

1<br />

*f(x,y)<br />

*f(x,y)<br />

G x<br />

∆f<br />

=<br />

∆x<br />

Si los valores <strong>de</strong> grises no son difer<strong>en</strong>tes <strong>en</strong>tonces se substituye un valor <strong>de</strong> gris<br />

intermedio, es <strong>de</strong>cir (128, 128, 128). Si hay gran<strong>de</strong>s difer<strong>en</strong>cias (<strong>en</strong> contornos) <strong>en</strong>tonces se<br />

alejarán mas <strong>de</strong> la escala <strong>de</strong> gris intermedio.<br />

prgb = (RGBTRIPLE*) pData;<br />

for (y = 0 ; y < pvi->bmiHea<strong>de</strong>r.biHeight; y++) {<br />

grey2 = (prgb->rgbtRed + prgb->rgbtGre<strong>en</strong>) >> 1;<br />

prgb->rgbtRed = prgb->rgbtGre<strong>en</strong> = prgb->rgbtBlue = (BYTE) 128;<br />

prgb++;<br />

for (x = 1 ; x < pvi->bmiHea<strong>de</strong>r.biWidth; x++) {<br />

grey = (prgb->rgbtRed + prgb->rgbtGre<strong>en</strong>) >> 1;<br />

temp = grey - grey2;<br />

if (temp > 127) temp = 127;<br />

if (temp < -127) temp = -127;<br />

temp += 128;<br />

prgb->rgbtRed = prgb->rgbtGre<strong>en</strong> = prgb->rgbtBlue = (BYTE) temp;<br />

grey2 = grey;<br />

prgb++;<br />

}<br />

}


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 76<br />

Figura 5.21 Efecto <strong>de</strong> <strong>real</strong>ce


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 77<br />

5.7 Aplicación<br />

La aplicación construye <strong>en</strong> primera instancia el gráfico <strong>de</strong> filtros completo <strong>de</strong><br />

manera automática. La configuración obt<strong>en</strong>ida <strong>de</strong>p<strong>en</strong><strong>de</strong> <strong>de</strong> la fu<strong>en</strong>te seleccionada por el<br />

usuario (tarjeta <strong>de</strong> TV o un archivo multimedia), si la fu<strong>en</strong>te es un archivo, se <strong>de</strong>be crear<br />

una instancia <strong>de</strong>l admiministrador <strong>de</strong>l grafico <strong>de</strong> filtros que cree el gráfico <strong>de</strong> filtros y lo<br />

ponga <strong>en</strong> ejecución.<br />

Por otra parte <strong>de</strong>be proporcionar la v<strong>en</strong>tana <strong>de</strong> vi<strong>de</strong>o al sistema operativo para su<br />

<strong>de</strong>spliegue <strong>en</strong> la v<strong>en</strong>tana <strong>de</strong> la aplicación. También se requiere <strong>de</strong>splegar la pagina<br />

propietaria.<br />

Si el usuario seleccionó la tarjeta <strong>de</strong> captura <strong>de</strong> vi<strong>de</strong>o <strong>en</strong>tonces se requiere la<br />

elaboración automática <strong>de</strong>l gráfico <strong>de</strong> captura, para <strong>de</strong>spués insertar el filtro <strong>de</strong> efectos y<br />

finalm<strong>en</strong>te la reproducción <strong>de</strong>l vi<strong>de</strong>o <strong>en</strong> la v<strong>en</strong>tana <strong>de</strong> la aplicación. Veremos <strong>en</strong> los<br />

sigui<strong>en</strong>tes apartados casa uno <strong>de</strong> los pasos para la elaboración <strong>de</strong> nuestra aplicación.<br />

5.7.1 Ejecución <strong>de</strong> un archivo<br />

Una <strong>de</strong> las funciones <strong>de</strong> la aplicación es ejecutar un archivo multimedia. Esto<br />

incluye cuatro pasos básicos:<br />

1. Crear una instancia <strong>de</strong>l Manejador <strong>de</strong>l Gráfico <strong>de</strong> filtros.<br />

2. Usar el Manejador <strong>de</strong>l gráfico <strong>de</strong> filtros para crear un grafico <strong>de</strong> filtros.<br />

3. Usar el Manejador <strong>de</strong>l gráfico <strong>de</strong> filtros para ejecutar el gráfico <strong>de</strong> filtros<br />

4. Esperar a que la ejecución se complete<br />

Para llevar a cabo estas operaciones se hace uso <strong>de</strong> las sigui<strong>en</strong>tes interfaces COM:<br />

• IGraphBuil<strong>de</strong>r: Construye el grafico <strong>de</strong> filtros.<br />

• IMediaControl: Maneja el flujo <strong>de</strong> datos <strong>en</strong> el gráfico <strong>de</strong> filtros.<br />

• IMediaEv<strong>en</strong>t: Maneja los ev<strong>en</strong>tos <strong>en</strong> el gráfico <strong>de</strong> filtros.<br />

Iniciamos llamando a la función CoInitialize, la cual inicializa la librería COM.<br />

Entonces llamamos a la función CoCreateInstance para crear el Manejador <strong>de</strong>l gráfico <strong>de</strong><br />

filtros.<br />

IGraphBuil<strong>de</strong>r *pGraph;<br />

CoInitialize(NULL);<br />

CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,<br />

IID_IGraphBuil<strong>de</strong>r, (void **)&pGB);


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 78<br />

La función CoCreateInstance regresa un apuntador a la interfaz IgraphBuil<strong>de</strong>r <strong>de</strong>l<br />

Manejador <strong>de</strong>l gráfico <strong>de</strong> filtros. Utilizamos este apuntador para accesar a las otras dos<br />

interfaces IMediaControl y IMediaEv<strong>en</strong>t:<br />

IMediaControl *pMC = NULL;<br />

IMediaEv<strong>en</strong>tEx *pME = NULL;<br />

pGB->QueryInterface(IID_IMediaControl, (void **)&pMC);<br />

pGB->QueryInterface(IID_IMediaEv<strong>en</strong>tEx, (void **)&pME);<br />

Posteriorm<strong>en</strong>te se coloca el corazón <strong>de</strong>l programa<br />

pGB->R<strong>en</strong><strong>de</strong>rFile(L"C:\\Example.avi", NULL);<br />

pMediaControl->Run();<br />

El método IGraphBuil<strong>de</strong>r::R<strong>en</strong><strong>de</strong>rFile construye un gráfico <strong>de</strong> filtros que<br />

ejecutará el archivo especificado. El prefijo “L” convierte una ca<strong>de</strong>na ASCII a una ca<strong>de</strong>na<br />

Unico<strong>de</strong> .<br />

Después que el Manejador <strong>de</strong>l gráfico <strong>de</strong> filtros ha construido el grafico, este se<br />

<strong>en</strong>cu<strong>en</strong>tra listo para ejecutarse. El método Run lo lleva a cabo, y los datos multimedia<br />

comi<strong>en</strong>zan a circular <strong>en</strong> el grafico <strong>de</strong> filtros.<br />

El gráfico <strong>de</strong> filtros queda configurado <strong>en</strong>tonces como <strong>en</strong> la figura 5.23.<br />

Figura 5.23 Configuración automática <strong>de</strong>l gráfico <strong>de</strong> filtros<br />

En el pres<strong>en</strong>te trabajo se requiere añadir el filtro <strong>de</strong> efectos que construimos por lo<br />

cual se proce<strong>de</strong> a <strong>de</strong>sconectar el filtro r<strong>en</strong><strong>de</strong>rer y <strong>real</strong>izar la conexión <strong>de</strong> nuestro filtro como<br />

sigue:<br />

// Desconectamos los últimos dos filtros <strong>de</strong>l grafico<br />

EnumFilters("MPEG Vi<strong>de</strong>o Deco<strong>de</strong>r", PINDIR_SALIDA); //Busca el salida pin <strong>de</strong>l p<strong>en</strong>ultimo<br />

filtro...<br />

hr = pGB->Disconnect(pOutPin);<br />

EnumFilters("Vi<strong>de</strong>o R<strong>en</strong><strong>de</strong>rer", PINDIR_INPUT); //Busca el <strong>en</strong>tradapin <strong>de</strong>l ultimo filtro...<br />

hr = pGB->Disconnect(pInputPin);<br />

// Añadimos el filtro <strong>de</strong> efectos <strong>en</strong> la imag<strong>en</strong><br />

hr = CoCreateInstance(CLSID_EZrgb24, NULL, CLSCTX_INPROC_SERVER,<br />

IID_IBaseFilter, reinterpret_cast(&pFX));<br />

hr = pGB->AddFilter(pFX, L"Image Effects");<br />

//Conectamos filtro <strong>de</strong> efectos y MPEG vi<strong>de</strong>o <strong>de</strong>co<strong>de</strong>r<br />

EnumFilters("Image Effects", PINDIR_INPUT); // Busca <strong>en</strong>tradapin <strong>de</strong> filtro Efectos<br />

hr = pGB->Connect(pOutPin, pInputPin);<br />

//Raconexion automatica <strong>en</strong>tre Image Effects y vi<strong>de</strong>o r<strong>en</strong><strong>de</strong>r<br />

EnumFilters("Image Effects", PINDIR_SALIDA);<br />

EnumFilters("Vi<strong>de</strong>o R<strong>en</strong><strong>de</strong>rer", PINDIR_INPUT);<br />

hr = pGB->Connect(pOutPin, pInputPin);<br />

El Gráfico <strong>de</strong> filtros resultante <strong>en</strong>tonces se muestra <strong>en</strong> la figura 5.24.


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 79<br />

Figura 5.24 Gráfico con el filtro <strong>de</strong> efectos incorporado<br />

5.7.2 Ajuste <strong>de</strong> la v<strong>en</strong>tana <strong>de</strong> vi<strong>de</strong>o<br />

Cuando se pres<strong>en</strong>ta un archivo <strong>de</strong> vi<strong>de</strong>o, el grafico <strong>de</strong> filtros cont<strong>en</strong>drá un filtro<br />

vi<strong>de</strong>o r<strong>en</strong><strong>de</strong>rer. El vi<strong>de</strong>o r<strong>en</strong><strong>de</strong>rer toma datos <strong>de</strong> vi<strong>de</strong>o sin comprimir como <strong>en</strong>trada y<br />

pres<strong>en</strong>ta estos hacia la pantalla <strong>de</strong>ntro <strong>de</strong> una v<strong>en</strong>tana. La v<strong>en</strong>tana <strong>de</strong> vi<strong>de</strong>o playback es una<br />

v<strong>en</strong>tana totalm<strong>en</strong>te in<strong>de</strong>p<strong>en</strong>di<strong>en</strong>te con sus propios bor<strong>de</strong>s y barra <strong>de</strong> titulo. Pero si se<br />

requiere que aparezca <strong>en</strong> una v<strong>en</strong>tana creada por nuestra aplicación, se <strong>de</strong>be hacer que la<br />

v<strong>en</strong>tana <strong>de</strong> vi<strong>de</strong>o sea una hija <strong>de</strong> la v<strong>en</strong>tana <strong>de</strong> la aplicación. Esto se logra ajustando las<br />

propieda<strong>de</strong>s <strong>de</strong> la v<strong>en</strong>tana <strong>de</strong> vi<strong>de</strong>o para especificar el propietario, el estilo, y posición <strong>de</strong> la<br />

v<strong>en</strong>tana, mediante la interfaz IVi<strong>de</strong>oWindow.<br />

Para pegar la v<strong>en</strong>tana <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> la <strong>de</strong> la aplicación <strong>en</strong>tonces se llama al método<br />

IVi<strong>de</strong>oWindow::put_Owner y se le pasa un handle a la v<strong>en</strong>tana propietaria. Este método<br />

toma una variable <strong>de</strong>l tipo OAHWND.<br />

IVi<strong>de</strong>oWindow *pVW = NULL;<br />

pGB->QueryInterface(IID_IVi<strong>de</strong>oWindow, (void **)&pVW);<br />

JIF(pVW->put_Owner((OAHWND)ghApp));<br />

Se cambia el estilo <strong>de</strong> la v<strong>en</strong>tana <strong>de</strong> vi<strong>de</strong>o a una v<strong>en</strong>tana hija. Esto mediante el<br />

método IVi<strong>de</strong>oWindow::put_WindowStyle pasándole una combinación <strong>de</strong> ban<strong>de</strong>ras. La<br />

ban<strong>de</strong>ra WS_CHILD indica que la v<strong>en</strong>tana es una v<strong>en</strong>tana hija; la v<strong>en</strong>tana<br />

WS_CLIPSIBLINGS previ<strong>en</strong>e a la v<strong>en</strong>tana <strong>de</strong> dibujar <strong>de</strong>ntro <strong>de</strong>l área cli<strong>en</strong>te <strong>de</strong> otra<br />

v<strong>en</strong>tana hija.<br />

pVW->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);<br />

Se ajusta la posición <strong>de</strong> la v<strong>en</strong>tana <strong>de</strong> vi<strong>de</strong>o mediante una llamada al método<br />

IVi<strong>de</strong>oWindow::SetWindowPosition. Este método toma las coor<strong>de</strong>nadas <strong>de</strong>l dispositivo<br />

especificando la esquina superior izquierda, ancho y alto <strong>de</strong> la v<strong>en</strong>tana.<br />

RECT rect;<br />

GetCli<strong>en</strong>tRect(ghApp, &rect);<br />

pVW->SetWindowPosition(rect.left, rect.top, rect.right, rect.bottom);<br />

Antes <strong>de</strong> que la aplicación salga, es importante que se ajuste la visibilidad <strong>de</strong> la<br />

v<strong>en</strong>tana <strong>de</strong> vi<strong>de</strong>o a false. De otro modo, un reman<strong>en</strong>te <strong>de</strong> imag<strong>en</strong> <strong>de</strong> vi<strong>de</strong>o quedaría <strong>en</strong> la<br />

pantalla y el usuario no podría quitarlo. Después se restaura el valor <strong>de</strong> owner a NULL; <strong>de</strong><br />

otro modo los m<strong>en</strong>sajes serán <strong>en</strong>viados a la v<strong>en</strong>tana equivocada causando errores.


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 80<br />

pVW->put_Visible(OAFALSE);<br />

hr = pVW->put_Owner(NULL);<br />

5.7.3 Despliegue <strong>de</strong> la pagina propietaria<br />

El filtro <strong>de</strong> efectos múltiples que añadimos soporta una pagina propietaria mediante<br />

la cual po<strong>de</strong>mos cambiar los efectos.<br />

Los filtros con pagina propietaria expon<strong>en</strong> la interfaz ISpecifyPropertyPages. Para<br />

<strong>de</strong>terminar si un filtro <strong>de</strong>fine una pagina propietaria, se consulta al filtro mediante<br />

QueryInterface.<br />

Dado que nosotros creamos una instancia <strong>de</strong>l filtro, ya t<strong>en</strong>emos un apuntador al<br />

filtro <strong>de</strong> efectos, <strong>en</strong>tonces solo requerimos llamar al método<br />

ISpecifyPropertyPages::GetPages. Este método ll<strong>en</strong>a un arreglo <strong>de</strong> conteo <strong>de</strong><br />

i<strong>de</strong>ntificadores globales únicos (GUIDs) con los i<strong>de</strong>ntificadores <strong>de</strong> clases (CLSID) <strong>de</strong> cada<br />

pagina propietaria. Un arreglo <strong>de</strong> conteo es <strong>de</strong>finido por una estructura CAUUID, la cual se<br />

<strong>de</strong>be asignar pero no utilizar. El método GetPages localiza el arreglo, el cual está cont<strong>en</strong>ido<br />

<strong>en</strong> el miembro pElems <strong>de</strong> la estructura CAUUID. Cuando esto se haya <strong>real</strong>izado, se libera<br />

el arreglo mediante una llamada a la función CoTaskMemFree.<br />

La función OleCreatePropertyFrame provee una forma simple <strong>de</strong> <strong>de</strong>splegar la<br />

pagina propietaria <strong>de</strong>ntro <strong>de</strong> una caja <strong>de</strong> dialogo.<br />

// Muestra la pagina propietaria<br />

// Obti<strong>en</strong>e el nombre <strong>de</strong>l filtro y un apuntador IUnknown.<br />

FILTER_INFO FilterInfo;<br />

pFX->QueryFilterInfo(&FilterInfo);<br />

IUnknown *pFilterUnk;<br />

pFX->QueryInterface(IID_IUnknown, (void **)&pFilterUnk);<br />

CAUUID caGUID;<br />

pProp->GetPages(&caGUID);<br />

pProp->Release();<br />

OleCreatePropertyFrame(<br />

hWnd, // V<strong>en</strong>tana padre<br />

0, 0, // (Reservado)<br />

FilterInfo.achName, // Captura para la caja <strong>de</strong> dialogo<br />

1, // Numero <strong>de</strong> objetos (solo <strong>de</strong>l filtro)<br />

&pFilterUnk, // Arreglo <strong>de</strong> apuntadores a objetos<br />

caGUID.cElems, // Numero <strong>de</strong> paginas propietarias<br />

caGUID.pElems, // Arreglo <strong>de</strong> CLSIDs <strong>de</strong> paginas propietarias<br />

0, // I<strong>de</strong>ntificador local<br />

0, NULL // Reservado<br />

);<br />

// Limpieza.<br />

pFilterUnk->Release();<br />

FilterInfo.pGraph->Release();<br />

CoTaskMemFree(caGUID.pElems);<br />

Esta es nuestra pagina propietaria con 9 efectos posibles:


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 81<br />

5.7.4 Captura <strong>de</strong> vi<strong>de</strong>o WinTV<br />

Figura 5.25 Pagina propietaria <strong>de</strong> nuestra aplicación<br />

Ent<strong>en</strong><strong>de</strong>mos por captura <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> nuestro caso no a la escritura <strong>de</strong> datos media<br />

sino a la previsualización <strong>de</strong> estos <strong>en</strong> una v<strong>en</strong>tana <strong>de</strong> vi<strong>de</strong>o. El dispositivo <strong>de</strong> captura es la<br />

tarjeta <strong>de</strong> vi<strong>de</strong>o WinTV.<br />

DirectShow maneja la captura <strong>de</strong> vi<strong>de</strong>o también a través <strong>de</strong> filtros. Este tipo <strong>de</strong><br />

gráfico se <strong>de</strong>nomina gráfico <strong>de</strong> captura.<br />

Si un dispositivo <strong>de</strong> captura utiliza un controlador Windows Driver Mo<strong>de</strong>l(WDM),<br />

el grafico pue<strong>de</strong> necesitar ciertos filtros upstream <strong>de</strong>l filtro <strong>de</strong> captura. Estos filtros<br />

<strong>de</strong>nominados filtros manejadores <strong>de</strong> clase flujo, soportan funcionalida<strong>de</strong>s adicionales<br />

provistas por el hardware. Por ejemplo, una tarjeta <strong>de</strong> sintonía <strong>de</strong> TV ti<strong>en</strong>e una<br />

funcionalidad para ajustar el canal.<br />

El diagrama 5.26 muestra los tipos <strong>de</strong> filtros <strong>en</strong> un grafico <strong>de</strong> captura típico. Las<br />

líneas punteadas indican don<strong>de</strong> los filtros adicionales pue<strong>de</strong>n requerirse, tales como filtros<br />

<strong>de</strong>codificadores o filtros splitter.


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 82<br />

Figura 5.26 Gráfico <strong>de</strong> captura típico<br />

Para simplificar el proceso <strong>de</strong> construcción <strong>de</strong> gráficos <strong>de</strong> captura, DirectShow<br />

provee una compon<strong>en</strong>te llamada el Capture Graph Buil<strong>de</strong>r. Este expone la interfaz<br />

ICaptureGraphBuil<strong>de</strong>r2, la cual ti<strong>en</strong>e métodos para construir y controlar gráficos <strong>de</strong><br />

captura.<br />

Un filtro <strong>de</strong> captura <strong>en</strong>trega datos a través <strong>de</strong> uno o más pins salida. Un pin salida<br />

pue<strong>de</strong> ser clasificado por el tipo <strong>de</strong> datos media que este <strong>en</strong>trega, y por su pin category.<br />

El tipo <strong>de</strong> media se repres<strong>en</strong>ta por un major type GUID . Los tipos más comunes <strong>de</strong> datos<br />

media se muestran <strong>en</strong> la sigui<strong>en</strong>te tabla.<br />

Tipo <strong>de</strong> Media Major type GUID<br />

Audio MEDIATYPE_Audio<br />

Interleaved <strong>digital</strong> vi<strong>de</strong>o (DV) MEDIATYPE_Interleaved<br />

MPEG Flujo MEDIATYPE_Flujo<br />

Vi<strong>de</strong>o MEDIATYPE_Vi<strong>de</strong>o<br />

Pin category <strong>de</strong>scribe el propósito o función <strong>de</strong>l pin, y es repres<strong>en</strong>tada por un GUID<br />

propietario. Hay varias pin category, pero las dos utilizadas son:<br />

• PIN_CATEGORY_CAPTURE: El pin provee datos para capturar a un archivo.<br />

• PIN_CATEGORY_PREVIEW: El pin provee datos para previsualizar.<br />

Se pue<strong>de</strong> consultar a un pin directam<strong>en</strong>te por su tipo <strong>de</strong> media y su pin category. Para<br />

obt<strong>en</strong>er el tipo <strong>de</strong> media, se llama al método IPin::EnumMediaTypes. Para obt<strong>en</strong>er el pin<br />

category, se llama al método IKsPropertySet::Get. Utilizando los métodos, se pue<strong>de</strong><br />

limitar las operaciones a un tipo <strong>de</strong> media <strong>de</strong>terminado o pin category, sin consultar a cada<br />

pin. A pesar <strong>de</strong> que por lógica <strong>de</strong>biéramos utilizar PIN_CATEGORY_PREVIEW <strong>en</strong> las<br />

pruebas con las cuatro pantallas no funciona, sin embargo con<br />

PIN_CATEGORY_CAPTURE si, una posible razòn es el tipo <strong>de</strong> tarjeta <strong>de</strong> adquisición <strong>de</strong><br />

vi<strong>de</strong>o utilizada.<br />

5.7.4.1 Gráfico <strong>de</strong> captura<br />

El primer paso para crear el gráfico <strong>de</strong> captura es crear el Manejador <strong>de</strong>l gráfico <strong>de</strong><br />

filtros y el Capture Graph Buil<strong>de</strong>r. Entonces se llama a para asociar el gráfico <strong>de</strong> filtros con<br />

el capture graph buil<strong>de</strong>r. como sigue:<br />

IGraphBuil<strong>de</strong>r *pGraph = NULL;<br />

ICaptureGraphBuil<strong>de</strong>r2 *pBuil<strong>de</strong>r = NULL;<br />

// Crea el FGM<br />

CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC, IID_IGraphBuil<strong>de</strong>r, (void **)&pGB);<br />

// Crea el Capture Graph Buil<strong>de</strong>r.<br />

CoCreateInstance(CLSID_CaptureGraphBuil<strong>de</strong>r2, NULL, CLSCTX_INPROC, IID_ICaptureGraphBuil<strong>de</strong>r2,<br />

(void **)&pBuil<strong>de</strong>r);<br />

// Asocia el gráfico con el buil<strong>de</strong>r<br />

pBuil<strong>de</strong>r->SetFiltergraph(pGB);


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 83<br />

El sigui<strong>en</strong>te paso es seleccionar un dispositivo <strong>de</strong> captura, utilizando el System<br />

Device Enumerator. El sigui<strong>en</strong>te código <strong>en</strong>umera los dispositivos <strong>de</strong> captura <strong>de</strong> vi<strong>de</strong>o y<br />

selecciona el primer dispositivo:<br />

// Crea el system <strong>de</strong>vice <strong>en</strong>umerator.<br />

ICreateDevEnum *pDevEnum = NULL;<br />

CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC, IID_ICreateDevEnum, (void<br />

**)&pDevEnum);<br />

// Crea un <strong>en</strong>umerador para vi<strong>de</strong>o capture <strong>de</strong>vices.<br />

IEnumMoniker *pClassEnum = NULL;<br />

pDevEnum->CreateClassEnumerator(CLSID_Vi<strong>de</strong>oInputDeviceCategory, &pClassEnum, 0);<br />

ULONG cFetched;<br />

IMoniker *pMoniker = NULL;<br />

IBaseFilter *pSrc = NULL;<br />

if (pClassEnum->Next(1, &pMoniker, &cFetched) == S_OK)<br />

{<br />

// Liga el primer moniker a un objeto filtro.<br />

pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pSrc);<br />

pMoniker->Release();<br />

}<br />

pClassEnum->Release();<br />

pDevEnum->Release();<br />

Ahora se aña<strong>de</strong> el filtro <strong>de</strong> captura al gráfico:<br />

// Se aña<strong>de</strong> el filtro <strong>de</strong> captura a nuestro gráfico<br />

hr = pGB->AddFilter(pSrc, L"Vi<strong>de</strong>o Capture");<br />

El paso final <strong>en</strong> la construcción <strong>de</strong> un grafico <strong>de</strong> captura es pres<strong>en</strong>tar el flujo. El<br />

método ICaptureGraphBuil<strong>de</strong>r2::R<strong>en</strong><strong>de</strong>rFlujo <strong>real</strong>iza dicha función.<br />

// Muestra el pin <strong>de</strong> captura <strong>en</strong> el filtro <strong>de</strong> captura <strong>de</strong> vi<strong>de</strong>o.<br />

// Se usa esta instrucción <strong>en</strong> lugar <strong>de</strong> pBuil<strong>de</strong>r->R<strong>en</strong><strong>de</strong>rFile<br />

hr = pBuil<strong>de</strong>r->R<strong>en</strong><strong>de</strong>rFlujo (&PIN_CATEGORY_CAPTURE , &MEDIATYPE_Vi<strong>de</strong>o,<br />

pSrc, NULL, NULL);<br />

Los primeros dos parámetros especifican el pin category y el tipo <strong>de</strong> media. Los<br />

sigui<strong>en</strong>tes tres parámetros son apuntadores a los sigui<strong>en</strong>tes filtros:<br />

• El filtro <strong>de</strong> captura<br />

• Un filtro <strong>de</strong> compresión adicional (no usado)<br />

• El multiplexor o filtro r<strong>en</strong><strong>de</strong>rer. (no usado)<br />

Finalm<strong>en</strong>te y como <strong>en</strong> el apartado 5.7.1 se incorpora el filtro multiefectos.<br />

5.8 Resultados<br />

Se logró la elaboración <strong>de</strong>l filtro aunque su inclusión <strong>en</strong> la aplicación resultó<br />

problemática, <strong>de</strong>bido a que no se quería reconocer la exist<strong>en</strong>cia <strong>de</strong>l filtro como librería <strong>de</strong><br />

<strong>en</strong>lace dinámico, sin embargo se pudo finalm<strong>en</strong>te resolver el problema con ayuda <strong>de</strong>l grupo<br />

<strong>de</strong> usuarios especificado <strong>en</strong> el anexo.<br />

En la figura 5.27 se muestra una imag<strong>en</strong> <strong>en</strong> pantalla completa <strong>de</strong>l vi<strong>de</strong>owall<br />

funcionando. El vi<strong>de</strong>o ofrece una pres<strong>en</strong>tación aceptable aunque se observa cierto retardo<br />

<strong>en</strong> la actualización <strong>de</strong> la imag<strong>en</strong>, sobre todo <strong>en</strong> las pantallas secundarias. Al ser reproducido


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 84<br />

el vi<strong>de</strong>o a partir <strong>de</strong> la tarjeta <strong>de</strong> vi<strong>de</strong>o WinTV, se observan los mismos problemas anteriores<br />

pero <strong>de</strong> un modo mas significativo. También se aprecia un <strong>de</strong>sfasami<strong>en</strong>to <strong>en</strong>tre el audio y el<br />

vi<strong>de</strong>o, presuponemos que otra tarjeta <strong>de</strong> vi<strong>de</strong>o pudiera dar resultados distinto.<br />

Figura5.27 Vi<strong>de</strong>owall <strong>de</strong> 4 monitores a pantalla completa


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 85<br />

6. Evaluación<br />

Las pruebas han sido parte interactiva <strong>de</strong>l proyecto, y se han <strong>real</strong>izado <strong>en</strong> paralelo<br />

con el <strong>de</strong>sarrollo. Cada efecto se probó hasta obt<strong>en</strong>er un <strong>de</strong>sempeño a<strong>de</strong>cuado, y esto<br />

significa que la imag<strong>en</strong> se reproduzca sin pausas y sin omitir frames.<br />

Estas pruebas se <strong>real</strong>izaron solo <strong>en</strong> el modo <strong>de</strong> una tarjeta <strong>de</strong> vi<strong>de</strong>o conectada, <strong>en</strong><br />

este caso nos referimos a la ATI 3D Rage Pro conectada al puerto PCI y <strong>en</strong> la<br />

configuración <strong>de</strong> 1024 x 768 a 24 bits.<br />

Hubo un efecto adicional que no fue incluido <strong>de</strong>bido a que no se pudo obt<strong>en</strong>er el<br />

correcto funcionami<strong>en</strong>to <strong>de</strong>l mismo, y se trató <strong>de</strong> obt<strong>en</strong>er una animación que se superponga<br />

al vi<strong>de</strong>o. Dicha animación se lograría almac<strong>en</strong>ando <strong>en</strong> un buffer la sigui<strong>en</strong>te imag<strong>en</strong>:<br />

Figura 6.1 Imag<strong>en</strong> para animación<br />

Cada una <strong>de</strong> las llantas se iría pres<strong>en</strong>tando consecutivam<strong>en</strong>te superpuesta al vi<strong>de</strong>o, lo<br />

cual daría el efecto <strong>de</strong> giro <strong>de</strong> la llanta. Sin embargo a pesar <strong>de</strong> los distintos métodos<br />

utilizados, no se logro el resultado esperado, <strong>de</strong>bido a que solo se pres<strong>en</strong>taba la primer<br />

imag<strong>en</strong> y no se hacia el cambio hacia la sigui<strong>en</strong>te imag<strong>en</strong>. La posible razón es que la<br />

ejecución <strong>de</strong>l código <strong>en</strong> la función Transform( ) no se respeta <strong>de</strong>bido a que ti<strong>en</strong>e prioridad<br />

la pres<strong>en</strong>tación <strong>de</strong> la muestra <strong>de</strong> vi<strong>de</strong>o hacia la v<strong>en</strong>tana <strong>de</strong> la aplicación, y <strong>en</strong>tonces se<br />

omit<strong>en</strong> las instrucciones <strong>de</strong> código subsigui<strong>en</strong>tes, reiniciándose el hilo <strong>de</strong> ejecución.<br />

En todos los casos se ha t<strong>en</strong>ido problemas <strong>en</strong> la pres<strong>en</strong>tación para las 4 pantallas al<br />

mismo <strong>tiempo</strong>, esto es <strong>en</strong> las pruebas <strong>de</strong>l vi<strong>de</strong>owall, sobre todo cuando la fu<strong>en</strong>te <strong>de</strong> vi<strong>de</strong>o<br />

provi<strong>en</strong>e <strong>de</strong> la tarjeta WinTV. El primer problema resi<strong>de</strong> <strong>en</strong> la omisión <strong>de</strong> frames,<br />

provocando un vi<strong>de</strong>o discontinuo, y el segundo problema consiste <strong>en</strong> la <strong>de</strong>sincronización<br />

<strong>en</strong>tre la señal <strong>de</strong> vi<strong>de</strong>o y <strong>de</strong> audio, esto se pone <strong>de</strong> manifiesto cuando la imag<strong>en</strong> se va<br />

“retrasando” y los vi<strong>de</strong>os no se pres<strong>en</strong>tan con la rapi<strong>de</strong>z a<strong>de</strong>cuada. Se <strong>real</strong>izaron distintas<br />

pruebas y configuraciones para <strong>de</strong>terminar las posibles causas.<br />

Debido a que no hemos establecido un método para cuantificar el error producido <strong>en</strong><br />

la pres<strong>en</strong>tación <strong>de</strong>l vi<strong>de</strong>o solo hacemos un com<strong>en</strong>tario subjetivo sobre cual es la que exhibe<br />

una mejor imag<strong>en</strong>.


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 86<br />

El primer problema <strong>en</strong> la configuración <strong>de</strong> vi<strong>de</strong>owall es que la imag<strong>en</strong> <strong>de</strong> vi<strong>de</strong>o solo<br />

se pue<strong>de</strong> mostrar <strong>en</strong> la pantalla principal, el motivo ti<strong>en</strong>e que ver con el hardware <strong>de</strong><br />

adquisición <strong>de</strong> vi<strong>de</strong>o. Tanto <strong>en</strong> el modo <strong>de</strong> superposición <strong>de</strong> vi<strong>de</strong>o como <strong>en</strong> el modo <strong>de</strong><br />

superficie principal, la imag<strong>en</strong> <strong>digital</strong>izada adquirida por WinTV se <strong>en</strong>vía directam<strong>en</strong>te a la<br />

memoria <strong>de</strong> la tarjeta VGA principal por el bus PCI.<br />

Para lograr que se visualice <strong>en</strong> los <strong>de</strong>más monitores, se requiere hacer uso <strong>de</strong>l pin<br />

Capture <strong>en</strong> la tarjeta WinTV, así <strong>en</strong> lugar <strong>de</strong> <strong>en</strong>viar la información a la pantalla principal se<br />

<strong>en</strong>vía a un buffer que <strong>de</strong>spués es accesado por el sistema operativo para po<strong>de</strong>r hacer la<br />

pres<strong>en</strong>tación <strong>en</strong> múltiples pantallas. Otra forma es la <strong>de</strong> obligar al sistema con el sigui<strong>en</strong>te<br />

gráfico <strong>de</strong> filtros:<br />

Figura 6.2 Incorporación <strong>de</strong>l filtro Smart Tee<br />

El filtro Smart Tee ti<strong>en</strong>e las sigui<strong>en</strong>tes particularida<strong>de</strong>s:<br />

• Entrega los datos <strong>en</strong> preview únicam<strong>en</strong>te cuando al hacerlo no se dañe el<br />

performance <strong>de</strong>l pin Capture<br />

• Remueve los time stamps <strong>de</strong>l flujo preview, esto evita que el r<strong>en</strong><strong>de</strong>rer elimine<br />

frames innecesariam<strong>en</strong>te.<br />

Desafortunadam<strong>en</strong>te <strong>en</strong> ambos casos se sigu<strong>en</strong> obt<strong>en</strong>i<strong>en</strong>do errores <strong>en</strong> la pres<strong>en</strong>tación <strong>de</strong>l<br />

vi<strong>de</strong>o.<br />

La afirmación anterior se <strong>de</strong>duce a partir <strong>de</strong> las pruebas <strong>real</strong>izadas con una cámara<br />

web, la cual no <strong>en</strong>vía directam<strong>en</strong>te las imág<strong>en</strong>es <strong>de</strong> vi<strong>de</strong>o hacia la memoria <strong>de</strong> la tarjeta<br />

VGA, sino que pasan a un buffer intermedio, lo cual no provoca errores.<br />

Los errores <strong>en</strong> la pres<strong>en</strong>tación <strong>de</strong> vi<strong>de</strong>o ti<strong>en</strong><strong>en</strong> dos causas principales a saber:<br />

1. Las dim<strong>en</strong>siones <strong>de</strong> la imag<strong>en</strong> adquirida por WinTV<br />

2. El formato <strong>de</strong> la imag<strong>en</strong> obt<strong>en</strong>ida por WinTV<br />

En el primer caso la dim<strong>en</strong>sión con la que pue<strong>de</strong> adquirirse la imag<strong>en</strong> toma 9 posibles<br />

valores:<br />

160x112, 160x120, 176x144, 192x142, 320x240, 352x288, 384x284, 400x320, 640x480.<br />

La cantidad <strong>de</strong> pixeles obt<strong>en</strong>idos varia <strong>en</strong>tonces <strong>de</strong>s<strong>de</strong> 17,920 hasta 307,200.<br />

Haci<strong>en</strong>do uso <strong>de</strong> la herrami<strong>en</strong>ta <strong>de</strong> Windows “Monitor <strong>de</strong>l sistema” pudimos<br />

observar que para una dim<strong>en</strong>sión <strong>de</strong> 320x240 el procesador se sobrecargaba a 100%, sin<br />

embargo para una dim<strong>en</strong>sión <strong>de</strong> 640x480 el procesador solo trabajaba al 40%. En<br />

contraparte el mayor flujo <strong>de</strong> datos <strong>de</strong>bido a una mayor resolución satura mas el bus y por<br />

consigui<strong>en</strong>te la imag<strong>en</strong> exhibe mas discontinuida<strong>de</strong>s.<br />

D<strong>en</strong>tro <strong>de</strong> la segunda causa se ti<strong>en</strong><strong>en</strong> 7 posibles formatos <strong>de</strong> adquisición:<br />

32 bit RGBA, 24bit RGB, 15 bit RGB, YUY2, BTYUV, YUV9, YUV12.


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 87<br />

Dep<strong>en</strong>di<strong>en</strong>do <strong>de</strong>l formato <strong>de</strong>seado se insertan filtros o no <strong>en</strong> el gráfico, esto requerirá un<br />

<strong>tiempo</strong> <strong>de</strong> procesami<strong>en</strong>to adicional <strong>de</strong>p<strong>en</strong>di<strong>en</strong>do <strong>de</strong>l tipo <strong>de</strong> filtro insertado. Cabe aquí<br />

aclarar que es importante mant<strong>en</strong>er una resolución <strong>de</strong> la tarjeta VGA alta para evitar alguna<br />

conversión <strong>de</strong> color, <strong>en</strong> nuestro caso se mantuvieron todas a 24 bits como mínimo.


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 88<br />

7. Conclusiones y perspectivas<br />

Se ha obt<strong>en</strong>ido el software para el procesami<strong>en</strong>to <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong>, cuyas<br />

capacida<strong>de</strong>s se han explorado <strong>de</strong> manera experim<strong>en</strong>tal y han <strong>de</strong>jado ver las caracteristicas<br />

que exhib<strong>en</strong> los mo<strong>de</strong>rnos procesadores <strong>de</strong> proposito g<strong>en</strong>eral. Dado que el procesami<strong>en</strong>to<br />

<strong>de</strong> vi<strong>de</strong>o cubre un amplio rango <strong>de</strong> posibilida<strong>de</strong>s y complejidad, se com<strong>en</strong>zò <strong>real</strong>izandose<br />

procesami<strong>en</strong>to bàsico que involucrase pocas operaciones matematicas, y fuè<br />

increm<strong>en</strong>tandose la complejidad <strong>de</strong> dichas operaciones hasta obt<strong>en</strong>erse <strong>de</strong>fectos <strong>en</strong> el vi<strong>de</strong>o.<br />

Consi<strong>de</strong>rese la dificultad <strong>de</strong> <strong>de</strong>terminar las capacida<strong>de</strong>s <strong>de</strong>l pres<strong>en</strong>te software con<br />

antelación, consi<strong>de</strong>rando que se <strong>de</strong>sconoce el porc<strong>en</strong>taje <strong>de</strong>l procesador utilizado <strong>en</strong> las<br />

tareas bàsicas <strong>de</strong>l sistema operativo. Entre las que se añadió el control simultaneo <strong>de</strong> varias<br />

tarjetas <strong>de</strong> vi<strong>de</strong>o.<br />

El procesami<strong>en</strong>to <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> para los efectos <strong>de</strong>scritos se ha logrado <strong>de</strong><br />

manera satisfactoria solo <strong>en</strong> el caso <strong>de</strong> una pantalla, esto es no trabajando simultaneam<strong>en</strong>te<br />

con el vi<strong>de</strong>owall <strong>de</strong>bido a una consi<strong>de</strong>rable perdida <strong>en</strong> la calidad visual. El procesami<strong>en</strong>to<br />

que requiere la división <strong>de</strong> imág<strong>en</strong>es para formar un vi<strong>de</strong>owall se obti<strong>en</strong>e también <strong>de</strong> modo<br />

aceptable al trabajar <strong>de</strong> manera in<strong>de</strong>p<strong>en</strong>di<strong>en</strong>te a los efectos.<br />

La <strong>de</strong>terminaciòn <strong>de</strong> la variación <strong>de</strong> la calidad <strong>de</strong>l vi<strong>de</strong>o respecto a la cantidad <strong>de</strong><br />

operaciones matematicas efectuadas, no se <strong>real</strong>izó, pero esta pue<strong>de</strong> ser también una <strong>de</strong> las<br />

tareas sigui<strong>en</strong>tes sobre todo por la necesidad <strong>de</strong> evaluar el <strong>de</strong>sempeño <strong>en</strong> este ambito con<br />

los nuevos procesadores y <strong>de</strong>sarrollos <strong>de</strong> hardware.<br />

Las herrami<strong>en</strong>tas <strong>de</strong> software DirectX sobre las cuales se ha construido nuestra<br />

aplicaciòn han sido fundam<strong>en</strong>tales para el pres<strong>en</strong>te trabajo, algunas funciones que se han<br />

implem<strong>en</strong>tado <strong>en</strong> forma <strong>de</strong> objetos compon<strong>en</strong>tes han sido posibles tambièn solo gracias al<br />

apoyo <strong>de</strong>l grupo <strong>de</strong> usuarios <strong>en</strong> internet. En otros casos se <strong>de</strong>tectaron errores <strong>en</strong> el software<br />

<strong>de</strong> <strong>de</strong>sarrollo DirectShow que produjeron salidas inesperadas y que se solv<strong>en</strong>tarón con<br />

algun truco no docum<strong>en</strong>tado. Estas modificaciones se expon<strong>en</strong> via codigo fu<strong>en</strong>te con su<br />

respectivo com<strong>en</strong>tario <strong>en</strong> el pres<strong>en</strong>te trabajo.<br />

Es recom<strong>en</strong>dable que se <strong>real</strong>ic<strong>en</strong> pruebas con otros procesadores distintos al Intel®<br />

y con algunos dispositivos <strong>de</strong> adquisición <strong>de</strong> vi<strong>de</strong>o difer<strong>en</strong>tes, se espera también que otros<br />

sistemas operativos proporcion<strong>en</strong> características adicionales que puedan mejorar el<br />

<strong>de</strong>sempeño.<br />

D<strong>en</strong>tro <strong>de</strong> los tipos <strong>de</strong> procesami<strong>en</strong>to <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> se ti<strong>en</strong>e una amplia<br />

área <strong>de</strong> trabajo, ya sea <strong>de</strong>sarrollando métodos <strong>de</strong> compresión o <strong>real</strong>izando procesami<strong>en</strong>to<br />

experim<strong>en</strong>tal sobre vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong>.<br />

Otra alternativa interesante es el procesami<strong>en</strong>to <strong>de</strong> vi<strong>de</strong>o distribuido, consi<strong>de</strong>rando<br />

que se ti<strong>en</strong><strong>en</strong> velocida<strong>de</strong>s altas <strong>en</strong> la transmisión <strong>de</strong> red local y que se dispone <strong>de</strong><br />

mecanismos diversos <strong>de</strong> compresión se pue<strong>de</strong> <strong>real</strong>izar algunos proyectos con mas <strong>de</strong> una<br />

computadora.


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 89<br />

Se espera que el pres<strong>en</strong>te trabajo sea <strong>de</strong> utilidad para aquellos que se interes<strong>en</strong> <strong>en</strong><br />

procesami<strong>en</strong>to <strong>de</strong> vi<strong>de</strong>o a bajo costo, por lo pronto es difícil la inclusión <strong>de</strong> una mayor<br />

cantidad <strong>de</strong> monitores no solo por la limitante <strong>de</strong>l numero <strong>de</strong> puertos PCI sino también<br />

porque se requiere mayor velocidad <strong>de</strong> procesami<strong>en</strong>to. Se pue<strong>de</strong> increm<strong>en</strong>tar el r<strong>en</strong>dimi<strong>en</strong>to<br />

si <strong>en</strong> posteriores versiones <strong>de</strong> DirectX se pue<strong>de</strong> manejar pantalla completa <strong>en</strong> los monitores<br />

secundarios. D<strong>en</strong>tro <strong>de</strong> las pruebas hechas <strong>en</strong> LINUX el r<strong>en</strong>dimi<strong>en</strong>to fue muy bajo <strong>en</strong> el uso<br />

<strong>de</strong> multimonitor, aunque se ti<strong>en</strong>e la v<strong>en</strong>taja <strong>de</strong> acceso a modificación <strong>de</strong>l kernel.<br />

Las aplicaciones <strong>de</strong> <strong>tiempo</strong> <strong>real</strong> <strong>en</strong> la actualidad también hac<strong>en</strong> uso <strong>de</strong> sistemas<br />

operativos <strong>de</strong>dicados y esta me parece otra gran alternativa para mant<strong>en</strong>er el bajo costo y<br />

aum<strong>en</strong>tar el <strong>de</strong>sempeño <strong>de</strong>l procesami<strong>en</strong>to.


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 90<br />

Consultas <strong>real</strong>izadas<br />

[1] Watkinson, John, An introduction to <strong>digital</strong> vi<strong>de</strong>o, Focal Press, 1994<br />

[2] Luther, Arch C., Principles of <strong>digital</strong> audio and vi<strong>de</strong>o, Artech House, Inc., 1997<br />

[3] Poynton, Charles A., A technical introduction to <strong>digital</strong> vi<strong>de</strong>o, John Wiley & Sons,<br />

1996<br />

[4] Bradley Barg<strong>en</strong>, Insi<strong>de</strong> DirectX , Mc Graw Hill, 1998<br />

[5] Barry B. Brey, Los microprocesadores intel, arquitectura, programación e<br />

interfases, Pr<strong>en</strong>tice Hall, 1995<br />

[6] Phillip E. Mattison, Practical <strong>digital</strong> vi<strong>de</strong>o with programming examples in C, John<br />

Wiley & Sons, 1994<br />

[7] Rafael C. Gonzalez, <strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> imág<strong>en</strong>es, Addison Wesley, 1995<br />

[8] Sean Wallace, Digital vi<strong>de</strong>o effects processor, Sr. Design Project, 1998<br />

[9] Jorge Pascual, Francisco Charte, Programación Avanzada <strong>en</strong> Windows 2000, Mc<br />

Graw Hill, 1994<br />

[10] David B<strong>en</strong>nett, Visual C++ 5 Para Desarrolladores, Pr<strong>en</strong>tice Hall, 1999<br />

[11] Andrew Dowsey M<strong>en</strong>g, DirectShow TV Display with Real –Time Vi<strong>de</strong>o<br />

Processing, http://keeper.warhead.org.uk<br />

[12] M. Robin & M. Poulin, Digital Television Fundam<strong>en</strong>tals<br />

[13] G. Eddon, H. Eddon, Insi<strong>de</strong> Distributed COM, Microsoft Press, (1998)<br />

[14] Docum<strong>en</strong>tación Microsoft DirectShow,<br />

http://msdn.microsoft.com/library/<strong>de</strong>fault.asp?URL=/library/psdk/directx/dx8_c/ds/<br />

<strong>de</strong>fault.htm<br />

[15] Fco. Javier Cevallos, Visual C++ 6 Aplicaciones para Win32, Alfaomega<br />

[16] Fco. Javier Cevallos, Visual C++6 Programación Avanzada <strong>en</strong> Win32,<br />

Alfaomega


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 91<br />

Anexos<br />

Fu<strong>en</strong>tes <strong>de</strong> internet<br />

[1] MSDN newsgroup<br />

http://www.microsoft.com/isapi/redir.dll?prd=ie&pver=5.0&ar=IStart<br />

[2] Corporación Intel<br />

http://www.intel.com<br />

[3] AV Sci<strong>en</strong>ce Forum, Sección Home Theatre Computers<br />

http://www.avsforum.com/ubbcgi/Ultimate.cgi?action=intro&showall=1<br />

[4] Hauppauge Computer Works<br />

http://www.hauppauge.com<br />

[5] AVerMedia<br />

http://www.avermedia.com<br />

[6] ATI Technologies Inc.<br />

http://www.ati.com<br />

[7] DirectX Low-Level Ext<strong>en</strong>sions for Windows, Microsoft Corporation,<br />

http://www.microsoft.com/directx<br />

[8] Vi<strong>de</strong>o4Linux2<br />

http://www.thedirks.org/v4l2/<br />

[9] Advanced Micro Devices (AMD)<br />

http://www.amd.com<br />

[10] <strong>Procesami<strong>en</strong>to</strong> <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> usando DSP<br />

http://dynamio.<strong>en</strong>c.purdue.edu/~ace/<strong>de</strong>lp-pub.html<br />

[11] Sun Microsystems (JMF) Java Media Framework,<br />

http://java.sun.com/products/java-media/jmf/in<strong>de</strong>x.html


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 92<br />

Manual <strong>de</strong> usuario<br />

El programa DEXTERMedia se auto instala automáticam<strong>en</strong>te a partir <strong>de</strong> la<br />

inserción <strong>de</strong>l CD. Este proceso incluirá la librería <strong>de</strong> <strong>en</strong>lace dinámico ezrgb24.ax, la cual<br />

conti<strong>en</strong>e los efectos <strong>de</strong> filtrado.<br />

Para su funcionami<strong>en</strong>to <strong>en</strong> cuatro pantallas como vi<strong>de</strong>owall se requiere instalar <strong>en</strong><br />

los puertos PCI libres las cuatro tarjetas <strong>de</strong> vi<strong>de</strong>o y hacer la sigui<strong>en</strong>te configuración.<br />

Configuración <strong>de</strong> 4 monitores<br />

Consi<strong>de</strong>rando que se ti<strong>en</strong>e una tarjeta <strong>de</strong> vi<strong>de</strong>o instalada, se aña<strong>de</strong> la sigui<strong>en</strong>te<br />

tarjeta con el equipo apagado y al reiniciar, el sistema <strong>de</strong>berá reconocer la nueva tarjeta. Si<br />

todo va bi<strong>en</strong> solo se <strong>de</strong>be ir hacia Display Properties: Se da clic <strong>en</strong> Start, Settings, Control<br />

Panel, Display, y finalm<strong>en</strong>te <strong>en</strong>, Settings.<br />

Para habilitar el nuevo dispositivo, simplem<strong>en</strong>te se da clic sobre el nuevo monitor, y<br />

<strong>en</strong>tonces se selecciona "Ext<strong>en</strong>d my Windows <strong>de</strong>sktop onto this monitor."<br />

En el caso <strong>de</strong> que se t<strong>en</strong>ga problemas <strong>en</strong> saber cual monitor es cual, sobre todo<br />

cuando se ti<strong>en</strong><strong>en</strong> 4 monitores o más, solo se da click con el botón <strong>de</strong>recho sobre el monitor<br />

y se selecciona I<strong>de</strong>ntify. Entonces aparecerá el numero correspondi<strong>en</strong>te al monitor actual, el<br />

monitor principal ti<strong>en</strong>e el numero 1 por <strong>de</strong>fault.


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 93<br />

De la misma forma se aña<strong>de</strong>n los subsigui<strong>en</strong>tes monitores hasta obt<strong>en</strong>er los 4<br />

monitores. Posteriorm<strong>en</strong>te se proce<strong>de</strong> a configurarlos todos con la misma resolución<br />

800x600 y la cantidad <strong>de</strong> colores <strong>de</strong>berá ser <strong>de</strong> por lo m<strong>en</strong>os 24 bits <strong>en</strong> todas las tarjetas.<br />

Dado que Windows utiliza un sistema <strong>de</strong> coor<strong>de</strong>nadas para refer<strong>en</strong>ciar cualquier<br />

elem<strong>en</strong>to sobre la pantalla. La esquina superior izquierda <strong>en</strong> una pantalla con resolución<br />

800x600 es la coor<strong>de</strong>nada 0,0. La coor<strong>de</strong>nada <strong>de</strong> la esquina inferior <strong>de</strong>recha es 800, 600.<br />

En el caso <strong>de</strong> múltiple monitor, la esquina superior izquierda <strong>de</strong>l monitor primario<br />

ti<strong>en</strong>e la coor<strong>de</strong>nada 0,0. Si t<strong>en</strong>emos un sistema con 2 monitores a 1024x768, con el<br />

secundario colocado al lado <strong>de</strong>recho <strong>de</strong>l primario. Entonces la esquina inferior <strong>de</strong>recha <strong>de</strong><br />

la pantalla virtual será 2048x768.<br />

La configuración <strong>de</strong> monitores <strong>de</strong>be <strong>real</strong>izarse <strong>de</strong> manera que se obt<strong>en</strong>ga la<br />

sigui<strong>en</strong>te pantalla virtual.<br />

La aplicación<br />

Al ejecutar la aplicación po<strong>de</strong>mos observar la sigui<strong>en</strong>te v<strong>en</strong>tana principal.<br />

Se ti<strong>en</strong>e <strong>en</strong> la barra <strong>de</strong> M<strong>en</strong>ús solo dos elem<strong>en</strong>tos, Archivo y Control, los cuales<br />

pue<strong>de</strong>n acce<strong>de</strong>rse mediante la combinación <strong>de</strong> teclas ALT+A y ALT+C respectivam<strong>en</strong>te.<br />

El m<strong>en</strong>ú Archivo, muestra las sigui<strong>en</strong>tes opciones


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 94<br />

La opción Abrir clip..., permite abrir archivos multimedia con ext<strong>en</strong>siones avi, mov<br />

o mpg, ubicados <strong>en</strong> el disco duro o <strong>en</strong> CD-ROM. En el caso <strong>de</strong> que el archivo multimedia<br />

no sea compatible se indicará <strong>en</strong> el sistema un error <strong>de</strong> lectura.<br />

La opción TV visualiza la imag<strong>en</strong> <strong>de</strong> televisión proporcionada por una tarjeta <strong>de</strong><br />

televisión conectada al sistema.<br />

El m<strong>en</strong>ú Control muestra las sigui<strong>en</strong>tes opciones<br />

La opción Pausa/Reproducir permite pasar <strong>de</strong>l estado <strong>de</strong> reproducción al <strong>de</strong> pausa<br />

y viceversa. Det<strong>en</strong>er para la reproducción <strong>de</strong>l archivo multimedia, Cerrar clip ocasiona<br />

que se liber<strong>en</strong> los recursos asociados con la reproducción <strong>de</strong>l vi<strong>de</strong>o actual. Sil<strong>en</strong>cio/Sonido<br />

<strong>de</strong>ti<strong>en</strong>e el sonido pero continua la reproducción <strong>de</strong>l vi<strong>de</strong>o o la televisión.<br />

La opción Media pantalla provoca que la v<strong>en</strong>tana tome una dim<strong>en</strong>sión <strong>de</strong>l 50% <strong>de</strong><br />

la original, <strong>de</strong>l mismo modo Tres cuartos el 75% y Normal el 100%. Vi<strong>de</strong>owall permite<br />

observar la imag<strong>en</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> los cuatro monitores. Finalm<strong>en</strong>te Pantalla Completa<br />

pres<strong>en</strong>tará la imag<strong>en</strong> <strong>en</strong> la totalidad <strong>de</strong> la pantalla.


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 95<br />

Los efectos <strong>de</strong> vi<strong>de</strong>o<br />

Para acce<strong>de</strong>r a los distintos efectos <strong>de</strong> vi<strong>de</strong>o, solo se presiona la tecla F!, con lo cual<br />

aparecerá la sigui<strong>en</strong>te pagina propietaria:<br />

Para iniciar el efecto se selecciona el ovalo correspondi<strong>en</strong>te y posteriorm<strong>en</strong>te el<br />

botón Apply, con lo cual este se ejecutará inmediatam<strong>en</strong>te.


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 96<br />

Código Fu<strong>en</strong>te <strong>de</strong>l filtro<br />

//------------------------------------------------------------------------------<br />

// Archivo: EZRGB24.cpp<br />

//<br />

// Desc: Filtro <strong>de</strong> efectos especiales <strong>en</strong> la imag<strong>en</strong><br />

//<br />

//------------------------------------------------------------------------------<br />

// Resum<strong>en</strong><br />

//<br />

// Este es un filtro <strong>de</strong> efectos especiales y trabaja solo con formatos RGB24<br />

// Este filtro pue<strong>de</strong> ser insertado <strong>en</strong>tre <strong>de</strong>codificadores <strong>de</strong> vi<strong>de</strong>o y r<strong>en</strong><strong>de</strong>rers<br />

//<br />

// Archivos<br />

//<br />

// ezprop.cpp Pagina propietaria para controlar los efectos <strong>de</strong> vi<strong>de</strong>o<br />

// ezprop.h Definición <strong>de</strong> clases para el objeto pagina propietaria<br />

// ezprop.rc Template para la caja <strong>de</strong> dialogo <strong>en</strong> la pagina propietaria<br />

// ezrgb24.cpp Codigo <strong>de</strong>l filtro principal que hace los efectos especiales<br />

// ezrgb24.<strong>de</strong>f Que APIs importamos y exportamos <strong>de</strong>s<strong>de</strong> esta DLL<br />

// ezrgb24.h Definicion <strong>de</strong> clases para los filtros <strong>de</strong> efectos especiales<br />

// ezuids.h Archivos Hea<strong>de</strong>r cont<strong>en</strong>i<strong>en</strong>do los CLSID <strong>de</strong>l filtro<br />

// iez.h Define la interfaz personalizada <strong>de</strong> los efectos especiales<br />

// makefile<br />

// resource.h Archivos g<strong>en</strong>erados por Microsoft Visual C++<br />

//<br />

//<br />

// clases Base utilizadas<br />

//<br />

// CTransformFilter Un filtro transform con un input y un output<br />

// CPersistStream Maneja los soportes para IPersistStream<br />

//<br />

//<br />

#inclu<strong>de</strong> <br />

#inclu<strong>de</strong> <br />

#inclu<strong>de</strong> <br />

#if (1100 > _MSC_VER)<br />

#inclu<strong>de</strong> <br />

#else<br />

#inclu<strong>de</strong> <br />

#<strong>en</strong>dif<br />

#inclu<strong>de</strong> "EZuids.h"<br />

#inclu<strong>de</strong> "iEZ.h"<br />

#inclu<strong>de</strong> "EZprop.h"<br />

#inclu<strong>de</strong> "EZrgb24.h"<br />

#inclu<strong>de</strong> "resource.h"<br />

// Información <strong>de</strong> Setup<br />

const AMOVIESETUP_MEDIATYPE sudPinTypes =<br />

{<br />

&MEDIATYPE_Vi<strong>de</strong>o, // tipo Major<br />

&MEDIASUBTYPE_NULL // tipo Minor<br />

};<br />

const AMOVIESETUP_PIN sudpPins[] =<br />

{<br />

{ L"Input", // Nombre <strong>de</strong> Pins<br />

FALSE, // Será r<strong>en</strong><strong>de</strong>red<br />

FALSE, // Este no es un output<br />

FALSE, // No estamos permiti<strong>en</strong>do ninguno<br />

FALSE, // Permitimos muchos<br />

&CLSID_NULL, // Conexiones al filtro<br />

NULL, // Conexion al pin<br />

1, // Numero <strong>de</strong> tipos<br />

&sudPinTypes // Informacion <strong>de</strong>l Pin


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 97<br />

};<br />

},<br />

{ L"Output", // Nombre <strong>de</strong>l Pin<br />

FALSE, // Sera r<strong>en</strong><strong>de</strong>red<br />

TRUE, // Este es un output<br />

FALSE, // No permitimos ninguno<br />

FALSE, // Y soportamos muchos<br />

&CLSID_NULL, // Conexiones al filtro<br />

NULL, // Conexion al pin<br />

1, // Numero <strong>de</strong> tipos<br />

&sudPinTypes // Informacion <strong>de</strong>l pin<br />

}<br />

const AMOVIESETUP_FILTER sudEZrgb24 =<br />

{<br />

&CLSID_EZrgb24, // CLSID <strong>de</strong>l filtro<br />

L"Image Effects", // nombre<br />

MERIT_DO_NOT_USE, // Merito <strong>de</strong>l filtro<br />

2, // Numero <strong>de</strong> pins<br />

sudpPins // Informacion <strong>de</strong>l Pin<br />

};<br />

// Lista <strong>de</strong> clases Ids y funciones para la clase factory. Esta provee el <strong>en</strong>lace<br />

// <strong>en</strong>tre el punto <strong>de</strong> <strong>en</strong>trada OLE <strong>en</strong> la DLL y un objeto que será creado.<br />

// La clase factory llamará a CreateInstance<br />

CFactoryTemplate g_Templates[] = {<br />

{ L"Image Effects"<br />

, &CLSID_EZrgb24<br />

, CEZrgb24::CreateInstance<br />

, NULL<br />

, &sudEZrgb24 }<br />

,<br />

{ L"Special Effects"<br />

, &CLSID_EZrgb24PropertyPage<br />

, CEZrgb24Properties::CreateInstance }<br />

};<br />

int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);<br />

//<br />

// DllRegisterServer<br />

//<br />

// Maneja el registro y <strong>de</strong>sregistro <strong>de</strong> la muestra<br />

//<br />

STDAPI DllRegisterServer()<br />

{<br />

return AMovieDllRegisterServer2( TRUE );<br />

} // DllRegisterServer<br />

//<br />

// DllUnregisterServer<br />

//<br />

STDAPI DllUnregisterServer()<br />

{<br />

return AMovieDllRegisterServer2( FALSE );<br />

} // DllUnregisterServer<br />

//<br />

// Constructor<br />

//<br />

CEZrgb24::CEZrgb24(TCHAR *tszName,<br />

LPUNKNOWN punk,<br />

HRESULT *phr) :<br />

CTransformFilter(tszName, punk, CLSID_EZrgb24),<br />

m_effect(IDC_NONE),<br />

m_lBufferRequest(1),


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 98<br />

{<br />

CPersistStream(punk, phr)<br />

char sz[60];<br />

GetProfileStringA("Quartz", "EffectStart", "0.0", sz, 60);<br />

m_effectStartTime = COARefTime(atof(sz));<br />

GetProfileStringA("Quartz", "EffectL<strong>en</strong>gth", "50000.0", sz, 60);<br />

m_effectTime = COARefTime(atof(sz));<br />

} // (Constructor)<br />

//<br />

// CreateInstance<br />

//<br />

// Provee la via para que COM cree un objeto EZrgb24<br />

//<br />

CUnknown *CEZrgb24::CreateInstance(LPUNKNOWN punk, HRESULT *phr)<br />

{<br />

CEZrgb24 *pNewObject = new CEZrgb24(NAME("Image Effects"), punk, phr);<br />

if (pNewObject == NULL) {<br />

*phr = E_OUTOFMEMORY;<br />

}<br />

return pNewObject;<br />

} // CreateInstance<br />

//<br />

// NonDelegatingQueryInterface<br />

//<br />

// Pres<strong>en</strong>ta las paginas propietarias IIPEffect y ISpecifyPropertyPages<br />

//<br />

STDMETHODIMP CEZrgb24::NonDelegatingQueryInterface(REFIID riid, void **ppv)<br />

{<br />

CheckPointer(ppv,E_POINTER);<br />

if (riid == IID_IIPEffect) {<br />

return GetInterface((IIPEffect *) this, ppv);<br />

} else if (riid == IID_ISpecifyPropertyPages) {<br />

return GetInterface((ISpecifyPropertyPages *) this, ppv);<br />

} else {<br />

return CTransformFilter::NonDelegatingQueryInterface(riid, ppv);<br />

}<br />

} // NonDelegatingQueryInterface<br />

//<br />

// Transform<br />

//<br />

// Copia la muestra <strong>de</strong> <strong>en</strong>trada hacia la muestra <strong>de</strong> salida - <strong>en</strong>tonces transforma<br />

// la muestra <strong>de</strong> salida 'in place'.<br />

HRESULT CEZrgb24::Transform(IMediaSample *pIn, IMediaSample *pOut)<br />

{<br />

// Copia las propieda<strong>de</strong>s<br />

HRESULT hr = Copy(pIn, pOut);<br />

if (FAILED(hr)) {<br />

return hr;<br />

}<br />

// Checa para ver si es <strong>tiempo</strong> <strong>de</strong> hacer la muestra<br />

CRefTime tStart, tStop ;<br />

pIn->GetTime((REFERENCE_TIME *) &tStart, (REFERENCE_TIME *) &tStop);<br />

if (tStart >= m_effectStartTime) {<br />

if (tStop


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 99<br />

return NOERROR;<br />

} // Transform<br />

//<br />

// Copy<br />

//<br />

// Hace <strong>en</strong> el <strong>de</strong>stino una copia i<strong>de</strong>ntica <strong>de</strong> la fu<strong>en</strong>te Make<br />

//<br />

HRESULT CEZrgb24::Copy(IMediaSample *pSource, IMediaSample *pDest) const<br />

{<br />

// Copia los datos <strong>en</strong> la muestra<br />

BYTE *pSourceBuffer, *pDestBuffer;<br />

long lSourceSize = pSource->GetActualDataL<strong>en</strong>gth();<br />

#if<strong>de</strong>f DEBUG<br />

long lDestSize = pDest->GetSize();<br />

ASSERT(lDestSize >= lSourceSize);<br />

#<strong>en</strong>dif<br />

pSource->GetPointer(&pSourceBuffer);<br />

pDest->GetPointer(&pDestBuffer);<br />

CopyMemory( (PVOID) pDestBuffer,(PVOID) pSourceBuffer,lSourceSize);<br />

// Copia los <strong>tiempo</strong>s <strong>de</strong> la muestra<br />

REFERENCE_TIME TimeStart, TimeEnd;<br />

if (NOERROR == pSource->GetTime(&TimeStart, &TimeEnd)) {<br />

pDest->SetTime(&TimeStart, &TimeEnd);<br />

}<br />

LONGLONG MediaStart, MediaEnd;<br />

if (pSource->GetMediaTime(&MediaStart,&MediaEnd) == NOERROR) {<br />

pDest->SetMediaTime(&MediaStart,&MediaEnd);<br />

}<br />

// Copia los puntos propietarios Sync<br />

HRESULT hr = pSource->IsSyncPoint();<br />

if (hr == S_OK) {<br />

pDest->SetSyncPoint(TRUE);<br />

}<br />

else if (hr == S_FALSE) {<br />

pDest->SetSyncPoint(FALSE);<br />

}<br />

else { // un error inesperado ocurrió...<br />

return E_UNEXPECTED;<br />

}<br />

// Copia el tipo <strong>de</strong> media<br />

AM_MEDIA_TYPE *pMediaType;<br />

pSource->GetMediaType(&pMediaType);<br />

pDest->SetMediaType(pMediaType);<br />

DeleteMediaType(pMediaType);<br />

// Copia las propieda<strong>de</strong>s preroll<br />

hr = pSource->IsPreroll();<br />

if (hr == S_OK) {<br />

pDest->SetPreroll(TRUE);<br />

}<br />

else if (hr == S_FALSE) {<br />

pDest->SetPreroll(FALSE);<br />

}<br />

else { // un error inesperado ocurrió...<br />

return E_UNEXPECTED;<br />

}


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 100<br />

// Copia la propiedad Discontinuity<br />

hr = pSource->IsDiscontinuity();<br />

if (hr == S_OK) {<br />

pDest->SetDiscontinuity(TRUE);<br />

}<br />

else if (hr == S_FALSE) {<br />

pDest->SetDiscontinuity(FALSE);<br />

}<br />

else { // un error inesperado ocurrió...<br />

return E_UNEXPECTED;<br />

}<br />

// Copia la longitud <strong>de</strong> datos actual<br />

long lDataL<strong>en</strong>gth = pSource->GetActualDataL<strong>en</strong>gth();<br />

pDest->SetActualDataL<strong>en</strong>gth(lDataL<strong>en</strong>gth);<br />

return NOERROR;<br />

} // Copy<br />

//<br />

// Transformación (in place)<br />

//<br />

// Se aplica el efecto a la imag<strong>en</strong> <strong>en</strong> el modo 'in place' dado que la muestra<br />

// <strong>de</strong> salida no es mayor que la <strong>de</strong> <strong>en</strong>trada<br />

HRESULT CEZrgb24::Transform(IMediaSample *pMediaSample) //Objeto COM Media Sample<br />

{<br />

AM_MEDIA_TYPE* pType = &m_pInput->Curr<strong>en</strong>tMediaType(); // Esctructura que conti<strong>en</strong>e el<br />

bloque <strong>de</strong> formato<br />

VIDEOINFOHEADER *pvi = (VIDEOINFOHEADER *) pType->pbFormat; //Estructura con informacion<br />

sobre la imag<strong>en</strong> y por consigui<strong>en</strong>te razon <strong>de</strong> datos permisible<br />

BYTE *pData; // Char sin signo, apunta al buffer <strong>de</strong> imag<strong>en</strong> actual<br />

long lDataL<strong>en</strong>; // Conti<strong>en</strong>e la longitud <strong>de</strong> una muestra dada<br />

unsigned int grey,grey2; // Se usan para efectuar efectos <strong>de</strong> gris<br />

int iPixel, jPixel; // Utilizado para circular por los pixeles <strong>de</strong> la imag<strong>en</strong><br />

int temp,x,y; // Contadores <strong>de</strong> ciclos para transformaciones<br />

RGBTRIPLE *prgb; // Manti<strong>en</strong>e un apuntador al pixel actual la estructura<br />

conti<strong>en</strong>e los compon<strong>en</strong>tes RGB<br />

congela<br />

pMediaSample->GetPointer(&pData);<br />

lDataL<strong>en</strong> = pMediaSample->GetSize();<br />

// Obti<strong>en</strong>e las propieda<strong>de</strong>s <strong>de</strong> la imag<strong>en</strong> usando BITMAPINFOHEADER<br />

int cxImage = pvi->bmiHea<strong>de</strong>r.biWidth; // Ancho <strong>de</strong> la imag<strong>en</strong><br />

int cyImage = pvi->bmiHea<strong>de</strong>r.biHeight; // Altura <strong>de</strong> la imag<strong>en</strong><br />

int numPixels = cxImage * cyImage;<br />

int i = 0;<br />

// int iPixelSize = pvi->bmiHea<strong>de</strong>r.biBitCount / 8;<br />

// int cbImage = cyImage * cxImage * iPixelSize;<br />

// Incluyo la imag<strong>en</strong> <strong>en</strong> un arreglo <strong>de</strong> estructuras<br />

RGBQUAD bmiColors[61][99]; // Es importante no exce<strong>de</strong>r eswte limite <strong>de</strong> matriz o se<br />

// Para cargar la imag<strong>en</strong> .bmp<br />

HBITMAP hbitmap = (HBITMAP)LoadImage(NULL, "C:\\Mis docum<strong>en</strong>tos\\UAM6.bmp",<br />

IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);<br />

// Crea un dc <strong>de</strong> memoria<br />

HDC hMemDC = ::CreateCompatibleDC(NULL);<br />

//Selecciona el mapa <strong>de</strong> bits <strong>en</strong> el dc <strong>de</strong> memoria<br />

SelectObject(hMemDC, hbitmap);<br />

for(iPixel = 0; iPixel < 61; iPixel++)<br />

for(jPixel = 0; jPixel < 99; jPixel++){


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 101<br />

colores);<br />

colores);<br />

}<br />

COLORREF colores = GetPixel(hMemDC, jPixel, iPixel);<br />

bmiColors[iPixel][jPixel].rgbBlue = GetBValue((DWORD)<br />

bmiColors[iPixel][jPixel].rgbGre<strong>en</strong> = GetGValue((DWORD)<br />

bmiColors[iPixel][jPixel].rgbRed = GetRValue((DWORD) colores);<br />

//Borra el dc <strong>de</strong> memoria y el mapa <strong>de</strong> bits<br />

::DeleteDC(hMemDC);<br />

::DeleteObject(hbitmap);<br />

::DeleteDC(hMemDC); //Curioso, pero su repeticion evita que la matriz bmicolors se<br />

vaya a blanco, ver pp251<br />

switch (m_effect)<br />

{<br />

case IDC_NONE: break;<br />

prgb++);<br />

255) {<br />

// Se eliminan las otras dos compon<strong>en</strong>tes <strong>de</strong> color para <strong>de</strong>jar solo<br />

// la roja, la ver<strong>de</strong> o la azul<br />

case IDC_RED:<br />

prgb = (RGBTRIPLE*) pData;<br />

for (iPixel=0; iPixel < numPixels; iPixel++, prgb++) {<br />

prgb->rgbtGre<strong>en</strong> = 0;<br />

prgb->rgbtBlue = 0;<br />

}<br />

break;<br />

case IDC_GREEN:<br />

prgb = (RGBTRIPLE*) pData;<br />

for (iPixel=0; iPixel < numPixels; iPixel++, prgb++) {<br />

if(!(rand() % 3)) {<br />

prgb->rgbtGre<strong>en</strong> = 255;<br />

prgb->rgbtBlue = 255;<br />

prgb->rgbtRed = 255;<br />

}<br />

}<br />

break;<br />

case IDC_BLUE:<br />

prgb = (RGBTRIPLE*) pData;<br />

bmiColors[iPixel][jPixel].rgbRed;<br />

bmiColors[iPixel][jPixel].rgbGre<strong>en</strong>;<br />

bmiColors[iPixel][jPixel].rgbBlue;<br />

prgb++);<br />

break;<br />

//offset <strong>de</strong> la imag<strong>en</strong> superpuesta<br />

for(i = 0; i < (int)((cyImage/25)*(1 + cxImage)); i++,<br />

for(iPixel = 0; iPixel < 60; iPixel++) {<br />

for(jPixel = 0; jPixel < 98; jPixel++, prgb++){<br />

if(bmiColors[iPixel][jPixel].rgbGre<strong>en</strong> !=<br />

}<br />

// Desplaza cada compon<strong>en</strong>te a la <strong>de</strong>recha 1 posicion<br />

// esto resulta <strong>en</strong> una imag<strong>en</strong> mas obscura<br />

case IDC_DARKEN:<br />

prgb->rgbtRed =<br />

prgb->rgbtGre<strong>en</strong> =<br />

prgb->rgbtBlue =<br />

}<br />

}<br />

for(jPixel = 98; jPixel < cxImage; jPixel++,


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 102<br />

prgb++);<br />

prgb = (RGBTRIPLE*) pData;<br />

//offset <strong>de</strong> la imag<strong>en</strong> superpuesta<br />

for(i = 0; i < (int)((cyImage/25)*(1 + cxImage)); i++,<br />

for(iPixel = 0; iPixel < 60; iPixel++) {<br />

for(jPixel = 0; jPixel < 98; jPixel++, prgb++){<br />

if(bmiColors[iPixel][jPixel].rgbGre<strong>en</strong> !=<br />

255) {<br />

prgb->rgbtRed = (prgb->rgbtRed<br />

+ bmiColors[iPixel][jPixel].rgbRed)/2;<br />

prgb->rgbtGre<strong>en</strong> = (prgb-<br />

>rgbtGre<strong>en</strong> + bmiColors[iPixel][jPixel].rgbGre<strong>en</strong>)/2;<br />

prgb->rgbtBlue = (prgb-<br />

>rgbtBlue + bmiColors[iPixel][jPixel].rgbBlue)/2;<br />

}<br />

}<br />

for(jPixel = 98; jPixel < cxImage; jPixel++,<br />

prgb++);<br />

}<br />

break;<br />

/* PRUEBAS PARA QUITAR EL LOGO<br />

//offset <strong>de</strong>l Logotipo MTV<br />

prgb = (RGBTRIPLE*) pData;<br />

255) {<br />

* 2 - 255;<br />

>rgbtGre<strong>en</strong> * 2 - 255;<br />

* 2 - 255;<br />

prgb++);<br />

*/<br />

for(i = 0; i < (cyImage-43) * cxImage + 303; i++, prgb++);<br />

for(iPixel = 0; iPixel < 29; iPixel++) {<br />

for(jPixel = 0; jPixel < 34; jPixel++, prgb++){<br />

//if(bmiColors[iPixel][jPixel].rgbGre<strong>en</strong> !=<br />

}<br />

prgb->rgbtRed = prgb->rgbtRed<br />

prgb->rgbtGre<strong>en</strong> = prgb-<br />

prgb->rgbtBlue = prgb->rgbtBlue<br />

//}<br />

}<br />

for(jPixel = 34; jPixel < cxImage; jPixel++,<br />

// Cambia ceros por unos y viceversa produci<strong>en</strong>do un negativo<br />

case IDC_XOR:<br />

prgb = (RGBTRIPLE*) pData;<br />

for (iPixel=0; iPixel < numPixels; iPixel++, prgb++) {<br />

prgb->rgbtRed = (BYTE) (~prgb->rgbtRed);<br />

prgb->rgbtGre<strong>en</strong> = (BYTE) (~prgb->rgbtGre<strong>en</strong>);<br />

prgb->rgbtBlue = (BYTE) (~prgb->rgbtBlue);<br />

}<br />

break;<br />

// Se hac<strong>en</strong> cero los 5 bits m<strong>en</strong>os significativos para cada compon<strong>en</strong>te<br />

case IDC_POSTERIZE:<br />

prgb = (RGBTRIPLE*) pData;<br />

for (iPixel=0; iPixel < numPixels; iPixel++, prgb++) {<br />

prgb->rgbtRed = (BYTE) (prgb->rgbtRed & 0xe0);<br />

prgb->rgbtGre<strong>en</strong> = (BYTE) (prgb->rgbtGre<strong>en</strong> & 0xe0);<br />

prgb->rgbtBlue = (BYTE) (prgb->rgbtBlue & 0xe0);<br />

}<br />

break;<br />

// Toma un pixel y el sigui<strong>en</strong>te mas cercano a dos pixeles a su <strong>de</strong>recha<br />

// Los promedia y lo sobreescribe.<br />

case IDC_BLUR:<br />

prgb = (RGBTRIPLE*) pData;


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 103<br />

cercanos.<br />

medio.<br />

for (y = 0 ; y < pvi->bmiHea<strong>de</strong>r.biHeight; y++) {<br />

for (x = 2 ; x < pvi->bmiHea<strong>de</strong>r.biWidth; x++,prgb++) {<br />

prgb->rgbtRed = (BYTE) ((prgb->rgbtRed + prgb[2].rgbtRed) >> 1);<br />

prgb->rgbtGre<strong>en</strong> = (BYTE) ((prgb->rgbtGre<strong>en</strong> + prgb[2].rgbtGre<strong>en</strong>) >> 1);<br />

prgb->rgbtBlue = (BYTE) ((prgb->rgbtBlue + prgb[2].rgbtBlue) >> 1);<br />

}<br />

prgb +=2;<br />

}<br />

break;<br />

// Un calculo <strong>de</strong> la escala <strong>de</strong> grises es:<br />

// grey = (30 * red + 59 * gre<strong>en</strong> + 11 * blue) / 100<br />

// Un calculo mas rapido es el sigui<strong>en</strong>te:<br />

// grey = (red + gre<strong>en</strong>) / 2<br />

case IDC_GREY:<br />

prgb = (RGBTRIPLE*) pData;<br />

for (iPixel=0; iPixel < numPixels ; iPixel++, prgb++) {<br />

grey = (prgb->rgbtRed + prgb->rgbtGre<strong>en</strong>) >> 1;<br />

prgb->rgbtRed = prgb->rgbtGre<strong>en</strong> = prgb->rgbtBlue = (BYTE) grey;<br />

}<br />

break;<br />

// Comparamos los valores <strong>de</strong> escala <strong>de</strong> grises <strong>de</strong> los dos mas<br />

// Si no son difer<strong>en</strong>tes, <strong>en</strong>tonces un gris intermedio (128, 128, 128)<br />

// se sobrepone. Gran<strong>de</strong>s difer<strong>en</strong>cias se alejan mas <strong>de</strong> la escala <strong>de</strong> gris<br />

case IDC_EMBOSS:<br />

prgb = (RGBTRIPLE*) pData;<br />

for (y = 0 ; y < pvi->bmiHea<strong>de</strong>r.biHeight; y++) {<br />

grey2 = (prgb->rgbtRed + prgb->rgbtGre<strong>en</strong>) >> 1;<br />

prgb->rgbtRed = prgb->rgbtGre<strong>en</strong> = prgb->rgbtBlue = (BYTE) 128;<br />

prgb++;<br />

for (x = 1 ; x < pvi->bmiHea<strong>de</strong>r.biWidth; x++) {<br />

grey = (prgb->rgbtRed + prgb->rgbtGre<strong>en</strong>) >> 1;<br />

temp = grey - grey2;<br />

if (temp > 127) temp = 127;<br />

if (temp < -127) temp = -127;<br />

temp += 128;<br />

prgb->rgbtRed = prgb->rgbtGre<strong>en</strong> = prgb->rgbtBlue = (BYTE) temp;<br />

grey2 = grey;<br />

prgb++;<br />

}<br />

}<br />

break;<br />

}<br />

return NOERROR;<br />

} // Transform (in place)<br />

// Checa que el tipo input sea OK, retorna un error <strong>en</strong> caso contrario<br />

HRESULT CEZrgb24::CheckInputType(const CMediaType *mtIn)<br />

{<br />

// checa que sea un tipo VIDEOINFOHEADER<br />

}<br />

//<br />

if (*mtIn->FormatType() != FORMAT_Vi<strong>de</strong>oInfo) {<br />

return E_INVALIDARG;<br />

}<br />

// Se pue<strong>de</strong> transformar este tipo?<br />

if (CanPerformEZrgb24(mtIn)) {<br />

return NOERROR;<br />

}<br />

return E_FAIL;


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 104<br />

// Checktransform<br />

//<br />

// Checa que una transformacion pueda llevarse a cabo <strong>en</strong>tre estos formatos<br />

//<br />

HRESULT CEZrgb24::CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut)<br />

{<br />

if (CanPerformEZrgb24(mtIn)) {<br />

if (*mtIn == *mtOut) {<br />

return NOERROR;<br />

}<br />

}<br />

return E_FAIL;<br />

} // CheckTransform<br />

//<br />

// Deci<strong>de</strong>BufferSize<br />

//<br />

// Le dice al localizador <strong>de</strong>l pin output que tamaño <strong>de</strong> buffer requerimos.<br />

// Po<strong>de</strong>mos hacer esto solo cuando el input esta conectado<br />

//<br />

HRESULT CEZrgb24::Deci<strong>de</strong>BufferSize(IMemAllocator *pAlloc,ALLOCATOR_PROPERTIES *pProperties)<br />

{<br />

// Esta conectado el input pin?<br />

if (m_pInput->IsConnected() == FALSE) {<br />

return E_UNEXPECTED;<br />

}<br />

ASSERT(pAlloc);<br />

ASSERT(pProperties);<br />

HRESULT hr = NOERROR;<br />

pProperties->cBuffers = 1;<br />

pProperties->cbBuffer = m_pInput->Curr<strong>en</strong>tMediaType().GetSampleSize();<br />

ASSERT(pProperties->cbBuffer);<br />

// Pregunta al locaclizador para reservarnos alguna memoria para la muestra.<br />

ALLOCATOR_PROPERTIES Actual;<br />

hr = pAlloc->SetProperties(pProperties,&Actual);<br />

if (FAILED(hr)) {<br />

return hr;<br />

}<br />

ASSERT( Actual.cBuffers == 1 );<br />

if (pProperties->cBuffers > Actual.cBuffers ||<br />

pProperties->cbBuffer > Actual.cbBuffer) {<br />

return E_FAIL;<br />

}<br />

return NOERROR;<br />

} // Deci<strong>de</strong>BufferSize<br />

//<br />

// GetMediaType<br />

//<br />

// Soporto un tipo, normalem<strong>en</strong>te el tipo <strong>de</strong>l input pin<br />

// Este tipo solo esta disponible si mi input esta conectado<br />

//<br />

HRESULT CEZrgb24::GetMediaType(int iPosition, CMediaType *pMediaType)<br />

{<br />

// Esta conectado el input pin?<br />

if (m_pInput->IsConnected() == FALSE) {<br />

return E_UNEXPECTED;<br />

}


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 105<br />

// Esto nunca <strong>de</strong>be suce<strong>de</strong>r<br />

if (iPosition < 0) {<br />

return E_INVALIDARG;<br />

}<br />

// T<strong>en</strong>emos mas items para ofertar?<br />

if (iPosition > 0) {<br />

return VFW_S_NO_MORE_ITEMS;<br />

}<br />

*pMediaType = m_pInput->Curr<strong>en</strong>tMediaType();<br />

return NOERROR;<br />

} // GetMediaType<br />

//<br />

// CanPerformEZrgb24<br />

//<br />

// Checa si este es un formato <strong>de</strong> color RGB24 valido<br />

//<br />

BOOL CEZrgb24::CanPerformEZrgb24(const CMediaType *pMediaType) const<br />

{<br />

if (IsEqualGUID(*pMediaType->Type(), MEDIATYPE_Vi<strong>de</strong>o)) {<br />

if (IsEqualGUID(*pMediaType->Subtype(), MEDIASUBTYPE_RGB24)) {<br />

VIDEOINFOHEADER *pvi = (VIDEOINFOHEADER *) pMediaType->Format();<br />

return (pvi->bmiHea<strong>de</strong>r.biBitCount == 24);<br />

}<br />

}<br />

return FALSE;<br />

} // CanPerformEZrgb24<br />

#<strong>de</strong>fine WRITEOUT(var) hr = pStream->Write(&var, sizeof(var), NULL); \<br />

if (FAILED(hr)) return hr;<br />

#<strong>de</strong>fine READIN(var) hr = pStream->Read(&var, sizeof(var), NULL); \<br />

if (FAILED(hr)) return hr;<br />

//<br />

// GetClassID<br />

//<br />

// Este es el unico metodo <strong>de</strong> IPersist<br />

//<br />

STDMETHODIMP CEZrgb24::GetClassID(CLSID *pClsid)<br />

{<br />

return CBaseFilter::GetClassID(pClsid);<br />

} // GetClassID<br />

//<br />

// ScribbleToStream<br />

//<br />

// Imposibilitado para escribir nuestro estado hacia un stream<br />

//<br />

HRESULT CEZrgb24::ScribbleToStream(IStream *pStream)<br />

{<br />

HRESULT hr;<br />

WRITEOUT(m_effect);<br />

WRITEOUT(m_effectStartTime);<br />

WRITEOUT(m_effectTime);<br />

return NOERROR;<br />

} // ScribbleToStream<br />

//


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 106<br />

// ReadFromStream<br />

//<br />

// Imposibilitado para restaurar nuestro estado <strong>de</strong>s<strong>de</strong> un stream<br />

//<br />

HRESULT CEZrgb24::ReadFromStream(IStream *pStream)<br />

{<br />

HRESULT hr;<br />

READIN(m_effect);<br />

READIN(m_effectStartTime);<br />

READIN(m_effectTime);<br />

return NOERROR;<br />

} // ReadFromStream<br />

//<br />

// GetPages<br />

//<br />

// Retorna el clsid <strong>de</strong> la pagina propietaria que nosotros soportamos<br />

//<br />

STDMETHODIMP CEZrgb24::GetPages(CAUUID *pPages)<br />

{<br />

pPages->cElems = 1;<br />

pPages->pElems = (GUID *) CoTaskMemAlloc(sizeof(GUID));<br />

if (pPages->pElems == NULL) {<br />

return E_OUTOFMEMORY;<br />

}<br />

*(pPages->pElems) = CLSID_EZrgb24PropertyPage;<br />

return NOERROR;<br />

} // GetPages<br />

//<br />

// get_IPEffect<br />

//<br />

// Retorna el efecto actual seleccionado<br />

//<br />

STDMETHODIMP CEZrgb24::get_IPEffect(int *IPEffect,REFTIME *start,REFTIME *l<strong>en</strong>gth)<br />

{<br />

CAutoLock cAutolock(&m_EZrgb24Lock);<br />

CheckPointer(IPEffect,E_POINTER);<br />

CheckPointer(start,E_POINTER);<br />

CheckPointer(l<strong>en</strong>gth,E_POINTER);<br />

*IPEffect = m_effect;<br />

*start = COARefTime(m_effectStartTime);<br />

*l<strong>en</strong>gth = COARefTime(m_effectTime);<br />

return NOERROR;<br />

} // get_IPEffect<br />

//<br />

// put_IPEffect<br />

//<br />

// Selecciona el efecto <strong>de</strong> vi<strong>de</strong>o requerido<br />

//<br />

STDMETHODIMP CEZrgb24::put_IPEffect(int IPEffect,REFTIME start,REFTIME l<strong>en</strong>gth)<br />

{<br />

CAutoLock cAutolock(&m_EZrgb24Lock);<br />

m_effect = IPEffect;<br />

m_effectStartTime = COARefTime(start);<br />

m_effectTime = COARefTime(l<strong>en</strong>gth);<br />

SetDirty(TRUE);<br />

return NOERROR;<br />

} // put_IPEffect


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 107<br />

//------------------------------------------------------------------------------<br />

// File: EZProp.cpp<br />

//<br />

// Desc: DirectShow - implem<strong>en</strong>tación <strong>de</strong> la clase CEZRgb24Properties<br />

//<br />

//------------------------------------------------------------------------------<br />

#inclu<strong>de</strong> <br />

#inclu<strong>de</strong> <br />

#inclu<strong>de</strong> <br />

#inclu<strong>de</strong> <br />

#inclu<strong>de</strong> <br />

#inclu<strong>de</strong> <br />

#inclu<strong>de</strong> <br />

#inclu<strong>de</strong> <br />

#inclu<strong>de</strong> <br />

#inclu<strong>de</strong> "resource.h"<br />

#inclu<strong>de</strong> "EZuids.h"<br />

#inclu<strong>de</strong> "iEZ.h"<br />

#inclu<strong>de</strong> "EZrgb24.h"<br />

#inclu<strong>de</strong> "EZprop.h"<br />

//<br />

// CreateInstance<br />

//<br />

// Usada por las clases base <strong>de</strong> DirectShow para crear instancias<br />

//<br />

CUnknown *CEZrgb24Properties::CreateInstance(LPUNKNOWN lpunk, HRESULT *phr)<br />

{<br />

CUnknown *punk = new CEZrgb24Properties(lpunk, phr);<br />

if (punk == NULL) {<br />

*phr = E_OUTOFMEMORY;<br />

}<br />

return punk;<br />

} // CreateInstance<br />

//<br />

// Constructor<br />

//<br />

CEZrgb24Properties::CEZrgb24Properties(LPUNKNOWN pUnk, HRESULT *phr) :<br />

CBasePropertyPage(NAME("Special Effects Property Page"),<br />

pUnk,IDD_EZrgb24PROP,IDS_TITLE),<br />

m_pIPEffect(NULL),<br />

m_bIsInitialized(FALSE)<br />

{<br />

ASSERT(phr);<br />

} // (Constructor)<br />

//<br />

// OnReceiveMessage<br />

//<br />

// Maneja los m<strong>en</strong>sajes para nuestra v<strong>en</strong>tana propietaria<br />

//<br />

BOOL CEZrgb24Properties::OnReceiveMessage(HWND hwnd,<br />

UINT uMsg,<br />

WPARAM wParam,<br />

LPARAM lParam)<br />

{<br />

switch (uMsg)<br />

{<br />

case WM_COMMAND:<br />

{<br />

if (m_bIsInitialized)<br />

{<br />

m_bDirty = TRUE;


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 108<br />

}<br />

if (m_pPageSite)<br />

{<br />

m_pPageSite->OnStatusChange(PROPPAGESTATUS_DIRTY);<br />

}<br />

}<br />

return (LRESULT) 1;<br />

}<br />

return CBasePropertyPage::OnReceiveMessage(hwnd,uMsg,wParam,lParam);<br />

} // OnReceiveMessage<br />

//<br />

// OnConnect<br />

//<br />

// Se llama cuando nos conectamos a un filtro transform<br />

//<br />

HRESULT CEZrgb24Properties::OnConnect(IUnknown *pUnknown)<br />

{<br />

ASSERT(m_pIPEffect == NULL);<br />

HRESULT hr = pUnknown->QueryInterface(IID_IIPEffect, (void **) &m_pIPEffect);<br />

if (FAILED(hr)) {<br />

return E_NOINTERFACE;<br />

}<br />

ASSERT(m_pIPEffect);<br />

// Obti<strong>en</strong>e el efecto inicial<br />

m_pIPEffect->get_IPEffect(&m_effect, &m_start, &m_l<strong>en</strong>gth);<br />

m_bIsInitialized = FALSE ;<br />

return NOERROR;<br />

} // OnConnect<br />

//<br />

// OnDisconnect<br />

//<br />

// Se llama cuando nos <strong>de</strong>sconectamos <strong>de</strong> un filtro<br />

//<br />

HRESULT CEZrgb24Properties::OnDisconnect()<br />

{<br />

// Actualizacion <strong>de</strong> la interfaz <strong>de</strong>spues <strong>de</strong> ajustar los valores <strong>de</strong> los antiguos<br />

efectos<br />

if (m_pIPEffect == NULL) {<br />

return E_UNEXPECTED;<br />

}<br />

m_pIPEffect->Release();<br />

m_pIPEffect = NULL;<br />

return NOERROR;<br />

} // OnDisconnect<br />

//<br />

// OnActivate<br />

//<br />

// Cuando seamos activados<br />

//<br />

HRESULT CEZrgb24Properties::OnActivate()<br />

{<br />

TCHAR sz[60];<br />

_stprintf(sz, TEXT("%f"), m_l<strong>en</strong>gth);<br />

Edit_SetText(GetDlgItem(m_Dlg, IDC_LENGTH), sz);<br />

_stprintf(sz, TEXT("%f"), m_start);


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 109<br />

Edit_SetText(GetDlgItem(m_Dlg, IDC_START), sz);<br />

CheckRadioButton(m_Dlg, IDC_EMBOSS, IDC_NONE, m_effect);<br />

m_bIsInitialized = TRUE;<br />

return NOERROR;<br />

} // OnActivate<br />

//<br />

// OnDeactivate<br />

//<br />

// Cuando seamos <strong>de</strong>sactivados<br />

//<br />

HRESULT CEZrgb24Properties::OnDeactivate(void)<br />

{<br />

ASSERT(m_pIPEffect);<br />

m_bIsInitialized = FALSE;<br />

GetControlValues();<br />

return NOERROR;<br />

} // OnDeactivate<br />

//<br />

// OnApplyChanges<br />

//<br />

// Aplica cualquier cambio que sea <strong>real</strong>izado<br />

//<br />

HRESULT CEZrgb24Properties::OnApplyChanges()<br />

{<br />

GetControlValues();<br />

m_pIPEffect->put_IPEffect(m_effect, m_start, m_l<strong>en</strong>gth);<br />

return NOERROR;<br />

} // OnApplyChanges<br />

void CEZrgb24Properties::GetControlValues()<br />

{<br />

ASSERT(m_pIPEffect);<br />

TCHAR sz[STR_MAX_LENGTH];<br />

REFTIME tmp1, tmp2 ;<br />

// Obti<strong>en</strong>e el inicio y final <strong>de</strong>l efecto<br />

Edit_GetText(GetDlgItem(m_Dlg, IDC_LENGTH), sz, STR_MAX_LENGTH);<br />

#if<strong>de</strong>f UNICODE<br />

int rc;<br />

// Convierte ca<strong>de</strong>nas multibyte a ANSI<br />

char szANSI[STR_MAX_LENGTH];<br />

rc = Wi<strong>de</strong>CharToMultiByte(CP_ACP, 0, sz, -1, szANSI, STR_MAX_LENGTH, NULL, NULL);<br />

tmp2 = COARefTime(atof(szANSI));<br />

#else<br />

tmp2 = COARefTime(atof(sz));<br />

#<strong>en</strong>dif<br />

Edit_GetText(GetDlgItem(m_Dlg, IDC_START), sz, STR_MAX_LENGTH);<br />

#if<strong>de</strong>f UNICODE<br />

// Convierte ca<strong>de</strong>nas multibyte a ANSI<br />

rc = Wi<strong>de</strong>CharToMultiByte(CP_ACP, 0, sz, -1, szANSI, STR_MAX_LENGTH, NULL, NULL);<br />

tmp1 = COARefTime(atof(szANSI));<br />

#else<br />

tmp1 = COARefTime(atof(sz));<br />

#<strong>en</strong>dif<br />

// Validacion rapida <strong>de</strong> los campos


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 110<br />

}<br />

if (tmp1 >= 0 && tmp2 >= 0) {<br />

m_start = tmp1;<br />

m_l<strong>en</strong>gth = tmp2;<br />

}<br />

// Encu<strong>en</strong>tra cual efecto especial hemos seleccionado<br />

for (int i = IDC_EMBOSS; i


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 111<br />

// { 8B498502-1218-11cf-ADC4-00A0D100041B }<br />

DEFINE_GUID(CLSID_EZrgb24PropertyPage,<br />

0x8b498502, 0x1218, 0x11cf, 0xad, 0xc4, 0x0, 0xa0, 0xd1, 0x0, 0x4, 0x1b);<br />

//------------------------------------------------------------------------------<br />

// File: EZRGB24.h<br />

//<br />

// Desc: DirectShow sample co<strong>de</strong> - special effects filter hea<strong>de</strong>r file.<br />

//<br />

// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.<br />

//------------------------------------------------------------------------------<br />

class CEZrgb24 : public CTransformFilter,<br />

public IIPEffect,<br />

public ISpecifyPropertyPages,<br />

public CPersistStream<br />

{<br />

public:<br />

DECLARE_IUNKNOWN;<br />

static CUnknown * WINAPI CreateInstance(LPUNKNOWN punk, HRESULT *phr);<br />

// Reveals IEZrgb24 and ISpecifyPropertyPages<br />

STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv);<br />

// CPersistStream stuff<br />

HRESULT ScribbleToStream(IStream *pStream);<br />

HRESULT ReadFromStream(IStream *pStream);<br />

// Overrri<strong>de</strong>n from CTransformFilter base class<br />

HRESULT Transform(IMediaSample *pIn, IMediaSample *pOut);<br />

HRESULT CheckInputType(const CMediaType *mtIn);<br />

HRESULT CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut);<br />

HRESULT Deci<strong>de</strong>BufferSize(IMemAllocator *pAlloc,<br />

ALLOCATOR_PROPERTIES *pProperties);<br />

HRESULT GetMediaType(int iPosition, CMediaType *pMediaType);<br />

// These implem<strong>en</strong>t the custom IIPEffect interface<br />

STDMETHODIMP get_IPEffect(int *IPEffect, REFTIME *StartTime, REFTIME *L<strong>en</strong>gth);<br />

STDMETHODIMP put_IPEffect(int IPEffect, REFTIME StartTime, REFTIME L<strong>en</strong>gth);<br />

// ISpecifyPropertyPages interface<br />

STDMETHODIMP GetPages(CAUUID *pPages);<br />

// CPersistStream overri<strong>de</strong><br />

STDMETHODIMP GetClassID(CLSID *pClsid);<br />

private:<br />

// Constructor<br />

CEZrgb24(TCHAR *tszName, LPUNKNOWN punk, HRESULT *phr);<br />

// Look after doing the special effect<br />

BOOL CanPerformEZrgb24(const CMediaType *pMediaType) const;<br />

HRESULT Copy(IMediaSample *pSource, IMediaSample *pDest) const;<br />

HRESULT Transform(IMediaSample *pMediaSample);<br />

CCritSec m_EZrgb24Lock; // Private play critical section<br />

int m_effect; // Which effect are we processing<br />

CRefTime m_effectStartTime; // Wh<strong>en</strong> the effect will begin<br />

CRefTime m_effectTime; // And how long it will last for<br />

const long m_lBufferRequest; // The number of buffers to use<br />

}; // EZrgb2


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 112<br />

Código fu<strong>en</strong>te <strong>de</strong> la aplicación<br />

//------------------------------------------------------------------------------<br />

// Archivo: PlayWnd.cpp<br />

//<br />

// Descripcion: Reproductor <strong>de</strong> audio y vi<strong>de</strong>o que utiliza las librerias DirectShow<br />

// Pausa, <strong>de</strong>t<strong>en</strong>er, sil<strong>en</strong>cio, y cambio apantalla completa pue<strong>de</strong>n llevarse<br />

// a cabo mediante la barra <strong>de</strong> m<strong>en</strong>us o teclas.<br />

//<br />

//------------------------------------------------------------------------------<br />

#inclu<strong>de</strong> <br />

#inclu<strong>de</strong> <br />

#inclu<strong>de</strong> <br />

#inclu<strong>de</strong> <br />

#inclu<strong>de</strong> <br />

#inclu<strong>de</strong> //Es importante incluir antes <strong>de</strong> las <strong>de</strong>finir los GUIDS <strong>en</strong> "ezuids.h"<br />

// De lo contrario marca el error "error<br />

LNK2001: unresolved external symbol"<br />

#inclu<strong>de</strong> "ezuids.h" // Lo incluí para que reconozca el filtro ezrgb<br />

#inclu<strong>de</strong> "playwnd.h"<br />

//<br />

// Para permitir el registro <strong>de</strong> este grafico <strong>de</strong> filtros se <strong>de</strong>fine REGISTER_FILTERGRAPH.<br />

//<br />

#<strong>de</strong>fine REGISTER_FILTERGRAPH<br />

//<br />

// Variables globales<br />

//<br />

HWND ghApp=0;<br />

HINSTANCE ghInst;<br />

TCHAR g_szFileName[MAX_PATH]={0};<br />

BOOL g_bAudioOnly=FALSE;<br />

LONG g_lVolume=VOLUME_FULL;<br />

DWORD g_dwGraphRegister=0;<br />

PLAYSTATE g_psCurr<strong>en</strong>t=Stopped;<br />

// OJO CLSID CLSID_EZrgb24;<br />

// Interfaces DirectShow<br />

IGraphBuil<strong>de</strong>r *pGB = NULL;<br />

IMediaControl *pMC = NULL;<br />

IMediaEv<strong>en</strong>tEx *pME = NULL;<br />

IVi<strong>de</strong>oWindow *pVW = NULL;<br />

IBasicAudio *pBA = NULL;<br />

IBasicVi<strong>de</strong>o *pBV = NULL;<br />

IMediaSeeking *pMS = NULL;<br />

IBaseFilter *pFX = NULL; // Interfaz para el manejo <strong>de</strong>l nuevo filtro F1<br />

IPin *pOutPin = NULL; //Interfaz <strong>de</strong>l Pin <strong>de</strong> salida<br />

IPin *pInputPin = NULL; //Interfaz <strong>de</strong>l pin <strong>de</strong> <strong>en</strong>trada<br />

ISpecifyPropertyPages *pProp; // Para exponer la pagina propietaria<br />

ICaptureGraphBuil<strong>de</strong>r2 *pBuil<strong>de</strong>r = NULL; //Para la TV<br />

// Función que inicia la reproducción <strong>de</strong>l archivo multimedia<br />

HRESULT PlayMovieInWindow(LPTSTR szFile)<br />

{<br />

WCHAR wFile[MAX_PATH];<br />

HRESULT hr;<br />

IFilterGraph *pGraph = NULL;<br />

//CComPtr pSysDevEnum; // Se añadió al ultimo<br />

pGraph = pGB;


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 113<br />

// Se limpian los reman<strong>en</strong>tes <strong>de</strong> dialogo abiertos antes <strong>de</strong> llamar a R<strong>en</strong><strong>de</strong>rFile()<br />

UpdateWindow(ghApp);<br />

#ifn<strong>de</strong>f UNICODE<br />

MultiByteToWi<strong>de</strong>Char(CP_ACP, 0, szFile, -1, wFile, MAX_PATH);<br />

#else<br />

lstrcpy(wFile, szFile);<br />

#<strong>en</strong>dif<br />

// Se obti<strong>en</strong>e la interfaz para el constructor <strong>de</strong>l grafico <strong>de</strong> filtros GraphBuil<strong>de</strong>r<br />

JIF(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuil<strong>de</strong>r,<br />

(void **)&pGB));<br />

if(SUCCEEDED(hr))<br />

{<br />

// Se construye automaticam<strong>en</strong>te el grafico <strong>de</strong> filtros que ejecutara el archivo<br />

especificado<br />

JIF(pGB->R<strong>en</strong><strong>de</strong>rFile(wFile, NULL));<br />

// Desconectamos los ultimos dos filtros <strong>de</strong>l grafico<br />

EnumFilters("MPEG Vi<strong>de</strong>o Deco<strong>de</strong>r", PINDIR_OUTPUT); //Busca el output pin<br />

<strong>de</strong>l p<strong>en</strong>ultimo filtro...<br />

hr = pGB->Disconnect(pOutPin); //OK :-)<br />

ultimo filtro...<br />

Efectos<br />

EnumFilters("Vi<strong>de</strong>o R<strong>en</strong><strong>de</strong>rer", PINDIR_INPUT); //Busca el input pin <strong>de</strong>l<br />

hr = pGB->Disconnect(pInputPin); //OK :-)<br />

// pSysDevEnum->CreateClassEnumerator(CLSID_EZrgb24, &pEnumCat, 0);<br />

// Añadimos el filtro <strong>de</strong> efectos <strong>en</strong> la imag<strong>en</strong><br />

hr = CoCreateInstance(CLSID_EZrgb24, NULL, CLSCTX_INPROC_SERVER,<br />

IID_IBaseFilter, reinterpret_cast(&pFX));<br />

hr = pGB->AddFilter(pFX, L"Image Effects"); //:-) OK<br />

//Conectamos filtro <strong>de</strong> efectos y MPEG vi<strong>de</strong>o <strong>de</strong>co<strong>de</strong>r<br />

EnumFilters("Image Effects", PINDIR_INPUT); // Busca input pin <strong>de</strong> filtro<br />

hr = pGB->Connect(pOutPin, pInputPin);<br />

//Raconexion automatica <strong>en</strong>tre Image Effects y vi<strong>de</strong>o r<strong>en</strong><strong>de</strong>r<br />

EnumFilters("Image Effects", PINDIR_OUTPUT);<br />

EnumFilters("Vi<strong>de</strong>o R<strong>en</strong><strong>de</strong>rer", PINDIR_INPUT);<br />

hr = pGB->Connect(pOutPin, pInputPin);<br />

// QueryInterface para las interfaces DirectShow<br />

JIF(pGB->QueryInterface(IID_IMediaControl, (void **)&pMC));<br />

JIF(pGB->QueryInterface(IID_IMediaEv<strong>en</strong>tEx, (void **)&pME));<br />

JIF(pGB->QueryInterface(IID_IMediaSeeking, (void **)&pMS));<br />

// Consulta las interfaces <strong>de</strong> vi<strong>de</strong>o, las cuales pue<strong>de</strong>n no ser relevantes<br />

para archivos <strong>de</strong> audio<br />

JIF(pGB->QueryInterface(IID_IVi<strong>de</strong>oWindow, (void **)&pVW));<br />

JIF(pGB->QueryInterface(IID_IBasicVi<strong>de</strong>o, (void **)&pBV));<br />

// Consulta por interfaces <strong>de</strong> audio, las cuales no pue<strong>de</strong>n ser relevantes<br />

para archivos solo <strong>de</strong> vi<strong>de</strong>o<br />

JIF(pGB->QueryInterface(IID_IBasicAudio, (void **)&pBA));<br />

// Es este un archivo solo <strong>de</strong> audio (no hay compon<strong>en</strong>te <strong>de</strong> vi<strong>de</strong>o)?<br />

CheckVisibility();<br />

if (!g_bAudioOnly)<br />

{<br />

JIF(pVW->put_Owner((OAHWND)ghApp));<br />

JIF(pVW->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN));<br />

}<br />

// Ti<strong>en</strong>e grafico ev<strong>en</strong>tos via llamadas a la v<strong>en</strong>tana por llevar a cabo<br />

JIF(pME->SetNotifyWindow((OAHWND)ghApp, WM_GRAPHNOTIFY, 0));


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 114<br />

if (g_bAudioOnly)<br />

{<br />

JIF(InitPlayerWindow());<br />

}<br />

else<br />

{<br />

JIF(InitVi<strong>de</strong>oWindow(1, 1));<br />

}<br />

// Aqui vi<strong>en</strong>e lo bu<strong>en</strong>o se vera?!<br />

ShowWindow(ghApp, SW_SHOWNORMAL);<br />

UpdateWindow(ghApp);<br />

SetForegroundWindow(ghApp);<br />

SetFocus(ghApp);<br />

UpdateMainTitle();<br />

#if<strong>de</strong>f REGISTER_FILTERGRAPH<br />

hr = AddGraphToRot(pGB, &g_dwGraphRegister);<br />

if (FAILED(hr))<br />

{<br />

Msg(TEXT("Falló al registrar el grafico <strong>de</strong> filtros con ROT! hr=0x%x"), hr);<br />

g_dwGraphRegister = 0;<br />

}<br />

#<strong>en</strong>dif<br />

}<br />

}<br />

// Corre el grafico <strong>de</strong> filtros que ejecutará el archivo multimedia<br />

JIF(pMC->Run());<br />

g_psCurr<strong>en</strong>t=Running;<br />

SetFocus(ghApp);<br />

return hr;<br />

// Función que inicia la v<strong>en</strong>tana <strong>de</strong> vi<strong>de</strong>o con un factor <strong>de</strong>terminado<br />

HRESULT InitVi<strong>de</strong>oWindow(int nMultiplier, int nDivi<strong>de</strong>r)<br />

{<br />

LONG lHeight, lWidth;<br />

HRESULT hr = S_OK;<br />

RECT rect;<br />

if (!pBV)<br />

return S_OK;<br />

// Lee el tamaño <strong>de</strong> vi<strong>de</strong>o actual<br />

JIF(pBV->GetVi<strong>de</strong>oSize(&lWidth, &lHeight));<br />

// Actualiza al tamaño requerido, normal, mitad ...<br />

lWidth = lWidth * nMultiplier / nDivi<strong>de</strong>r;<br />

lHeight = lHeight * nMultiplier / nDivi<strong>de</strong>r;<br />

SetWindowPos(ghApp, NULL, 0, 0, lWidth, lHeight,<br />

SWP_NOMOVE | SWP_NOOWNERZORDER);<br />

int nTitleHeight = GetSystemMetrics(SM_CYCAPTION);<br />

int nBor<strong>de</strong>rWidth = GetSystemMetrics(SM_CXBORDER);<br />

int nBor<strong>de</strong>rHeight = GetSystemMetrics(SM_CYBORDER);<br />

// Actualiza <strong>de</strong>p<strong>en</strong>di<strong>en</strong>do <strong>de</strong>l tamaño <strong>de</strong> la barra <strong>de</strong> titulo y bor<strong>de</strong>s para un<br />

// acoplami<strong>en</strong>to exacto <strong>de</strong> la v<strong>en</strong>tana <strong>de</strong> vi<strong>de</strong>o a el area <strong>de</strong>l cli<strong>en</strong>te <strong>en</strong> la v<strong>en</strong>tana<br />

SetWindowPos(ghApp, NULL, 0, 0, lWidth + 2*nBor<strong>de</strong>rWidth,<br />

lHeight + nTitleHeight + 2*nBor<strong>de</strong>rHeight,<br />

SWP_NOMOVE | SWP_NOOWNERZORDER);<br />

GetCli<strong>en</strong>tRect(ghApp, &rect);<br />

JIF(pVW->SetWindowPosition(rect.left, rect.top, rect.right, rect.bottom));<br />

return hr;


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 115<br />

}<br />

// Función que inicializa la v<strong>en</strong>tana <strong>de</strong> <strong>de</strong>spliegue <strong>en</strong> un tamaño por <strong>de</strong>fault<br />

HRESULT InitPlayerWindow(void)<br />

{<br />

// Restaura a un tamaño <strong>de</strong>fault para audio y <strong>de</strong>spues <strong>de</strong> cerrar un vi<strong>de</strong>o<br />

SetWindowPos(ghApp, NULL, 0, 0,<br />

DEFAULT_AUDIO_WIDTH,<br />

DEFAULT_AUDIO_HEIGHT,<br />

SWP_NOMOVE | SWP_NOOWNERZORDER);<br />

}<br />

return S_OK;<br />

// Función que hace un reajuste <strong>de</strong> la v<strong>en</strong>tana <strong>en</strong> caso <strong>de</strong> mover o reajustar tamaño <strong>de</strong> la<br />

v<strong>en</strong>tana principal<br />

void MoveVi<strong>de</strong>oWindow(void)<br />

{<br />

HRESULT hr;<br />

}<br />

// Sigue el movimi<strong>en</strong>to <strong>de</strong>l cont<strong>en</strong>edor <strong>de</strong> vi<strong>de</strong>o y reajusta el tamaño si es necesario<br />

if(pVW)<br />

{<br />

RECT cli<strong>en</strong>t;<br />

}<br />

GetCli<strong>en</strong>tRect(ghApp, &cli<strong>en</strong>t);<br />

hr = pVW->SetWindowPosition(cli<strong>en</strong>t.left, cli<strong>en</strong>t.top,<br />

cli<strong>en</strong>t.right, cli<strong>en</strong>t.bottom);<br />

// Revisa si el archivo ti<strong>en</strong>e compon<strong>en</strong>te <strong>de</strong> vi<strong>de</strong>o o no<br />

void CheckVisibility(void)<br />

{<br />

long lVisible;<br />

HRESULT hr;<br />

}<br />

g_bAudioOnly = FALSE;<br />

if ((!pVW) || (!pBV))<br />

{<br />

g_bAudioOnly = TRUE;<br />

return;<br />

}<br />

hr = pVW->get_Visible(&lVisible);<br />

if (FAILED(hr))<br />

{<br />

// Si este es un clip solo <strong>de</strong> audio, get_Visible no trabajará<br />

//<br />

// Tambi<strong>en</strong> si este vi<strong>de</strong>o esta codificado con un co<strong>de</strong>c no soportado,<br />

// no veremos ningun vi<strong>de</strong>o, <strong>en</strong> contraparte el audio si trabajara<br />

// si este se <strong>en</strong>cu<strong>en</strong>tra <strong>en</strong> un formato soportado<br />

//<br />

if (hr == E_NOINTERFACE)<br />

{<br />

g_bAudioOnly = TRUE;<br />

}<br />

else<br />

{<br />

Msg(TEXT("Falló(%08lx) in pVW->get_Visible()!\r\n"), hr);<br />

}<br />

}<br />

// Función que implem<strong>en</strong>ta la pausa <strong>en</strong> el clip multimedia<br />

void PauseClip(void)<br />

{<br />

HRESULT hr;<br />

if (!pMC)


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 116<br />

}<br />

return;<br />

// Hace el cambio <strong>en</strong>tre los estados <strong>de</strong> Pausa/Reproducir<br />

if((g_psCurr<strong>en</strong>t == Paused) || (g_psCurr<strong>en</strong>t == Stopped))<br />

{<br />

hr = pMC->Run();<br />

g_psCurr<strong>en</strong>t = Running;<br />

}<br />

else<br />

{<br />

hr = pMC->Pause();<br />

g_psCurr<strong>en</strong>t = Paused;<br />

}<br />

UpdateMainTitle();<br />

// Función que <strong>de</strong>ti<strong>en</strong>e el gráfico <strong>de</strong> filtros<br />

void StopClip(void)<br />

{<br />

HRESULT hr;<br />

}<br />

if ((!pMC) || (!pMS))<br />

return;<br />

// Deti<strong>en</strong>e y restaura la posición al principio<br />

if((g_psCurr<strong>en</strong>t == Paused) || (g_psCurr<strong>en</strong>t == Running))<br />

{<br />

LONGLONG pos = 0;<br />

hr = pMC->Stop();<br />

g_psCurr<strong>en</strong>t = Stopped;<br />

}<br />

hr = pMS->SetPositions(&pos, AM_SEEKING_AbsolutePositioning ,<br />

NULL, AM_SEEKING_NoPositioning);<br />

// Despliega el primer frame para indicar la condición <strong>de</strong> reset<br />

hr = pMC->Pause();<br />

UpdateMainTitle();<br />

void Tele()<br />

{<br />

HRESULT hr;<br />

// Se limpian los reman<strong>en</strong>tes <strong>de</strong> dialogo abiertos antes <strong>de</strong> la pres<strong>en</strong>tacion<br />

UpdateWindow(ghApp);<br />

**)&pGB);<br />

// Crea el FGM<br />

CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC, IID_IGraphBuil<strong>de</strong>r, (void<br />

// Crea el Capture Graph Buil<strong>de</strong>r.<br />

CoCreateInstance(CLSID_CaptureGraphBuil<strong>de</strong>r2, NULL, CLSCTX_INPROC,<br />

IID_ICaptureGraphBuil<strong>de</strong>r2, (void **)&pBuil<strong>de</strong>r);<br />

// Asocia el gráfico con el buil<strong>de</strong>r<br />

pBuil<strong>de</strong>r->SetFiltergraph(pGB);<br />

// Obti<strong>en</strong>e interfaces para media control y Vi<strong>de</strong>o Window<br />

hr = pGB->QueryInterface(IID_IMediaControl,(LPVOID *) &pMC);<br />

// QueryInterface para las interfaces DirectShow<br />

pGB->QueryInterface(IID_IMediaEv<strong>en</strong>tEx, (void **)&pME);<br />

pGB->QueryInterface(IID_IMediaSeeking, (void **)&pMS);<br />

// Consulta las interfaces <strong>de</strong> vi<strong>de</strong>o, las cuales pue<strong>de</strong>n no ser relevantes para<br />

archivos <strong>de</strong> audio<br />

pGB->QueryInterface(IID_IVi<strong>de</strong>oWindow, (void **)&pVW);


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 117<br />

pGB->QueryInterface(IID_IBasicVi<strong>de</strong>o, (void **)&pBV);<br />

// Consulta por interfaces <strong>de</strong> audio, las cuales no pue<strong>de</strong>n ser relevantes para<br />

archivos solo <strong>de</strong> vi<strong>de</strong>o<br />

pGB->QueryInterface(IID_IBasicAudio, (void **)&pBA);<br />

// Crea el system <strong>de</strong>vice <strong>en</strong>umerator.<br />

ICreateDevEnum *pDevEnum = NULL;<br />

CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC, IID_ICreateDevEnum,<br />

(void **)&pDevEnum);<br />

// Crea un <strong>en</strong>umerador para vi<strong>de</strong>o capture <strong>de</strong>vices.<br />

IEnumMoniker *pClassEnum = NULL;<br />

pDevEnum->CreateClassEnumerator(CLSID_Vi<strong>de</strong>oInputDeviceCategory, &pClassEnum, 0);<br />

ULONG cFetched;<br />

IMoniker *pMoniker = NULL;<br />

IBaseFilter *pSrc = NULL;<br />

if (pClassEnum->Next(1, &pMoniker, &cFetched) == S_OK)<br />

{<br />

// Liga el primer moniker a un objeto filtro.<br />

pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pSrc);<br />

pMoniker->Release();<br />

}<br />

pClassEnum->Release();<br />

pDevEnum->Release();<br />

// Se aña<strong>de</strong> el filtro <strong>de</strong> captura a nuestro gráfico<br />

hr = pGB->AddFilter(pSrc, L"Vi<strong>de</strong>o Capture");<br />

// Muestra el pin <strong>de</strong> captura <strong>en</strong> el filtro <strong>de</strong> captura <strong>de</strong> vi<strong>de</strong>o.<br />

// Se usa esta instrucción <strong>en</strong> lugar <strong>de</strong> pBuil<strong>de</strong>r->R<strong>en</strong><strong>de</strong>rFile<br />

hr = pBuil<strong>de</strong>r->R<strong>en</strong><strong>de</strong>rStream (&PIN_CATEGORY_CAPTURE , &MEDIATYPE_Vi<strong>de</strong>o,<br />

pSrc, NULL, NULL);<br />

// Ahora que el filtro se ha añadido al gráfico y hemos pres<strong>en</strong>tado<br />

// su stream, po<strong>de</strong>mos actualizar esta refer<strong>en</strong>cia al filtro.<br />

pSrc->Release();<br />

// Desconectamos los ultimos dos filtros <strong>de</strong>l grafico<br />

EnumFilters("Color Space Converter", PINDIR_OUTPUT); //Busca el output pin <strong>de</strong>l<br />

p<strong>en</strong>ultimo filtro...<br />

hr = pGB->Disconnect(pOutPin);<br />

filtro...<br />

EnumFilters("Vi<strong>de</strong>o R<strong>en</strong><strong>de</strong>rer", PINDIR_INPUT); //Busca el input pin <strong>de</strong>l ultimo<br />

hr = pGB->Disconnect(pInputPin);<br />

// Añadimos el filtro <strong>de</strong> efectos <strong>en</strong> la imag<strong>en</strong><br />

hr = CoCreateInstance(CLSID_EZrgb24, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter,<br />

reinterpret_cast(&pFX));<br />

hr = pGB->AddFilter(pFX, L"Image Effects");<br />

//Conectamos filtro <strong>de</strong> efectos y Color Space converter<br />

EnumFilters("Image Effects", PINDIR_INPUT); // Busca input pin <strong>de</strong> filtro Efectos<br />

hr = pGB->Connect(pOutPin, pInputPin);<br />

//Reconexion automatica <strong>en</strong>tre Image Effects y vi<strong>de</strong>o r<strong>en</strong><strong>de</strong>r<br />

EnumFilters("Image Effects", PINDIR_OUTPUT);<br />

EnumFilters("Vi<strong>de</strong>o R<strong>en</strong><strong>de</strong>rer", PINDIR_INPUT);<br />

hr = pGB->Connect(pOutPin, pInputPin);<br />

#if<strong>de</strong>f REGISTER_FILTERGRAPH<br />

hr = AddGraphToRot(pGB, &g_dwGraphRegister);<br />

#<strong>en</strong>dif<br />

pVW->put_Owner((OAHWND)ghApp);<br />

pVW->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);<br />

InitVi<strong>de</strong>oWindow(1, 1);


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 118<br />

}<br />

// Aqui vi<strong>en</strong>e lo bu<strong>en</strong>o se vera?!<br />

ShowWindow(ghApp, SW_SHOWNORMAL);<br />

UpdateWindow(ghApp);<br />

SetForegroundWindow(ghApp);<br />

SetFocus(ghApp);<br />

UpdateMainTitle();<br />

// Inicia la previsualización <strong>de</strong> los datos<br />

hr =pMC->Run();<br />

// Recuerda el estado actual<br />

g_psCurr<strong>en</strong>t = Running;<br />

// Función que abre un archivo multimedia<br />

void Op<strong>en</strong>Clip()<br />

{<br />

HRESULT hr;<br />

// Si no hay un nombre <strong>de</strong> archivo especificado <strong>en</strong> la linea <strong>de</strong> comandos, muestra el<br />

dialogo <strong>de</strong> abrir archivo<br />

if(g_szFileName[0] == L'\0')<br />

{<br />

TCHAR szFil<strong>en</strong>ame[MAX_PATH];<br />

UpdateMainTitle();<br />

// Si no hay nombre <strong>de</strong> archivo especificado, <strong>en</strong>tonces la v<strong>en</strong>tana <strong>de</strong><br />

vi<strong>de</strong>o<br />

// no ha sido creado o se ha hecho visible. Hacemos muestra v<strong>en</strong>tana<br />

principal<br />

// visible y la llevamos al fr<strong>en</strong>te para permitir la seleccion <strong>de</strong><br />

archivos<br />

InitPlayerWindow();<br />

ShowWindow(ghApp, SW_SHOWNORMAL);<br />

SetForegroundWindow(ghApp);<br />

if (! GetClipFileName(szFil<strong>en</strong>ame))<br />

{<br />

DWORD dwDlgErr = CommDlgExt<strong>en</strong><strong>de</strong>dError();<br />

// No muestra una salida si el usuario canceló la selección<br />

(no hay dialogo <strong>de</strong> error)<br />

if (dwDlgErr)<br />

{<br />

Msg(TEXT("¡Falló GetClipFileName! Error=0x%x\r\n"), GetLastError());<br />

}<br />

return;<br />

}<br />

// Esta aplicacion no soporta reproduccion <strong>de</strong> arvhivos ASX<br />

// Dado que esto podría confundir al usuario, <strong>de</strong>splegamos un m<strong>en</strong>saje<br />

// <strong>de</strong> advert<strong>en</strong>cia si un archivo ASX fué abierto.<br />

if (_tcsstr((_tcslwr(szFil<strong>en</strong>ame)), TEXT(".asx")))<br />

{<br />

Msg(TEXT("ASX Playlists are not supported by this application. Please select a<br />

media file.\0"));<br />

return;<br />

}<br />

}<br />

lstrcpy(g_szFileName, szFil<strong>en</strong>ame);<br />

// Reinicializa variables <strong>de</strong> estado<br />

g_psCurr<strong>en</strong>t = Stopped;<br />

g_lVolume = VOLUME_FULL;


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 119<br />

}<br />

hr = PlayMovieInWindow(g_szFileName);<br />

// Si no po<strong>de</strong>mos ejecutar el clip, limpiamos.<br />

if (FAILED(hr))<br />

CloseClip();<br />

BOOL GetClipFileName(LPTSTR szName)<br />

{<br />

static OPENFILENAME ofn={0};<br />

static BOOL bSetInitialDir = FALSE;<br />

}<br />

*szName = 0;<br />

ofn.lStructSize = sizeof(OPENFILENAME);<br />

ofn.hwndOwner = ghApp;<br />

ofn.lpstrFilter = NULL;<br />

ofn.lpstrFilter = FILE_FILTER_TEXT;<br />

ofn.lpstrCustomFilter = NULL;<br />

ofn.nFilterIn<strong>de</strong>x = 1;<br />

ofn.lpstrFile = szName;<br />

ofn.nMaxFile = MAX_PATH;<br />

ofn.lpstrTitle = TEXT("Op<strong>en</strong> Media File...\0");<br />

ofn.lpstrFileTitle = NULL;<br />

ofn.lpstrDefExt = TEXT("*\0");<br />

ofn.Flags = OFN_FILEMUSTEXIST | OFN_READONLY | OFN_PATHMUSTEXIST;<br />

// Recordamos el path <strong>de</strong>l primer archivo seleccionado<br />

if (bSetInitialDir == FALSE)<br />

{<br />

ofn.lpstrInitialDir = DEFAULT_MEDIA_PATH;<br />

bSetInitialDir = TRUE;<br />

}<br />

else<br />

ofn.lpstrInitialDir = NULL;<br />

return GetOp<strong>en</strong>FileName((LPOPENFILENAME)&ofn);<br />

// Función que cierra el clip actual<br />

void CloseClip()<br />

{<br />

HRESULT hr;<br />

}<br />

if(pMC)<br />

hr = pMC->Stop();<br />

g_psCurr<strong>en</strong>t = Stopped;<br />

g_bAudioOnly = TRUE;<br />

CloseInterfaces();<br />

// Limpia <strong>de</strong>l arreglo el nombre <strong>de</strong> archivo para permitir una nueva eleccion<br />

g_szFileName[0] = L'\0';<br />

// Borramos el estado actual <strong>de</strong> ejecucion multimedia<br />

g_psCurr<strong>en</strong>t = Init;<br />

RECT rect;<br />

GetCli<strong>en</strong>tRect(ghApp, &rect);<br />

InvalidateRect(ghApp, &rect, TRUE);<br />

UpdateMainTitle();<br />

InitPlayerWindow();<br />

//Funcion que busca un filtro <strong>en</strong> el grafico, y su pin input o output


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 120<br />

void EnumFilters (char *nomFiltro, PIN_DIRECTION PinDir)<br />

{<br />

IFilterGraph *pGraph = NULL;<br />

IEnumFilters *pEnum = NULL;<br />

IBaseFilter *pFilter;<br />

ULONG cFetched;<br />

}<br />

pGraph = pGB;<br />

pGraph->EnumFilters(&pEnum);<br />

while(pEnum->Next(1, &pFilter, &cFetched) == S_OK)<br />

{<br />

FILTER_INFO FilterInfo;<br />

char szName[256];<br />

pFilter->QueryFilterInfo(&FilterInfo);<br />

Wi<strong>de</strong>CharToMultiByte(CP_ACP, 0, FilterInfo.achName, -1, szName, 256, 0, 0);<br />

// Si el nombre <strong>de</strong>l filtro se localiza busca el apuntador al pin output<br />

if(!strcmp(szName, nomFiltro) && PinDir == PINDIR_OUTPUT)<br />

pOutPin = GetPin(pFilter, PinDir);<br />

if(!strcmp(szName, nomFiltro) && PinDir == PINDIR_INPUT)<br />

pInputPin = GetPin(pFilter, PinDir);<br />

FilterInfo.pGraph->Release();<br />

pFilter->Release();<br />

}<br />

pEnum->Release();<br />

// Funcion que obti<strong>en</strong>e la direccion <strong>de</strong> un Pin Output<br />

IPin *GetPin(IBaseFilter *pFilter, PIN_DIRECTION PinDir)<br />

{<br />

BOOL bFound = FALSE;<br />

IEnumPins *pEnum;<br />

IPin *pPin;<br />

}<br />

pFilter->EnumPins(&pEnum);<br />

while(pEnum->Next(1, &pPin, 0) == S_OK)<br />

{<br />

PIN_DIRECTION PinDirThis;<br />

pPin->QueryDirection(&PinDirThis);<br />

if (bFound = (PinDir == PinDirThis))<br />

break;<br />

pPin->Release();<br />

}<br />

pEnum->Release();<br />

return (bFound ? pPin : 0);<br />

void CloseInterfacesTV(void)<br />

{<br />

// DEti<strong>en</strong>e los datos pres<strong>en</strong>tados<br />

if (pMC)<br />

pMC->StopWh<strong>en</strong>Ready();<br />

g_psCurr<strong>en</strong>t = Stopped;<br />

// Deti<strong>en</strong>e la recepción <strong>de</strong> ev<strong>en</strong>tos<br />

if (pME)<br />

pME->SetNotifyWindow(NULL, WM_GRAPHNOTIFY, 0);<br />

if(pVW)<br />

{<br />

pVW->put_Visible(OAFALSE);<br />

pVW->put_Owner(NULL);<br />

}<br />

#if<strong>de</strong>f REGISTER_FILTERGRAPH<br />

// Remueve el grafico <strong>de</strong> filtros <strong>de</strong> la tabla<br />

if (g_dwGraphRegister)


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 121<br />

#<strong>en</strong>dif<br />

}<br />

RemoveGraphFromRot(g_dwGraphRegister);<br />

// Actualiza las interfaces DirectShow<br />

SAFE_RELEASE(pMC);<br />

SAFE_RELEASE(pME);<br />

SAFE_RELEASE(pVW);<br />

SAFE_RELEASE(pGB);<br />

SAFE_RELEASE(pBuil<strong>de</strong>r);<br />

// Función que cierra las interfaces <strong>de</strong> DirectShow<br />

void CloseInterfaces(void)<br />

{<br />

HRESULT hr;<br />

// Recuperacion <strong>de</strong> <strong>de</strong>rechos <strong>de</strong> propietario <strong>de</strong>spues <strong>de</strong> ocultar la v<strong>en</strong>tana <strong>de</strong> vi<strong>de</strong>o<br />

if(pVW)<br />

{<br />

hr = pVW->put_Visible(OAFALSE);<br />

hr = pVW->put_Owner(NULL);<br />

}<br />

#if<strong>de</strong>f REGISTER_FILTERGRAPH<br />

if (g_dwGraphRegister)<br />

{<br />

RemoveGraphFromRot(g_dwGraphRegister);<br />

g_dwGraphRegister = 0;<br />

}<br />

#<strong>en</strong>dif<br />

}<br />

SAFE_RELEASE(pME);<br />

SAFE_RELEASE(pMS);<br />

SAFE_RELEASE(pMC);<br />

SAFE_RELEASE(pBA);<br />

SAFE_RELEASE(pBV);<br />

SAFE_RELEASE(pVW);<br />

SAFE_RELEASE(pGB);<br />

#if<strong>de</strong>f REGISTER_FILTERGRAPH<br />

// Función que aña<strong>de</strong> el grafico <strong>de</strong> filtros<br />

HRESULT AddGraphToRot(IUnknown *pUnkGraph, DWORD *pdwRegister)<br />

{<br />

IMoniker * pMoniker;<br />

IRunningObjectTable *pROT;<br />

if (FAILED(GetRunningObjectTable(0, &pROT))) {<br />

return E_FAIL;<br />

}<br />

WCHAR wsz[128];<br />

wsprintfW(wsz, L"FilterGraph %08x pid %08x", (DWORD_PTR)pUnkGraph,<br />

GetCurr<strong>en</strong>tProcessId());<br />

HRESULT hr = CreateItemMoniker(L"!", wsz, &pMoniker);<br />

if (SUCCEEDED(hr)) {<br />

hr = pROT->Register(0, pUnkGraph, pMoniker, pdwRegister);<br />

pMoniker->Release();<br />

}<br />

pROT->Release();<br />

return hr;<br />

}<br />

// Quita el grafico <strong>de</strong> filtros<br />

void RemoveGraphFromRot(DWORD pdwRegister)<br />

{<br />

IRunningObjectTable *pROT;<br />

if (SUCCEEDED(GetRunningObjectTable(0, &pROT))) {<br />

pROT->Revoke(pdwRegister);<br />

pROT->Release();<br />

}<br />

}


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 122<br />

#<strong>en</strong>dif<br />

// Despliega los nombres <strong>de</strong> archivo <strong>en</strong> la caja <strong>de</strong> m<strong>en</strong>sajes<br />

void Msg(char *szFormat, ...)<br />

{<br />

TCHAR szBuffer[512]; // Buffer gran<strong>de</strong> para nombres <strong>de</strong> archivos largos como los HTTTP<br />

}<br />

va_list pArgs;<br />

va_start(pArgs, szFormat);<br />

vsprintf(szBuffer, szFormat, pArgs);<br />

va_<strong>en</strong>d(pArgs);<br />

MessageBox(NULL, szBuffer, "UAM Multimedia", MB_OK);<br />

// Función para activar el sil<strong>en</strong>cio shhh...<br />

HRESULT ToggleMute(void)<br />

{<br />

HRESULT hr=S_OK;<br />

}<br />

if ((!pGB) || (!pBA))<br />

return S_OK;<br />

// Read curr<strong>en</strong>t volume<br />

hr = pBA->get_Volume(&g_lVolume);<br />

if (hr == E_NOTIMPL)<br />

{<br />

// Falla si este es un archivo <strong>de</strong> solo vi<strong>de</strong>o<br />

return S_OK;<br />

}<br />

else if (FAILED(hr))<br />

{<br />

Msg(TEXT("Fallo al leer el volum<strong>en</strong> <strong>de</strong> audio ! hr=0x%x\r\n"), hr);<br />

return hr;<br />

}<br />

// Cambia los niveles <strong>de</strong> volum<strong>en</strong><br />

if (g_lVolume == VOLUME_FULL)<br />

g_lVolume = VOLUME_SILENCE;<br />

else<br />

g_lVolume = VOLUME_FULL;<br />

// Ajusta el nuevo volum<strong>en</strong><br />

JIF(pBA->put_Volume(g_lVolume));<br />

UpdateMainTitle();<br />

return hr;<br />

// Función que actualiza la etiqueta que actualiza el estado actual <strong>de</strong>l streaming<br />

void UpdateMainTitle(void)<br />

{<br />

TCHAR szTitle[MAX_PATH], szFile[MAX_PATH];<br />

// Si ningun archivo es cargado, solo muestra el titulo <strong>de</strong> la aplicacion<br />

if (g_szFileName[0] == L'\0')<br />

{<br />

wsprintf(szTitle, TEXT("%s"), APPLICATIONNAME);<br />

}<br />

// De otro modo, muestra información <strong>en</strong> uso, incluy<strong>en</strong>do nombre <strong>de</strong> archivo y estado<br />

<strong>de</strong> ejecución<br />

else<br />

{<br />

// Obti<strong>en</strong>e nombre <strong>de</strong> archivo sin path completo<br />

GetFil<strong>en</strong>ame(g_szFileName, szFile);<br />

// Actualiza el titulo <strong>de</strong> la v<strong>en</strong>tana para mostrar el estado<br />

Sil<strong>en</strong>cio/Sonido<br />

wsprintf(szTitle, TEXT("%s [%s] %s%s"),


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 123<br />

}<br />

}<br />

szFile,<br />

g_bAudioOnly ? TEXT("Audio") : TEXT("Vi<strong>de</strong>o"),<br />

(g_lVolume == VOLUME_SILENCE) ? TEXT("(En sil<strong>en</strong>cio)") : TEXT(""),<br />

(g_psCurr<strong>en</strong>t == Paused) ? TEXT("(Pausado)") : TEXT(""));<br />

SetWindowText(ghApp, szTitle);<br />

//Funcion que obti<strong>en</strong>e el nombre <strong>de</strong>l archivo a reproducir<br />

void GetFil<strong>en</strong>ame(TCHAR *pszFull, TCHAR *pszFile)<br />

{<br />

int nL<strong>en</strong>gth;<br />

TCHAR szPath[MAX_PATH]={0};<br />

BOOL bSetFil<strong>en</strong>ame=FALSE;<br />

}<br />

_tcscpy(szPath, pszFull);<br />

nL<strong>en</strong>gth = _tcsl<strong>en</strong>(szPath);<br />

for (int i=nL<strong>en</strong>gth-1; i>=0; i--)<br />

{<br />

if ((szPath[i] == '\\') || (szPath[i] == '/'))<br />

{<br />

szPath[i] = '\0';<br />

lstrcpy(pszFile, &szPath[i+1]);<br />

bSetFil<strong>en</strong>ame = TRUE;<br />

break;<br />

}<br />

}<br />

// Si no se proporcionó un Path (solo un nombre <strong>de</strong> archivo), <strong>en</strong>tonces<br />

// solo copia el path completo a el path <strong>de</strong>stino<br />

if (!bSetFil<strong>en</strong>ame)<br />

_tcscpy(pszFile, pszFull);<br />

// Función que permite la pantalla completa<br />

HRESULT ToggleFullScre<strong>en</strong>(void)<br />

{<br />

HRESULT hr=S_OK;<br />

LONG lMo<strong>de</strong>;<br />

static HWND hDrain=0;<br />

// No permitir pantalla completa <strong>en</strong> archivos <strong>de</strong> solo audio<br />

if ((g_bAudioOnly) || (!pVW))<br />

return S_OK;<br />

if (!pVW)<br />

return S_OK;<br />

// Lee el estado actual<br />

JIF(pVW->get_FullScre<strong>en</strong>Mo<strong>de</strong>(&lMo<strong>de</strong>));<br />

if (lMo<strong>de</strong> == OAFALSE)<br />

{<br />

// Salvar el m<strong>en</strong>saje actual<br />

LIF(pVW->get_MessageDrain((OAHWND *) &hDrain));<br />

}<br />

else<br />

{<br />

// Ajustar el m<strong>en</strong>saje actual a la aplicación <strong>de</strong> la v<strong>en</strong>tana principal<br />

LIF(pVW->put_MessageDrain((OAHWND) ghApp));<br />

// Cambiar al modo <strong>de</strong> pantalla completa<br />

lMo<strong>de</strong> = OATRUE;<br />

JIF(pVW->put_FullScre<strong>en</strong>Mo<strong>de</strong>(lMo<strong>de</strong>));<br />

// Cambiar <strong>de</strong> regreso al modo <strong>de</strong> v<strong>en</strong>tana<br />

lMo<strong>de</strong> = OAFALSE;<br />

JIF(pVW->put_FullScre<strong>en</strong>Mo<strong>de</strong>(lMo<strong>de</strong>));


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 124<br />

}<br />

}<br />

// Undo change of message drain<br />

LIF(pVW->put_MessageDrain((OAHWND) hDrain));<br />

// Reinicializar v<strong>en</strong>tana <strong>de</strong> vi<strong>de</strong>o<br />

LIF(pVW->SetWindowForeground(-1));<br />

// Reclamar la at<strong>en</strong>ción <strong>de</strong>l teclado<br />

UpdateWindow(ghApp);<br />

SetForegroundWindow(ghApp);<br />

SetFocus(ghApp);<br />

return hr;<br />

// Manejador <strong>de</strong> ev<strong>en</strong>tos <strong>en</strong> el Gráfico <strong>de</strong> filtros<br />

HRESULT HandleGraphEv<strong>en</strong>t(void)<br />

{<br />

LONG evCo<strong>de</strong>, evParam1, evParam2;<br />

HRESULT hr=S_OK;<br />

while(SUCCEEDED(pME->GetEv<strong>en</strong>t(&evCo<strong>de</strong>, &evParam1, &evParam2, 0)))<br />

{<br />

// Recorrido atraves <strong>de</strong> los ev<strong>en</strong>tos<br />

hr = pME->FreeEv<strong>en</strong>tParams(evCo<strong>de</strong>, evParam1, evParam2);<br />

implem<strong>en</strong>tar<br />

rrecorrer<br />

}<br />

}<br />

if(EC_COMPLETE == evCo<strong>de</strong>)<br />

{<br />

LONGLONG pos=0;<br />

}<br />

// Reinicializa al primer frame <strong>de</strong>l vi<strong>de</strong>o clip<br />

hr = pMS->SetPositions(&pos, AM_SEEKING_AbsolutePositioning ,<br />

NULL, AM_SEEKING_NoPositioning);<br />

if (FAILED(hr))<br />

{<br />

// Algunos filtros personalizados pue<strong>de</strong>n no<br />

}<br />

return hr;<br />

// interfaces <strong>de</strong> a<strong>de</strong>lantar/atrasar.Para permitir<br />

// hacia el inicio. En este caso, solo <strong>de</strong>t<strong>en</strong>er<br />

// y reiniciar para el mismo efecto. Esto no <strong>de</strong>beria<br />

//ser necesario <strong>en</strong> muchos casos.<br />

if (FAILED(hr = pMC->Stop()))<br />

{<br />

Msg(TEXT("!Fallo(0x%08lx) para <strong>de</strong>t<strong>en</strong>er el clip multimedia!\r\n"), hr);<br />

break;<br />

}<br />

if (FAILED(hr = pMC->Run()))<br />

{<br />

Msg(TEXT("Falló(0x%08lx) para reiniciar el clip multimedia!\r\n"), hr);<br />

break;<br />

}<br />

// Gestor <strong>de</strong> m<strong>en</strong>sajes <strong>de</strong> Windows<br />

LRESULT CALLBACK WndMainProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)<br />

{<br />

switch(message)<br />

{<br />

// Reajusta el tamaño <strong>de</strong> vi<strong>de</strong>o cuando la v<strong>en</strong>tana cambia<br />

case WM_MOVE:<br />

case WM_SIZE:<br />

if ((hWnd == ghApp) && (!g_bAudioOnly))<br />

MoveVi<strong>de</strong>oWindow();<br />

break;


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 125<br />

case WM_KEYDOWN:<br />

switch(wParam)<br />

{<br />

case 'P': // Pausar/ Reproducir<br />

PauseClip();<br />

break;<br />

case 'D': // Det<strong>en</strong>er clip<br />

StopClip();<br />

break;<br />

CloseClip();<br />

break;<br />

case 'S': // Sil<strong>en</strong>cio/Sonido<br />

ToggleMute();<br />

break;<br />

case 'A': // Pantalla completa<br />

ToggleFullScre<strong>en</strong>();<br />

break;<br />

case 'M': // Media pantalla<br />

InitVi<strong>de</strong>oWindow(1,2);<br />

break;<br />

case 'T': // 3/4 pantalla<br />

InitVi<strong>de</strong>oWindow(3,4);<br />

break;<br />

case 'N': // Pantalla normal<br />

InitVi<strong>de</strong>oWindow(1,1);<br />

break;<br />

case 'V': // OJO Vi<strong>de</strong>owall<br />

InitVi<strong>de</strong>oWindow(5,1);<br />

break;<br />

case 'C': // Cerrar Clip<br />

case VK_F1: // Veremos las paginas propietarias <strong>de</strong>l<br />

filtro<br />

{<br />

HRESULT hr = pFX-<br />

>QueryInterface(IID_ISpecifyPropertyPages, (void **)&pProp);<br />

if (SUCCEEDED(hr)) {<br />

// Muestra la pagina propietaria<br />

// Obti<strong>en</strong>e el nombre <strong>de</strong>l filtro<br />

y un apuntador IUnknown.<br />

FILTER_INFO FilterInfo;<br />

pFX-<br />

>QueryFilterInfo(&FilterInfo);<br />

IUnknown *pFilterUnk;<br />

pFX-<br />

>QueryInterface(IID_IUnknown, (void **)&pFilterUnk);<br />

// V<strong>en</strong>tana padre<br />

// (Reservado)<br />

// Captura para la caja <strong>de</strong> dialogo<br />

// Numero <strong>de</strong> objetos (solo <strong>de</strong>l filtro)<br />

// Arreglo <strong>de</strong> apuntadores a objetos<br />

CAUUID caGUID;<br />

pProp->GetPages(&caGUID);<br />

pProp->Release();<br />

OleCreatePropertyFrame(<br />

hWnd,<br />

0, 0,<br />

FilterInfo.achName,<br />

1,<br />

&pFilterUnk,


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 126<br />

// Numero <strong>de</strong> paginas propietarias<br />

// Arreglo <strong>de</strong> CLSIDs <strong>de</strong> paginas propietarias<br />

// I<strong>de</strong>ntificador local<br />

// Reservado<br />

case VK_ESCAPE:<br />

case VK_F12:<br />

case 'Q':<br />

case 'X':<br />

CloseClip();<br />

break;<br />

}<br />

break;<br />

case WM_COMMAND:<br />

switch(wParam)<br />

{ // M<strong>en</strong>us<br />

case ID_FILE_OPENCLIP:<br />

cerramos y apagamos DShow<br />

if (g_psCurr<strong>en</strong>t != Init)<br />

CloseClip();<br />

Op<strong>en</strong>Clip();<br />

break;<br />

case ID_FILE_EXIT:<br />

CloseClip();<br />

PostQuitMessage(0);<br />

break;<br />

case ID_FILE_PAUSE:<br />

PauseClip();<br />

break;<br />

case ID_FILE_STOP:<br />

StopClip();<br />

break;<br />

case ID_FILE_CLOSE:<br />

CloseClip();<br />

break;<br />

case ID_FILE_MUTE:<br />

ToggleMute();<br />

break;<br />

}<br />

}<br />

break;<br />

case ID_TV:<br />

Tele();<br />

break;<br />

);<br />

caGUID.cElems,<br />

caGUID.pElems,<br />

0,<br />

0, NULL<br />

// Limpieza.<br />

pFilterUnk->Release();<br />

FilterInfo.pGraph->Release();<br />

CoTaskMemFree(caGUID.pElems);<br />

// Si t<strong>en</strong>emos algun archivo abierto, lo<br />

// Abre el nuevo clip<br />

CloseInterfaces();<br />

CloseInterfacesTV();


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 127<br />

}<br />

case ID_FILE_FULLSCREEN:<br />

ToggleFullScre<strong>en</strong>();<br />

break;<br />

case ID_FILE_SIZE_HALF:<br />

InitVi<strong>de</strong>oWindow(1,2);<br />

break;<br />

case ID_FILE_SIZE_NORMAL:<br />

InitVi<strong>de</strong>oWindow(1,1);<br />

break;<br />

case ID_FILE_SIZE_DOUBLE:<br />

InitVi<strong>de</strong>oWindow(2,1);<br />

break;<br />

case ID_FILE_SIZE_THREEQUARTER:<br />

InitVi<strong>de</strong>oWindow(3,4);<br />

break;<br />

} // M<strong>en</strong>us<br />

break;<br />

case WM_GRAPHNOTIFY:<br />

HandleGraphEv<strong>en</strong>t();<br />

break;<br />

case WM_CLOSE:<br />

S<strong>en</strong>dMessage(ghApp, WM_COMMAND, ID_FILE_EXIT, 0);<br />

break;<br />

case WM_DESTROY:<br />

PostQuitMessage(0);<br />

break;<br />

<strong>de</strong>fault:<br />

return DefWindowProc(hWnd, message, wParam, lParam);<br />

} // Manejador <strong>de</strong> m<strong>en</strong>sajes <strong>de</strong> la v<strong>en</strong>tana<br />

return DefWindowProc(hWnd, message, wParam, lParam);<br />

// Función main <strong>de</strong> Windows<br />

int PASCAL WinMain(HINSTANCE hInstC, HINSTANCE hInstP, LPTSTR lpCmdLine, int nCmdShow)<br />

{<br />

MSG msg;<br />

WNDCLASS wc;<br />

// Initialize COM<br />

if(FAILED(CoInitialize(NULL)))<br />

{<br />

Msg(TEXT("Falló CoInitialize!\r\n"));<br />

exit(1);<br />

}<br />

// Fué especificado el nombre <strong>de</strong>l archivo <strong>en</strong> la linea <strong>de</strong> comandos?<br />

if(lpCmdLine[0] != L'\0')<br />

lstrcpy(g_szFileName, lpCmdLine);<br />

// Ajusta el estado <strong>de</strong> multimedia inicial<br />

g_psCurr<strong>en</strong>t = Init;<br />

// Registra la clase window<br />

ZeroMemory(&wc, sizeof wc);<br />

wc.lpfnWndProc = WndMainProc;<br />

ghInst = wc.hInstance = hInstC;<br />

wc.lpszClassName = CLASSNAME;<br />

wc.lpszM<strong>en</strong>uName = MAKEINTRESOURCE(IDR_MENU);<br />

wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);<br />

wc.hCursor = LoadCursor(NULL, IDC_ARROW);


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 128<br />

0,0<br />

}<br />

wc.hIcon = LoadIcon(hInstC, MAKEINTRESOURCE(IDI_INWINDOW));<br />

if(!RegisterClass(&wc))<br />

{<br />

Msg(TEXT("Falló RegisterClass! Error=0x%x\r\n"), GetLastError());<br />

CoUninitialize();<br />

exit(1);<br />

}<br />

// Crea la v<strong>en</strong>tana principal. El estilo WS_CLIPCHILDREN es requerido, se ubica <strong>en</strong><br />

ghApp = CreateWindow(CLASSNAME, APPLICATIONNAME,<br />

WS_OVERLAPPEDWINDOW | WS_CAPTION | WS_CLIPCHILDREN,<br />

0, 0,<br />

CW_USEDEFAULT, CW_USEDEFAULT,<br />

0, 0, ghInst, 0);<br />

if(ghApp)<br />

{<br />

ShowWindow(ghApp, nCmdShow);<br />

UpdateWindow(ghApp);<br />

// Lazo <strong>de</strong> m<strong>en</strong>sajes principal<br />

while(GetMessage(&msg,NULL,0,0))<br />

{<br />

TranslateMessage(&msg);<br />

DispatchMessage(&msg);<br />

}<br />

}<br />

else<br />

{<br />

Msg(TEXT("Falló para crear la v<strong>en</strong>tana principal! Error=0x%x\r\n"), GetLastError());<br />

}<br />

//Terminamos con el mo<strong>de</strong>lo <strong>de</strong> objetos compon<strong>en</strong>tes COM<br />

CoUninitialize();<br />

return msg.wParam;<br />

//------------------------------------------------------------------------------<br />

// Archivo: PlayWnd.h<br />

//<br />

// Descripción: Archivo hea<strong>de</strong>r para el archivo reproductor <strong>de</strong> multimedia<br />

//<br />

//<br />

//------------------------------------------------------------------------------<br />

//<br />

// Prototipos <strong>de</strong> función<br />

//<br />

HRESULT InitPlayerWindow(void);<br />

HRESULT InitVi<strong>de</strong>oWindow(int nMultiplier, int nDivi<strong>de</strong>r);<br />

HRESULT HandleGraphEv<strong>en</strong>t(void);<br />

BOOL GetClipFileName(LPTSTR szName);<br />

void PaintAudioWindow(void);<br />

void MoveVi<strong>de</strong>oWindow(void);<br />

void CheckVisibility(void);<br />

void CloseInterfaces(void);<br />

void CloseInterfacesTV(void);<br />

void Tele(void);<br />

void Op<strong>en</strong>Clip(void);<br />

void PauseClip(void);<br />

void StopClip(void);<br />

void CloseClip(void);


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 129<br />

IPin *GetPin(IBaseFilter *pFilter, PIN_DIRECTION PinDir); //Pin que localiza un pin <strong>en</strong> el<br />

filtro<br />

void EnumFilters (char *nomFiltro, PIN_DIRECTION PinDir); // Funcion que <strong>en</strong>cu<strong>en</strong>tra el filtro<br />

y pin <strong>en</strong> el grafico<br />

void PaginaProp(void); // Funcion que <strong>de</strong>spliega la pagina propietaria<br />

void UpdateMainTitle(void);<br />

void GetFil<strong>en</strong>ame(TCHAR *pszFull, TCHAR *pszFile);<br />

void Msg(char *szFormat, ...);<br />

HRESULT AddGraphToRot(IUnknown *pUnkGraph, DWORD *pdwRegister);<br />

void RemoveGraphFromRot(DWORD pdwRegister);<br />

//<br />

// Constantes<br />

//<br />

#<strong>de</strong>fine VOLUME_FULL 0L<br />

#<strong>de</strong>fine VOLUME_SILENCE -10000L<br />

// Archivos filtrados <strong>en</strong> el dialogo Op<strong>en</strong>File<br />

#<strong>de</strong>fine FILE_FILTER_TEXT \<br />

TEXT("Archivos <strong>de</strong> Vi<strong>de</strong>o (*.avi; *.qt; *.mov; *.mpg; *.mpeg; *.m1v)\0*.avi; *.qt; *.mov;<br />

*.mpg; *.mpeg; *.m1v\0")\<br />

TEXT("Archivos <strong>de</strong> Audio (*.wav; *.mpa; *.mp2; *.mp3; *.au; *.aif; *.aiff; *.snd)\0*.wav;<br />

*.mpa; *.mp2; *.mp3; *.au; *.aif; *.aiff; *.snd\0")\<br />

TEXT("Archivos WMT (*.asf; *.wma; *.wmv)\0*.asf; *.wma; *.wmv\0")\<br />

TEXT("Archivos MIDI (*.mid, *.midi, *.rmi)\0*.mid; *.midi; *.rmi\0") \<br />

TEXT("Archivos <strong>de</strong> Imag<strong>en</strong> (*.jpg, *.bmp, *.gif, *.tga)\0*.jpg; *.bmp; *.gif; *.tga\0") \<br />

TEXT("Todos los archivos (*.*)\0*.*;\0\0")<br />

// Directorio raiz por <strong>de</strong>fault para la busqueda <strong>de</strong> media<br />

#<strong>de</strong>fine DEFAULT_MEDIA_PATH TEXT("\\\0")<br />

// Valores por <strong>de</strong>fault utilizados con archivos <strong>de</strong> solo-audio<br />

#<strong>de</strong>fine DEFAULT_AUDIO_WIDTH 240<br />

#<strong>de</strong>fine DEFAULT_AUDIO_HEIGHT 120<br />

#<strong>de</strong>fine DEFAULT_VIDEO_WIDTH 320<br />

#<strong>de</strong>fine DEFAULT_VIDEO_HEIGHT 240<br />

#<strong>de</strong>fine APPLICATIONNAME TEXT("DEXTERMedia")<br />

#<strong>de</strong>fine CLASSNAME TEXT("PlayWndMediaPlayer")<br />

#<strong>de</strong>fine WM_GRAPHNOTIFY WM_USER+13<br />

<strong>en</strong>um PLAYSTATE {Stopped, Paused, Running, Init};<br />

//<br />

// Macros<br />

//<br />

#<strong>de</strong>fine SAFE_RELEASE(x) { if (x) x->Release(); x = NULL; }<br />

#<strong>de</strong>fine JIF(x) if (FAILED(hr=(x))) \<br />

{Msg(TEXT("FAILED(hr=0x%x) in ") TEXT(#x) TEXT("\n"), hr); return hr;}<br />

#<strong>de</strong>fine LIF(x) if (FAILED(hr=(x))) \<br />

{Msg(TEXT("FAILED(hr=0x%x) in ") TEXT(#x) TEXT("\n"), hr);}<br />

//<br />

// Constantes pre<strong>de</strong>finidas<br />

//<br />

#<strong>de</strong>fine IDI_INWINDOW 100<br />

#<strong>de</strong>fine IDR_MENU 101<br />

#<strong>de</strong>fine ID_FILE_OPENCLIP 40001<br />

#<strong>de</strong>fine ID_FILE_EXIT 40002<br />

#<strong>de</strong>fine ID_FILE_PAUSE 40003<br />

#<strong>de</strong>fine ID_FILE_STOP 40004<br />

#<strong>de</strong>fine ID_FILE_CLOSE 40005<br />

#<strong>de</strong>fine ID_FILE_MUTE 40006<br />

#<strong>de</strong>fine ID_FILE_FULLSCREEN 40007


<strong>Procesami<strong>en</strong>to</strong> <strong>digital</strong> <strong>de</strong> vi<strong>de</strong>o <strong>en</strong> <strong>tiempo</strong> <strong>real</strong> y “vi<strong>de</strong>o wall” con la PC 130<br />

#<strong>de</strong>fine ID_FILE_SIZE_NORMAL 40008<br />

#<strong>de</strong>fine ID_FILE_SIZE_HALF 40009<br />

#<strong>de</strong>fine ID_FILE_SIZE_DOUBLE 40010<br />

#<strong>de</strong>fine ID_FILE_SIZE_QUARTER 40011<br />

#<strong>de</strong>fine ID_FILE_SIZE_THREEQUARTER 40012<br />

#<strong>de</strong>fine ID_TV 40013

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!