108 lines
4.2 KiB
C++
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
|