From e788e467de02ca4795095a4e2e512216f78abc30 Mon Sep 17 00:00:00 2001 From: dpt <1013505110@qq.com> Date: 星期四, 20 二月 2025 11:52:14 +0800 Subject: [PATCH] 2.19更新 --- Client/董澎韬/code/main.cpp | 11 + Client/董澎韬/code/rtspthread.cpp | 13 + Client/董澎韬/code/qffmpeg.cpp | 113 ++++++++++++ Client/董澎韬/log/日志_董澎韬_0219.doc | 0 Client/董澎韬/log/日志_董澎韬_0218.doc | 0 Client/董澎韬/code/rtspthread.h | 22 ++ Client/董澎韬/code/facexmainwindow.cpp | 204 ++++++++++++++++++++++ Client/董澎韬/code/qffmpeg.h | 63 +++++++ Client/董澎韬/code/facexmainwindow.h | 82 +++++++++ 9 files changed, 508 insertions(+), 0 deletions(-) diff --git "a/Client/\350\221\243\346\276\216\351\237\254/code/facexmainwindow.cpp" "b/Client/\350\221\243\346\276\216\351\237\254/code/facexmainwindow.cpp" new file mode 100644 index 0000000..4d398d3 --- /dev/null +++ "b/Client/\350\221\243\346\276\216\351\237\254/code/facexmainwindow.cpp" @@ -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() << "鎺ユ敹鍒扮殑鍥惧儚涓虹┖"; + } +} diff --git "a/Client/\350\221\243\346\276\216\351\237\254/code/facexmainwindow.h" "b/Client/\350\221\243\346\276\216\351\237\254/code/facexmainwindow.h" new file mode 100644 index 0000000..71a4542 --- /dev/null +++ "b/Client/\350\221\243\346\276\216\351\237\254/code/facexmainwindow.h" @@ -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鍜孋99鏍囧噯 +#ifndef INT64_C +#define INT64_C +#define UINT64_C +#endif + +//鍥犱负#include <libavcodec/avcodec.h>鏄疌鏂囦欢锛屾墍浠ラ渶瑕佺敤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 diff --git "a/Client/\350\221\243\346\276\216\351\237\254/code/main.cpp" "b/Client/\350\221\243\346\276\216\351\237\254/code/main.cpp" new file mode 100644 index 0000000..168202d --- /dev/null +++ "b/Client/\350\221\243\346\276\216\351\237\254/code/main.cpp" @@ -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(); +} diff --git "a/Client/\350\221\243\346\276\216\351\237\254/code/qffmpeg.cpp" "b/Client/\350\221\243\346\276\216\351\237\254/code/qffmpeg.cpp" new file mode 100644 index 0000000..756314e --- /dev/null +++ "b/Client/\350\221\243\346\276\216\351\237\254/code/qffmpeg.cpp" @@ -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();//鐢宠涓�涓狝VFormatContext缁撴瀯鐨勫唴瀛�,骞惰繘琛岀畝鍗曞垵濮嬪寲 + 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); + + //鎵撳紑瀵瑰簲瑙g爜鍣� + result=avcodec_open2(pAVCodecContext,pAVCodec,NULL); + if (result<0){ + qDebug()<<"鎵撳紑瑙g爜鍣ㄥけ璐�"; + 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() << "瑙g爜鎴愬姛锛屽彂閫佸浘鍍忎俊鍙�"; + mutex.unlock(); + } + } + av_packet_unref(&pAVPacket); + } + avformat_close_input(&pAVFormatContext); +} diff --git "a/Client/\350\221\243\346\276\216\351\237\254/code/qffmpeg.h" "b/Client/\350\221\243\346\276\216\351\237\254/code/qffmpeg.h" new file mode 100644 index 0000000..9085958 --- /dev/null +++ "b/Client/\350\221\243\346\276\216\351\237\254/code/qffmpeg.h" @@ -0,0 +1,63 @@ +#ifndef QFFMPEG_H +#define QFFMPEG_H + +//蹇呴』鍔犱互涓嬪唴瀹�,鍚﹀垯缂栬瘧涓嶈兘閫氳繃,涓轰簡鍏煎C鍜孋99鏍囧噯 +#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 diff --git "a/Client/\350\221\243\346\276\216\351\237\254/code/rtspthread.cpp" "b/Client/\350\221\243\346\276\216\351\237\254/code/rtspthread.cpp" new file mode 100644 index 0000000..0420869 --- /dev/null +++ "b/Client/\350\221\243\346\276\216\351\237\254/code/rtspthread.cpp" @@ -0,0 +1,13 @@ +#include "rtspthread.h" + +RtspThread::RtspThread(QFFmpeg *ffmpeg,QObject *parent) : + QThread(parent), ffmpeg(ffmpeg) +{ +} + +void RtspThread::run() +{ + if (ffmpeg) { + ffmpeg->Play(); + } +} diff --git "a/Client/\350\221\243\346\276\216\351\237\254/code/rtspthread.h" "b/Client/\350\221\243\346\276\216\351\237\254/code/rtspthread.h" new file mode 100644 index 0000000..3232a8b --- /dev/null +++ "b/Client/\350\221\243\346\276\216\351\237\254/code/rtspthread.h" @@ -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 diff --git "a/Client/\350\221\243\346\276\216\351\237\254/log/\346\227\245\345\277\227_\350\221\243\346\276\216\351\237\254_\346\227\245\346\234\237.doc" "b/Client/\350\221\243\346\276\216\351\237\254/log/\346\227\245\345\277\227_\350\221\243\346\276\216\351\237\254_0218.doc" similarity index 100% rename from "Client/\350\221\243\346\276\216\351\237\254/log/\346\227\245\345\277\227_\350\221\243\346\276\216\351\237\254_\346\227\245\346\234\237.doc" rename to "Client/\350\221\243\346\276\216\351\237\254/log/\346\227\245\345\277\227_\350\221\243\346\276\216\351\237\254_0218.doc" Binary files differ diff --git "a/Client/\350\221\243\346\276\216\351\237\254/log/\346\227\245\345\277\227_\350\221\243\346\276\216\351\237\254_0219.doc" "b/Client/\350\221\243\346\276\216\351\237\254/log/\346\227\245\345\277\227_\350\221\243\346\276\216\351\237\254_0219.doc" new file mode 100644 index 0000000..37c4831 --- /dev/null +++ "b/Client/\350\221\243\346\276\216\351\237\254/log/\346\227\245\345\277\227_\350\221\243\346\276\216\351\237\254_0219.doc" Binary files differ -- Gitblit v1.8.0