Integración de FFmpeg moderno en entornos Qt y Visual Studio 2022

El desarrollo de aplicaciones multimedia ha evolucionado significativamente, dejando atrás las implementaciones basadas en versiones antiguas de FFmpeg. Actualmente, el estándar para sistemas Windows de 64 bits implica el uso de Visual Studio 2022 junto con el frmaework Qt, aprovechando las nuevas APIs de iteración de FFmpeg (versiones 5.x y superiores) que ofrecen un manejo de memoria más robusto y una estructura más limpia.

Configuración del Entorno de Desarrollo

Para trabajar con las versiones actuales de FFmpeg, es fundamental descargar los builds que incluyan las carpetas include (cabeceras), lib (archivos de enlace estático) y bin (librerías de enlace dinámico o DLLs). A diferencia de las versiones heredadas de 32 bits, los entornos modernos de Qt operan mayoritariamente en x64, lo que requiere una consistencia total en la arquitectura del proyecto.

La inclusión de las librerías en C++ requiere el uso de extern "C" para evitar problemas de decoración de nombres (name mangling), y se puede automatizar la vinculación de los archivos .lib mediante directivas de preprocesador:

// Inclusión de cabeceras de FFmpeg para compatibilidad con C++
extern "C" {
    #include "libavcodec/avcodec.h"
    #include "libavformat/avformat.h"
    #include "libavfilter/avfilter.h"
    #include "libavutil/avutil.h"
}

// Vinculación automática de librerías en entorno Windows
#pragma comment(lib, "avcodec.lib")
#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "avfilter.lib")
#pragma comment(lib, "avutil.lib")
#pragma comment(lib, "swresample.lib")
#pragma comment(lib, "swscale.lib")
#pragma comment(lib, "Ws2_32.lib")

Extracción de Metadatos y Capacidades del Sistema

Las versiones recientes de FFmpeg han reemplazado las antiguas listas enlazadas por un sistema de iteradores basados en punteros opacos (void**). A continuación, se presenta una clase denominada MultimediaInspector que encapsula la lógica para recuperar información sobre protocolos, codecs y filtros soportados.

Definición de la Clase (MultimediaInspector.h)

#pragma once
#include <QObject>
#include <QString>

class MultimediaInspector : public QObject {
    Q_OBJECT
public:
    explicit MultimediaInspector(QObject* parent = nullptr);
    
    QString getSupportedProtocols();
    QString getFormatRegistry();
    QString getCodecList();
    QString getFilterInfo();
    QString getBuildSettings();
};

Implementación de la Lógica (MultimediaInspector.cpp)

En esta implementación, utilizamos los nuevos iteradores como av_demuxer_iterate y av_codec_iterate, los cuales son más seguros que sus predecesores.

#include "MultimediaInspector.h"
#include <QTextStream>

MultimediaInspector::MultimediaInspector(QObject* parent) : QObject(parent) {
    // Inicialización global de la red para protocolos URL
    avformat_network_init();
}

QString MultimediaInspector::getSupportedProtocols() {
    QString output = "Protocolos de Entrada:\n";
    void* iterator = nullptr;
    const char* protocolName;

    // Enumerar protocolos de entrada
    while ((protocolName = avio_enum_protocols(&iterator, 0))) {
        output.append(QString(" - %1\n").arg(protocolName));
    }

    output.append("\nProtocolos de Salida:\n");
    iterator = nullptr;
    // Enumerar protocolos de salida
    while ((protocolName = avio_enum_protocols(&iterator, 1))) {
        output.append(QString(" - %1\n").arg(protocolName));
    }
    return output;
}

QString MultimediaInspector::getFormatRegistry() {
    QString result = "Demuxers Disponibles:\n";
    const AVInputFormat* i_fmt = nullptr;
    void* i_ptr = nullptr;

    while ((i_fmt = av_demuxer_iterate(&i_ptr))) {
        result.append(QString("[%1] ").arg(i_fmt->name));
    }

    result.append("\n\nMuxers Disponibles:\n");
    const AVOutputFormat* o_fmt = nullptr;
    void* o_ptr = nullptr;

    while ((o_fmt = av_muxer_iterate(&o_ptr))) {
        result.append(QString("[%1] ").arg(o_fmt->name));
    }
    return result;
}

QString MultimediaInspector::getCodecList() {
    QString list;
    void* opaque = nullptr;
    const AVCodec* currentCodec = nullptr;

    while ((currentCodec = av_codec_iterate(&opaque))) {
        bool isDecoder = avcodec_find_decoder(currentCodec->id);
        list.append(isDecoder ? "[DEC]" : "[ENC]");

        switch (currentCodec->type) {
            case AVMEDIA_TYPE_VIDEO: list.append("[Video] "); break;
            case AVMEDIA_TYPE_AUDIO: list.append("[Audio] "); break;
            default: list.append("[Otro]  "); break;
        }
        list.append(QString("%1\n").arg(currentCodec->name));
    }
    return list;
}

QString MultimediaInspector::getFilterInfo() {
    QString filters = "Filtros Registrados:\n";
    const AVFilter* filter = nullptr;
    void* iterator = nullptr;

    while ((filter = av_filter_iterate(&iterator))) {
        filters.append(QString("%1 ").arg(filter->name));
    }
    return filters;
}

QString MultimediaInspector::getBuildSettings() {
    return QString("Configuración de Compilación:\n%1").arg(avcodec_configuration());
}

Consideraciones sobre la API Moderna

Es vital notar que muchas funciones globales que antes se llamaban al inicio del programa, como av_register_all(), han sido marcadas como obsoletas o eliminadas. En FFmpeg 5.x+, el registro de componentes es automático. El uso de avformat_network_init() sigue siendo necesario si se planea realizar streaming sobre protocolos de red como RTSP o HTTP.

La migración a estos nuevos métodos de iteración no solo garantiza la compatibilidad con compiladores modernos en Visual Studio 2022, sino que también facilita la integración con los tipos de datos de Qt, como QString, permitiendo crear herramientas de diagnóstico multimedia de alto rendimiento con una interfaz gráfica moderna.

Etiquetas: FFmpeg Qt C++ Visual Studio 2022 Multimedia

Publicado el 7-15 07:07