Saltar a contenido

Captura de Webcam en C# Usando el SDK DirectShow .NET

Introducción

Esta guía demuestra cómo crear una aplicación de captura de webcam en C# usando el Video Capture SDK .Net con tecnología Microsoft DirectShow. DirectShow es un poderoso framework multimedia de Windows que permite a las aplicaciones controlar y procesar datos de audio y video desde varias fuentes, incluyendo webcams y cámaras USB.

El código fuente completo de la aplicación de ejemplo está disponible en el repositorio de GitHub.

Prerrequisitos

  • Visual Studio 2019 o posterior
  • Sistema operativo Windows 10 u 11
  • Webcam u otro dispositivo de captura de video (cámara USB)
  • Comprensión básica de programación en C#

Instalación

Consulta la guía de instalación principal para pasos detallados sobre cómo instalar el SDK DirectShow .NET en tu aplicación.

Componentes Clave

Clases Principales

  • VideoCaptureCore - Clase principal para capturar video desde un dispositivo fuente
  • VideoCaptureSource - Representa un dispositivo fuente de video (webcam, cámara)
  • AudioCaptureSource - Representa un dispositivo de captura de audio (micrófono)

Guía de Implementación

1. Inicializar el Motor de Captura

El primer paso en cualquier aplicación DirectShow es crear el objeto principal de captura:

// Crear una nueva instancia con una vista de video
var captureCore = await VideoCaptureCore.CreateAsync(videoView as IVideoView);

// Registrar manejador de errores para desarrollo de aplicaciones robusto
captureCore.OnError += (sender, args) => {
    Console.WriteLine($"Error: {args.Message}");
};

2. Enumeración y Selección de Dispositivos

Enumerar Dispositivos Disponibles

Para acceder a webcams y micrófonos, necesitas enumerar los dispositivos disponibles:

// Obtener fuentes de video
foreach (var item in captureCore.Video_CaptureDevices())
{
    Console.WriteLine($"Dispositivo de video: {item.Name}");

    // Listar formatos disponibles para este dispositivo
    foreach (var format in item.VideoFormats)
    {
        Console.WriteLine($"  Formato: {format}");
    }
}

// Obtener fuentes de audio
foreach (var item in captureCore.Audio_CaptureDevices())
{
    Console.WriteLine($"Dispositivo de audio: {item.Name}");

    foreach (var format in item.Formats)
    {
        Console.WriteLine($"  Formato: {format}");
    }
}

Configurar Fuentes de Captura de Video y Audio

Este código de ejemplo muestra cómo filtrar y seleccionar formatos específicos de video y audio requeridos por tu aplicación:

// Encontrar y configurar fuente de video con formato específico
var videoDevices = captureCore.Video_CaptureDevices();
VideoCaptureSource selectedVideoDevice = null;
string targetVideoFormat = null;

// Encontrar un dispositivo con soporte 1280x720 MJPG
foreach (var item in videoDevices)
{
    Console.WriteLine($"Verificando dispositivo de video: {item.Name}");

    foreach (var format in item.VideoFormats)
    {
        Console.WriteLine($"  Formato: {format}");

        // Buscar formato 1280x720 MJPG
        if (format.Contains("1280x720") && format.Contains("MJPG"))
        {
            selectedVideoDevice = item;
            targetVideoFormat = format;
            Console.WriteLine($"  SELECCIONADO: {format}");
            break;
        }
    }

    if (selectedVideoDevice != null)
        break;
}

// Encontrar y configurar fuente de audio con formato específico
var audioDevices = captureCore.Audio_CaptureDevices();
AudioCaptureSource selectedAudioDevice = null;
string targetAudioFormat = null;

// Encontrar un dispositivo con soporte 44100 Hz, 16 bit, 2 canales
foreach (var item in audioDevices)
{
    Console.WriteLine($"Verificando dispositivo de audio: {item.Name}");

    foreach (var format in item.Formats)
    {
        Console.WriteLine($"  Formato: {format}");

        // Buscar formato 44100 Hz, 16 bit, 2 canales
        if (format.Contains("44100 Hz") && format.Contains("16 Bit") && format.Contains("2 Channel"))
        {
            selectedAudioDevice = item;
            targetAudioFormat = format;
            Console.WriteLine($"  SELECCIONADO: {format}");
            break;
        }
    }

    if (selectedAudioDevice != null)
        break;
}

// Configurar captura de video con el dispositivo y formato seleccionados
if (selectedVideoDevice != null)
{
    captureCore.Video_CaptureDevice = new VideoCaptureSource(selectedVideoDevice.Name);

    if (targetVideoFormat != null)
    {
        captureCore.Video_CaptureDevice.Format = targetVideoFormat;
        captureCore.Video_CaptureDevice.Format_UseBest = false; // Usando formato específico
    }
    else
    {
        captureCore.Video_CaptureDevice.Format_UseBest = true; // Usar el mejor formato disponible
    }

    // Configurar tasa de fotogramas de video si es necesario
    captureCore.Video_CaptureDevice.FrameRate = new VideoFrameRate(30.0);
}
else
{
    Console.WriteLine("No se encontró dispositivo de video con 1280x720 MJPG.");

    // Alternativa al primer dispositivo disponible con mejor formato
    if (videoDevices.Count() > 0)
    {
        captureCore.Video_CaptureDevice = new VideoCaptureSource(videoDevices[0].Name);
        captureCore.Video_CaptureDevice.Format_UseBest = true;
    }
}

// Seleccionar dispositivo de captura de audio. Especificar el nombre del dispositivo y formato
if (selectedAudioDevice != null)
{
    captureCore.Audio_CaptureDevice = new AudioCaptureSource(selectedAudioDevice.Name);

    if (targetAudioFormat != null)
    {
        captureCore.Audio_CaptureDevice.Format = targetAudioFormat;
        captureCore.Audio_CaptureDevice.Format_UseBest = false; // Usando formato específico
    }
    else
    {
        captureCore.Audio_CaptureDevice.Format_UseBest = true; // Establecer true para detectar el mejor formato automáticamente
    }
}
else
{
    Console.WriteLine("No se encontró dispositivo de audio con 44100 Hz, 16 bit, 2 canales.");

    // Alternativa al primer dispositivo disponible
    if (audioDevices.Count() > 0)
    {
        captureCore.Audio_CaptureDevice = new AudioCaptureSource(audioDevices[0].Name);
        captureCore.Audio_CaptureDevice.Format_UseBest = true;
    }
}

// Abrir diálogos de configuración del dispositivo si es necesario
// captureCore.Video_CaptureDevice_SettingsDialog_Show(IntPtr.Zero, captureCore.Video_CaptureDevice.Name);
// captureCore.Audio_CaptureDevice_SettingsDialog_Show(IntPtr.Zero, captureCore.Audio_CaptureDevice.Name);

3. Configurando Ajustes de Audio

Controla la grabación y reproducción de audio con estos ajustes:

// Habilitar grabación de audio
captureCore.Audio_RecordAudio = true;

// Habilitar reproducción de audio durante la captura
captureCore.Audio_PlayAudio = true;

// Configurar dispositivo de salida de audio
captureCore.Audio_OutputDevice = "Default DirectSound Device";

// Establecer volumen de audio (0-100)
captureCore.Audio_OutputDevice_Volume_Set(75);

// Establecer balance de audio (-100 a 100)
captureCore.Audio_OutputDevice_Balance_Set(0);

4. Configuración de Salida

Salida de Video MP4

Para guardar el video capturado en un archivo MP4, usa el siguiente código:

// Establecer modo de captura
captureCore.Mode = VideoCaptureMode.VideoCapture;
captureCore.Output_Filename = "salida.mp4";

// Configurar salida MP4 (CPU/QuickSync)
var mp4Output = new MP4Output
{
    MP4Mode = MP4Mode.CPU_QSV,
    AudioFormat = MP4AudioEncoder.AAC
};

// Configurar ajustes de audio AAC
mp4Output.Audio_AAC = new M4AOutput
{
    Bitrate = 128,
    Object = AACObject.Low,
    Output = AACOutput.RAW,
    Version = AACVersion.MPEG4
};

// O usar MP3 para audio (vía codificador LAME)
var mp3Output = new MP3Output();
mp4Output.Audio_LAME = mp3Output;
mp4Output.AudioFormat = MP4AudioEncoder.MP3_LAME;

// Configurar ajustes de video H.264
mp4Output.Video = new MP4OutputH264Settings
{
    // Ajustes básicos
    Bitrate = 3500,
    MaxBitrate = 6000,
    MinBitrate = 1500,
    BitrateAuto = false,

    // Perfil y nivel
    Profile = H264Profile.ProfileMain,
    Level = H264Level.Level41,

    // Estructura de fotogramas
    IDR_Period = 15,         // Intervalo de I-frame en fotogramas
    P_Period = 3,            // Distancia entre fotogramas clave I o P (si es 1, sin B-frames)

    // Ajustes de codificación
    RateControl = H264RateControl.VBR,
    MBEncoding = H264MBEncoding.CAVLC,  // o CABAC para mejor compresión
    TargetUsage = H264TargetUsage.Balanced,
    Preset = H264Peset.Balanced,

    // Otras opciones
    Deblocking = true,
    GOP = true,
    PictureType = H264PictureType.Auto
};

// Asignar formato de salida
captureCore.Output_Format = mp4Output;

Codificación Acelerada por Hardware

Para aceleración por hardware usando GPU NVIDIA:

// Usar aceleración por hardware con NVENC
var mp4HWOutput = new MP4HWOutput
{
    // Ajustes H264
    Video = new MFVideoEncoderSettings
    {
        Codec = MFVideoEncoder.NVENC_H264,  // o MS_H264, QSV_H264, AMD_H264
        AvgBitrate = 3500,
        MaxBitrate = 6000,
        Profile = MFH264Profile.Main,
        Level = MFH264Level.Level41,
        RateControl = MFCommonRateControlMode.CBR,
        CABAC = true,
        QualityVsSpeed = 85,
        MaxKeyFrameSpacing = 125
    },

    // Ajustes AAC
    Audio = new M4AOutput
    {
        Bitrate = 128,
        Object = AACObject.Low
    }
};

captureCore.Output_Format = mp4HWOutput;

Formatos de Salida Personalizados

Para configuraciones de salida más avanzadas:

5. Procesamiento de Video y Efectos

DirectShow permite el procesamiento de video a través de filtros. Aquí está cómo añadir varios efectos:

// Habilitar efectos de video
captureCore.Video_Effects_Enabled = true;
captureCore.Video_Effects_MergeImageLogos = true;
captureCore.Video_Effects_MergeTextLogos = true;

// Añadir efecto de escala de grises
var grayscale = new VideoEffectGrayscale(true);
captureCore.Video_Effects_Add(grayscale);

// Añadir efecto de contraste (0-200)
var contrast = new VideoEffectContrast(true, 50);
captureCore.Video_Effects_Add(contrast);

// Añadir efecto de brillo (0-200)
var lightness = new VideoEffectLightness(true, 50);
captureCore.Video_Effects_Add(lightness);

// Añadir efecto de saturación (0-255)
var saturation = new VideoEffectSaturation(120);
captureCore.Video_Effects_Add(saturation);

// Añadir efecto de oscuridad (0-200)
var darkness = new VideoEffectDarkness(true, 20);
captureCore.Video_Effects_Add(darkness);

// Añadir efecto de inversión de colores
var invert = new VideoEffectInvert(true);
captureCore.Video_Effects_Add(invert);

// Añadir efectos de volteo
var flipHorizontal = new VideoEffectFlipHorizontal(true);
captureCore.Video_Effects_Add(flipHorizontal);

var flipVertical = new VideoEffectFlipVertical(true);
captureCore.Video_Effects_Add(flipVertical);

Añadiendo Superposiciones

// Añadir logo de imagen
var imageLogo = new VideoEffectImageLogo(true, "MiLogo");
imageLogo.Filename = "logo.png"; // Ruta a tu imagen de logo
// Configurar propiedades del logo aquí
captureCore.Video_Effects_Add(imageLogo);

// Añadir logo de texto
var textLogo = new VideoEffectTextLogo(true, "MiLogoDeTexto");
textLogo.Text = "Mi Logo de Texto";
// Configurar propiedades del texto aquí
captureCore.Video_Effects_Add(textLogo);

// Añadir texto con desplazamiento
var scrollingText = new VideoEffectScrollingTextLogo(true);
// Configurar propiedades del texto aquí
captureCore.Video_Effects_Add(scrollingText);

Filtros DirectShow Personalizados

El poder de DirectShow viene de su arquitectura basada en filtros. Aquí está cómo añadir un filtro para procesamiento de video:

// Listar todos los filtros DirectShow disponibles
var filters = captureCore.DirectShow_Filters();

// Usar un filtro específico
var filter = filters.FirstOrDefault(f => f.Name == "MiFiltro");

captureCore.Video_Filters_Add(new CustomProcessingFilter(filter));

6. Control de Captura

Controla el flujo de medios con estos métodos simples:

// Establecer opciones de depuración si es necesario
captureCore.Debug_Mode = true;
captureCore.Debug_Dir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "VisioForge");

// Iniciar captura
await captureCore.StartAsync();

// Pausar captura
await captureCore.PauseAsync();

// Reanudar captura
await captureCore.ResumeAsync();

// Detener captura
await captureCore.StopAsync();

// Liberar cuando termine
captureCore.Dispose();

7. Tomando Capturas de Pantalla

Captura imágenes fijas de tu flujo de video:

// Tomar una captura y guardar como JPEG con calidad 85
await captureCore.Frame_SaveAsync("captura.jpg", ImageFormat.Jpeg, 85);

// Otros formatos soportados
await captureCore.Frame_SaveAsync("captura.png", ImageFormat.Png, 0);
await captureCore.Frame_SaveAsync("captura.bmp", ImageFormat.Bmp, 0);
await captureCore.Frame_SaveAsync("captura.gif", ImageFormat.Gif, 0);
await captureCore.Frame_SaveAsync("captura.tiff", ImageFormat.Tiff, 0);

Temas Avanzados

Para funcionalidad más avanzada del SDK DirectShow .NET, explora:

  • Publicación de flujos en red
  • Grabación multi-fuente
  • Gráficos de filtros personalizados
  • Manejo de eventos y notificaciones
  • Edición de línea de tiempo

Solución de Problemas

Problemas comunes cuando trabajas con DirectShow en C#:

  • Dispositivo ocupado o inaccesible: Asegúrate de que ninguna otra aplicación esté usando la webcam
  • Compatibilidad de formato: No todos los formatos funcionan con todos los filtros y configuraciones de salida
  • Fugas de memoria: Siempre libera los objetos DirectShow correctamente
  • Problemas de controladores: Asegúrate de que los controladores de webcam/cámara estén actualizados

Conclusión

Este tutorial demuestra la funcionalidad principal necesaria para crear una aplicación de captura de video en C# usando el SDK DirectShow .NET. Con este framework, puedes construir aplicaciones que capturen, procesen y guarden video y audio desde varias fuentes como webcams y cámaras USB. La arquitectura DirectShow proporciona acceso a una amplia gama de capacidades de procesamiento multimedia a través de su diseño basado en filtros, haciéndolo una opción poderosa para aplicaciones multimedia de Windows.