Buenas buenas, aqui traigo una clase escrita en VB.NET que implementa la funcionalidad de Microsoft DirectShow para Abrir, Manejar, Reproducir, etc archivos multimedia Link al final de POST, la misma cuenta con diferentes metodos que permiten obtener diferente informacion sobre el Stream abierto como asi tambien algunos metodos de armado avanzados de Filter Graphs
Esta clase expone gran parte de su funcionalidad implementando los filtros de LAV (splitter, audio decoder, video decoder) por lo cual es recomendable tenerlos instalados en el sistema de destino para obtener el maximo rendimiento de la misma, la misma tambien hace uso del Video Mixing Renderer 9 (Microsoft VMR9) para presentar el video en el dispositivo de salida
Tambien es capaz de armar el Filter Graph manualmente (agregando uno a uno los filtros, negociar conexiones, conectarlos, etc) como tambien dispone de un metodo para utilizar Intelligent Connect en caso de que el armado del Filter Graph personalizado falle (por ejemplo, no se tiene los filtros de LAV instalados o dichos filtros no son compatibles con el stream que se intenta reproducir, aunque este ultimo punto es realmente dificil que suceda debido a que soportan un amplio margen de formatos distintos, pero igualmente podria darse el caso), el hecho de usar Intelligent Connect la hace compatible con un amplio numero de formatos distintos
Referencia de la clase
Enumeraciones
Estado: Esta enumeracion se utiliza para determinar en que estado se encuentra el stream, consta de los siguientes miembros
ERROR_LIST Esta enumeracion es utilizada por el evento "Error()" para especificar el motivo de falla de un metodo, consta de los siguientes miembros
FILTER_TYPE No implementada actualmente, en un futuro sera utilizada por el metodo UnderTheHood
TIME_FORMAT: esta enumeracion nos sirve para especificar el formato de tiempo mediante el cual queremos hacer referencia al stream actual, la misma consta de los siguientes miembros
PROP esta enumeracion es utilizada para establecer los valores ProcAmp del stream de video actual,, NOTA: Los parametros de ProcAmp se establecen utilizando el Mixer del Video Mixing Renderer 9 (VMR9), por lo cual si se provee a la aplicacion con un Custom Compositor (del cual depende el mixer de VMR9) estos metodos dejaran de funcionar, consta de los siguientes miembros
Estructuras
UNDER_THE_HOOD: Esta estructura se utiliza para recuperar informacion sobre todos los filtros, pines, direccion de los mismos, parametros de negociacion entre filtros, tamaño de los samples (allocators), etc, consta de los siguientes campos
PIN_INFO: Esta estructura contiene informacion sobre un determinado pin es utilizada por la estructura UNDER_THE_HOOD para enumerar los pines de cada filtro y sus propiedades como asi tambien los MediaTypes (parametros de negociacion) de cada pin, consta de los siguientes campos
VIDEO_STATS Esta estructura se utiliza para devolver ciertos parametros sobre la renderizacion de video en tiempo real desde el Video Mixing Renderer (VMR9), consta de los siguientes campos
AUDIO_STATS Esta estructura se utiliza para devolver ciertos parametros sobre la renderizacion de audio en tiempo real desde el Audio Decoder, consta de los siguientes campos
M_M_V_D Esta estructura se utiliza para establecer u obtener los valores de ProcAmp del stream de video actual, IMPORTANTE es muy importante determinar los valores maximos y minimos por defecto antes de establecer valores de ProcAmp para un stream debido a que los mismos VARIAN de un hardware de video a otro, la misma cuenta con los siguientes campos
TextOverlayParams Esta estructura nos permite especificar los valores que se utilizaran por defecto para dibujar texto sobre el stream de video , consta de los siguientes campos
Eventos
La clase es capaz de disparar eventos simples, aunque no sera capaz de disparar eventos con suscripcion (Event Handlers) debido a que no son necesarios por el momento
Los eventos que la clase puede disparar son:
Propiedades
Metodos Publicos
Public Sub RW(ByVal uUnits As Long)
Se desplaza "uUnits" Frames hacia adelante en el stream de video , el mismo debe soportar el formato de tiempo Frames y ademas soportar FrameSkipping (hasta ahora no encontre ninguno de los que tengo aca que lo soporte) asi que de estar esta, pero casi nunca funciona
Public Sub RW(ByVal uUnits As Long)
Se desplaza "uUnits" hacia atras en el stream de video , el mismo debe soportar el formato de tiempo Frames y ademas soportar FrameSkipping (hasta ahora no encontre ninguno de los que tengo aca que lo soporte) asi que de estar esta, pero casi nunca funciona y encima debe ser soportado por el filtro que expone esta interfaz (el splitter en este caso)
Public Function GetCurrentImage(ByVal sFileName As String) As Boolean
Este metodo guarda el cuadro actual de video en un archivo JPEG especificado por el argumento sFileName, el mismo devuelve True si el proceso se realizo satisfactoriamente o False caso contrario
Public Function GetCurrentImage(ByRef retBMP As Image) As Boolean
Sobrecarga del metodo GetCurrentImage(ByVal sFileName As String) As Boolean
en lugar de guardar el archivo a disco lo devuelve en un objeto Image para que pueda ser editado y/o manipulado a gusto antes de guardarlo
Public Function GetValues(ByVal sProp As ENUMS.PROP) As ESTRUCTURAS.M_M_V_D
Este metodo permite obtener los valores necesarios para poder luego modificar los parametros de ProcAmp (como de ser, brillo, contraste, saturacion, etc)
Es indispensable llamar a este metodo antes de establecer dichos valores debido a que los valores posibles para cada parametro varian dependiendo del hardware de video
sProp: determina que valor se desea obtener
Valor Devuelto: Estructura M_M_V_D con los valores para la propiedad especificada
Public Function SetProcAmpValue(ByVal PropToSet As ENUMS.PROP, ByVal dwVal As Single) As Boolean
Este metodo establece el valor de ProcAmp especificado por el argumento PropToSet, este valor debe estar dentro de los parametros especificados por el controlador/hardware de video
PropToSet: Enumeracion que permite especificar que valor se establecera
dwVal: Nuevo valor que se establece para la propiedad PropToSet, el rango de variacion debe ser obtenida por GetValues()
Valor Devuelto: Boolean: True si la operacion se completo correctamente, caso contrario devolvera False
Public Function Open() As Boolean
Este metodo abrira el archivo especificado por la propiedad FileName, el mismo intentara abrir el archivo en el siguiente orden
1º Intentara armar el Filter Graph personalizado con los filtros de LAV
2º Intentara usar Intelligent Connect para renderizar el archivo
3º Fallara la apertura del archivo (si llego hasta aqui es porque no hay forma de abrir dicho archivo en la configuracion actual de sistema)
Valor Devuelvo: True si se abrio el archivo, False caso contrario, evaluar los eventos CustomGraphRendered() y/o UsingIC() para determinar el mecanismo utilizado por el metodo para la apertura
Public Function Close() As Boolean
Este metodo cerrara el stream abierto actualmente (en caso de haber alguno) y liberara todos los recursos utilizados por los objetos tanto administrados como no administrados
Valor Devuelto: True si se logro cerrar el archivo con exito, False caso contrario
Public Function Play() As Boolean
Este metodo comenzara la reproduccion del archivo abierto actualmente (en caso de haber alguno)
Valor Devuelto: True si se pudo comenzar la reproduccion, False caso contrario
Public Function Pause() As Boolean
Este metodo pondra el estado del stream actual en "Pausado" en caso de haber algun stream abierto
Valor Devuelto: True si se logro el cambio de estado, False caso contrario
Public Function Stop() As Boolean
Este metodo pondra el estado del stream actual en "Detenido" en caso de haber algun stream abierto
Valor Devuelto: True si se logro el cambio de estado, False caso contrario
Public Sub RepaintVideo()
Este metodo informa al Renderer de Video ( Video Mixing Renderer 9) que se debe repintar el area de video , como practica general, deberia llamar a este metodo en el evento paint del control que muestra el video
Public Function WriteOverlayText(ByVal szText As String, ByVal bShow As Boolean) As Boolean
Este metodo dibujara un texto encima del stream de video , el mismo se ubicara en la parte inferior central del video , no es necesario pausar el stream para realizar la mezcla
Argumentos:
szText: Texto que se desea colocar (puede ser nulo si bShow es igual a False) el texto se dibujara con los parametros previamente establecidos por las propiedades de tratamiento de texto
Public Function GetVideoStats(ByRef dwStats As ESTRUCTURAS.VIDEO_STATS) As Boolean
Este metodo devuelve informacion sobre el stream de video actual
Argumentos: dwStats: aqui se depositara la informacion que se recupere del Video Renderer
Valor Devuelvo: True si se completo exitosamente, False en caso contrario
Public Function GetAudioInfo(ByRef dwRet As ESTRUCTURAS.AUDIO_STATS) As Boolean
Este metodo devuelve informacion sobre el stream de audio actual
Argumentos: dwRet: aqui se depositara la informacion que se recuperar del Decoder de Audio
Valor Devuelto: True si se completo exitosamente, False en caso contrario
Public Function UnderTheHood(ByRef dwRet() As ESTRUCTURAS.UNDER_THE_HOOD) As Boolean
Este metodo devolvera informacion sobre todos los filtros, pines, MediaTypes y SampleAllocatorsSize presentes en el FilterGraph, esta informacion puede resultar particularmente util a la hora de depurar un Filter Graph
Argumentos: dwRet(): este arreglo contendra toda la informacion, cada registro del arreglo correspondera a un filtro del Graph y el mismo contendra informacion sobre todos sus pines, los arreglos se reservan dinamicamente asi que no intente asignar un valor al arreglo en tiempo de diseño o el metodo fallara
Valor Devuelvo: True si la se completo exitosamente, False de lo contrario
Metodos Privados
Private Function InitializeDirect3D() As Boolean
Este metodo inicializa el Device y el Surface de direct3D que se usara para mezclar el texto sobre el stream de video
Argumentos: Este metodo no toma argumentos
Valor Devuelto: True si se completo exitosamente, False caso contrario
Private Function CreateCustomFilterGraph(ByVal szFileName As String) As Boolean
Este metodo intenta crear el FilterGraph personalizado (usando el set de filtros de LAV) para obtener asi un mayor control sobre el stream
Argumentos
Valor Devuelto: True si la operacion fue exitosa, False caso contrario
Private Function ConfigureRenderer() As Boolean
Este metodo configura el Renderer de video ( Video Mixing Renderer 9) para ser utilizado en nuestro FilterGraph
Argumentos: Este metodo no tiene argumentos
Valor Devuelto: True si se completo exitosamente, False caso contrario
Private Function CustomGraphHasAudio(ByVal splitterFilter As IBaseFilter) As Boolean
Este metodo determina si el Custom Filter Graph posee stream de audio y se utiliza para cargar el decoder y renderer de audio bajo demanda
Argumentos
Valor Devuelto: True si se completo exitosamente, False caso contrario
Private Function CustomGraphHasVideo(ByVal splitterFilter As IBaseFilter) As Boolean
Este metodo determina si el Custom Filter Graph tiene un stream de video para poder asi cargar el Decoder y Renderer de video bajo demanda
Argumentos
Valor Devuelto: True si la operacion fue exitosa, False caso contrario
Private Function ConnectCustomPinByNumber(ByVal USFilter As IBaseFilter, ByVal DSFilter As IBaseFilter, Optional ByVal USPinNumber As Integer = 0, Optional ByVal DSPinNumber As Integer = 0, Optional ByVal bUseICIfFailure As Boolean = False) As Boolean
Este metodo conectara un pin desde un UpStream filter a un Downstream filter utilizando el ordinal del pin dentro de dicho filtro
Argumentos
Valor Devuelvo: True si se completo exitosamente, False caso contrario
Private Function ConnectCustomPinByName(ByVal USFilter As IBaseFilter, ByVal DSFilter As IBaseFilter, ByVal USPinName As String, ByVal DSPinName As String, Optional ByVal bUseICIfFailure As Boolean = False) As Boolean
Este metodo conectara un pin desde un Upstream Filter a un Downstream Filter utilizando el nombre del pin dentro de dicho filtro
Argumentos
Valor Devuelvo: True si se completo exitosamente, False caso contrario
Private Function AddCustomFilter(ByVal bIsSource As Boolean, ByVal filterCLSiD As String, ByVal filterFriendlyName As String, ByRef Filter As IBaseFilter, Optional ByVal szFileName As String = ""
As Boolean
Este metodo agregara un filtro especificado al Custom Filter Graph
Argumentos
Valor Devuelto: True si se completo exitosamente, False caso contrario
Private Function ReleaseCustomFG() As Boolean
Este metodo se asegura de liberar todos los recursos utilizados por el Custom Filter Graph
Argumentos: Este metodo no acepta argumentos
Valor Devuelto: True si se completo exitosamente, False caso contrario
Private Function CloseAndRelease() As Boolean
Este metodo se encarga de liberar los recursos utilizados en el orden que corresponde, una vez hecho esto, internamente llama al metodo ReleaseCustomFG()
Argumentos: Este metodo no acepta argumentos
Valor Devuelto: True si se completo exitosamente, False caso contrario
Private Function CreateRectText(ByVal txt As String, ByVal ImgSize As Size, ByVal fntface As FontFamily, ByVal facecolor As Color, ByVal alphakey As Color, ByVal bBorder As Boolean, Optional ByVal bUnderline As Boolean = False, Optional ByVal bBold As Boolean = True, Optional ByVal bItalic As Boolean = False, Optional ByVal bStrikeThru As Boolean = False, Optional ByVal outlineSize As Single = 4.0, Optional ByVal fontSize As Single = 15.0F, Optional ByVal getBestFit As Boolean = True) As Image
Este metodo crea un Bitmap con el tamaño especifico y le agrega el texto especificado al mismo
Argumentos:
Valor Devuelto: Image: devuelve la imagen lista para el Overlay
Private Function RenderIntelligentConnect(ByVal szFileName As String) As Boolean
Este metodo configura lo necesario e intenta abrir el stream solicitado mediante IntelligentConnect
Argumentos
szFileName: Nombre de archivo que se desea reproducir
Valor Devuelto: True si se completo exitosamente, False caso contrario
Esta clase Implementa ademas los metodos de IDisposable, para realizar la limpieza necesaria de objetos ya sea administrados como no administrados
Asegurese de llamar al metodo Dispose() cuando deje de utilizar la instancia
Bueno, ahora sin mas, publicare el codigo fuente en un repo de GitHub
De mas esta decir lo que costo hacer todo esto (no se que costo mas, si diseñar/escribir el codigo fuente, o esta documentacion) asi que se agradeceria cualquier tipo de feedback
en una proxima entrega publicare informacion sobre el codigo de la clase en si mismo y como hace que y cada cosa, como tambien algunos ejemplos de como crear instancias y utilizarlas para diferentes tareas
como asi tambien una clase que utiliza parte de esta para extraer audio de un video y guardarlo en un archivo mp3 como tambien extraer el video (sacandole el audio) y rescribirlo a disco sin audio
esto ultimo no sirve para mucho pero al menos les dara un pantallazo general sobre como funcionan los compresores y que podemos tunear para alterar la salida de los mismos, como asi tambien el uso del InfinitePin tee Filter
Links de Interes
DirectShowNet (Necesario)
DirectX Managed SDK (Necesario)
Nota Muy Importante al incluir los DLL de Direct3D en el proyecto probablemente los quiera obligar a usar el Framework 1.1 (cosa que no funciona muy bien) yo lo resolvi asi
agregar en el app.config
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0"/>
</startup>
En caso de que los putee por la arquitectura, les informo que lamentablemente el SDK de directX no corre bajo arquitectruas x64 por lo cual si estan compilando para x64 o AnyCPU (ambos release) deberan cambiarlos por x86
ahora si, aca va el link del codigo
DirectShow AV Player Class
Esta clase expone gran parte de su funcionalidad implementando los filtros de LAV (splitter, audio decoder, video decoder) por lo cual es recomendable tenerlos instalados en el sistema de destino para obtener el maximo rendimiento de la misma, la misma tambien hace uso del Video Mixing Renderer 9 (Microsoft VMR9) para presentar el video en el dispositivo de salida
Tambien es capaz de armar el Filter Graph manualmente (agregando uno a uno los filtros, negociar conexiones, conectarlos, etc) como tambien dispone de un metodo para utilizar Intelligent Connect en caso de que el armado del Filter Graph personalizado falle (por ejemplo, no se tiene los filtros de LAV instalados o dichos filtros no son compatibles con el stream que se intenta reproducir, aunque este ultimo punto es realmente dificil que suceda debido a que soportan un amplio margen de formatos distintos, pero igualmente podria darse el caso), el hecho de usar Intelligent Connect la hace compatible con un amplio numero de formatos distintos
Referencia de la clase
Enumeraciones
Estado: Esta enumeracion se utiliza para determinar en que estado se encuentra el stream, consta de los siguientes miembros
- ESTADO_CERRADO: Indica que no hay un Stream Abierto
- ESTADO_ABIERTO: Indica que hay un stream listo para reproducir
- ESTADO_REPRODUCIENDO: Indica que se esta reproduciendo actualmente un Stream
- ESTADO_PAUSADO: Indica que el stream actual se encuentra en estado pausado
- ESTADO_DETENIDO Indica que el stream se encuentra detenido, al comenzar la reproduccion esta comenzara desde cero
ERROR_LIST Esta enumeracion es utilizada por el evento "Error()" para especificar el motivo de falla de un metodo, consta de los siguientes miembros
- ERL_DIRECTSHOW Indica que se ha producido un error de DirectShow
- ERL_D3DDEVICE Indica que fallo la creacion del dispositivo de Direct3D
- ERL_D3DSURFACE Indica que fallo la creacion del surface de Direct3D
- ERL_RUTAINCORRECTA Indica que el archivo especificado no existe
- ERL_MODOINCORRECTO Indica que el estado del stream no es correcto para este comando
- ERL_VALORINCORRECTO Indica que el argumento no es correcto
- ERL_TFNOSOPORTADO Indica que el stream actual no soporta el formato de tiempo solicitado
- ERL_VENTANAINEXISTENTE Indica que algun handle de ventana (HWND) no es correcto
- ERL_DESCONOCIDO Indica un error no especificado, con el tiempo la idea es que este desaparezca y que el informe de errores sea lo mas especifico posible
FILTER_TYPE No implementada actualmente, en un futuro sera utilizada por el metodo UnderTheHood
TIME_FORMAT: esta enumeracion nos sirve para especificar el formato de tiempo mediante el cual queremos hacer referencia al stream actual, la misma consta de los siguientes miembros
- TF_MILLISECONDS: Indica que el formato de tiempo sera especificado en Milisegundos (1/1000) segundos
- TF_FRAMES Indica que el formato de tiempo sera especificado en cuadros (Frames) notar que solo es compatible con algunos formatos de video
- TF_SECONDS Indica que el tiempo sera espeficado en segundos
- TF_MEDIATIME Indica que es el valor sera especificado en la unidad que maneja el RefClock de DirectShow (1/100 nanosegundos)
- TF_SAMPLES Indica que el valor de tiempo sera especificado uasndo Samples (muestras)
PROP esta enumeracion es utilizada para establecer los valores ProcAmp del stream de video actual,, NOTA: Los parametros de ProcAmp se establecen utilizando el Mixer del Video Mixing Renderer 9 (VMR9), por lo cual si se provee a la aplicacion con un Custom Compositor (del cual depende el mixer de VMR9) estos metodos dejaran de funcionar, consta de los siguientes miembros
- BRIGHNESS: Indica que se debe obtener o establecer el brillo
- HUE: Indica que se debe obtener o establecer el Hue (Luminancia)
- SATURATION Indica que se debe obtener o establecer la saturacion del video
- CONTRAST Indica que se debe obtener o establecer el contraste del video
Estructuras
UNDER_THE_HOOD: Esta estructura se utiliza para recuperar informacion sobre todos los filtros, pines, direccion de los mismos, parametros de negociacion entre filtros, tamaño de los samples (allocators), etc, consta de los siguientes campos
- FilterName: (String) Nombre del filtro actual dentro del FilterGraph
- Pins(): (PIN_INFO) Arreglo que contendra informacion sobre todos los pines que posee cada filtro
PIN_INFO: Esta estructura contiene informacion sobre un determinado pin es utilizada por la estructura UNDER_THE_HOOD para enumerar los pines de cada filtro y sus propiedades como asi tambien los MediaTypes (parametros de negociacion) de cada pin, consta de los siguientes campos
- PinName (String): Nombre del pin actual dentro del filtro
- PinDirection (PinDirection): Direccion del pin, puede ser PinDirection.Input o PinDirection.Output, Esta enumeracion se proviene del espacio de nombres DirectShowLib
- MajorType (Guid) Este campo contiene el GUID del tipo de datos negociado por el pin actual (puede utilizar la enumeracion DirectShowLib.MediaType para obtener informacion sobre este GUID)
- SubType (Guid): Este campo contiene el GUID del subtipo de datos negociado por el pin actual (puede utilizar la enumeracion DirectShowLib.MediaSubType para obtener informacion sobre este GUID)
- SampleSize (Long): Este campo posee informacion sobre el tamaño de los Samples (Tamaño negociado de los Allocators entre filtros), si el SampleSize es dinamico (algunos filtros lo soportan) puede que este campo no devuelva el valor correcto, usar bajo su responsabilidad
VIDEO_STATS Esta estructura se utiliza para devolver ciertos parametros sobre la renderizacion de video en tiempo real desde el Video Mixing Renderer (VMR9), consta de los siguientes campos
- AVG_FRAME_RATE (Double): Este campo devuelve la cantidad promedio de cuadros por segundo dibujados por VMR9 (Frames Per Second o FPS)
- AVG_SYNC_OFFSET (Long): Este campo devuelve la cantidad promedio de cuadros que tuvieron que esperar en el allocator antes de ser dibujados debido a un error de sincronismo en el Filter Graph
- FRAMES_DRAWN (Long): Este campo determina la cantidad de cuadros dibujados por VMR9
- FRAMES_DROPPED (Long): Este campo determina la cantidad de cuadros que tuvieron que ser eliminados debido a errores de sincronismo irrecuperables
AUDIO_STATS Esta estructura se utiliza para devolver ciertos parametros sobre la renderizacion de audio en tiempo real desde el Audio Decoder, consta de los siguientes campos
- CHANNELS (Long): Este campo determina si el stream posee sonido MonoAural (1) o sonido Stereo (2)
- SAMPLES_PER_SEC (Long): Este campo determina la cantidad de Samples (muestreos) por segundo que se envian a DirectSound a traves del Renderer
- AVG_BYTES_PER_SEC (Long): Este campo determina la cantidad promedio de Bytes Por Segundo que se envian a DirectSound a traves del Renderer
- BUFFER_DURATION (Long): Este campo informa la duracion (en MILISEGUNDOS) del buffer de DirectSound a traves del Renderer
- BUFFER_FILL (Long): Este campo determina en tiempo real el porcentaje de llenado del Buffer de DirectSound
M_M_V_D Esta estructura se utiliza para establecer u obtener los valores de ProcAmp del stream de video actual, IMPORTANTE es muy importante determinar los valores maximos y minimos por defecto antes de establecer valores de ProcAmp para un stream debido a que los mismos VARIAN de un hardware de video a otro, la misma cuenta con los siguientes campos
- dwMinValue (Single): Este campo nos sirve para determinar el valor minimo de la propiedad actual
- dwMaxValue (Single): Este campo nos sirve para determinar el valor maximo de la propiedad actual
- dwStep (Single): Este campo nos sirve para determinar el valor minimo de incremento o decremento de la propiedad actual
- dwDefault (Single): Este campo nos sirve para determinar el valor por defecto de la propiedad actual
- dwCurrrentValue (Single): Este campo nos permite especificar un nuevo valor para la propiedad actual de ProcAmp
TextOverlayParams Esta estructura nos permite especificar los valores que se utilizaran por defecto para dibujar texto sobre el stream de video , consta de los siguientes campos
- FontFace (String): Este campo nos permite establecer el nombre de la fuente a utilizar
- FontColor (Color): Este campo nos permite establecer el color de la fuente
- Bold (Boolean): Este campo nos permite establecer si la fuente sera Negrita
- Italic (Boolean): Este campo nos permite establecer si la fuente sera Italic (K)
- UnderLine (Boolean): Este campo nos permite establecer si al fuente estara subrayada
- DrawBorder (Boolean): Este campo nos permite establecer si se dibujara un contorno color negro alrededor de la fuente, esto es util en ambientes donde el cuadro de video tenga color similar al color de la fuente
- AlphaColor (Color): Este campo no esta implementado debido a que Direct3D tiene la posibilidad de aplicar AlphaBlending sobre las Surfaces
- OutlineSize (Single): Este campo determina el ancho del contorno
- FontSize (Single): Este campo determina el tamaño de la fuente (ver informacion sobre metodo de dibujado para mayor informacion sobre este valor)
Eventos
La clase es capaz de disparar eventos simples, aunque no sera capaz de disparar eventos con suscripcion (Event Handlers) debido a que no son necesarios por el momento
Los eventos que la clase puede disparar son:
- FileOpened(): Este evento se llamara cuando se haya abierto satisfactoriamente un archivo
- CustomGraphRendered(): Este evento se disparara cuando se haya logrado armar el Filter Graph usando LAV
- UsingIC(): Este evento se disparara cuando habiendo fallado el Custom Filter Graph, se opte por Intelligent Connect
- VolumeChanged(): Este evento se disparara cuando se haya modificado satisfactoriamente el Volumen
- BalanceChanged(): Este evento se disparara cuando se haya modificado satisfactoriamente el balance
- TimeFormatChanged(): Este evento se disparara cuando haya modificado satisfactoriamente el Formato de tiempo utilizado por el stream actual
- Error(ERROR_LIST): Este evento se disparara cuando se produzca un error al realizar una tarea, el argumento de tipo ERROR_LIST posee informacion sobre el fallo
Propiedades
- Filename (String): Obtiene o establece el nombre de archivo a reproducir por la instancia actual
- VideoWindow (IntPtr): Obtiene o establece el Handle de ventana (HWND) que se utilizara para reproducir el video , debe ser una ventana valida
- MainHandle (IntPtr): Obtiene o establece el Handle de ventana (HWND) de la ventana principal que contiene el subcontrol que reproduce el video , el mismo sera utilizado por Direct3D
- VideoSize (Size): Obtiene o establece el tamaño actual del video , si es stream no soporta video se disparara un evento de error
- NativeVideoSize (Size) (Solo Lectura): Obtiene el tamaño original del video
- HasVideo (Boolean) (Solo Lectura): Obtiene un valor que determina si el stream actual posee video
- HasAudio (Boolean) (Solo Lectura): Obtiene un valor que determina si el stream posee audio, esto solo funcionara con el filtro de LAV en el Filter Graph, caso contrario siempre devolvera True
- HasText (Boolean) (Solo Lectura): Obtiene un valor que determina si hay actualmente un texto dibujado sobre el stream de video
- TimeFormat (TIME_FORMAT): Obtiene o establece el formato de tiempo utilizado por el stream actual, todas las llamadas a Position() y Duration() devolveran un valor usando este formato
- Position (Long): Devuelve la posicion actual de reproduccion dentro del stream
- Duration (Long) (Solo Lectura): Devuelve la duracion total del stream
- Rate(Double): Obtiene o establece la velocidad de reproduccion del stream actual, los posibles valores van desde 0 hasta 2.0F siendo 1.0F el valor original
Metodos Publicos
Public Sub RW(ByVal uUnits As Long)
Se desplaza "uUnits" Frames hacia adelante en el stream de video , el mismo debe soportar el formato de tiempo Frames y ademas soportar FrameSkipping (hasta ahora no encontre ninguno de los que tengo aca que lo soporte) asi que de estar esta, pero casi nunca funciona

Public Sub RW(ByVal uUnits As Long)
Se desplaza "uUnits" hacia atras en el stream de video , el mismo debe soportar el formato de tiempo Frames y ademas soportar FrameSkipping (hasta ahora no encontre ninguno de los que tengo aca que lo soporte) asi que de estar esta, pero casi nunca funciona y encima debe ser soportado por el filtro que expone esta interfaz (el splitter en este caso)
Public Function GetCurrentImage(ByVal sFileName As String) As Boolean
Este metodo guarda el cuadro actual de video en un archivo JPEG especificado por el argumento sFileName, el mismo devuelve True si el proceso se realizo satisfactoriamente o False caso contrario
Public Function GetCurrentImage(ByRef retBMP As Image) As Boolean
Sobrecarga del metodo GetCurrentImage(ByVal sFileName As String) As Boolean
en lugar de guardar el archivo a disco lo devuelve en un objeto Image para que pueda ser editado y/o manipulado a gusto antes de guardarlo
Public Function GetValues(ByVal sProp As ENUMS.PROP) As ESTRUCTURAS.M_M_V_D
Este metodo permite obtener los valores necesarios para poder luego modificar los parametros de ProcAmp (como de ser, brillo, contraste, saturacion, etc)
Es indispensable llamar a este metodo antes de establecer dichos valores debido a que los valores posibles para cada parametro varian dependiendo del hardware de video
sProp: determina que valor se desea obtener
Valor Devuelto: Estructura M_M_V_D con los valores para la propiedad especificada
Public Function SetProcAmpValue(ByVal PropToSet As ENUMS.PROP, ByVal dwVal As Single) As Boolean
Este metodo establece el valor de ProcAmp especificado por el argumento PropToSet, este valor debe estar dentro de los parametros especificados por el controlador/hardware de video
PropToSet: Enumeracion que permite especificar que valor se establecera
dwVal: Nuevo valor que se establece para la propiedad PropToSet, el rango de variacion debe ser obtenida por GetValues()
Valor Devuelto: Boolean: True si la operacion se completo correctamente, caso contrario devolvera False
Public Function Open() As Boolean
Este metodo abrira el archivo especificado por la propiedad FileName, el mismo intentara abrir el archivo en el siguiente orden
1º Intentara armar el Filter Graph personalizado con los filtros de LAV
2º Intentara usar Intelligent Connect para renderizar el archivo
3º Fallara la apertura del archivo (si llego hasta aqui es porque no hay forma de abrir dicho archivo en la configuracion actual de sistema)
Valor Devuelvo: True si se abrio el archivo, False caso contrario, evaluar los eventos CustomGraphRendered() y/o UsingIC() para determinar el mecanismo utilizado por el metodo para la apertura
Public Function Close() As Boolean
Este metodo cerrara el stream abierto actualmente (en caso de haber alguno) y liberara todos los recursos utilizados por los objetos tanto administrados como no administrados
Valor Devuelto: True si se logro cerrar el archivo con exito, False caso contrario
Public Function Play() As Boolean
Este metodo comenzara la reproduccion del archivo abierto actualmente (en caso de haber alguno)
Valor Devuelto: True si se pudo comenzar la reproduccion, False caso contrario
Public Function Pause() As Boolean
Este metodo pondra el estado del stream actual en "Pausado" en caso de haber algun stream abierto
Valor Devuelto: True si se logro el cambio de estado, False caso contrario
Public Function Stop() As Boolean
Este metodo pondra el estado del stream actual en "Detenido" en caso de haber algun stream abierto
Valor Devuelto: True si se logro el cambio de estado, False caso contrario
Public Sub RepaintVideo()
Este metodo informa al Renderer de Video ( Video Mixing Renderer 9) que se debe repintar el area de video , como practica general, deberia llamar a este metodo en el evento paint del control que muestra el video
Public Function WriteOverlayText(ByVal szText As String, ByVal bShow As Boolean) As Boolean
Este metodo dibujara un texto encima del stream de video , el mismo se ubicara en la parte inferior central del video , no es necesario pausar el stream para realizar la mezcla
Argumentos:
szText: Texto que se desea colocar (puede ser nulo si bShow es igual a False) el texto se dibujara con los parametros previamente establecidos por las propiedades de tratamiento de texto
Public Function GetVideoStats(ByRef dwStats As ESTRUCTURAS.VIDEO_STATS) As Boolean
Este metodo devuelve informacion sobre el stream de video actual
Argumentos: dwStats: aqui se depositara la informacion que se recupere del Video Renderer
Valor Devuelvo: True si se completo exitosamente, False en caso contrario
Public Function GetAudioInfo(ByRef dwRet As ESTRUCTURAS.AUDIO_STATS) As Boolean
Este metodo devuelve informacion sobre el stream de audio actual
Argumentos: dwRet: aqui se depositara la informacion que se recuperar del Decoder de Audio
Valor Devuelto: True si se completo exitosamente, False en caso contrario
Public Function UnderTheHood(ByRef dwRet() As ESTRUCTURAS.UNDER_THE_HOOD) As Boolean
Este metodo devolvera informacion sobre todos los filtros, pines, MediaTypes y SampleAllocatorsSize presentes en el FilterGraph, esta informacion puede resultar particularmente util a la hora de depurar un Filter Graph
Argumentos: dwRet(): este arreglo contendra toda la informacion, cada registro del arreglo correspondera a un filtro del Graph y el mismo contendra informacion sobre todos sus pines, los arreglos se reservan dinamicamente asi que no intente asignar un valor al arreglo en tiempo de diseño o el metodo fallara
Valor Devuelvo: True si la se completo exitosamente, False de lo contrario
Metodos Privados
Private Function InitializeDirect3D() As Boolean
Este metodo inicializa el Device y el Surface de direct3D que se usara para mezclar el texto sobre el stream de video
Argumentos: Este metodo no toma argumentos
Valor Devuelto: True si se completo exitosamente, False caso contrario
Private Function CreateCustomFilterGraph(ByVal szFileName As String) As Boolean
Este metodo intenta crear el FilterGraph personalizado (usando el set de filtros de LAV) para obtener asi un mayor control sobre el stream
Argumentos
- FileName: este argumento especifica el archivo que se desea renderizar
Valor Devuelto: True si la operacion fue exitosa, False caso contrario
Private Function ConfigureRenderer() As Boolean
Este metodo configura el Renderer de video ( Video Mixing Renderer 9) para ser utilizado en nuestro FilterGraph
Argumentos: Este metodo no tiene argumentos
Valor Devuelto: True si se completo exitosamente, False caso contrario
Private Function CustomGraphHasAudio(ByVal splitterFilter As IBaseFilter) As Boolean
Este metodo determina si el Custom Filter Graph posee stream de audio y se utiliza para cargar el decoder y renderer de audio bajo demanda
Argumentos
- splitterFilter: Referencia al splitter Filter del que se extraera la informacion
Valor Devuelto: True si se completo exitosamente, False caso contrario
Private Function CustomGraphHasVideo(ByVal splitterFilter As IBaseFilter) As Boolean
Este metodo determina si el Custom Filter Graph tiene un stream de video para poder asi cargar el Decoder y Renderer de video bajo demanda
Argumentos
- splitterFilter: Referencia al Splitter Filter del que se extraera la informacion
Valor Devuelto: True si la operacion fue exitosa, False caso contrario
Private Function ConnectCustomPinByNumber(ByVal USFilter As IBaseFilter, ByVal DSFilter As IBaseFilter, Optional ByVal USPinNumber As Integer = 0, Optional ByVal DSPinNumber As Integer = 0, Optional ByVal bUseICIfFailure As Boolean = False) As Boolean
Este metodo conectara un pin desde un UpStream filter a un Downstream filter utilizando el ordinal del pin dentro de dicho filtro
Argumentos
- USFilter: Referencia al filtro desde el cual se conectara el pin
- DSFilter: Referencia al filtro al cual se conectara el pin
- USPinNumber: Numero de pin en el filtro de origen que se conectara, si no se especifica, se asumira el primer pin del filtro
- DSPinNumber: Numero de pin en el filtro de destino que se conectara, si no se especifica , se asumira el primer pin del filtro
- bUseICIfFailure: Si se no se pueden conectar dos filtros automaticamente, este argumento determina si se debe usar IntelligentConnect entre ambos filtros, por defecto no se utilizara y la conexion fallara
Valor Devuelvo: True si se completo exitosamente, False caso contrario
Private Function ConnectCustomPinByName(ByVal USFilter As IBaseFilter, ByVal DSFilter As IBaseFilter, ByVal USPinName As String, ByVal DSPinName As String, Optional ByVal bUseICIfFailure As Boolean = False) As Boolean
Este metodo conectara un pin desde un Upstream Filter a un Downstream Filter utilizando el nombre del pin dentro de dicho filtro
Argumentos
- USFilter: Referencia al filtro desde el cual se conectara el pin
- DSFilter: Referencia al filtro al cual se conectara el pin
- USPinName Nombre de pin en el filtro de origen que se conectara
- DSPinName: Nombre de pin en el filtro de destino que se conectara
- bUseICIfFailure: Si se no se pueden conectar dos filtros automaticamente, este argumento determina si se debe usar IntelligentConnect entre ambos filtros, por defecto no se utilizara y la conexion fallara
Valor Devuelvo: True si se completo exitosamente, False caso contrario
Private Function AddCustomFilter(ByVal bIsSource As Boolean, ByVal filterCLSiD As String, ByVal filterFriendlyName As String, ByRef Filter As IBaseFilter, Optional ByVal szFileName As String = ""

As Boolean
Este metodo agregara un filtro especificado al Custom Filter Graph
Argumentos
- bIsDetermina si el filtro es un Source Filter
- filterCLSID: ClassID del filtro que se desea agregar
- FilterFriendlyName: Nombre del filtro que se deesea agregar
- Filter: Aqui se colocara la referencia al objeto que se acaba de alocacionar
- szFileName: Nombre de archivo que se desea abrir, este argumento se puede obviar si bIsSource esta establecido a False
Valor Devuelto: True si se completo exitosamente, False caso contrario
Private Function ReleaseCustomFG() As Boolean
Este metodo se asegura de liberar todos los recursos utilizados por el Custom Filter Graph
Argumentos: Este metodo no acepta argumentos
Valor Devuelto: True si se completo exitosamente, False caso contrario
Private Function CloseAndRelease() As Boolean
Este metodo se encarga de liberar los recursos utilizados en el orden que corresponde, una vez hecho esto, internamente llama al metodo ReleaseCustomFG()
Argumentos: Este metodo no acepta argumentos
Valor Devuelto: True si se completo exitosamente, False caso contrario
Private Function CreateRectText(ByVal txt As String, ByVal ImgSize As Size, ByVal fntface As FontFamily, ByVal facecolor As Color, ByVal alphakey As Color, ByVal bBorder As Boolean, Optional ByVal bUnderline As Boolean = False, Optional ByVal bBold As Boolean = True, Optional ByVal bItalic As Boolean = False, Optional ByVal bStrikeThru As Boolean = False, Optional ByVal outlineSize As Single = 4.0, Optional ByVal fontSize As Single = 15.0F, Optional ByVal getBestFit As Boolean = True) As Image
Este metodo crea un Bitmap con el tamaño especifico y le agrega el texto especificado al mismo
Argumentos:
- txt: Especifica el texto que se dibujara
- ImgSize: Especifica el tamaño de la imagen (generalmente al tamaño del video
- fntface: Especifica la fuente a utilizar
- facecolor: Especifica el color de la fuente para el texto
- alphaKey: Especifica el color de transparencia (actualmente no implementado)
- bBorder: Especifica si se debe dibujar un borde a cada letra
- bUnderline: Especifica si el texto estara subrayado
- bBold: Especifica si el texto estara en negrita
- bItalic: Especifica si el texto estara en Italic (K)
- bStrikeThru: Especifica si el texto aparecera tachado (no se implementa pq queda horrible, pero sobre gustos...) el metodo esta
- outlineSize: Tamaño del sombreado
- Fontsize: Tamaño del texto
- getBestFit: especifica si se debe utilizar el mayor tamaño posible de acuerdo con el tamaño del video (recomendado)
Valor Devuelto: Image: devuelve la imagen lista para el Overlay
Private Function RenderIntelligentConnect(ByVal szFileName As String) As Boolean
Este metodo configura lo necesario e intenta abrir el stream solicitado mediante IntelligentConnect
Argumentos
szFileName: Nombre de archivo que se desea reproducir
Valor Devuelto: True si se completo exitosamente, False caso contrario
Esta clase Implementa ademas los metodos de IDisposable, para realizar la limpieza necesaria de objetos ya sea administrados como no administrados
Asegurese de llamar al metodo Dispose() cuando deje de utilizar la instancia
Bueno, ahora sin mas, publicare el codigo fuente en un repo de GitHub
De mas esta decir lo que costo hacer todo esto (no se que costo mas, si diseñar/escribir el codigo fuente, o esta documentacion) asi que se agradeceria cualquier tipo de feedback
en una proxima entrega publicare informacion sobre el codigo de la clase en si mismo y como hace que y cada cosa, como tambien algunos ejemplos de como crear instancias y utilizarlas para diferentes tareas
como asi tambien una clase que utiliza parte de esta para extraer audio de un video y guardarlo en un archivo mp3 como tambien extraer el video (sacandole el audio) y rescribirlo a disco sin audio
esto ultimo no sirve para mucho pero al menos les dara un pantallazo general sobre como funcionan los compresores y que podemos tunear para alterar la salida de los mismos, como asi tambien el uso del InfinitePin tee Filter
Links de Interes
DirectShowNet (Necesario)
DirectX Managed SDK (Necesario)
Nota Muy Importante al incluir los DLL de Direct3D en el proyecto probablemente los quiera obligar a usar el Framework 1.1 (cosa que no funciona muy bien) yo lo resolvi asi
agregar en el app.config
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0"/>
</startup>
En caso de que los putee por la arquitectura, les informo que lamentablemente el SDK de directX no corre bajo arquitectruas x64 por lo cual si estan compilando para x64 o AnyCPU (ambos release) deberan cambiarlos por x86
ahora si, aca va el link del codigo
DirectShow AV Player Class