zero_copy_video_player/videodecoder.h
2026-08-05 14:07:38 -03:00

108 lines
4.2 KiB
C++

#ifndef VIDEODECODER_H
#define VIDEODECODER_H
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
#include <QElapsedTimer>
extern "C" {
// Cabeceras multimedia de FFmpeg
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
#include <libavutil/hwcontext.h>
}
/**
* @brief Hilo de decodificación encargado de leer y decodificar video por hardware (CUDA).
* Realiza la sincronización temporal basada en el reloj maestro del reproductor (PTS).
*/
class VideoDecoder : public QThread {
Q_OBJECT
public:
explicit VideoDecoder(QObject *parent = nullptr);
~VideoDecoder() override;
// Abre el archivo de video e inicializa el contexto de decodificación de hardware
bool openFile(const QString &fileName);
// Cierra el archivo y libera todos los contextos asignados
void closeFile();
// Reanuda la reproducción de video
void play();
// Pausa la reproducción de video
void pause();
// Salta a una posición de tiempo específica en segundos
void seek(double seconds);
// Detiene de forma segura el bucle del hilo y espera a que finalice
void stopThread();
// Métodos de acceso a propiedades del video (Thread-Safe mediante lectura simple)
double getDuration() const { return m_duration; }
int getVideoWidth() const { return m_videoWidth; }
int getVideoHeight() const { return m_videoHeight; }
bool isPaused() const { return m_isPaused; }
// Retorna el tiempo actual de reproducción en milisegundos de acuerdo al reloj maestro
qint64 getPlaybackTimeMs() const;
// Método Thread-Safe para que OpenGL tome una referencia rápida al fotograma decodificado actual
bool getCurrentFrameRef(AVFrame *destFrame);
signals:
// Señal emitida cuando hay un nuevo fotograma decodificado listo en la GPU
void frameReady();
// Señal para actualizar la posición en tiempo real de la barra de progreso
void positionChanged(qint64 positionMs);
// Señal emitida al llegar al final del video
void playbackFinished();
protected:
// Bucle de decodificación principal que se ejecuta en el hilo secundario
void run() override;
private:
QString m_fileName; // Ruta del archivo de video abierto
bool m_running; // Controla si el bucle principal del hilo debe seguir ejecutándose
bool m_isPaused; // Bandera de pausa
bool m_seekRequested; // Bandera de solicitud de salto de tiempo (Seek)
double m_seekTimeSecs; // Tiempo al que saltar en segundos
QMutex m_mutex; // Mutex para proteger variables de control (pausa, running, seek)
QWaitCondition m_waitCond; // Condición de espera para no consumir CPU cuando el video está en pausa
double m_duration; // Duración total del video en segundos
int m_videoWidth; // Ancho del video en píxeles
int m_videoHeight; // Alto del video en píxeles
int m_videoStreamIndex; // Índice del flujo de video dentro del contenedor (mp4, mkv, etc.)
// Relojes de sincronización para reproducir al framerate correcto
QElapsedTimer m_playbackTimer; // Reloj de alta resolución que mide el tiempo real transcurrido
qint64 m_pausedElapsedMs; // Acumulador de tiempo transcurrido antes de la última pausa
// Estructuras principales de FFmpeg
AVFormatContext *m_formatContext; // Contexto de apertura y lectura del contenedor del archivo
AVCodecContext *m_codecContext; // Contexto del decodificador (NVDEC / CUDA)
AVBufferRef *m_hwDeviceCtx; // Contexto de hardware que asocia FFmpeg con el driver de CUDA
// Fotograma de video en VRAM que contiene el frame actual listo para renderizar
AVFrame *m_currentFrame;
// Mutex de exclusión mutua para proteger el acceso a m_currentFrame entre hilos
QMutex m_frameMutex;
// Formato de pixel de hardware que FFmpeg debe solicitar (CUDA)
static enum AVPixelFormat m_hwPixFmt;
// Callback estático requerido por FFmpeg para negociar el formato de decodificación
static enum AVPixelFormat get_hw_format(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts);
};
#endif // VIDEODECODER_H