Desarrollo de software QT: diseño de reproductor de video basado en FFMPEG: imagen de solución suave (1)

Desarrollo de software QT: diseño de reproductor de video basado en FFMPEG: video de solución de software de CPU (1)
https://xiaolong.blog.csdn.net/article/details/126832537

Desarrollo de software QT: diseño de reproductor de video basado en FFMPEG: video de solución dura de GPU (2)
https://xiaolong.blog.csdn.net/article/details/126833434

Desarrollo de software QT: diseño de un reproductor de video basado en FFMPEG: decodificación de audio (3)
https://xiaolong.blog.csdn.net/article/details/126836582

Desarrollo de software QT: diseño de un reproductor de video basado en FFMPEG: video de renderizado OpenGL (4)
https://xiaolong.blog.csdn.net/article/details/126842988

Desarrollo de software QT: reproductor de video de diseño basado en FFMPEG: reproductor multimedia de transmisión (5)
https://xiaolong.blog.csdn.net/article/details/126915003

Desarrollo de software QT - reproductor de video de diseño basado en FFMPEG - reproductor de video (6)
https://blog.csdn.net/xiaolong1126626497/article/details/126916817

I. Introducción

Hablando de ffmpeg, siempre que se dedique al desarrollo relacionado con audio y video, debería haber oído hablar de él. FFmpeg proporciona una biblioteca de códecs de audio/video muy avanzada y es compatible con varias plataformas.

Ahora hay muchos artículos y tutoriales relacionados con ffmpeg en Internet. ffmpeg en sí se usa principalmente para decodificar y codificar video y audio. No proporciona reproducción de imágenes, salida de sonido y otras funciones. Para diseñar su propio reproductor, primero necesita algún otro conocimiento para cooperar con llamar a ffmpeg para completar la tarea.

Para presentar el uso de ffmpeg de manera simple y rápida, revisaré varios artículos y escribiré varios casos para demostrar el uso de ffmpeg paso a paso, y finalmente completaré un desarrollo completo del reproductor sin involucrar conocimientos teóricos (hay demasiados conocimientos teóricos). en Internet), basado principalmente en el código y la función.

Introducción al entorno que usé para desarrollar el reproductor de video aquí:

ffmpeg版本:  4.2.2
Qt版本    :  5.12.6
编译器类型 : MinGW32bit 

La planificación de contenidos paso a paso y los casos de estos artículos son los siguientes:

(1) Use ffmpeg para decodificar el video, renderice la imagen decodificada a través de QWidget, admita el salto de la barra de progreso, la visualización de la barra de progreso, la visualización del tiempo total y la visualización de información básica del video.

Características: el uso de la decodificación de software (CPU), solo la decodificación de datos de imagen, ignorando los datos de audio, demuestra principalmente el proceso de uso básico de ffmpeg, cómo completar la decodificación de video a través de ffmpeg, convertir el formato de píxel de imagen y finalmente completar la representación de imagen.

(2) Use la interfaz de aceleración de hardware de ffmpeg para completar la decodificación de video, admita la detección de métodos de aceleración compatibles con el hardware actual, copie datos de la GPU a la CPU después de la decodificación, complete la conversión de píxeles y luego renderice imágenes a través de QWidget, admita salto de barra de progreso, barra de progreso Visualización, visualización de tiempo total, visualización de información básica de video.

Características: el uso de la decodificación acelerada por hardware (GPU), solo la decodificación de datos de imagen, ignorando los datos de audio, demuestra principalmente el proceso de uso básico de la decodificación de hardware ffmpeg, cómo completar la decodificación de video a través de ffmpeg, convertir el formato de píxel de imagen y finalmente completar la representación de imagen.

(3) Use ffmpeg para decodificar los paquetes de audio en el video y reproduzca los datos de audio a través de QAudioOutput.

Características: solo decodifica datos de audio e ignora los datos de imagen de video. Principalmente demuestra el proceso de uso básico de ffmpeg, cómo completar la decodificación de datos de audio a través de ffmpeg, convertir el formato de datos de audio y finalmente reproducirlo a través de QAudioOutput.

(4) Use la interfaz de aceleración de hardware de ffmpeg para completar la decodificación de video, admita la detección de métodos de aceleración admitidos por el hardware actual y QOpenGLWidgetadmita el salto de la barra de progreso, la visualización de la barra de progreso, la visualización del tiempo total y la visualización de información básica de video mediante la representación de datos de imagen decodificados.

Características: el uso de decodificación acelerada por hardware (GPU), renderizado OpenGL, solo decodificación de datos de imagen, ignorando datos de audio, demuestra principalmente el proceso de uso básico de decodificación de hardware ffmpeg y renderizado OpenGL.

(5) Agregue compatibilidad con la reproducción de medios de transmisión al (4) ejemplo, admita formatos de medios de transmisión comunes como rtmp, rtsp, HLS (protocolo HTTP), use la interfaz de aceleración de hardware de ffmpeg para completar la decodificación de video y admita la detección del soporte de hardware actual. forma acelerada de QOpenGLWidgetrenderizar datos de imagen decodificados.

Características: el uso de decodificación acelerada por hardware (GPU), renderizado OpenGL, solo decodificación de datos de imagen, ignorando datos de audio, demuestra principalmente el proceso de uso básico de decodificación de hardware ffmpeg y renderizado OpenGL.

(6) Combinando los ejemplos (3) y (5), agregue decodificación y reproducción de paquetes de audio, use la interfaz de aceleración de hardware de ffmpeg para completar la decodificación de video, admita la detección de métodos de aceleración admitidos por el hardware actual y renderice los datos de imagen decodificados. QOpenGLWidgeta través de QAudioOutput reproduce datos de audio. Admite salto de barra de progreso, visualización de barra de progreso, visualización de tiempo total, visualización de información básica de video.

Características: el uso de decodificación acelerada por hardware (GPU), renderizado OpenGL, solo decodificación de datos de imagen, ignorando datos de audio, demuestra principalmente el proceso de uso básico de decodificación de hardware ffmpeg y renderizado OpenGL, y el proceso de reproducción de datos de audio a través de QAudioOutput.

(7) Combinando con los ejemplos anteriores, diseñe el reproductor de video completo.

2. Decodificación y renderizado

Si desea hacer un reproductor de video, resuelva principalmente tres problemas: (1) decodificación (2) reproducción (3) sincronización de audio y video

2.1 Decodificación

ffmpeg admite decodificación de software puro y decodificación acelerada de hardware. Siempre que la decodificación de software puro dependa de la CPU, si la decodificación de software de video con una resolución grande (4K y superior) consumirá una gran cantidad de CPU, y la velocidad de decodificación será relativamente lenta, más el tiempo de renderizado, el total El reproductor de video congelará Phenomenon. Si usa aceleración de hardware (GPU) para decodificar, el tiempo de decodificación se acortará considerablemente. Mi computadora es una CPU i7 de bajo consumo. Lo probé en mi computadora: para un video con una resolución de 3840x2160, se tarda unos 300 ms en decodificar un cuadro por software. Si la decodificación acelerada por hardware está habilitada, se tarda unos 10 ms en decodificar un cuadro La diferencia de velocidad es muy grande. Y durante la decodificación suave, el uso de la CPU es casi del 100 %. Si se decodifica mediante GPU, la carga en la CPU será muy baja, lo que puede liberar más tiempo para hacer otras cosas.

La diferencia entre la solución suave y la solución dura no es muy grande, porque ffmpeg ya ha encapsulado todas las API, solo necesita llamarlo y no necesita entender muchas cosas en la capa inferior, por lo que es muy conveniente para desarrollar.

Hay muchos ejemplos proporcionados bajo el código fuente de ffmpeg, incluidos ejemplos de decodificación de video.

ffmpeg\doc\examples\decode_video.c
ffmpeg\doc\examples\hw_decode.c

Estos dos ejemplos son de gran valor de referencia. Entre ellos hw_decode.c se encuentra el ejemplo de decodificación acelerada por hardware de ffmpeg. A través de este ejemplo, puede comprender cómo ffmpeg llama a la GPU para la decodificación de hardware.

Por supuesto, ffmpeg también trae un reproductor de línea de comandos, el código fuente es ffplay.c, este código está muy bien implementado, es solo un reproductor, pero ffplay.c tiene más códigos, además de la propia llamada API de ffmpeg, el representación La parte se implementa a través de SDL.Si no está muy familiarizado con ffmpeg y SDL en la etapa inicial, puede que no sea muy efectivo ir directamente a ffplay.c.

La mejor manera es comenzar de manera simple, entender paso a paso y finalmente ir a ffplay.c, así el efecto será mucho mejor.

2.2 Representación

ffmpeg en sí mismo es solo una biblioteca para decodificar y codificar, y la representación de la imagen decodificada debe implementarse por sí mismo. El llamado renderizado consiste en mostrar los datos de imagen obtenidos después de que ffmpeg decodifica el video. La renderización también se divide en renderización por software y renderización acelerada por hardware. Actualmente, mi interfaz de usuario aquí está hecha con Qt. Hay muchas formas de mostrar imágenes en Qt, como dibujar directamente a través de Qwidget, mostrarlas con QLabel, etc. Este método es el método más convencional y el método más simple. Este método usa CPU para dibujar, lo que requiere una gran cantidad de CPU, y debe mostrarse a través de Qwidget, QLabel, etc., y los datos decodificados por ffmpeg deben ser convertido en formato de píxel El reempaquetado en QImageun formato es un proceso que requiere mucho tiempo. Si desea reducir el uso de la CPU y acelerar el procesamiento, puede usar OpenGL para el procesamiento, que está empaquetado en Qt QOpenGLWidget, y es relativamente conveniente llamar a OpenGL.

3. Diseño del reproductor de video

3.1 Descripción del diseño

Use ffmpeg para decodificar video, renderice la imagen decodificada a través de QWidget, admita el salto de la barra de progreso, la visualización de la barra de progreso, la visualización del tiempo total y la visualización de información básica del video.

Características: el uso de la decodificación de software (CPU), solo la decodificación de datos de imagen, ignorando los datos de audio, demuestra principalmente el proceso de uso básico de ffmpeg, cómo completar la decodificación de video a través de ffmpeg, convertir el formato de píxel de imagen y finalmente completar la representación de imagen.

La decodificación de video adopta un subproceso independiente, y los datos de imagen obtenidos después de la decodificación se transmiten a la interfaz de interfaz de usuario para renderizar a través de la transmisión de ranura de señal.

3.2 Proceso de decodificación

El siguiente es el flujo básico de decodificación del software ffmpeg:

//1.打开多媒体流,并且获取一些信息
avformat_open_input(&format_ctx, m_MediaFile, nullptr, nullptr)


//2. 读取媒体文件的数据包以获取流信息
avformat_find_stream_info(format_ctx, nullptr)


//3. 查找解码器
AVCodec *video_pCodec=avcodec_find_decoder(stream->codecpar->codec_id);

//4. 打开解码器
avcodec_open2(stream->codec,video_pCodec,nullptr)

//5. 读取一帧数据
av_read_frame(format_ctx, &pkt)

//6. 发送视频帧
avcodec_send_packet(format_ctx->streams[video_stream_index]->codec,&pkt)

//7. 对视频帧进行解码
avcodec_receive_frame(format_ctx->streams[video_stream_index]->codec, SRC_VIDEO_pFrame)

//8. 转换像素格式
sws_scale(img_convert_ctx,
	   (uint8_t const **) SRC_VIDEO_pFrame->data,
	   SRC_VIDEO_pFrame->linesize, 0, video_height, RGB24_pFrame->data,
	   RGB24_pFrame->linesize);

//9. 渲染

Lo que lleva más tiempo aquí es sws_scaleque cuanto mayor sea la resolución del video, más tiempo llevará. El segundo es avcodec_receive_framey renderizado, si el video decodificado por software excede 4K, la decodificación llevará mucho tiempo.Si la resolución es inferior a 4K, el tiempo consumido para la decodificación es aceptable.

3.3 Efecto de la operación

imagen-20220913140928520

4. Código fuente

4.1 Descifrando thread.cpp

//指定文件的编码为UTF-8
#pragma execution_character_set("utf-8")

#include "ReverseDecodThread.h"

ReverseDecodThread::ReverseDecodThread()
{
    
    
    qDebug() << "FFMPEG版本信息:" << av_version_info();
}

ReverseDecodThread::~ReverseDecodThread()
{
    
    

}


/*
功能: 设置媒体文件
*/
int ReverseDecodThread::set_VideoFile(QString media)
{
    
    
    //打开媒体文件
    QByteArray array=media.toUtf8();
    strncpy(m_MediaFile, array.data(), sizeof(m_MediaFile));
}


void ReverseDecodThread::SetSate(int run)
{
    
    
	m_run = run;
}

int ReverseDecodThread::GetSate()
{
    
    
	return m_run;
}


//跳转视频帧
void ReverseDecodThread::SetSeekPos(qint64 pos)
{
    
    
	is_CurrentSeekPos = 1;
    m_n64CurrentSeekPos = pos;
    m_run=1;  //运行状态

    //获取系统本地时间
    play_base_time=QDateTime::currentMSecsSinceEpoch();
}


void ReverseDecodThread::PausePlay()
{
    
    
	m_run = 2;
}

void ReverseDecodThread::StopPlay()
{
    
    
	m_run = 0;
}

void ReverseDecodThread::LogSend(QString text)
{
    
    
	qDebug() << text;
}


//线程执行起点
void ReverseDecodThread::run()
{
    
    
    LogSend("开始播放视频.\n");
    StartPlay();
}


//播放视频
int ReverseDecodThread::StartPlay()
{
    
    
    //1.打开多媒体流,并且获取一些信息
    if(avformat_open_input(&format_ctx, m_MediaFile, nullptr, nullptr) != 0)
    {
    
    
         LogSend(tr("无法打开视频文件: %1").arg(m_MediaFile));
         return -1;
    }

    //2. 读取媒体文件的数据包以获取流信息
    if(avformat_find_stream_info(format_ctx, nullptr) < 0)
    {
    
    
        LogSend(tr("无法获取流信息.\n"));
        return -1;
    }

    //3.打印视频的信息
    LogSend(tr("视频中流的数量: %1\n").arg(format_ctx->nb_streams));
    for(int i = 0; i < format_ctx->nb_streams; ++i)
    {
    
    
        const AVStream* stream = format_ctx->streams[i];
        if(stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
        {
    
    
            //查找解码器
            AVCodec *video_pCodec=avcodec_find_decoder(stream->codecpar->codec_id);
            //打开解码器
            if(avcodec_open2(stream->codec,video_pCodec,nullptr)!=0)
            {
    
    
                  LogSend(tr("解码器打开失败.\n"));
                  return -1;
            }
            video_stream_index = i;
            //得到视频帧的宽高
            video_width=stream->codecpar->width;
            video_height=stream->codecpar->height;

            LogSend(tr("视频帧的尺寸(以像素为单位): (宽X高)%1x%2 像素格式: %3\n").arg(
                stream->codecpar->width).arg(stream->codecpar->height).arg(stream->codecpar->format));
        }
    }

    if (video_stream_index == -1)
    {
    
    
         LogSend("没有检测到视频流.\n");
         return -1;
    }

    AVRational frameRate = format_ctx->streams[video_stream_index]->avg_frame_rate;

    /*设置视频转码器*/
    SRC_VIDEO_pFrame = av_frame_alloc();
    RGB24_pFrame = av_frame_alloc();// 存放解码后YUV数据的缓冲区

    //将解码后的YUV数据转换成RGB24
    img_convert_ctx = sws_getContext(video_width, video_height,
            format_ctx->streams[video_stream_index]->codec->pix_fmt,video_width, video_height,
            AV_PIX_FMT_RGB24, SWS_BICUBIC, nullptr, nullptr, nullptr);

    //计算RGB图像所占字节大小
    int numBytes=avpicture_get_size(AV_PIX_FMT_RGB24,video_width,video_height);

    //申请空间存放RGB图像数据
    out_buffer_rgb = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t));

    // avpicture_fill函数将ptr指向的数据填充到picture内,但并没有拷贝,只是将picture结构内的data指针指向了ptr的数据
    avpicture_fill((AVPicture *) RGB24_pFrame, out_buffer_rgb, AV_PIX_FMT_RGB24,
            video_width, video_height);

    qDebug()<<"format_ctx->duration:"<<format_ctx->duration;

    //获取系统本地时间
    play_base_time=QDateTime::currentMSecsSinceEpoch();

    //表示视频加载成功
    while(m_run)
    {
    
    
        if(m_run == 2)
        {
    
    
            msleep(100); //暂停播放
			continue;
        }

		if (is_CurrentSeekPos)
		{
    
    
			is_CurrentSeekPos = 0;
            //偏移到指定位置再开始解码    AVSEEK_FLAG_BACKWARD 向后找最近的关键帧
            av_seek_frame(format_ctx, -1, m_n64CurrentSeekPos* AV_TIME_BASE, AVSEEK_FLAG_BACKWARD);
            qDebug()<<"跳转的位置:"<<m_n64CurrentSeekPos;
		}

        double video_clock;
        AVPacket pkt;

        //1. 读取一帧数据
        if(av_read_frame(format_ctx, &pkt) < 0)
        {
    
    
            m_run=2; //设置为暂停状态
            qDebug()<<"数据读取完毕.";
            continue;
        }

        if(pkt.stream_index == video_stream_index)
        {
    
    
            //当前时间
           video_clock = av_q2d(format_ctx->streams[video_stream_index]->time_base) * pkt.pts;

           qDebug()<<"pkt.pts:"<<pkt.pts<<"video_clock:"<<video_clock;


           //解码视频 frame
           //2. 发送视频帧
            if (avcodec_send_packet(format_ctx->streams[video_stream_index]->codec,&pkt) != 0)
            {
    
    
                av_packet_unref(&pkt);//不成功就释放这个pkt
                continue;
            }

            //3. 接受后对视频帧进行解码
            if (avcodec_receive_frame(format_ctx->streams[video_stream_index]->codec, SRC_VIDEO_pFrame) != 0)
            {
    
    
                av_packet_unref(&pkt);//不成功就释放这个pkt
                continue;
            }

            //4. 转格式
           sws_scale(img_convert_ctx,
                   (uint8_t const **) SRC_VIDEO_pFrame->data,
                   SRC_VIDEO_pFrame->linesize, 0, video_height, RGB24_pFrame->data,
                   RGB24_pFrame->linesize);


    
           //5. 加载图片数据
           QImage image(out_buffer_rgb,video_width,video_height,QImage::Format_RGB888);


           //通过pts同步视频帧--显示视频帧
//           while (true)
//           {
    
    
//                qint64 t1=QDateTime::currentMSecsSinceEpoch();
//                qint64 t2=t1-play_base_time;

//                qDebug()<<"t1:"<<t1;
//                qDebug()<<"t2:"<<t2;
//                qDebug()<<"video_clock:"<<video_clock*1000;

//                if(t2>=video_clock*1000)
//                {
    
    
//                    break;
//                }
//                else
//                {
    
    
//                     QThread::msleep(1);
//                }
//           }

           //通知界面更新
           VideoDataOutput(image.copy());

           //时间信号
           sig_getCurrentTime(video_clock, format_ctx->duration *1.0 / AV_TIME_BASE);

          // QThread::msleep(40);
        }
               //释放包
           av_packet_unref(&pkt);

    }

    LogSend("视频音频解码播放器的线程退出成功.\n");

    if(SRC_VIDEO_pFrame) av_frame_free(&SRC_VIDEO_pFrame);
    if(RGB24_pFrame) av_frame_free(&RGB24_pFrame);
    if(img_convert_ctx)sws_freeContext(img_convert_ctx);
    if(out_buffer_rgb)av_free(out_buffer_rgb);

    SRC_VIDEO_pFrame=nullptr;
    RGB24_pFrame=nullptr;
    img_convert_ctx=nullptr;
    out_buffer_rgb=nullptr;

    if(format_ctx)
    {
    
    
        avformat_close_input(&format_ctx);//释放解封装器的空间,以防空间被快速消耗完
        avformat_free_context(format_ctx);
    }

    return 0;
}

4.2 Hilo de decodificación.h

#ifndef VIDEO_PLAY_H
#define VIDEO_PLAY_H

#include <QThread>
#include <qdebug.h>
#include <QImage>
#include <QDateTime>

extern "C" {
    
    
#include <libavutil/opt.h>
#include <libavutil/mem.h>
#include <libavutil/fifo.h>
#include <libavutil/pixfmt.h>
#include <libavutil/log.h>
#include <libavutil/opt.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
#include <libavfilter/avfilter.h>
#include <libavfilter/buffersrc.h>
#include <libavfilter/buffersink.h>
}


//视频音频解码线程
class ReverseDecodThread: public QThread
{
    
    
    Q_OBJECT
public:

    //构造函数
    ReverseDecodThread();
    ~ReverseDecodThread();
	char m_MediaFile[1024];
	int m_run; //1表示运行 0表示停止 2表示暂停
    double m_n64CurrentSeekPos = 0;  //当前seek位置
	bool is_CurrentSeekPos = 0; //1需要跳转 0不需要

	void SetSate(int run);
	int GetSate();
	void SetSeekPos(qint64 pos);
	void PausePlay();
	void StopPlay();
	void LogSend(QString text);

    //加载视频文件
    int set_VideoFile(QString media);

protected:
    void run();
	int StartPlay();
signals:
    void sig_getCurrentTime(double Sec, double total_Sec);
    void VideoDataOutput(QImage); //输出信号
private:
    int video_width=0;
    int video_height=0;
    AVFormatContext *format_ctx=nullptr;
    int video_stream_index = -1;
    AVFrame *RGB24_pFrame = nullptr;
    AVFrame *SRC_VIDEO_pFrame= nullptr;
    uint8_t *out_buffer_rgb= nullptr;
    struct SwsContext *img_convert_ctx=nullptr;  //用于解码后的视频格式转换

    double video_clock_tmp;

    qint64 play_base_time=0;
};
#endif // VIDEO_PLAY_H

4.3 representación de widgets

#include "VideoFrameDisplay.h"

#include <QPainter>

VideoFrameDisplay::VideoFrameDisplay(QWidget *parent) :
    QWidget(parent)
{
    
    
    m_nRotateDegree=0;
    this->setMouseTracking(true);
}

VideoFrameDisplay::~VideoFrameDisplay()
{
    
    

}

void VideoFrameDisplay::Set_Rotate(int Rotate)
{
    
    
    m_nRotateDegree=Rotate;
}

void VideoFrameDisplay::paintEvent(QPaintEvent *event)
{
    
    
    QPainter painter(this);
	
	painter.setRenderHint(QPainter::Antialiasing);
    painter.setRenderHint(QPainter::TextAntialiasing);
    painter.setRenderHint(QPainter::SmoothPixmapTransform);
    painter.setRenderHint(QPainter::HighQualityAntialiasing);
	
    painter.setBrush(Qt::black);
    painter.drawRect(0,0,this->width(),this->height()); //先画成黑色

    if (mImage.size().width() <= 0) return;

    //将图像按比例缩放成和窗口一样大小
    QImage img = mImage.scaled(this->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation); 

    //画面旋转
    if(m_nRotateDegree > 0)
    {
    
    
        QTransform matrix;
        matrix.rotate(m_nRotateDegree);
        img = img.transformed(matrix, Qt::SmoothTransformation);
    }

    int x = this->width() - img.width();
    int y = this->height() - img.height();

    x /= 2;
    y /= 2;

    painter.drawImage(QPoint(x,y),img); //画出图像
}


void VideoFrameDisplay::slotSetOneFrame(QImage img)
{
    
    
    src_mImage =mImage = img;
    update(); //调用update将执行 paintEvent函数
}


/*
功能: 获取原图数据
*/
QImage VideoFrameDisplay::GetImage()
{
    
    
    return src_mImage.copy();
}

/*
功能: 鼠标双击事件
*/
void VideoFrameDisplay::mouseDoubleClickEvent(QMouseEvent *e)
{
    
    
    emit s_VideoWidgetEvent(1);
}

4.4 ui hilo principal widget.cpp

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    
    
    ui->setupUi(this);

    ui->horizontalSlider_time->installEventFilter(this);

    //关联视频解码器
    connect(&DecodeWorkThread, SIGNAL(VideoDataOutput(QImage)), ui->widget_video, SLOT(slotSetOneFrame(QImage)));

    //当前时间
    connect(&DecodeWorkThread, SIGNAL(sig_getCurrentTime(double, double)), this, SLOT(slotGetCurrentTime(double, double)));
}


Widget::~Widget()
{
    
    
    delete ui;
}


void Widget::slotGetCurrentTime(double pts, double duration)
{
    
    
    ui->horizontalSlider_time->setMaximum(duration);
    ui->horizontalSlider_time->setMinimum(0);
    ui->horizontalSlider_time->setValue(pts);

    ui->label_duration->setText(QString("%1/%2").arg(pts).arg(duration));
}


void Widget::on_pushButton_play_clicked()
{
    
    
    DecodeWorkThread.SetSate(0);
    DecodeWorkThread.quit();
    DecodeWorkThread.wait();

    DecodeWorkThread.SetSate(1);

    QString filename = QFileDialog::getOpenFileName(this, "选择打开的文件", "C:/", tr("*.*"));
    DecodeWorkThread.set_VideoFile(filename);
    DecodeWorkThread.start();
}


void Widget::on_pushButton_pause_clicked()
{
    
    
    if (DecodeWorkThread.GetSate() == 2)
    {
    
    
        DecodeWorkThread.SetSate(1);
    }
    else if(DecodeWorkThread.GetSate() == 1)
    {
    
    
        DecodeWorkThread.SetSate(2);
    }
}


void Widget::on_pushButton_stop_clicked()
{
    
    
     DecodeWorkThread.SetSate(0);
}


bool Widget::eventFilter(QObject *obj, QEvent *event)
{
    
    
    //解决QSlider点击不能到鼠标指定位置的问题
    if(obj==ui->horizontalSlider_time)
    {
    
    
        if (event->type()==QEvent::MouseButtonPress) //判断类型
        {
    
    
            QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
            if (mouseEvent->button() == Qt::LeftButton)	//判断左键
            {
    
    
               int value = QStyle::sliderValueFromPosition(ui->horizontalSlider_time->minimum(), ui->horizontalSlider_time->maximum(), mouseEvent->pos().x(), ui->horizontalSlider_time->width());
               ui->horizontalSlider_time->setValue(value);

               qDebug()<<"value:"<<value;
               //跳转到指定位置
               DecodeWorkThread.SetSeekPos(ui->horizontalSlider_time->value());
            }
        }
    }
    return QObject::eventFilter(obj,event);
}

Archivo 4.5 pro (cargar biblioteca ffmpeg)

win32
{
    
    
    message('运行win32版本')
    INCLUDEPATH+=C:/FFMPEG/ffmpeg_x86_4.2.2/include
    LIBS+=C:/FFMPEG/ffmpeg_x86_4.2.2/bin/av*
    LIBS+=C:/FFMPEG/ffmpeg_x86_4.2.2/bin/sw*
    LIBS+=C:/FFMPEG/ffmpeg_x86_4.2.2/bin/pos*
}

Supongo que te gusta

Origin blog.csdn.net/xiaolong1126626497/article/details/126832537
Recomendado
Clasificación