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 ...
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>, ¶m1, ¶m2, 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>, ¶m1, ¶m2, 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