dpt
2025-02-20 e788e467de02ca4795095a4e2e512216f78abc30
2.19更新
8个文件已添加
1 文件已重命名
508 ■■■■■ 已修改文件
Client/董澎韬/code/facexmainwindow.cpp 204 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Client/董澎韬/code/facexmainwindow.h 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Client/董澎韬/code/main.cpp 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Client/董澎韬/code/qffmpeg.cpp 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Client/董澎韬/code/qffmpeg.h 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Client/董澎韬/code/rtspthread.cpp 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Client/董澎韬/code/rtspthread.h 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Client/董澎韬/log/日志_董澎韬_0218.doc 补丁 | 查看 | 原始文档 | blame | 历史
Client/董澎韬/log/日志_董澎韬_0219.doc 补丁 | 查看 | 原始文档 | blame | 历史
Client/¶­Åìèº/code/facexmainwindow.cpp
New file
@@ -0,0 +1,204 @@
#include "facexmainwindow.h"
#include "ui_facexmainwindow.h"
#include <QMessageBox>
#include <QStringList>
#include <QFileDialog>
#include <QGuiApplication>
#include <QScreen>
#include <QException>
#include <QThread>
FaceXMainWindow::FaceXMainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::FaceXMainWindow),
    m_player(new QMediaPlayer),
    m_playerlist(new QMediaPlaylist),
    m_videowidget(new QVideoWidget(this)),
    m_ffmpeg(new QFFmpeg(this)),
    m_rtspThread(nullptr)
{
    ui->setupUi(this);
    //设置可移动区域
    dragArea = QRect(0, 0, width(), 40);
    setWindowFlags(Qt::FramelessWindowHint);//隐藏边框
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    // è®¾ç½®æ’­æ”¾æŒ‰é’®å›¾æ ‡ä¸ºæ’­æ”¾å›¾æ ‡
    ui->btn_play->setStyleSheet("border-image: url(:/image/start.png)");
    //设置播放器播放队列
    m_player->setPlaylist(m_playerlist);
    //设置播放器显示窗口
    m_player->setVideoOutput(m_videowidget);
    // è®¾ç½®æ’­æ”¾å™¨æ˜¾ç¤ºçª—口
    m_videowidget->resize(ui->label_video->size());
    m_videowidget->move(ui->label_video->pos());
    m_videowidget->show();
    ui->label_video->show();
    // è¿žæŽ¥ QFFmpeg çš„信号
    connect(m_ffmpeg, &QFFmpeg::GetImage, this, &FaceXMainWindow::SetImage, Qt::QueuedConnection);
    // è¿žæŽ¥æ’­æ”¾å™¨çš„错误信号
    connect(m_player, QOverload<QMediaPlayer::Error>::of(&QMediaPlayer::error), this, [this](QMediaPlayer::Error error) {
        QMessageBox::critical(this, "播放错误", m_player->errorString());
    });
}
FaceXMainWindow::~FaceXMainWindow()
{
    if (m_rtspThread && m_rtspThread->isRunning()) {
        m_rtspThread->quit();
        m_rtspThread->wait();
    }
    delete ui;
}
void FaceXMainWindow::mousePressEvent(QMouseEvent *event)
{
    if (dragArea.contains(event->pos())) {
        offset = event->globalPos() - pos();
        isDragging = true;
    }
}
void FaceXMainWindow::mouseMoveEvent(QMouseEvent *event)
{
    if (isDragging && dragArea.contains(event->pos())) {
        move(event->globalPos() - offset);
    }
}
void FaceXMainWindow::mouseReleaseEvent(QMouseEvent *event)
{
    isDragging = false;
}
//查询按钮
void FaceXMainWindow::on_btnSelect_clicked()
{
    QDate dateStart = ui->dateStart->date();
    QDate dateEnd = ui->dateEnd->date();
    if (dateStart > dateEnd) {
        QMessageBox::critical(nullptr, "错误", "开始时间不能大于结束时间!");
        return;
    }
    //将日期转换为日期时间计算相差的天数,超过60天则提示不用继续
    QDateTime dateTimeStart = ui->dateStart->dateTime();
    QDateTime dateTimeEnd = ui->dateEnd->dateTime();
    if (dateTimeStart.daysTo(dateTimeEnd) >= 60) {
        QMessageBox::critical(nullptr, "错误", "每次最大只能查询60天内!");
        return;
    }
    QStringList fileNames = QFileDialog::getOpenFileNames(this, "选择文件", "D:/", "视频文件 (*.mp4 *.avi *.mov);;所有文件 (*.*)");
    if (!fileNames.isEmpty()) {
        m_playerlist->clear();
        m_ffmpeg->SetUrl(fileNames.first());
        if (m_ffmpeg->Init()) {
            if (m_rtspThread && m_rtspThread->isRunning()) {
                m_rtspThread->quit();
                m_rtspThread->wait();
            }
            m_rtspThread = new RtspThread(m_ffmpeg, this);
            m_rtspThread->start();
        }
        QMessageBox::information(this, "成功", "文件已添加到播放列表");
    } else {
        QMessageBox::information(this, "提示", "未选择任何文件");
    }
}
//隐藏窗口按钮
void FaceXMainWindow::on_toolButton_clicked()
{
    hide();
}
//最小化按钮
void FaceXMainWindow::on_toolButton_3_clicked()
{
    showMinimized();
}
//最大化按钮
void FaceXMainWindow::on_toolButton_2_clicked()
{
    if(windowState() != Qt::WindowMaximized)
    {
        this->showMaximized();
    }
    else
    {
        this->showNormal();
    }
}
//鼠标双击最大化
void FaceXMainWindow::mouseDoubleClickEvent(QMouseEvent *event)
{
    if(windowState() != Qt::WindowMaximized)
    {
        this->showMaximized();
    }
    else
    {
        this->showNormal();
    }
}
void FaceXMainWindow::setPlayButtonIcon(bool isPlaying)
{
    if (isPlaying) {
        ui->btn_play->setStyleSheet("border-image: url(:/image/pause.png)");
    } else {
        ui->btn_play->setStyleSheet("border-image: url(:/image/start.png)");
    }
}
//播放按钮
void FaceXMainWindow::on_btn_play_clicked()
{
    if (m_ffmpeg) {
        if (!m_rtspThread || !m_rtspThread->isRunning()) {
            if (m_ffmpeg->Init()) {
                m_rtspThread = new RtspThread(m_ffmpeg, this);
                m_rtspThread->start();
            }
        }
    } else {
        QMessageBox::critical(this, "错误", "播放器未初始化");
    }
}
//截图按钮
void FaceXMainWindow::on_btn_cut_clicked()
{
    QScreen *screen = QGuiApplication::primaryScreen();
    if (screen) {
        QPixmap screenshot = screen->grabWindow(this->winId());
        screenshot.save("screenshot.png");
        QMessageBox::information(this, "提示", "截图已保存为 screenshot.png");
    }
}
void FaceXMainWindow::SetImage(const QImage &image)
{
    qDebug() << "图像尺寸: " << image.width() << "x" << image.height();
    qDebug() << "图像格式: " << image.format();
    qDebug() << "接收到图像信号";
    if (!image.isNull()) {
        ui->label_video->setScaledContents(true); // è®¾ç½®å›¾åƒè‡ªåŠ¨ç¼©æ”¾
        ui->label_video->setPixmap(QPixmap::fromImage(image));
        ui->label_video->adjustSize();
        ui->label_video->update();
        qDebug() << "图像已更新";
    } else {
        qDebug() << "接收到的图像为空";
    }
}
Client/¶­Åìèº/code/facexmainwindow.h
New file
@@ -0,0 +1,82 @@
#ifndef FACEXMAINWINDOW_H
#define FACEXMAINWINDOW_H
#include <QMainWindow>
#include <QMouseEvent>
#include <QRect>
#include <QMediaPlayer>     //播放器
#include <QMediaPlaylist>   //播放队列
#include <QVideoWidget>     //视频显示窗口
#include "qffmpeg.h"
#include "rtspthread.h"
//必须加以下内容,否则编译不能通过,为了兼容C和C99标准
#ifndef INT64_C
#define INT64_C
#define UINT64_C
#endif
//因为#include <libavcodec/avcodec.h>是C文件,所以需要用extern
extern "C"
{
#include <libavcodec/avcodec.h>     //实现音视频的编解码功能
#include <libavformat/avformat.h>   //实现音视频文件的读取和写入功能,支持多种音视频格式
#include <libavfilter/avfilter.h>
#include <libswscale/swscale.h>
#include <libavutil/frame.h>
}
QT_BEGIN_NAMESPACE
namespace Ui {
class FaceXMainWindow;
}
QT_END_NAMESPACE
class FaceXMainWindow : public QMainWindow
{
    Q_OBJECT
public:
    explicit FaceXMainWindow(QWidget *parent = 0);
    ~FaceXMainWindow();
    void mousePressEvent(QMouseEvent *event)override;
    void mouseMoveEvent(QMouseEvent *event)override;
    void mouseReleaseEvent(QMouseEvent *event)override;
    void mouseDoubleClickEvent(QMouseEvent *event)override;
private slots:
    void on_btnSelect_clicked();
    void on_toolButton_clicked();
    void on_toolButton_3_clicked();
    void on_toolButton_2_clicked();
    void on_btn_play_clicked();
    void on_btn_cut_clicked();
    void SetImage(const QImage &image);
private:
    Ui::FaceXMainWindow *ui;
    QPoint offset;
    QRect dragArea;
    bool isDragging;
    QMediaPlayer *m_player;
    QMediaPlaylist *m_playerlist;
    QVideoWidget *m_videowidget;
    QFFmpeg *m_ffmpeg;
    RtspThread *m_rtspThread;
    void setPlayButtonIcon(bool isPlaying);
};
#endif // FACEXMAINWINDOW_H
Client/¶­Åìèº/code/main.cpp
New file
@@ -0,0 +1,11 @@
#include "facexmainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    FaceXMainWindow w;
    w.show();
    return a.exec();
}
Client/¶­Åìèº/code/qffmpeg.cpp
New file
@@ -0,0 +1,113 @@
#include "qffmpeg.h"
#include <QDateTime>
#include <QDebug>
QFFmpeg::QFFmpeg(QObject *parent) :
    QObject(parent)
{
    videoStreamIndex=-1;
    av_register_all();//注册库中所有可用的文件格式和解码器
    avformat_network_init();//初始化网络流格式,使用RTSP网络流时必须先执行
    pAVFormatContext = avformat_alloc_context();//申请一个AVFormatContext结构的内存,并进行简单初始化
    pAVFrame=av_frame_alloc();
}
QFFmpeg::~QFFmpeg()
{
    if (pAVFormatContext) {
        avformat_close_input(&pAVFormatContext);
        avformat_free_context(pAVFormatContext);
    }
    if (pAVFrame) {
        av_frame_free(&pAVFrame);
    }
    if (pSwsContext) {
        sws_freeContext(pSwsContext);
    }
    avpicture_free(&pAVPicture);
}
bool QFFmpeg::Init()
{
    //打开视频流
    int result=avformat_open_input(&pAVFormatContext, url.toStdString().c_str(),NULL,NULL);
    if (result<0){
        qDebug()<<"打开视频流失败";
        return false;
    }
    //获取视频流信息
    result=avformat_find_stream_info(pAVFormatContext,NULL);
    if (result<0){
        qDebug()<<"获取视频流信息失败";
        avformat_close_input(&pAVFormatContext);
        return false;
    }
    //获取视频流索引
    videoStreamIndex = -1;
//    qDebug()<<"nb:"<<pAVFormatContext->nb_streams;
//    qDebug()<<"type:"<<pAVFormatContext->streams[0]->codec->codec_type;
//    qDebug()<<"AVMEDIA_TYPE_VIDEO:"<<AVMEDIA_TYPE_VIDEO;
    for (uint i = 0; i < pAVFormatContext->nb_streams; i++) {
        if (pAVFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
            videoStreamIndex = i;
            break;
        }
    }
    if (videoStreamIndex==-1){
        qDebug()<<"获取视频流索引失败";
        avformat_close_input(&pAVFormatContext);
        return false;
    }
    //获取视频流的分辨率大小
    pAVCodecContext = pAVFormatContext->streams[videoStreamIndex]->codec;
    videoWidth=pAVCodecContext->width;
    videoHeight=pAVCodecContext->height;
    avpicture_alloc(&pAVPicture,AV_PIX_FMT_RGB24,videoWidth,videoHeight);
    AVCodec *pAVCodec;
    //获取视频流解码器
    pAVCodec = avcodec_find_decoder(pAVCodecContext->codec_id);
    pSwsContext = sws_getContext(videoWidth,videoHeight,AV_PIX_FMT_YUV420P,videoWidth,videoHeight,AV_PIX_FMT_RGB24,SWS_BICUBIC,0,0,0);
    //打开对应解码器
    result=avcodec_open2(pAVCodecContext,pAVCodec,NULL);
    if (result<0){
        qDebug()<<"打开解码器失败";
        avpicture_free(&pAVPicture);
        sws_freeContext(pSwsContext);
        avformat_close_input(&pAVFormatContext);
        return false;
    }
    qDebug()<<"初始化视频流成功";
    return true;
}
void QFFmpeg::Play()
{
    //一帧一帧读取视频
    int frameFinished = 0;
    while (av_read_frame(pAVFormatContext, &pAVPacket) >= 0) {
        if (pAVPacket.stream_index == videoStreamIndex) {
            qDebug() << "开始解码" << QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss");
            avcodec_decode_video2(pAVCodecContext, pAVFrame, &frameFinished, &pAVPacket);
            if (frameFinished) {
                mutex.lock();
                sws_scale(pSwsContext, (const uint8_t* const *)pAVFrame->data, pAVFrame->linesize, 0, videoHeight, pAVPicture.data, pAVPicture.linesize);
                QImage image(pAVPicture.data[0], videoWidth, videoHeight, QImage::Format_RGB888);
                QImage copyImage = image.copy(); // æ·±æ‹·è´
                emit GetImage(copyImage, this->index);
                qDebug() << "解码成功,发送图像信号";
                mutex.unlock();
            }
        }
        av_packet_unref(&pAVPacket);
    }
    avformat_close_input(&pAVFormatContext);
}
Client/¶­Åìèº/code/qffmpeg.h
New file
@@ -0,0 +1,63 @@
#ifndef QFFMPEG_H
#define QFFMPEG_H
//必须加以下内容,否则编译不能通过,为了兼容C和C99标准
#ifndef INT64_C
#define INT64_C
#define UINT64_C
#endif
//引入ffmpeg头文件
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavfilter/avfilter.h>
#include <libswscale/swscale.h>
#include <libavutil/frame.h>
}
#include <QObject>
#include <QMutex>
#include <QImage>
class QFFmpeg : public QObject
{
    Q_OBJECT
public:
    explicit QFFmpeg(QObject *parent = 0);
    ~QFFmpeg();
    bool Init();        // åˆå§‹åŒ–
    void Play();        // æ’­æ”¾
    void SetUrl(QString url){this->url=url;}    // è®¾ç½®è§†é¢‘源
    QString Url()const{return url;}
    int VideoWidth()const{return videoWidth;}
    int VideoHeight()const{return videoHeight;}
    void SetIndex(int x){this->index=x;}
private:
    QMutex mutex;
    AVPicture  pAVPicture;
    AVFormatContext *pAVFormatContext;
    AVCodecContext *pAVCodecContext;
    AVFrame *pAVFrame;
    SwsContext * pSwsContext;
    AVPacket pAVPacket;
    QString url;
    int videoWidth;
    int videoHeight;
    int videoStreamIndex;
    int index;
signals:
    void GetImage(const QImage &image,int x);    // å‘送解码后的图像信号
public slots:
};
#endif // QFFMPEG_H
Client/¶­Åìèº/code/rtspthread.cpp
New file
@@ -0,0 +1,13 @@
#include "rtspthread.h"
RtspThread::RtspThread(QFFmpeg *ffmpeg,QObject *parent) :
    QThread(parent), ffmpeg(ffmpeg)
{
}
void RtspThread::run()
{
    if (ffmpeg) {
        ffmpeg->Play();
    }
}
Client/¶­Åìèº/code/rtspthread.h
New file
@@ -0,0 +1,22 @@
#ifndef RTSPTHREAD_H
#define RTSPTHREAD_H
#include <QThread>
#include "qffmpeg.h"
class RtspThread : public QThread
{
    Q_OBJECT
public:
    explicit RtspThread(QFFmpeg *ffmpeg,QObject *parent = 0);
protected:
    void run()override;
private:
    QFFmpeg * ffmpeg;
};
#endif // RTSPTHREAD_H
Client/¶­Åìèº/log/ÈÕÖ¾_¶­Åìèº_0218.doc
Binary files differ
Client/¶­Åìèº/log/ÈÕÖ¾_¶­Åìèº_0219.doc
Binary files differ