From 3bf52b5d0c53c5e10f18cbc81badc79511008d9b Mon Sep 17 00:00:00 2001 From: fengli Date: Tue, 10 Jan 2023 18:08:23 +0800 Subject: [PATCH 001/107] =?UTF-8?q?fix:=20=E6=B7=BB=E5=8A=A0h264=E7=BC=96?= =?UTF-8?q?=E7=A0=81=E5=99=A8=E6=A3=80=E6=B5=8B=EF=BC=8C=E4=B8=8D=E5=AD=98?= =?UTF-8?q?=E5=9C=A8=E6=97=B6=E4=B8=8D=E6=94=AF=E6=8C=81mp4=E8=A7=86?= =?UTF-8?q?=E9=A2=91=E5=BD=95=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加h264编码器检测,不存在时不支持mp4视频录制 Log: 添加h264编码器检测,不存在时不支持mp4视频录制 --- src/main.cpp | 17 +++++++++++++++++ src/src/Settings.cpp | 9 +++++++-- src/src/basepub/datamanager.cpp | 10 ++++++++++ src/src/basepub/datamanager.h | 4 ++++ src/src/videowidget.cpp | 2 +- 5 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index aa9c8cbf..d36d1ce2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -82,7 +82,24 @@ static bool CheckFFmpegEnv() QString path = QLibraryInfo::location(QLibraryInfo::LibrariesPath); dir.setPath(path); QStringList list = dir.entryList(QStringList() << (QString("libavcodec") + "*"), QDir::NoDotAndDotDot | QDir::Files); + if (list.contains("libavcodec.so") || list.contains("libavcodec.so.58")) { + QLibrary libavcodec; //检查编码器是否存在 + libavcodec.setFileName("libavcodec.so"); + qDebug() << "编码库是否加载成功: "<< libavcodec.load(); + typedef AVCodec *(*p_avcodec_find_encoder)(enum AVCodecID id); + p_avcodec_find_encoder m_avcodec_find_encoder = nullptr; + m_avcodec_find_encoder = reinterpret_cast(libavcodec.resolve("avcodec_find_encoder")); + AVCodec *pCodec = m_avcodec_find_encoder(AV_CODEC_ID_H264); + + if (pCodec) { + qDebug() << "编码器存在 AVCodecID:" << AV_CODEC_ID_H264; + DataManager::instance()->setEncExists(true); + } else { + qWarning() << "Can not find output video encoder! (没有找到合适的编码器!) AVCodecID:" << AV_CODEC_ID_H264; + DataManager::instance()->setEncExists(false); + } + return true; } return false; diff --git a/src/src/Settings.cpp b/src/src/Settings.cpp index c4e88f40..3d753730 100644 --- a/src/src/Settings.cpp +++ b/src/src/Settings.cpp @@ -47,8 +47,13 @@ void Settings::init() QStringList videoFormatList; if (DataManager::instance()->encodeEnv() == FFmpeg_Env) { - videoFormatList << tr("mp4") - << tr("webm"); + if (DataManager::instance()->encExists()) { + videoFormatList << tr("mp4") << tr("webm"); + } else { + videoFormatList << tr("webm"); + m_settings->setOption("outsetting.outformat.vidformat", 0); + } + } else { videoFormatList << tr("webm"); m_settings->setOption("outsetting.outformat.vidformat", 0); diff --git a/src/src/basepub/datamanager.cpp b/src/src/basepub/datamanager.cpp index 5c18c9fb..502dba0f 100644 --- a/src/src/basepub/datamanager.cpp +++ b/src/src/basepub/datamanager.cpp @@ -46,6 +46,15 @@ EncodeEnv DataManager::encodeEnv() return m_encodeEnv; } +void DataManager::setEncExists(bool status) +{ + m_H264EncoderExists = status; +} + +bool DataManager::encExists(){ + return m_H264EncoderExists; +} + DataManager *DataManager::instance() { if (m_dataManager == nullptr) { @@ -63,5 +72,6 @@ DataManager::DataManager() m_videoCount = 0; m_encodeEnv = GStreamer_Env; m_devStatus = DeviceStatus::NOCAM; + m_H264EncoderExists = false; } diff --git a/src/src/basepub/datamanager.h b/src/src/basepub/datamanager.h index 7ef5ee73..082f30b2 100644 --- a/src/src/basepub/datamanager.h +++ b/src/src/basepub/datamanager.h @@ -140,6 +140,9 @@ class DataManager: public QObject */ EncodeEnv encodeEnv(); + void setEncExists(bool status); + bool encExists(); + private: DataManager(); static DataManager *m_dataManager; @@ -148,5 +151,6 @@ class DataManager: public QObject int m_videoCount; EncodeEnv m_encodeEnv; volatile enum DeviceStatus m_devStatus; + bool m_H264EncoderExists; }; #endif // DATAMANAGER_H diff --git a/src/src/videowidget.cpp b/src/src/videowidget.cpp index 209b96fd..72733b58 100755 --- a/src/src/videowidget.cpp +++ b/src/src/videowidget.cpp @@ -215,7 +215,7 @@ videowidget::videowidget(DWidget *parent) setGridType(Grid_None); if (dc::Settings::get().getOption("outsetting.outformat.vidformat").toInt() || - DataManager::instance()->encodeEnv() != FFmpeg_Env) + DataManager::instance()->encodeEnv() != FFmpeg_Env || !DataManager::instance()->encExists()) m_videoFormat = "webm"; } From 04af4652b1a5f5c51b25f2f8a414b8a48efcd440 Mon Sep 17 00:00:00 2001 From: fengli Date: Wed, 11 Jan 2023 13:22:55 +0800 Subject: [PATCH 002/107] =?UTF-8?q?fix:=20=E5=88=A4=E6=96=AD=E5=BA=93?= =?UTF-8?q?=E5=87=BD=E6=95=B0=E6=98=AF=E5=90=A6=E5=AF=BC=E5=87=BA=E6=88=90?= =?UTF-8?q?=E5=8A=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 判断库函数是否导出成功 Log: 判断库函数是否导出成功 --- src/main.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index d36d1ce2..ac3e00a8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -86,17 +86,20 @@ static bool CheckFFmpegEnv() if (list.contains("libavcodec.so") || list.contains("libavcodec.so.58")) { QLibrary libavcodec; //检查编码器是否存在 libavcodec.setFileName("libavcodec.so"); - qDebug() << "编码库是否加载成功: "<< libavcodec.load(); + qDebug() << "Whether the libavcodec is loaded successfully: "<< libavcodec.load(); typedef AVCodec *(*p_avcodec_find_encoder)(enum AVCodecID id); p_avcodec_find_encoder m_avcodec_find_encoder = nullptr; m_avcodec_find_encoder = reinterpret_cast(libavcodec.resolve("avcodec_find_encoder")); - AVCodec *pCodec = m_avcodec_find_encoder(AV_CODEC_ID_H264); + + AVCodec *pCodec = nullptr; + if (m_avcodec_find_encoder) + pCodec = m_avcodec_find_encoder(AV_CODEC_ID_H264); if (pCodec) { - qDebug() << "编码器存在 AVCodecID:" << AV_CODEC_ID_H264; + qDebug() << "Video encoder exists. AVCodecID:" << AV_CODEC_ID_H264; DataManager::instance()->setEncExists(true); } else { - qWarning() << "Can not find output video encoder! (没有找到合适的编码器!) AVCodecID:" << AV_CODEC_ID_H264; + qWarning() << "Can not find output video encoder! AVCodecID:" << AV_CODEC_ID_H264; DataManager::instance()->setEncExists(false); } From 48c906bec0e75c251acd48ae6334528de5b068e5 Mon Sep 17 00:00:00 2001 From: fengli Date: Thu, 12 Jan 2023 17:48:44 +0800 Subject: [PATCH 003/107] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E8=A7=86=E9=A2=91=E6=A0=BC=E5=BC=8F=E4=B8=8D=E4=B8=BA?= =?UTF-8?q?mp4=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 通过正则表达式匹配libavcodec库文件 Log: 通过正则表达式匹配libavcodec库文件 Bug: https://pms.uniontech.com/bug-view-183421.html --- src/main.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index ac3e00a8..63720fa8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -82,10 +82,18 @@ static bool CheckFFmpegEnv() QString path = QLibraryInfo::location(QLibraryInfo::LibrariesPath); dir.setPath(path); QStringList list = dir.entryList(QStringList() << (QString("libavcodec") + "*"), QDir::NoDotAndDotDot | QDir::Files); + QString libName = nullptr; + QRegExp re("libavcodec.so.*"); //Sometimes libavcodec.so may not exist, so find it through regular expression. + for (int i = 0; i < list.count(); i++) { + if (re.exactMatch(list[i])) { + libName = list[i]; + break; + } + } - if (list.contains("libavcodec.so") || list.contains("libavcodec.so.58")) { + if (libName != nullptr) { QLibrary libavcodec; //检查编码器是否存在 - libavcodec.setFileName("libavcodec.so"); + libavcodec.setFileName(libName); qDebug() << "Whether the libavcodec is loaded successfully: "<< libavcodec.load(); typedef AVCodec *(*p_avcodec_find_encoder)(enum AVCodecID id); p_avcodec_find_encoder m_avcodec_find_encoder = nullptr; From 864a9f1b64e3e67b1f159af5b815780ffce928fb Mon Sep 17 00:00:00 2001 From: xiepengfei Date: Tue, 31 Jan 2023 13:52:28 +0800 Subject: [PATCH 004/107] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=A4=A7?= =?UTF-8?q?=E7=AA=97=E5=8F=A3=E5=8D=A1=E9=A1=BF=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 去除多余连接 Bug: https://pms.uniontech.com/bug-view-177273.html Log: 修复部分已知问题 --- src/src/videowidget.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/src/videowidget.cpp b/src/src/videowidget.cpp index 72733b58..06d5042a 100755 --- a/src/src/videowidget.cpp +++ b/src/src/videowidget.cpp @@ -230,8 +230,6 @@ void videowidget::delayInit() setFlash(dc::Settings::get().getOption("photosetting.Flashlight.Flashlight").toBool()); setCapStatus(false); m_imgPrcThread->m_bTake = false; - connect(m_imgPrcThread, SIGNAL(SendMajorImageProcessing(QImage *, int)), - this, SLOT(ReceiveMajorImage(QImage *, int))); if (get_wayland_status() == true) { connect(m_imgPrcThread, SIGNAL(SendMajorImageProcessing(QImage *, int)), this, SLOT(ReceiveMajorImage(QImage *, int))); From 55b88ba2b8a3a6c3d0055b0d131b8366201b62bc Mon Sep 17 00:00:00 2001 From: pengfeixx <63588879+pengfeixx@users.noreply.github.com> Date: Tue, 7 Feb 2023 17:57:13 +0800 Subject: [PATCH 005/107] =?UTF-8?q?fix:=20=E6=9B=B4=E6=96=B0changlog?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 更新changlog Log: 更新changlog --- debian/changelog | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index d972a351..61081102 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,8 @@ -deepin-camera (2.0.0) unstable; urgency=medium +deepin-camera (1.4.9) unstable; urgency=medium - * New version 2.0.0 + * New version 1.4.9 - -- fengli Tue, 13 Jul 2022 10:03:54 +0800 + -- xiepengfei Tue, 07 Feb 2023 17:56:54 +0800 deepin-camera (1.0.0-1) unstable; urgency=medium From 739191964c153fd5898fb0d56a19bc9844221bb3 Mon Sep 17 00:00:00 2001 From: xiepengfei Date: Wed, 8 Feb 2023 09:41:56 +0800 Subject: [PATCH 006/107] =?UTF-8?q?fix:=20=E6=B7=BB=E5=8A=A0=E7=BF=BB?= =?UTF-8?q?=E8=AF=91=E9=85=8D=E7=BD=AE=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加翻译配置文件 Log: 添加翻译配置文件 --- .tx/deepin.conf | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .tx/deepin.conf diff --git a/.tx/deepin.conf b/.tx/deepin.conf new file mode 100644 index 00000000..c230b4f8 --- /dev/null +++ b/.tx/deepin.conf @@ -0,0 +1,2 @@ +[transifex] +branch = m20 From a00df79b02c38840cceb3eb67f6006396bdc4690 Mon Sep 17 00:00:00 2001 From: fengli Date: Thu, 23 Feb 2023 10:54:44 +0800 Subject: [PATCH 007/107] chore: new version 1.4.10 new version 1.4.10 Log: modify changelog --- debian/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index 61081102..ef4fac85 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +deepin-camera (1.4.10) UNSTABLE; urgency=medium + + * New version 1.4.10 + + -- fengli Thu, 23 Feb 2023 10:50:31 +0800 + deepin-camera (1.4.9) unstable; urgency=medium * New version 1.4.9 From 9f2b3c766ce85a9a5257ddd77ec9e8ca4f9654cc Mon Sep 17 00:00:00 2001 From: fengli Date: Mon, 27 Feb 2023 09:43:07 +0800 Subject: [PATCH 008/107] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E4=B8=BB?= =?UTF-8?q?=E9=A2=98=E5=88=87=E6=8D=A2=E7=9B=B8=E5=85=B3bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复主题切换相关bug Log: 修复主题切换相关bug Bug: https://pms.uniontech.com/bug-view-156737.html https://pms.uniontech.com/bug-view-187173.html --- src/src/mainwindow.cpp | 5 +++++ src/src/rollingbox.cpp | 10 ++++++++++ src/src/titlebar.cpp | 9 ++++----- src/src/titlebar.h | 2 +- src/src/videowidget.cpp | 6 ++++-- src/src/videowidget.h | 2 ++ 6 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/src/mainwindow.cpp b/src/src/mainwindow.cpp index 985d32ba..08322546 100644 --- a/src/src/mainwindow.cpp +++ b/src/src/mainwindow.cpp @@ -1290,6 +1290,8 @@ void CMainWindow::updateBlockSystem(bool bTrue) void CMainWindow::onNoCam() { + m_pTitlebar->titlebar()->setBackgroundTransparent(false); + m_pTitlebar->slotThemeTypeChanged(); showChildWidget(); onEnableSettings(true); } @@ -1859,6 +1861,9 @@ void CMainWindow::initConnection() connect(m_videoPre, SIGNAL(noCam()), this, SLOT(onNoCam())); //相机被抢占了,结束拍照、录制 connect(m_videoPre, SIGNAL(noCamAvailable()), this, SLOT(onNoCam())); + connect(m_videoPre, &videowidget::camAvailable, this, [=](){ + m_pTitlebar->titlebar()->setBackgroundTransparent(true); + }); //设置新的分辨率 connect(m_videoPre, SIGNAL(sigDeviceChange()), &Settings::get(), SLOT(setNewResolutionList())); diff --git a/src/src/rollingbox.cpp b/src/src/rollingbox.cpp index ee72f967..55b4a540 100644 --- a/src/src/rollingbox.cpp +++ b/src/src/rollingbox.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -35,6 +36,12 @@ RollingBox::RollingBox(QWidget *parent) : m_homingAnimation = new QPropertyAnimation(this, "deviation", this); m_homingAnimation->setDuration(300); m_homingAnimation->setEasingCurve(QEasingCurve::OutQuad); + + QGraphicsDropShadowEffect *shadowEffect = new QGraphicsDropShadowEffect(this); + shadowEffect->setOffset(0, 0); + shadowEffect->setColor(QColor(33, 33, 33, 125)); + shadowEffect->setBlurRadius(8); + this->setGraphicsEffect(shadowEffect); } void RollingBox::setRange(int min, int max) @@ -192,6 +199,9 @@ void RollingBox::paintEvent(QPaintEvent *e) QRect tmpRightRect(centerRect.topRight() - QPoint(BTN_HEIGHT, 0), QSize(BTN_HEIGHT, BTN_HEIGHT)); QPainterPath centerPath; +// painter.setPen(QColor(255, 0, 0)); +// painter.drawRect(this->rect()); + centerPath.moveTo(tmpLeftRect.topRight()); centerPath.arcTo(tmpLeftRect, 90, 180); centerPath.lineTo(centerRect.width() - BTN_HEIGHT / 2, centerRect.y() + BTN_HEIGHT); diff --git a/src/src/titlebar.cpp b/src/src/titlebar.cpp index df06fc0d..8790c6ee 100644 --- a/src/src/titlebar.cpp +++ b/src/src/titlebar.cpp @@ -36,9 +36,6 @@ Titlebar::Titlebar(QWidget *parent) : DBlurEffectWidget(parent), d_ptr(new Title setLayout(layout); d->m_titlebar = new DTitlebar(this); - //d->m_titlebar->setFocusPolicy(Qt::NoFocus); -// d->m_titlebar->setWindowFlags(Qt::WindowMinMaxButtonsHint | -// Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); d->m_titlebar->setBackgroundTransparent(true); d->m_titlebar->setBlurBackground(false); layout->addWidget(d->m_titlebar); @@ -88,8 +85,10 @@ void Titlebar::paintEvent(QPaintEvent *pe) linearGradient.setColorAt(0, QColor(0, 0, 0, 255 * 0.5)); //垂直线性渐变 linearGradient.setColorAt(1, QColor(0, 0, 0, 0)); - pa.setColor(QPalette::ButtonText, d->lightColor); - d->m_titlebar->setPalette(pa); + if(DataManager::instance()->getdevStatus() != NOCAM) { + pa.setColor(QPalette::ButtonText, d->lightColor); + d->m_titlebar->setPalette(pa); + } painter.setRenderHint(QPainter::Antialiasing, true); painter.setBrush(QBrush(linearGradient)); diff --git a/src/src/titlebar.h b/src/src/titlebar.h index e9fa2060..9102e477 100644 --- a/src/src/titlebar.h +++ b/src/src/titlebar.h @@ -31,7 +31,7 @@ class Titlebar : public DBlurEffectWidget */ DTitlebar *titlebar(); -private slots: +public slots: /** * @brief slotThemeTypeChanged 主题变化事件槽函数 */ diff --git a/src/src/videowidget.cpp b/src/src/videowidget.cpp index 06d5042a..37ff56af 100755 --- a/src/src/videowidget.cpp +++ b/src/src/videowidget.cpp @@ -203,8 +203,8 @@ videowidget::videowidget(DWidget *parent) connect(m_recordingTimer, SIGNAL(timeout()), this, SLOT(showRecTime()));//显示录制时长 m_flashTimer->setSingleShot(true); - //设置相机背景色为黑色 - QColor bgColor(0, 0, 0); + //设置相机背景色为灰色 + QColor bgColor(25, 25, 25); QPalette pal(this->palette()); pal.setColor(QPalette::Background, bgColor); this->setAutoFillBackground(true); @@ -425,6 +425,7 @@ void videowidget::ReceiveOpenGLstatus(bool result) m_openglwidget->show(); malloc_trim(0); + emit camAvailable(); } } @@ -480,6 +481,7 @@ void videowidget::ReceiveMajorImage(QImage *image, int result) default: break; } + emit camAvailable(); } } diff --git a/src/src/videowidget.h b/src/src/videowidget.h index b75eb87d..72458e4a 100644 --- a/src/src/videowidget.h +++ b/src/src/videowidget.h @@ -28,6 +28,7 @@ #include "previewopenglwidget.h" #include "filterpreviewbutton.h" #include "gridline.h" +#include "titlebar.h" #include "gstvideowriter.h" @@ -120,6 +121,7 @@ class videowidget : public DWidget * @brief noCamAvailable 无相机可获取 */ void noCamAvailable(); + void camAvailable(); /** * @brief filename 文件名 From 5b22b833fc2991bc26c00d114d24ef5a681d0c6e Mon Sep 17 00:00:00 2001 From: xiepengfei Date: Mon, 6 Mar 2023 10:25:08 +0800 Subject: [PATCH 009/107] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=84=A6?= =?UTF-8?q?=E7=82=B9=E5=88=9D=E5=A7=8B=E4=BD=8D=E7=BD=AE=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 设置初始位置为标题栏 Bug: https://pms.uniontech.com/bug-view-120099.html Log: 修复部分已知问题 --- src/src/mainwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/src/mainwindow.cpp b/src/src/mainwindow.cpp index 08322546..8daf740e 100644 --- a/src/src/mainwindow.cpp +++ b/src/src/mainwindow.cpp @@ -2271,7 +2271,7 @@ bool CMainWindow::eventFilter(QObject *obj, QEvent *e) DataManager::instance()->m_tabIndex = 9; } else if (e->type() == QEvent::MouseButtonPress) { DataManager::instance()->m_tabIndex = 0; - m_videoPre->setFocus(); + m_pTitlebar->setFocus(); } else { QWidget::eventFilter(obj, e);//调用父类事件过滤器 } From 0671cf59cb1c91247ea348a561ee6749a096a209 Mon Sep 17 00:00:00 2001 From: fengli Date: Tue, 21 Mar 2023 17:42:53 +0800 Subject: [PATCH 010/107] chore: New tag 1.4.11 New tag 1.4.11 Log: New tag 1.4.11 --- debian/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index ef4fac85..e3f45ac0 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +deepin-camera (1.4.11) unstable; urgency=medium + + * New version 1.4.11 + + -- fengli Tue, 21 Mar 2023 17:41:33 +0800 + deepin-camera (1.4.10) UNSTABLE; urgency=medium * New version 1.4.10 From 8a253a9c2d07f60def2e0a1b2237f68226ad3f67 Mon Sep 17 00:00:00 2001 From: fengli Date: Thu, 4 May 2023 17:27:54 +0800 Subject: [PATCH 011/107] =?UTF-8?q?fix:=20wayland=E9=94=81=E5=B1=8F?= =?UTF-8?q?=E5=90=8E=E6=8B=94=E6=8F=92=E6=91=84=E5=83=8F=E5=A4=B4=E5=B4=A9?= =?UTF-8?q?=E6=BA=83=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复wayland锁屏后拔插摄像头,解锁后点击录像按钮崩溃 Log: 修复wayland锁屏后拔插摄像头崩溃问题 Bug: https://pms.uniontech.com/bug-view-198571.html --- src/src/mainwindow.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/src/mainwindow.cpp b/src/src/mainwindow.cpp index 8daf740e..6c6913e5 100644 --- a/src/src/mainwindow.cpp +++ b/src/src/mainwindow.cpp @@ -1400,6 +1400,10 @@ void CMainWindow::onTimeoutLock(const QString &serviceName, QVariantMap key2valu onStopPhotoAndRecord(); m_videoPre->m_imgPrcThread->stop(); + + v4l2_dev_t *vd = get_v4l2_device_handler(); + if (vd != nullptr) + close_v4l2_device_handler(); qDebug() << "lock end"; } else { qDebug() << "restart use camera cause ScreenBlack or PoweerLock"; From 6dd09fc2b90504a2df99ccee094d087342cff40b Mon Sep 17 00:00:00 2001 From: fengli Date: Sat, 6 May 2023 15:59:46 +0800 Subject: [PATCH 012/107] =?UTF-8?q?fix:=20=E9=94=81=E5=B1=8F=E5=90=8E?= =?UTF-8?q?=E5=BF=AB=E9=80=9F=E8=A7=A3=E9=94=81=EF=BC=8C=E7=9B=B8=E6=9C=BA?= =?UTF-8?q?=E5=B4=A9=E6=BA=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复锁屏后快速解锁,相机崩溃问题 Log: 修复锁屏后快速解锁,相机崩溃问题 Bug: https://pms.uniontech.com/bug-view-198939.html --- src/src/mainwindow.cpp | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/src/src/mainwindow.cpp b/src/src/mainwindow.cpp index 6c6913e5..a0ea10b3 100644 --- a/src/src/mainwindow.cpp +++ b/src/src/mainwindow.cpp @@ -1392,31 +1392,30 @@ void CMainWindow::onTimeoutLock(const QString &serviceName, QVariantMap key2valu { qDebug() << serviceName << key2value << endl; //仅wayland需要锁屏结束录制并停止使用摄像头,从锁屏恢复重新开启摄像头 - if (m_bWayland) { + //wayland下只需要停止录像,不需要停止线程,需要在锁屏状态下继续处理摄像头状态 +// if (m_bWayland) { - if (key2value.value("Locked").value()) { - qDebug() << "locked"; +// if (key2value.value("Locked").value()) { +// qDebug() << "locked"; - onStopPhotoAndRecord(); +// onStopPhotoAndRecord(); - m_videoPre->m_imgPrcThread->stop(); +// m_videoPre->m_imgPrcThread->stop(); - v4l2_dev_t *vd = get_v4l2_device_handler(); - if (vd != nullptr) - close_v4l2_device_handler(); - qDebug() << "lock end"; - } else { - qDebug() << "restart use camera cause ScreenBlack or PoweerLock"; - //打开摄像头 - m_videoPre->onChangeDev(); - qDebug() << "v4l2core_start_stream OK"; - } +// v4l2_dev_t *vd = get_v4l2_device_handler(); +// qDebug() << "lock end"; +// } else { +// qDebug() << "restart use camera cause ScreenBlack or PoweerLock"; +// //打开摄像头 +// m_videoPre->onChangeDev(); +// qDebug() << "v4l2core_start_stream OK"; +// } - } else { //锁屏结束连拍 +// } else { //锁屏结束连拍 if (key2value.value("Locked").value()) { onStopPhotoAndRecord(); } - } +// } } void CMainWindow::onTrashFile(const QString &fileName) From 39bf02737a44a8c3aea574abfbb5d7af8267b00c Mon Sep 17 00:00:00 2001 From: fengli Date: Mon, 8 May 2023 15:16:59 +0800 Subject: [PATCH 013/107] chore: new version 1.4.12 New version 1.4.12 Log: new version 1.4.12 --- debian/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index e3f45ac0..0057a76d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +deepin-camera (1.4.12) unstable; urgency=medium + + * New version 1.4.12 + + -- fengli Mon, 08 May 2023 15:15:09 +0800 + deepin-camera (1.4.11) unstable; urgency=medium * New version 1.4.11 From ec5160b8c22a41b9bd077ffd870d896a62579794 Mon Sep 17 00:00:00 2001 From: deepin-admin-bot Date: Wed, 10 May 2023 02:01:23 +0000 Subject: [PATCH 014/107] chore: Sync by https://github.com/linuxdeepin/.github/commit/2e5e092ba3f86b16d1aabbabcf0bfd2ae65b19c8 sync by github workflow Log: none Influence: none --- .github/workflows/call-tag-build.yml | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 .github/workflows/call-tag-build.yml diff --git a/.github/workflows/call-tag-build.yml b/.github/workflows/call-tag-build.yml deleted file mode 100644 index 6420b293..00000000 --- a/.github/workflows/call-tag-build.yml +++ /dev/null @@ -1,13 +0,0 @@ -name: tag build -on: - push: - tags: "*" - -concurrency: - group: ${{ github.workflow }} - cancel-in-progress: true - -jobs: - build: - uses: linuxdeepin/.github/.github/workflows/tag-build.yml@master - secrets: inherit From 40e59c5c5d8c5b45451d8d717d06a0915089d71c Mon Sep 17 00:00:00 2001 From: fengli Date: Wed, 17 May 2023 13:17:40 +0800 Subject: [PATCH 015/107] =?UTF-8?q?fix:=20=E6=9C=80=E5=B0=8F=E5=8C=96?= =?UTF-8?q?=E5=90=8E=E6=97=A0=E6=B3=95=E5=94=A4=E9=86=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复最小化后无法通过全局搜索唤醒 Log: 修复最小化后无法通过全局搜索唤醒 Bug: https://pms.uniontech.com/bug-view-200273.html --- src/main.cpp | 5 +++++ src/src/dbus_adpator.cpp | 27 +++++++++++++++++++++++++++ src/src/dbus_adpator.h | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+) create mode 100644 src/src/dbus_adpator.cpp create mode 100644 src/src/dbus_adpator.h diff --git a/src/main.cpp b/src/main.cpp index 63720fa8..cafbfd56 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -11,6 +11,7 @@ extern "C" #include "capplication.h" #include "cameraconfig.h" #include "acobjectlist.h" +#include "dbus_adpator.h" extern "C" { @@ -211,5 +212,9 @@ int main(int argc, char *argv[]) w.show(); w.loadAfterShow(); + ApplicationAdaptor adaptor(&w); + QDBusConnection::sessionBus().registerService("com.deepin.camera"); + QDBusConnection::sessionBus().registerObject(QDir::separator(), &w); + return qApp->exec(); } diff --git a/src/src/dbus_adpator.cpp b/src/src/dbus_adpator.cpp new file mode 100644 index 00000000..7677ddde --- /dev/null +++ b/src/src/dbus_adpator.cpp @@ -0,0 +1,27 @@ +// Copyright (C) 2020 ~ 2021 Uniontech Software Technology Co.,Ltd. +// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "dbus_adpator.h" + +ApplicationAdaptor::ApplicationAdaptor(CMainWindow *mw) + : QDBusAbstractAdaptor(mw), m_mw(mw) +{ +} + +void ApplicationAdaptor::Raise() +{ + qDebug() << "raise window from dbus"; + m_mw->showNormal(); + m_mw->raise(); + m_mw->activateWindow(); +} + +ApplicationAdaptor::~ApplicationAdaptor() +{ + if (m_mw) { + m_mw->deleteLater(); + m_mw = nullptr; + } +} diff --git a/src/src/dbus_adpator.h b/src/src/dbus_adpator.h new file mode 100644 index 00000000..b01e2281 --- /dev/null +++ b/src/src/dbus_adpator.h @@ -0,0 +1,39 @@ +// Copyright (C) 2020 ~ 2021 Uniontech Software Technology Co.,Ltd. +// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef DBUS_ADAPTOR +#define DBUS_ADAPTOR + +#include "mainwindow.h" + +#include + +/** +* @brief CloseDialog 窗口大小适配 +* 窗口最小化后双击桌面图标弹出相应大小的窗口 +*/ +class ApplicationAdaptor: public QDBusAbstractAdaptor +{ + Q_OBJECT + +public: + explicit ApplicationAdaptor(CMainWindow *mw = nullptr); + Q_CLASSINFO("D-Bus Interface", "com.deepin.camera") + + ~ApplicationAdaptor(); + +public slots: + /** + * @brief Raise 升起窗口信号 + */ + void Raise(); + +private: + CMainWindow *m_mw; +}; + + +#endif /* ifndef DBUS_ADAPTOR */ + From af79293dd90438d7cd5e937b99ad9e9e727b7a37 Mon Sep 17 00:00:00 2001 From: pengfeixx <63588879+pengfeixx@users.noreply.github.com> Date: Tue, 30 May 2023 18:00:42 +0800 Subject: [PATCH 016/107] fix: update changelog (#251) new version 1.4.13 Log: new version 1.4.13 --- debian/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index 0057a76d..7650be3c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +deepin-camera (1.4.13) unstable; urgency=medium + + * New version 1.4.13 + + -- xiepengfei Tues, 30 May 2023 17:41:09 +0800 + deepin-camera (1.4.12) unstable; urgency=medium * New version 1.4.12 From 414886226dacb40e226d2322e2c336528bcdb6cf Mon Sep 17 00:00:00 2001 From: pengfeixx <63588879+pengfeixx@users.noreply.github.com> Date: Wed, 12 Jul 2023 13:03:21 +0800 Subject: [PATCH 017/107] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8Dwayland?= =?UTF-8?q?=E4=B8=8B=E5=BD=95=E5=83=8F=E6=9C=AA=E5=81=9C=E6=AD=A2=E9=97=AE?= =?UTF-8?q?=E9=A2=98=20(#253)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 通过kwayland接口获取wayland下窗口信息,当全屏覆盖相机时停止录像 Bug: https://pms.uniontech.com/bug-view-102292.html Log: 修复部分已知问题 --- debian/control | 1 + src/CMakeLists.txt | 10 ++++ src/src/mainwindow.cpp | 10 ++-- src/src/windowstatethread.cpp | 96 ++++++++++++++++++++++++++++++++++- src/src/windowstatethread.h | 40 ++++++++++++++- tests/CMakeLists.txt | 4 ++ 6 files changed, 154 insertions(+), 7 deletions(-) diff --git a/debian/control b/debian/control index 621b511b..7204cc45 100644 --- a/debian/control +++ b/debian/control @@ -8,6 +8,7 @@ Build-Depends: libavutil-dev, libavformat-dev, libavcodec-dev,libavfilter-dev,qttools5-dev, qttools5-dev-tools,deepin-gettext-tools,libdframeworkdbus-dev, libv4l-dev,libsdl2-dev,portaudio19-dev,libpng-dev,libasound2-dev, + libkf5wayland-dev, libusb-1.0-0-dev,zlib1g-dev,libudev-dev,libswscale-dev,libswresample-dev,libffmpegthumbnailer-dev, libx11-dev,libva-dev,libimageeditor-dev,libgstreamer1.0-dev,libgstreamer-plugins-base1.0-dev,gstreamer1.0-plugins-good Standards-Version: 4.1.2 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 809af532..c408c3cb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,6 +14,12 @@ set(LUT_DIR "/usr/share/libimagevisualresult/filter_cube") add_definitions(-DLUT_DIR="${LUT_DIR}") #add_definitions(-D__mips__) +execute_process(COMMAND cat /etc/os-version COMMAND grep MinorVersion COMMAND grep -o \\-\\?[0-9]\\+ OUTPUT_VARIABLE osversion) +if(NOT (${osversion} LESS 1050)) + message(${osversion}) + add_definitions(-DKF5_WAYLAND_FLAGE_ON) +endif() + include(GNUInstallDirs) if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX /usr) @@ -82,6 +88,7 @@ file (GLOB_RECURSE RESOURCES ${PROJECT_SOURCE_DIR}/assets/assets.qrc) pkg_check_modules(3rd_lib REQUIRED dtkwidget dtkcore gobject-2.0 + epoxy # libv4l2 # libudev # libusb-1.0 @@ -127,8 +134,11 @@ target_link_libraries(${TARGET_NAME} ${3rd_lib_LIBRARIES} pthread dl imagevisualresult + KF5WaylandClient ) +include_directories("/usr/include/KF5") + # 将工程与Qt模块链接起来 qt5_use_modules(${TARGET_NAME} ${QtModule}) diff --git a/src/src/mainwindow.cpp b/src/src/mainwindow.cpp index a0ea10b3..c5e329d7 100644 --- a/src/src/mainwindow.cpp +++ b/src/src/mainwindow.cpp @@ -1250,7 +1250,7 @@ void CMainWindow::loadAfterShow() m_filterName->setText(filterPreviewButton::filterName(filter_Normal)); showChildWidget(); - m_windowStateThread = new windowStateThread(this); + m_windowStateThread = new windowStateThread(m_bWayland, this); connect(m_windowStateThread, &windowStateThread::someWindowFullScreen, this, &CMainWindow::onStopPhotoAndRecord); QJsonObject obj{ @@ -1480,7 +1480,7 @@ void CMainWindow::onPhotoRecordBtnClked() int nContinuous = Settings::get().getOption("photosetting.photosnumber.takephotos").toInt(); if (nContinuous > 1) { // 仅在连拍模式下才开启窗口状态监听线程 - if (!m_windowStateThread->isRunning()) { + if (!m_windowStateThread->isRunning() && !m_bWayland) { m_windowStateThread->start(); } } @@ -1495,7 +1495,7 @@ void CMainWindow::onPhotoRecordBtnClked() return; m_videoPre->onTakeVideo(); - if (!m_windowStateThread->isRunning()) { + if (!m_windowStateThread->isRunning() && !m_bWayland) { m_windowStateThread->start(); } } @@ -1517,7 +1517,7 @@ void CMainWindow::onUpdateRecordState(int state) m_actionSettings->setEnabled(!m_bRecording); showChildWidget(); if (false == m_bRecording - && m_windowStateThread->isRunning()) { + && m_windowStateThread->isRunning() && !m_bWayland) { m_windowStateThread->requestInterruption(); } } @@ -1528,7 +1528,7 @@ void CMainWindow::onUpdatePhotoState(int state) m_photoState = state; showChildWidget(); if (photoNormal == state - && m_windowStateThread->isRunning()) { + && m_windowStateThread->isRunning() && !m_bWayland) { m_windowStateThread->requestInterruption(); } } diff --git a/src/src/windowstatethread.cpp b/src/src/windowstatethread.cpp index 77d29557..6afb9f25 100644 --- a/src/src/windowstatethread.cpp +++ b/src/src/windowstatethread.cpp @@ -9,10 +9,40 @@ #include #include -windowStateThread::windowStateThread(QObject *parent /*= nullptr*/) +windowStateThread::windowStateThread(bool isWayland, QObject *parent /*= nullptr*/) : QThread (parent) { setObjectName("windowStateThread"); +#ifdef KF5_WAYLAND_FLAGE_ON + if (isWayland) { + qInfo() << __FUNCTION__ << __LINE__ << "KF5_WAYLAND_FLAGE_ON is open!!"; + //wayland自动识别窗口 + m_connectionThread = new QThread(this); + m_connectionThreadObject = new ConnectionThread(); + connect(m_connectionThreadObject, &ConnectionThread::connected, this, + [this] { + m_eventQueue = new EventQueue(this); + m_eventQueue->setup(m_connectionThreadObject); + + Registry *registry = new Registry(this); + setupRegistry(registry); + }, + Qt::QueuedConnection + ); + m_connectionThreadObject->moveToThread(m_connectionThread); + m_connectionThread->start(); + m_connectionThreadObject->initConnection(); + } +#endif +} + +windowStateThread::~windowStateThread() +{ +#ifdef KF5_WAYLAND_FLAGE_ON + m_connectionThread->quit(); + m_connectionThread->wait(); + m_connectionThreadObject->deleteLater(); +#endif } void windowStateThread::run() @@ -70,3 +100,67 @@ QList windowStateThread::workspaceWindows() const return windowList; } +#ifdef KF5_WAYLAND_FLAGE_ON +void windowStateThread::setupRegistry(Registry *registry) +{ + connect(registry, &Registry::compositorAnnounced, this, + [this, registry](quint32 name, quint32 version) { + m_compositor = registry->createCompositor(name, version, this); + } + ); + + connect(registry, &Registry::clientManagementAnnounced, this, + [this, registry](quint32 name, quint32 version) { + m_clientManagement = registry->createClientManagement(name, version, this); + connect(m_clientManagement, &ClientManagement::windowStatesChanged, this, + [this] { + m_windowStates = m_clientManagement->getWindowStates(); + this->waylandwindowinfo(m_windowStates); + } + ); + } + ); + + connect(registry, &Registry::interfacesAnnounced, this, + [this] { + Q_ASSERT(m_compositor); + Q_ASSERT(m_clientManagement); + m_windowStates = m_clientManagement->getWindowStates(); + this->waylandwindowinfo(m_windowStates); + } + ); + + registry->setEventQueue(m_eventQueue); + registry->create(m_connectionThreadObject); + registry->setup(); +} + +void windowStateThread::waylandwindowinfo(const QVector &windowStates) +{ + if (windowStates.count() == 0) { + return; + } + + bool aheandInCamera = false; + QRect rect; + for (int i = 0; i < windowStates.count(); ++i) { + if (QString(windowStates[i].resourceName) != "deepin-camera") { + if (!aheandInCamera) + continue; + else { + if (windowStates[i].isFullScreen) { + QRect fullscreenRect(windowStates[i].geometry.x, windowStates[i].geometry.y, + windowStates[i].geometry.width, windowStates[i].geometry.height); + if (fullscreenRect.contains(rect)) + emit someWindowFullScreen(); + } + } + } else { + aheandInCamera = true; + rect = QRect(windowStates[i].geometry.x, windowStates[i].geometry.y, + windowStates[i].geometry.width, windowStates[i].geometry.height); + } + } +} +#endif + diff --git a/src/src/windowstatethread.h b/src/src/windowstatethread.h index 41431a62..33fe624c 100644 --- a/src/src/windowstatethread.h +++ b/src/src/windowstatethread.h @@ -13,12 +13,21 @@ #include #include +#ifdef KF5_WAYLAND_FLAGE_ON +#include +#include +#include +#include +using namespace KWayland::Client; +#endif + class windowStateThread : public QThread { Q_OBJECT public: - explicit windowStateThread(QObject *parent = nullptr); + explicit windowStateThread(bool isWayland, QObject *parent = nullptr); + ~windowStateThread(); QList workspaceWindows() const; void run(); @@ -26,6 +35,35 @@ class windowStateThread : public QThread void someWindowFullScreen(); private: +#ifdef KF5_WAYLAND_FLAGE_ON + /** + * @brief wayland获取屏幕窗口信息的安装注册函数 + * @param registry + */ + void setupRegistry(Registry *registry); + + /** + * @brief wayland获取屏幕窗口信息 + * @param m_windowStates + */ + void waylandwindowinfo(const QVector &m_windowStates); +#endif + +private: +#ifdef KF5_WAYLAND_FLAGE_ON + // 获取wayland窗口信息相关。 wayland获取窗口的方法对于x11有很大的区别 + QThread *m_connectionThread; + EventQueue *m_eventQueue = nullptr; + ConnectionThread *m_connectionThreadObject; + Compositor *m_compositor = nullptr; + PlasmaWindowManagement *m_windowManagement = nullptr; + ClientManagement *m_clientManagement = nullptr; + QVector m_windowStates; + /** + * @brief mips平台创建缓存文件的路径 + */ + std::string m_tempPath; +#endif }; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 7f2be316..82a1c725 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -114,8 +114,12 @@ target_link_libraries(${PROJECT_NAME} ${3rd_lib_LIBRARIES} # z imagevisualresult + KF5WaylandClient ) +include_directories("/usr/include/KF5") + + # 将工程与Qt模块链接起来 qt5_use_modules(${PROJECT_NAME} ${QtModule}) From 9c8f98fbb62f3561da8ae40cf9a3530bfbfee6a0 Mon Sep 17 00:00:00 2001 From: pengfeixx <63588879+pengfeixx@users.noreply.github.com> Date: Wed, 12 Jul 2023 15:50:49 +0800 Subject: [PATCH 018/107] fix: Update changelog (#254) Update changelog Log: Update changelog --- debian/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index 7650be3c..6221382b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +deepin-camera (1.4.14) unstable; urgency=medium + + * New version 1.4.14 + + -- xiepengfei Wed, 12 Jul 2023 14:47:36 +0800 + deepin-camera (1.4.13) unstable; urgency=medium * New version 1.4.13 From 724b443015faf80ed6782e18ff7db33c43962625 Mon Sep 17 00:00:00 2001 From: pengfeixx <63588879+pengfeixx@users.noreply.github.com> Date: Fri, 14 Jul 2023 10:47:55 +0800 Subject: [PATCH 019/107] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=89=93?= =?UTF-8?q?=E5=8C=85=E5=A4=B1=E8=B4=A5=E9=97=AE=E9=A2=98=20(#255)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 当环境无版本文件时不查找 Log: 修复部分已知问题 --- src/CMakeLists.txt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c408c3cb..c14f6e02 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,10 +14,12 @@ set(LUT_DIR "/usr/share/libimagevisualresult/filter_cube") add_definitions(-DLUT_DIR="${LUT_DIR}") #add_definitions(-D__mips__) -execute_process(COMMAND cat /etc/os-version COMMAND grep MinorVersion COMMAND grep -o \\-\\?[0-9]\\+ OUTPUT_VARIABLE osversion) -if(NOT (${osversion} LESS 1050)) - message(${osversion}) - add_definitions(-DKF5_WAYLAND_FLAGE_ON) +if(EXISTS /etc/os-version) + execute_process(COMMAND cat /etc/os-version COMMAND grep MinorVersion COMMAND grep -o \\-\\?[0-9]\\+ OUTPUT_VARIABLE osversion) + if(NOT (${osversion} LESS 1050)) + message(${osversion}) + add_definitions(-DKF5_WAYLAND_FLAGE_ON) + endif() endif() include(GNUInstallDirs) From cf1e32e0212b277cd64998306183d195e090a964 Mon Sep 17 00:00:00 2001 From: pengfeixx <63588879+pengfeixx@users.noreply.github.com> Date: Wed, 19 Jul 2023 15:31:08 +0800 Subject: [PATCH 020/107] =?UTF-8?q?fix:=20=E5=8E=BB=E9=99=A4=E5=A4=9A?= =?UTF-8?q?=E4=BD=99=E4=BE=9D=E8=B5=96=20(#257)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 去除多余依赖 Log: 修复部分已知问题 --- src/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c14f6e02..1b713de9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -90,7 +90,6 @@ file (GLOB_RECURSE RESOURCES ${PROJECT_SOURCE_DIR}/assets/assets.qrc) pkg_check_modules(3rd_lib REQUIRED dtkwidget dtkcore gobject-2.0 - epoxy # libv4l2 # libudev # libusb-1.0 From df9ab5d3d080262022019d76dd85b0b67d9f538a Mon Sep 17 00:00:00 2001 From: pengfeixx <63588879+pengfeixx@users.noreply.github.com> Date: Wed, 19 Jul 2023 17:49:39 +0800 Subject: [PATCH 021/107] fix: Update changelog (#258) Update changelog Log: Update changelog --- debian/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index 6221382b..9afe0d78 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +deepin-camera (1.4.15) unstable; urgency=medium + + * New version 1.4.15 + + -- xiepengfei Wed, 19 Jul 2023 16:05:28 +0800 + deepin-camera (1.4.14) unstable; urgency=medium * New version 1.4.14 From d6d561e596ff920e6827324b14efb1403cea1171 Mon Sep 17 00:00:00 2001 From: fengli Date: Tue, 1 Aug 2023 15:17:25 +0800 Subject: [PATCH 022/107] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8DUSB=E5=A3=B0?= =?UTF-8?q?=E5=8D=A1=E7=AB=AF=E5=8F=A3=E7=8A=B6=E6=80=81=E6=AD=A3=E5=B8=B8?= =?UTF-8?q?=EF=BC=8C=E4=BD=86=E6=97=A0=E6=B3=95=E8=8E=B7=E5=8F=96=E9=9F=B3?= =?UTF-8?q?=E9=A2=91=E6=95=B0=E6=8D=AE=E6=97=B6=E5=BD=95=E5=83=8F=E5=B4=A9?= =?UTF-8?q?=E6=BA=83=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 规避USB声卡端口状态正常,但无法获取音频数据时,点击结束录像崩溃问题 Log: 规避USB声卡端口状态正常,但无法获取音频数据时录像崩溃问题 Bug: https://pms.uniontech.com/bug-view-207319.html --- libcam/libcam_encoder/encoder.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/libcam/libcam_encoder/encoder.c b/libcam/libcam_encoder/encoder.c index 203cab2e..94fc3706 100644 --- a/libcam/libcam_encoder/encoder.c +++ b/libcam/libcam_encoder/encoder.c @@ -1791,9 +1791,14 @@ int encoder_encode_audio(encoder_context_t *encoder_ctx, void *audio_data) encoder_audio_context_t *enc_audio_ctx = encoder_ctx->enc_audio_ctx; - int outsize = 0; + int outsize = 0; + + if (!audio_data) { + fprintf(stderr, "ENCODER: audio_data is empty."); + return outsize; + } - if(!enc_audio_ctx) + if(!enc_audio_ctx) { if(verbosity > 1) printf("ENCODER: audio encoder not set\n"); From 970c8a453828e3d83ec6105182f6566e1a879091 Mon Sep 17 00:00:00 2001 From: pengfeixx <63588879+pengfeixx@users.noreply.github.com> Date: Thu, 3 Aug 2023 11:30:58 +0800 Subject: [PATCH 023/107] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8Dwayland?= =?UTF-8?q?=E4=B8=8B=E6=8E=A5=E5=8F=A3=E6=9C=AA=E5=AE=9A=E4=B9=89=20(#260)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复wayland下接口未定义 Log: 修复wayland下接口未定义 --- src/CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1b713de9..031bbe14 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -16,10 +16,13 @@ add_definitions(-DLUT_DIR="${LUT_DIR}") if(EXISTS /etc/os-version) execute_process(COMMAND cat /etc/os-version COMMAND grep MinorVersion COMMAND grep -o \\-\\?[0-9]\\+ OUTPUT_VARIABLE osversion) + message(${osversion}) if(NOT (${osversion} LESS 1050)) - message(${osversion}) add_definitions(-DKF5_WAYLAND_FLAGE_ON) endif() +else() + message("/etc/os-version is not exist") + add_definitions(-DKF5_WAYLAND_FLAGE_ON) endif() include(GNUInstallDirs) From 60958d9a82e2152b910e163a503b9b8473418153 Mon Sep 17 00:00:00 2001 From: pengfeixx <63588879+pengfeixx@users.noreply.github.com> Date: Fri, 4 Aug 2023 13:37:38 +0800 Subject: [PATCH 024/107] fix: Update changelog (#261) Update changelog Log: Update changelog --- debian/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index 9afe0d78..4763c5ee 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +deepin-camera (1.4.16) unstable; urgency=medium + + * New version 1.4.16 + + -- xiepengfei Fri, 04 Aug 2023 16:05:28 +0800 + deepin-camera (1.4.15) unstable; urgency=medium * New version 1.4.15 From 8563a25155a8a905d01790b4c3c0c7f6c4bef808 Mon Sep 17 00:00:00 2001 From: pengfeixx <63588879+pengfeixx@users.noreply.github.com> Date: Wed, 6 Sep 2023 14:49:12 +0800 Subject: [PATCH 025/107] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=AE=89?= =?UTF-8?q?=E9=81=93=E5=A4=A7=E5=B1=8F=E9=97=AA=E9=80=80=E9=97=AE=E9=A2=98?= =?UTF-8?q?=20(#262)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 获取分辨率时过滤异常分辨率 Log: 修复部分已知问题 --- libcam/libcam_v4l2core/v4l2_core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libcam/libcam_v4l2core/v4l2_core.c b/libcam/libcam_v4l2core/v4l2_core.c index 577fb545..2824ddfa 100644 --- a/libcam/libcam_v4l2core/v4l2_core.c +++ b/libcam/libcam_v4l2core/v4l2_core.c @@ -1699,7 +1699,10 @@ void v4l2core_prepare_valid_resolution(v4l2_dev_t *vd) for(int i=0; i < vd->list_stream_formats[format_index].numb_res; i++) { if( my_width <= vd->list_stream_formats[format_index].list_stream_cap[i].width && - my_height <= vd->list_stream_formats[format_index].list_stream_cap[i].height) + my_height <= vd->list_stream_formats[format_index].list_stream_cap[i].height && + ((vd->list_stream_formats[format_index].list_stream_cap[i].width % 8) == 0 + && (vd->list_stream_formats[format_index].list_stream_cap[i].width % 16) == 0 + && (vd->list_stream_formats[format_index].list_stream_cap[i].height % 8) == 0)) { my_width = vd->list_stream_formats[format_index].list_stream_cap[i].width; my_height = vd->list_stream_formats[format_index].list_stream_cap[i].height; From 22d4cc174aabd589e51185e320e29778fe9d3c35 Mon Sep 17 00:00:00 2001 From: Liu Zheng Date: Thu, 25 Jul 2024 13:58:39 +0800 Subject: [PATCH 026/107] fix: Optimize preview efficiency Optimize preview efficiency Log: Optimize preview efficiency --- src/src/majorimageprocessingthread.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/src/majorimageprocessingthread.cpp b/src/src/majorimageprocessingthread.cpp index 9796aac9..dfff61fa 100644 --- a/src/src/majorimageprocessingthread.cpp +++ b/src/src/majorimageprocessingthread.cpp @@ -377,7 +377,7 @@ void MajorImageProcessingThread::run() } QImage* imgTmp = nullptr; - if (m_rgbPtr) + if (m_rgbPtr && bUseRgb) imgTmp = new QImage(m_rgbPtr, m_frame->width, m_frame->height, QImage::Format_RGB888); /*拍照*/ From 33b0f61276e16da4039dc970753f226005808838 Mon Sep 17 00:00:00 2001 From: shuaijie Date: Fri, 30 Aug 2024 10:06:18 +0800 Subject: [PATCH 027/107] fix: the correct get the product machine name the correct get the product machine name Log: the correct get the product machine name Bug: https://pms.uniontech.com/bug-view-267231.html --- src/main.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 5fc4984f..d13d6cbe 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -124,7 +124,7 @@ int main(int argc, char *argv[]) int mp4Encode = -1; #ifdef DTKCORE_CLASS_DConfigFile - //需要查询是否对PGUX设置MP4编码缓存特殊处理 + //需要查询是否对X机型设置MP4编码缓存特殊处理 DConfig *dconfig = DConfig::create("org.deepin.camera", "org.deepin.camera.encode"); if (dconfig && dconfig->isValid() && dconfig->keyList().contains("mp4EncodeMode")) { mp4Encode = dconfig->value("mp4EncodeMode").toInt(); @@ -133,10 +133,11 @@ int main(int argc, char *argv[]) #endif qInfo() << "mp4EncodeMode value is:" << get_pugx_status(); if (mp4Encode == -1) { - //判断是否是pgux + //判断是否是X机型 QStringList options; options << QString(QStringLiteral("-c")); - options << QString(QStringLiteral("dmidecode -s system-product-name|awk '{print $NF}'")); + options << QString(QStringLiteral("dmidecode -t 11 | grep 'String 4' | awk '{print $NF}' && " + "dmidecode -s system-product-name|awk '{print $NF}'")); QProcess process; process.start(QString(QStringLiteral("bash")), options); process.waitForFinished(); From 2d9c20bb1e9c1a4ceb915297da349c1485c13e46 Mon Sep 17 00:00:00 2001 From: shuaijie Date: Mon, 21 Oct 2024 17:45:12 +0800 Subject: [PATCH 028/107] fix: hardware encoder stash in 7d55 mask the 7d55 for encoder Log: make the video record use softencode Bug: https://pms.uniontech.com/bug-view-278369.html --- libcam/libcam_encoder/encoder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcam/libcam_encoder/encoder.c b/libcam/libcam_encoder/encoder.c index e6ff475e..ce200ba1 100644 --- a/libcam/libcam_encoder/encoder.c +++ b/libcam/libcam_encoder/encoder.c @@ -2204,7 +2204,7 @@ static encoder_video_context_t *encoder_video_init_vaapi(encoder_context_t *enco if (0x8086 == dev->vendor_id) { // intel gpu support vaapi, vendor_id :0x8086 can find from file pci.ids //Iris Xe Graphics don't suppot vaapi, so softening coding. - if (dev->device_id == 0xa7a0) { + if (dev->device_id == 0xa7a0 || dev->device_id == 0x7d55) { is_vaapi = HW_VAAPI_FAIL1; return NULL; } From 78bede6eeecfb9ab7ec3a8203a23ed7f05d18652 Mon Sep 17 00:00:00 2001 From: shuaijie Date: Wed, 6 Nov 2024 16:09:44 +0800 Subject: [PATCH 029/107] =?UTF-8?q?fix:=20=E7=9B=B8=E6=9C=BA=E7=95=8C?= =?UTF-8?q?=E9=9D=A2=E5=8D=A1=E4=BD=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit crash on the write_pipe Log: 相机界面卡住 Bug: https://pms.uniontech.com/bug-view-283285.html --- src/src/devnummonitor.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/src/devnummonitor.cpp b/src/src/devnummonitor.cpp index a6757894..c256a963 100644 --- a/src/src/devnummonitor.cpp +++ b/src/src/devnummonitor.cpp @@ -58,14 +58,12 @@ void DevNumMonitor::timeOutSlot() } else { m_noDevice = false; emit existDevice(); - qDebug() << "There is a camera connected!"; } } else { m_noDevice = false; emit existDevice(); //显示切换按钮 emit seltBtnStateEnable(); - qDebug() << "There are two or more cameras connected!"; } } From 76ef7a15d2a2634e4373b027eef1a8aa7381ee9d Mon Sep 17 00:00:00 2001 From: shuaijie Date: Thu, 14 Nov 2024 16:13:40 +0800 Subject: [PATCH 030/107] fix: make screen flash stable during take photo screen flash during take photo Log: screen flash when take photo Bug: https://pms.uniontech.com/bug-view-285489.html --- src/src/videowidget.cpp | 16 ++++++++++++---- src/src/videowidget.h | 1 + 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/src/videowidget.cpp b/src/src/videowidget.cpp index 490c34f9..3fb4cdd6 100644 --- a/src/src/videowidget.cpp +++ b/src/src/videowidget.cpp @@ -429,7 +429,7 @@ void videowidget::ReceiveOpenGLstatus(bool result) } } - if (!m_openglwidget->isVisible()) + if (!m_openglwidget->isVisible() && !m_isFalsh) m_openglwidget->show(); malloc_trim(0); @@ -452,7 +452,9 @@ void videowidget::ReceiveMajorImage(QImage *image, int result) switch (result) { case 0: //Success // m_imgPrcThread->m_rwMtxImg.lock(); - m_pNormalView->show(); + + if (!m_isFalsh) + m_pNormalView->show(); m_pCamErrItem->hide(); m_pSvgItem->hide(); m_pNormalItem->show(); @@ -663,8 +665,10 @@ void videowidget::showCountdown() m_flashTimer->start(500); qDebug() << "flashTimer->start();"; - if (m_pNormalView) + if (m_pNormalView) { + m_isFalsh = true; m_pNormalView->hide(); + } if (m_openglwidget) m_openglwidget->hide(); if (m_gridlinewidget) @@ -837,9 +841,13 @@ void videowidget::flash() m_takePicSound->play(); #ifndef __mips__ - if (!get_wayland_status()) + if (!get_wayland_status()) { if (!m_openglwidget->isVisible() && filter_Normal == m_filterType && 0 == m_exposure) m_openglwidget->show(); + } else { + m_pNormalView->show(); + } + m_isFalsh = false; #endif m_flashLabel->hide(); //为避免没有关闭,放到定时器里边关闭 diff --git a/src/src/videowidget.h b/src/src/videowidget.h index d769086c..8c9cd022 100644 --- a/src/src/videowidget.h +++ b/src/src/videowidget.h @@ -465,6 +465,7 @@ private slots: GstVideoWriter *m_videoWriter; //基于GStreamer实现的视频帧数据写入器 efilterType m_filterType; //当前选择的滤镜名称 int m_exposure; + bool m_isFalsh = false; }; From 702a5c884cf42b05dd17884bb5cde9c082078175 Mon Sep 17 00:00:00 2001 From: shuaijie Date: Tue, 10 Dec 2024 16:47:22 +0800 Subject: [PATCH 031/107] fix: optimize delay for show optimize delay for show Log: delay for show Bug: https://pms.uniontech.com/bug-view-283415.html --- libcam/libcam/camview.c | 16 +++++++++++++++- libcam/libcam/camview.h | 4 ++++ src/assets/org.deepin.camera.encode.json | 12 +++++++++++- src/main.cpp | 6 ++++++ src/src/majorimageprocessingthread.cpp | 3 +++ src/src/previewopenglwidget.cpp | 13 +++++-------- 6 files changed, 44 insertions(+), 10 deletions(-) diff --git a/libcam/libcam/camview.c b/libcam/libcam/camview.c index 45687bdd..345ea311 100644 --- a/libcam/libcam/camview.c +++ b/libcam/libcam/camview.c @@ -104,6 +104,8 @@ static int my_encoder_status = 0; static int is_wayland = 0; //是否是wayland的窗口管理器 +static int statusForceGles = 0; //forceGles 1,强走GLES + static int is_pgux = 0; //是否是pugx static uint8_t soundTakePhoto = 1;//拍照声音提示 @@ -1344,9 +1346,21 @@ void set_wayland_status(int status) is_wayland = status; } +void set_forceGles(int status) +{ + statusForceGles = status; +} + +int is_forceGles() +{ + return statusForceGles; +} + int get_wayland_status() { - return is_wayland; + if (1 == is_forceGles()) + return 0; + return is_wayland; } void set_takeing_photo_sound(uint8_t status) diff --git a/libcam/libcam/camview.h b/libcam/libcam/camview.h index 5efd5b6a..e0e7e471 100644 --- a/libcam/libcam/camview.h +++ b/libcam/libcam/camview.h @@ -435,6 +435,10 @@ void set_pugx_status(int status); int get_pugx_status(); +void set_forceGles(int status); + +int is_forceGles(); + #ifdef __cplusplus } #endif diff --git a/src/assets/org.deepin.camera.encode.json b/src/assets/org.deepin.camera.encode.json index 64bad69a..592dc587 100644 --- a/src/assets/org.deepin.camera.encode.json +++ b/src/assets/org.deepin.camera.encode.json @@ -11,6 +11,16 @@ "description": "pugx mp4 code mode", "permissions": "readwrite", "visibility": "private" - } + }, + "forceGles": { + "value": -1, + "serial": 0, + "flags": ["global"], + "name": "forc elgs show in wayland", + "name[zh_CN]": "在 wayland 下特殊显示模式", + "description": "special mode do use gles to show", + "permissions": "readwrite", + "visibility": "private" + } } } \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index d13d6cbe..c2d55738 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -130,6 +130,12 @@ int main(int argc, char *argv[]) mp4Encode = dconfig->value("mp4EncodeMode").toInt(); set_pugx_status(mp4Encode); } + + int forceGles = -1; + if (dconfig && dconfig->isValid() && dconfig->keyList().contains("forceGles")) { + forceGles = dconfig->value("forceGles").toInt(); + set_forceGles(forceGles); + } #endif qInfo() << "mp4EncodeMode value is:" << get_pugx_status(); if (mp4Encode == -1) { diff --git a/src/src/majorimageprocessingthread.cpp b/src/src/majorimageprocessingthread.cpp index 1aef0dc3..872be145 100644 --- a/src/src/majorimageprocessingthread.cpp +++ b/src/src/majorimageprocessingthread.cpp @@ -265,6 +265,9 @@ void MajorImageProcessingThread::run() if (GStreamer_Env == m_eEncodeEnv) bUseRgb = true; + if (1 == is_forceGles()) + bUseRgb = false; + if (bUseRgb || (m_bPhoto && m_filtersGroupDislay)) { if (m_nVdWidth != static_cast(m_frame->width) || m_nVdHeight != static_cast(m_frame->height)) { m_nVdWidth = static_cast(m_frame->width); diff --git a/src/src/previewopenglwidget.cpp b/src/src/previewopenglwidget.cpp index 40b5c239..245ea910 100644 --- a/src/src/previewopenglwidget.cpp +++ b/src/src/previewopenglwidget.cpp @@ -82,9 +82,9 @@ void PreviewOpenglWidget::initializeGL() }"; const char *fsrc; - - if (get_wayland_status() == 0) { - fsrc = "varying vec2 textureOut; \ + if (1 == is_forceGles()) { + fsrc = "precision mediump float; \ + varying vec2 textureOut; \ uniform sampler2D tex_y; \ uniform sampler2D tex_u; \ uniform sampler2D tex_v; \ @@ -100,11 +100,8 @@ void PreviewOpenglWidget::initializeGL() 1.13983, -0.58060, 0) * yuv; \ gl_FragColor = vec4(rgb, 1); \ }"; - } else { - fsrc = "#ifdef GL_ES \ - precision mediump float; \ - #endif \ - varying vec2 textureOut; \ + } else if (get_wayland_status() == 0) { + fsrc = "varying vec2 textureOut; \ uniform sampler2D tex_y; \ uniform sampler2D tex_u; \ uniform sampler2D tex_v; \ From 49abf557935e696f516d6b248348394b8092916d Mon Sep 17 00:00:00 2001 From: wyu <97944796+wyu71@users.noreply.github.com> Date: Fri, 20 Dec 2024 16:13:37 +0800 Subject: [PATCH 032/107] fix: remove invalid url (#345) remove invalid url Log: remove invalid url --- src/src/circlepushbutton.cpp | 2 +- src/src/filterpreviewbutton.cpp | 2 +- src/src/imageitem.cpp | 2 +- src/src/photorecordbtn.cpp | 2 +- src/src/videowidget.cpp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/src/circlepushbutton.cpp b/src/src/circlepushbutton.cpp index cf147489..3b5f72cc 100644 --- a/src/src/circlepushbutton.cpp +++ b/src/src/circlepushbutton.cpp @@ -196,7 +196,7 @@ void circlePushButton::mousePressEvent(QMouseEvent *event) void circlePushButton::mouseMoveEvent(QMouseEvent *event) { - //解决bug 在按钮中可拖动相机界面,https://pms.uniontech.com/zentao/bug-view-100647.html + //解决bug 在按钮中可拖动相机界面,bug 100647 Q_UNUSED(event); return; } diff --git a/src/src/filterpreviewbutton.cpp b/src/src/filterpreviewbutton.cpp index 8dae1b30..e833caf4 100644 --- a/src/src/filterpreviewbutton.cpp +++ b/src/src/filterpreviewbutton.cpp @@ -188,7 +188,7 @@ void filterPreviewButton::mousePressEvent(QMouseEvent *event) void filterPreviewButton::mouseMoveEvent(QMouseEvent *event) { - //解决bug 在按钮中可拖动相机界面,https://pms.uniontech.com/zentao/bug-view-100647.html + //解决bug 在按钮中可拖动相机界面,bug 100647 Q_UNUSED(event); return; } diff --git a/src/src/imageitem.cpp b/src/src/imageitem.cpp index a47da7f6..4a0220dc 100644 --- a/src/src/imageitem.cpp +++ b/src/src/imageitem.cpp @@ -229,7 +229,7 @@ void ImageItem::mousePressEvent(QMouseEvent *event) void ImageItem::mouseMoveEvent(QMouseEvent *event) { - //解决bug 在缩略图中可拖动相机界面,https://pms.uniontech.com/zentao/bug-view-100647.html + //解决bug 在缩略图中可拖动相机界面,bug 100647 Q_UNUSED(event); return; } diff --git a/src/src/photorecordbtn.cpp b/src/src/photorecordbtn.cpp index 6fc05968..c70fda94 100644 --- a/src/src/photorecordbtn.cpp +++ b/src/src/photorecordbtn.cpp @@ -132,7 +132,7 @@ void photoRecordBtn::mousePressEvent(QMouseEvent *event) void photoRecordBtn::mouseMoveEvent(QMouseEvent *event) { - //解决bug 在按钮中可拖动相机界面,https://pms.uniontech.com/zentao/bug-view-100647.html + //解决bug 在按钮中可拖动相机界面,bug 100647 Q_UNUSED(event); return; } diff --git a/src/src/videowidget.cpp b/src/src/videowidget.cpp index 3fb4cdd6..b2d78546 100644 --- a/src/src/videowidget.cpp +++ b/src/src/videowidget.cpp @@ -40,7 +40,7 @@ static PRIVIEW_ENUM_STATE g_Enum_Camera_State = PICTRUE; // 重写QGraphicsView类,在子类中,直接将鼠标事件路由到QWidget,这样QGraphicsScene不会接收和处理鼠标事件 -// bug链接 https://pms.uniontech.com/zentao/bug-view-100791.html +// bug 100791 QGraphicsViewEx::QGraphicsViewEx(QWidget *parent) : QGraphicsView(parent) { From 7855880ae31d184878fc32715e37772434453ac8 Mon Sep 17 00:00:00 2001 From: ut001910 Date: Fri, 20 Dec 2024 15:47:23 +0800 Subject: [PATCH 033/107] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96=E7=9B=B8?= =?UTF-8?q?=E6=9C=BA=E6=98=BE=E7=A4=BA=E4=B8=8E=E5=BD=95=E5=88=B6=E5=8D=A1?= =?UTF-8?q?=E9=A1=BF=E5=9B=9E=E8=B7=B3=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 优化相机显示与录制卡顿回跳问题 Bug: https://pms.uniontech.com/bug-view-293127.html Log: 优化相机显示与录制卡顿回跳问题 --- libcam/libcam_encoder/encoder.c | 2 +- src/src/majorimageprocessingthread.cpp | 1 - src/src/previewopenglwidget.cpp | 22 ++++++++++++++++++---- src/src/previewopenglwidget.h | 1 + src/src/videowidget.cpp | 5 +++++ 5 files changed, 25 insertions(+), 6 deletions(-) diff --git a/libcam/libcam_encoder/encoder.c b/libcam/libcam_encoder/encoder.c index ce200ba1..372e6f8e 100644 --- a/libcam/libcam_encoder/encoder.c +++ b/libcam/libcam_encoder/encoder.c @@ -581,7 +581,7 @@ static encoder_video_context_t *encoder_video_init(encoder_context_t *encoder_ct if (video_defaults->gop_size > 0) { - if (pgux == 1) { + if (pgux == 1 || is_forceGles()) { video_codec_data->codec_context->gop_size = 3; } else { video_codec_data->codec_context->gop_size = video_defaults->gop_size; diff --git a/src/src/majorimageprocessingthread.cpp b/src/src/majorimageprocessingthread.cpp index 872be145..8a7535cb 100644 --- a/src/src/majorimageprocessingthread.cpp +++ b/src/src/majorimageprocessingthread.cpp @@ -443,7 +443,6 @@ void MajorImageProcessingThread::run() } } else if (m_frame->yuv_frame){ #ifndef __mips__ - emit sigRenderYuv(true); emit sigYUVFrame(m_yuvPtr, m_nVdWidth, m_nVdHeight); #endif } diff --git a/src/src/previewopenglwidget.cpp b/src/src/previewopenglwidget.cpp index 245ea910..0e292810 100644 --- a/src/src/previewopenglwidget.cpp +++ b/src/src/previewopenglwidget.cpp @@ -156,12 +156,20 @@ void PreviewOpenglWidget::paintGL() { if (m_yuvPtr == nullptr) return; - + bool bReBuildImage = false; + if(m_imgSize != QSize(m_videoWidth, m_videoHeight)) { + bReBuildImage = true; + m_imgSize = QSize(m_videoWidth, m_videoHeight); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } glActiveTexture(GL_TEXTURE0); //激活纹理单元GL_TEXTURE0,系统里面的 glBindTexture(GL_TEXTURE_2D, m_idY); //绑定y分量纹理对象id到激活的纹理单元 //使用内存中的数据创建真正的y分量纹理数据,https://blog.csdn.net/xipiaoyouzi/article/details/53584798 纹理参数解析 - glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, static_cast(m_videoWidth), static_cast(m_videoHeight), 0, GL_RED, GL_UNSIGNED_BYTE, m_yuvPtr); + if( bReBuildImage ) { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, static_cast(m_videoWidth), static_cast(m_videoHeight), 0, GL_RED, GL_UNSIGNED_BYTE, 0); + } + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, static_cast(m_videoWidth), static_cast(m_videoHeight), GL_RED, GL_UNSIGNED_BYTE, m_yuvPtr); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -171,7 +179,10 @@ void PreviewOpenglWidget::paintGL() glBindTexture(GL_TEXTURE_2D, m_idU); //使用内存中的数据创建真正的u分量纹理数据 - glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_videoWidth >> 1, m_videoHeight >> 1, 0, GL_RED, GL_UNSIGNED_BYTE, m_yuvPtr + m_videoWidth * m_videoHeight); + if( bReBuildImage ) { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_videoWidth >> 1, m_videoHeight >> 1, 0, GL_RED, GL_UNSIGNED_BYTE, 0); + } + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_videoWidth >> 1, m_videoHeight >> 1, GL_RED, GL_UNSIGNED_BYTE, m_yuvPtr + m_videoWidth * m_videoHeight); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -181,7 +192,10 @@ void PreviewOpenglWidget::paintGL() glBindTexture(GL_TEXTURE_2D, m_idV); //使用内存中的数据创建真正的v分量纹理数据 - glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_videoWidth >> 1, m_videoHeight >> 1, 0, GL_RED, GL_UNSIGNED_BYTE, m_yuvPtr + m_videoWidth * m_videoHeight * 5 / 4); + if( bReBuildImage ) { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_videoWidth >> 1, m_videoHeight >> 1, 0, GL_RED, GL_UNSIGNED_BYTE, 0); + } + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_videoWidth >> 1, m_videoHeight >> 1, GL_RED, GL_UNSIGNED_BYTE, m_yuvPtr + m_videoWidth * m_videoHeight * 5 / 4); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); diff --git a/src/src/previewopenglwidget.h b/src/src/previewopenglwidget.h index 1fb0789b..554eeda9 100644 --- a/src/src/previewopenglwidget.h +++ b/src/src/previewopenglwidget.h @@ -91,6 +91,7 @@ public slots: uint m_videoHeight; uchar *m_yuvPtr; + QSize m_imgSize; }; #endif // PREVIEWOPENGLWIDGET_H diff --git a/src/src/videowidget.cpp b/src/src/videowidget.cpp index b2d78546..eb8e81f4 100644 --- a/src/src/videowidget.cpp +++ b/src/src/videowidget.cpp @@ -244,6 +244,7 @@ void videowidget::delayInit() } else { connect(m_imgPrcThread, SIGNAL(SendMajorImageProcessing(QImage *, int)), this, SLOT(ReceiveMajorImage(QImage *, int))); + ReceiveOpenGLstatus(true); connect(m_imgPrcThread, SIGNAL(sigRenderYuv(bool)), this, SLOT(ReceiveOpenGLstatus(bool))); connect(m_imgPrcThread, SIGNAL(sigYUVFrame(uchar *, uint, uint)), m_openglwidget, SLOT(slotShowYuv(uchar *, uint, uint))); @@ -616,6 +617,10 @@ void videowidget::resizeEvent(QResizeEvent *size) if (m_gridlinewidget) m_gridlinewidget->resize(rect().size()); + + if(m_openglwidget && m_openglwidget->isVisible()) { + ReceiveOpenGLstatus(true); + } } void videowidget::showCountdown() From 9eff0fb79e991542017ce09be6afbc184a0d3b21 Mon Sep 17 00:00:00 2001 From: myk1343 <75473184+myk1343@users.noreply.github.com> Date: Mon, 30 Dec 2024 17:59:21 +0800 Subject: [PATCH 034/107] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E7=95=8C=E9=9D=A2=20(#346)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 优化显示界面与原来不一致问题 Bug: https://pms.uniontech.com/bug-view-293127.html Log: 优化显示界面 --- src/src/majorimageprocessingthread.cpp | 1 + src/src/videowidget.cpp | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/src/majorimageprocessingthread.cpp b/src/src/majorimageprocessingthread.cpp index 8a7535cb..872be145 100644 --- a/src/src/majorimageprocessingthread.cpp +++ b/src/src/majorimageprocessingthread.cpp @@ -443,6 +443,7 @@ void MajorImageProcessingThread::run() } } else if (m_frame->yuv_frame){ #ifndef __mips__ + emit sigRenderYuv(true); emit sigYUVFrame(m_yuvPtr, m_nVdWidth, m_nVdHeight); #endif } diff --git a/src/src/videowidget.cpp b/src/src/videowidget.cpp index eb8e81f4..990071dd 100644 --- a/src/src/videowidget.cpp +++ b/src/src/videowidget.cpp @@ -244,7 +244,6 @@ void videowidget::delayInit() } else { connect(m_imgPrcThread, SIGNAL(SendMajorImageProcessing(QImage *, int)), this, SLOT(ReceiveMajorImage(QImage *, int))); - ReceiveOpenGLstatus(true); connect(m_imgPrcThread, SIGNAL(sigRenderYuv(bool)), this, SLOT(ReceiveOpenGLstatus(bool))); connect(m_imgPrcThread, SIGNAL(sigYUVFrame(uchar *, uint, uint)), m_openglwidget, SLOT(slotShowYuv(uchar *, uint, uint))); From 6fb1958d18f9abfb9f70fac89248424e4aad97f1 Mon Sep 17 00:00:00 2001 From: Liu Zheng Date: Fri, 3 Jan 2025 09:27:43 +0800 Subject: [PATCH 035/107] fix: check vaapi encoder fail check vaapi encoder fail note wayland not support.(no device test) Log: check vaapi encoder fail --- libcam/libcam_encoder/encoder.c | 125 ++++++++++++++++++++++---------- src/CMakeLists.txt | 2 + 2 files changed, 87 insertions(+), 40 deletions(-) diff --git a/libcam/libcam_encoder/encoder.c b/libcam/libcam_encoder/encoder.c index 372e6f8e..66f991b1 100644 --- a/libcam/libcam_encoder/encoder.c +++ b/libcam/libcam_encoder/encoder.c @@ -45,6 +45,8 @@ #include #include +#include + #include "cameraconfig.h" #include "gviewencoder.h" #include "encoder.h" @@ -2154,6 +2156,84 @@ static int set_hwframe_ctx(AVCodecContext *ctx, AVBufferRef *hw_device_ctx, int return err; } +// 检查是否支持VAAPI硬编码的函数 +int check_vaapi_support() { + struct pci_device_iterator *iter; + struct pci_device *dev; + VADisplay va_display; + VAStatus status; + int major_version, minor_version; + int is_vaapi_supported = 0; + + // 初始化PCI系统 + if (pci_system_init() != 0) { + fprintf(stderr, "无法初始化PCI系统\n"); + return 0; + } + + iter = pci_slot_match_iterator_create(NULL); + if (iter == NULL) { + fprintf(stderr, "无法创建PCI插槽匹配迭代器\n"); + pci_system_cleanup(); + return 0; + } + + va_display = vaGetDisplay(NULL); // 这里假设使用X11,如果是Wayland需要使用vaGetDisplayWl + if (va_display == NULL) { + fprintf(stderr, "无法打开VA显示\n"); + pci_iterator_destroy(iter); + pci_system_cleanup(); + return 0; + } + + status = vaInitialize(va_display, &major_version, &minor_version); + if (status != VA_STATUS_SUCCESS) { + fprintf(stderr, "无法初始化VAAPI\n"); + vaTerminate(va_display); + pci_iterator_destroy(iter); + pci_system_cleanup(); + return 0; + } + + // 遍历PCI设备 + while ((dev = pci_device_next(iter)) != NULL) { + if (0x03 == ((dev->device_class >> 16) & 0x0ff)) { // 检查是否为显示设备 + printf("检测到显示设备: %04x:%04x\n", dev->vendor_id, dev->device_id); + + // 检查支持的配置文件 + int num_profiles; + VAProfile *profiles; + status = vaQueryConfigProfiles(va_display, NULL, &num_profiles); + if (status != VA_STATUS_SUCCESS) { + fprintf(stderr, "无法查询配置文件\n"); + continue; + } + + profiles = (VAProfile *)malloc(sizeof(VAProfile) * num_profiles); + status = vaQueryConfigProfiles(va_display, profiles, &num_profiles); + if (status != VA_STATUS_SUCCESS) { + fprintf(stderr, "无法查询配置文件\n"); + free(profiles); + continue; + } + + printf("支持的VAAPI配置文件:\n"); + for (int i = 0; i < num_profiles; i++) { + printf(" Profile %d\n", profiles[i]); + is_vaapi_supported = 1; // 如果找到任何支持的配置文件,设置支持标志 + } + + free(profiles); + break; // 找到一个支持的设备就可以退出循环 + } + } + + vaTerminate(va_display); + pci_iterator_destroy(iter); + pci_system_cleanup(); + + return is_vaapi_supported; +} /* @@ -2170,50 +2250,15 @@ static int set_hwframe_ctx(AVCodecContext *ctx, AVBufferRef *hw_device_ctx, int static encoder_video_context_t *encoder_video_init_vaapi(encoder_context_t *encoder_ctx) { struct pci_device_iterator *iter; - struct pci_device *dev; int ret; is_vaapi = HW_VAAPI_OK; - ret = pci_system_init(); - if (ret != 0) { - fprintf(stderr, "Couldn't initialize PCI system\n"); + + if(check_vaapi_support()) + { is_vaapi = HW_VAAPI_FAIL1; + fprintf(stderr, "no gpu card for vaapi\n"); return NULL; - } - iter = pci_slot_match_iterator_create(NULL); - - while (1) { - if ((dev = pci_device_next(iter)) == NULL) { - is_vaapi = HW_VAAPI_FAIL1; - fprintf(stderr, "no gpu card for vaapi\n"); - return NULL; - } - - if (0x03 == ((dev->device_class >> 16) & 0x0ff)) { - fprintf(stderr, " CLASS 0x%02x subclass 0x%02x prog-if_name 0x%02x REVISION 0x%02x\n", - (dev->device_class >> 16) & 0x0ff, - (dev->device_class >> 8) & 0x0ff, - (dev->device_class >> 0) & 0x0ff, - dev->revision); - fprintf(stderr, "bus 0x%04x cardnum 0x%02x function 0x%02x:" - " vendor 0x%04x device 0x%04x\n", - dev->bus, - dev->dev, - dev->func, - dev->vendor_id, - dev->device_id); - - if (0x8086 == dev->vendor_id) { // intel gpu support vaapi, vendor_id :0x8086 can find from file pci.ids - //Iris Xe Graphics don't suppot vaapi, so softening coding. - if (dev->device_id == 0xa7a0 || dev->device_id == 0x7d55) { - is_vaapi = HW_VAAPI_FAIL1; - return NULL; - } - fprintf(stderr, "try this gpu card for vaapi\n"); - break; - } - } - } - pci_system_cleanup(); + } //assertions assert(encoder_ctx != NULL); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e3b66cde..158114e2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -120,6 +120,8 @@ file (GLOB_RECURSE RESOURCES ${PROJECT_SOURCE_DIR}/assets/assets.qrc) pkg_check_modules(3rd_lib REQUIRED dtkwidget dtkcore gobject-2.0 pciaccess + libva + libva-x11 # libv4l2 # libudev # libusb-1.0 From d70d7c5538ccf3942f8be8a0a9c58ed7afb1d8ef Mon Sep 17 00:00:00 2001 From: ut001910 Date: Tue, 7 Jan 2025 21:30:35 +0800 Subject: [PATCH 036/107] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8Dmips=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复mips问题 Log: 修复mips问题 --- src/src/videowidget.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/src/videowidget.cpp b/src/src/videowidget.cpp index 990071dd..c255b131 100644 --- a/src/src/videowidget.cpp +++ b/src/src/videowidget.cpp @@ -616,10 +616,11 @@ void videowidget::resizeEvent(QResizeEvent *size) if (m_gridlinewidget) m_gridlinewidget->resize(rect().size()); - +#ifndef __mips__ if(m_openglwidget && m_openglwidget->isVisible()) { ReceiveOpenGLstatus(true); } +#endif } void videowidget::showCountdown() From 05ac5a542c33f651b052e1cfcfa4a23941d2d34a Mon Sep 17 00:00:00 2001 From: myk1343 <75473184+myk1343@users.noreply.github.com> Date: Thu, 9 Jan 2025 13:46:34 +0800 Subject: [PATCH 037/107] =?UTF-8?q?fix:=20=E7=9B=B8=E6=9C=BA=E8=BF=98?= =?UTF-8?q?=E5=8E=9F=E5=90=8E=E6=9F=A5=E7=9C=8B=E8=AE=BE=E5=A4=87=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=20(#349)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 相机还原后查看设备信息 Bug: https://pms.uniontech.com/bug-view-292759.html Log: 相机还原后查看设备信息 --- libcam/libcam_v4l2core/v4l2_devices.c | 1 + src/src/devnummonitor.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/libcam/libcam_v4l2core/v4l2_devices.c b/libcam/libcam_v4l2core/v4l2_devices.c index bb9c48a6..b3b20234 100644 --- a/libcam/libcam_v4l2core/v4l2_devices.c +++ b/libcam/libcam_v4l2core/v4l2_devices.c @@ -294,6 +294,7 @@ int enum_v4l2_devices() getUdev()->m_udev_enumerate_unref(enumerate); my_device_list.num_devices = num_dev; + printf("my_device_list.num_devices is %d\n", num_dev); return(E_OK); } diff --git a/src/src/devnummonitor.cpp b/src/src/devnummonitor.cpp index c256a963..97454bd3 100644 --- a/src/src/devnummonitor.cpp +++ b/src/src/devnummonitor.cpp @@ -58,6 +58,7 @@ void DevNumMonitor::timeOutSlot() } else { m_noDevice = false; emit existDevice(); + qDebug() << "existDevice!"; } } else { m_noDevice = false; From ae6e325dc205a78a632cde7188a049e0d4c3c131 Mon Sep 17 00:00:00 2001 From: ut001910 Date: Tue, 11 Mar 2025 20:58:34 +0800 Subject: [PATCH 038/107] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=BD=95?= =?UTF-8?q?=E5=88=B6=E8=A7=86=E9=A2=91=E6=97=B6=E5=8D=A1=E4=BD=8F=E9=97=AA?= =?UTF-8?q?=E9=80=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复录制视频时卡住闪退 Bug: https://pms.uniontech.com//bug-view-307545.html Log: 修复录制视频时卡住闪退 --- libcam/libcam_encoder/encoder.c | 3 ++- libcam/libcam_encoder/muxer.c | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/libcam/libcam_encoder/encoder.c b/libcam/libcam_encoder/encoder.c index 66f991b1..32304228 100644 --- a/libcam/libcam_encoder/encoder.c +++ b/libcam/libcam_encoder/encoder.c @@ -2253,7 +2253,7 @@ static encoder_video_context_t *encoder_video_init_vaapi(encoder_context_t *enco int ret; is_vaapi = HW_VAAPI_OK; - if(check_vaapi_support()) + if(!check_vaapi_support()) { is_vaapi = HW_VAAPI_FAIL1; fprintf(stderr, "no gpu card for vaapi\n"); @@ -2278,6 +2278,7 @@ static encoder_video_context_t *encoder_video_init_vaapi(encoder_context_t *enco if (!video_defaults) { fprintf(stderr, "ENCODER: defaults for video codec index %i not found: using raw (direct input)\n", encoder_ctx->video_codec_ind); is_vaapi = HW_VAAPI_FAIL1; + return NULL; } encoder_video_context_t *enc_video_ctx = calloc(1, sizeof(encoder_video_context_t)); diff --git a/libcam/libcam_encoder/muxer.c b/libcam/libcam_encoder/muxer.c index 74b5aa9f..7d10fcc8 100644 --- a/libcam/libcam_encoder/muxer.c +++ b/libcam/libcam_encoder/muxer.c @@ -263,6 +263,10 @@ void encoder_muxer_init(encoder_context_t *encoder_ctx, const char *filename) assert(encoder_ctx->enc_video_ctx != NULL); encoder_codec_data_t *video_codec_data = (encoder_codec_data_t *) encoder_ctx->enc_video_ctx->codec_data; + if(!video_codec_data) { + printf("deepin-camera: video_codec_data (encoder_ctx->enc_video_ctx->codec_data) is null\n"); + return; + } int video_codec_id = AV_CODEC_ID_NONE; From a2b7cdc153c2b7b44f3598b228b9b0c4d25b8fcc Mon Sep 17 00:00:00 2001 From: zhanghongyuan Date: Mon, 24 Mar 2025 10:30:10 +0800 Subject: [PATCH 039/107] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=BD=95?= =?UTF-8?q?=E5=88=B6=E8=A7=86=E9=A2=91=E9=9F=B3=E8=A7=86=E9=A2=91=E4=B8=8D?= =?UTF-8?q?=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复录制视频音视频不同步 Bug: https://pms.uniontech.com//bug-view-293127.html Log: 修复录制视频音视频不同步 --- libcam/libcam_encoder/encoder.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libcam/libcam_encoder/encoder.c b/libcam/libcam_encoder/encoder.c index 32304228..27532d13 100644 --- a/libcam/libcam_encoder/encoder.c +++ b/libcam/libcam_encoder/encoder.c @@ -583,10 +583,9 @@ static encoder_video_context_t *encoder_video_init(encoder_context_t *encoder_ct if (video_defaults->gop_size > 0) { + video_codec_data->codec_context->gop_size = video_defaults->gop_size; if (pgux == 1 || is_forceGles()) { - video_codec_data->codec_context->gop_size = 3; - } else { - video_codec_data->codec_context->gop_size = video_defaults->gop_size; + video_codec_data->codec_context->max_b_frames = 0; } } else { video_codec_data->codec_context->gop_size = video_codec_data->codec_context->time_base.den; From 00d8f16e56fc3a89ab3b01211548c45d89dc11f8 Mon Sep 17 00:00:00 2001 From: ut001910 Date: Wed, 7 May 2025 13:16:28 +0800 Subject: [PATCH 040/107] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=9B=B8?= =?UTF-8?q?=E6=9C=BA=E4=B8=8A=E6=96=B9=E8=BE=B9=E6=A1=86=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E4=B8=80=E6=9D=A1=E7=99=BD=E7=BA=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复相机上方边框显示一条白线 Bug: https://pms.uniontech.com/bug-view-315601.html Log: 修复相机上方边框显示一条白线 --- src/src/previewopenglwidget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/src/previewopenglwidget.cpp b/src/src/previewopenglwidget.cpp index 0e292810..8f5e2ddc 100644 --- a/src/src/previewopenglwidget.cpp +++ b/src/src/previewopenglwidget.cpp @@ -149,6 +149,7 @@ void PreviewOpenglWidget::initializeGL() void PreviewOpenglWidget::resizeGL(int w, int h) { glViewport(0, 0, w, h); + glClearColor(0.0, 0.0, 0.0, 1.0); update(); } From 331f6b2320e8ad9fa97f35fa9ecec805f1011960 Mon Sep 17 00:00:00 2001 From: ut001910 Date: Tue, 20 May 2025 09:30:38 +0800 Subject: [PATCH 041/107] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D4k=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E5=8D=A1=E9=A1=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复4k显示卡顿 Bug: https://pms.uniontech.com/bug-view-316663.html Log: 修复4k显示卡顿 --- src/src/majorimageprocessingthread.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/src/majorimageprocessingthread.cpp b/src/src/majorimageprocessingthread.cpp index 872be145..8150f5b8 100644 --- a/src/src/majorimageprocessingthread.cpp +++ b/src/src/majorimageprocessingthread.cpp @@ -470,7 +470,9 @@ void MajorImageProcessingThread::run() break; #endif //保证画面流畅的前提下降低刷新率 - msleep(33); + if(m_nVdWidth <= 1920) { + msleep(33); + } } v4l2core_stop_stream(m_videoDevice); From f375e3399c09f2ea92709d98144a420874209558 Mon Sep 17 00:00:00 2001 From: ut001910 Date: Mon, 16 Jun 2025 13:14:47 +0800 Subject: [PATCH 042/107] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E8=B0=83?= =?UTF-8?q?=E6=95=B4=E6=9B=9D=E5=85=89=E5=BA=A6=E7=9A=84=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复调整曝光度的显示问题 Bug: https://pms.uniontech.com/bug-view-320193.html Log: 修复调整曝光度的显示问题 --- src/src/majorimageprocessingthread.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/src/majorimageprocessingthread.cpp b/src/src/majorimageprocessingthread.cpp index 8150f5b8..c288aa52 100644 --- a/src/src/majorimageprocessingthread.cpp +++ b/src/src/majorimageprocessingthread.cpp @@ -265,9 +265,6 @@ void MajorImageProcessingThread::run() if (GStreamer_Env == m_eEncodeEnv) bUseRgb = true; - if (1 == is_forceGles()) - bUseRgb = false; - if (bUseRgb || (m_bPhoto && m_filtersGroupDislay)) { if (m_nVdWidth != static_cast(m_frame->width) || m_nVdHeight != static_cast(m_frame->height)) { m_nVdWidth = static_cast(m_frame->width); From 8c5f0f02552de9a47dad5c6f9d12c0bf63091b81 Mon Sep 17 00:00:00 2001 From: Zhang Hongyuan Date: Wed, 18 Jun 2025 14:32:44 +0800 Subject: [PATCH 043/107] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E9=95=BF?= =?UTF-8?q?=E6=97=B6=E9=97=B4=E5=BD=95=E5=88=B6=E8=A7=86=E9=A2=91=E9=9F=B3?= =?UTF-8?q?=E8=A7=86=E9=A2=91=E4=B8=8D=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复长时间录制视频音视频不同步 Bug: https://pms.uniontech.com//bug-view-319497.html Log: 修复长时间录制视频音视频不同步 --- libcam/libcam_encoder/encoder.c | 3 +- libcam/libcam_encoder/mp4.c | 94 ++++++++++++++++++++++++-- libcam/libcam_v4l2core/v4l2_core.c | 2 +- src/src/devnummonitor.cpp | 2 +- src/src/majorimageprocessingthread.cpp | 3 + src/src/majorimageprocessingthread.h | 2 + 6 files changed, 97 insertions(+), 9 deletions(-) diff --git a/libcam/libcam_encoder/encoder.c b/libcam/libcam_encoder/encoder.c index 27532d13..208822ff 100644 --- a/libcam/libcam_encoder/encoder.c +++ b/libcam/libcam_encoder/encoder.c @@ -581,7 +581,6 @@ static encoder_video_context_t *encoder_video_init(encoder_context_t *encoder_ct else video_codec_data->codec_context->time_base = (AVRational) {1, 15}; //fallback to 15 fps (e.g gspca) - if (video_defaults->gop_size > 0) { video_codec_data->codec_context->gop_size = video_defaults->gop_size; if (pgux == 1 || is_forceGles()) { @@ -1947,7 +1946,7 @@ int encoder_encode_audio(encoder_context_t *encoder_ctx, void *audio_data) void encoder_close(encoder_context_t *encoder_ctx) { encoder_clean_video_ring_buffer(); - + if (!encoder_ctx) return; diff --git a/libcam/libcam_encoder/mp4.c b/libcam/libcam_encoder/mp4.c index f4ad0696..486608f1 100644 --- a/libcam/libcam_encoder/mp4.c +++ b/libcam/libcam_encoder/mp4.c @@ -21,12 +21,21 @@ #include "mp4.h" #include +#include "camview.h" #include "load_libs.h" +#include // 为abs函数添加头文件 + +extern int verbosity; // 添加verbosity声明 static int64_t video_pts = 0; static int64_t audio_pts = 0; static int64_t first_pts = 0; static int64_t last_pts = 0; +static int64_t last_video_timestamp = 0; // 添加上一帧视频时间戳记录 + +// 添加同步检查变量 +static int frame_count = 0; +static int64_t last_sync_check_time = 0; AVFormatContext *mp4_create_context(const char *filename) { @@ -121,18 +130,67 @@ int mp4_write_packet( getAvformat()->m_av_write_frame(mp4_ctx, outpacket); set_video_time_capture((double)(pts)/1000/1000000); } else { - fprintf(stderr,"pts err:video_pts: %d last_pts: %d\n", video_pts, last_pts); + fprintf(stderr,"pts err:video_pts: %ld last_pts: %ld\n", video_pts, last_pts); } last_pts = video_pts; if (first_pts == 0) { first_pts = pts; + last_video_timestamp = pts; + video_pts = 0; // 第一个视频包的PTS为0 } else { - video_pts = (double)(pts - first_pts) / 1000000.0 / 33.0; + // 使用真实时间戳计算,而不是硬编码的33ms + // 将纳秒时间戳转换为帧数(基于time_base) + int64_t timestamp_diff = pts - first_pts; // 从开始录制的时间差(纳秒) + + // 根据编码器的time_base计算PTS + // time_base通常是1/fps,所以pts = 时间差 * fps + if (time_base.den > 0 && time_base.num > 0) { + video_pts = (timestamp_diff * time_base.den) / (time_base.num * 1000000000LL); + } else { + // 如果time_base无效,使用动态帧率计算 + int64_t frame_duration = pts - last_video_timestamp; + if (frame_duration > 0) { + // 基于实际帧间隔计算 + video_pts = timestamp_diff / frame_duration; + } else { + // 回退到固定帧率(但使用更精确的计算) + video_pts = timestamp_diff / 33333333LL; // 30fps = 33.33ms + } + } + + last_video_timestamp = pts; + if (video_pts == last_pts) //pts must be strictly incremented video_pts++; if(video_pts < last_pts) video_pts = last_pts + 1; + + if (verbosity > 2) { + fprintf(stderr, "video_pts: %ld (timestamp: %ld, first_pts: %ld)\n", + video_pts, pts, first_pts); + } + + // 每100帧检查一次音视频同步状态 + frame_count++; + if (frame_count % 100 == 0) { + int64_t video_time_ms = (pts - first_pts) / 1000000; // 视频实际时间(毫秒) + int64_t video_pts_time_ms = 0; + + // 根据time_base计算视频PTS对应的时间 + if (time_base.den > 0 && time_base.num > 0) { + video_pts_time_ms = (video_pts * time_base.num * 1000) / time_base.den; + } + + int64_t sync_diff = video_time_ms - video_pts_time_ms; + + if (verbosity > 0 && abs(sync_diff) > 100) { // 如果差异超过100ms + fprintf(stderr, "SYNC CHECK: Frame %d, Real time: %ldms, PTS time: %ldms, Diff: %ldms\n", + frame_count, video_time_ms, video_pts_time_ms, sync_diff); + } + + last_sync_check_time = pts; + } } } @@ -147,9 +205,31 @@ int mp4_write_packet( getLoadLibsInstance()->m_av_packet_rescale_ts(outpacket, time_base, audio_time); getAvformat()->m_av_write_frame(mp4_ctx, outpacket); - //AAC音频标准是1024 - //MP3音频标准是1152 - audio_pts+= 1024; + // 使用基于真实时间的音频PTS计算 + if (first_pts == 0) { + first_pts = pts; // 设置first_pts + audio_pts = 0; // 第一个音频包的PTS为0 + } else { + // 将纳秒时间戳转换为音频时间基准 + int64_t timestamp_diff = pts - first_pts; // 从开始录制的时间差(纳秒) + + if (time_base.den > 0 && time_base.num > 0) { + // 根据音频编码器的time_base计算PTS + audio_pts = (timestamp_diff * time_base.den) / (time_base.num * 1000000000LL); + } else { + // 如果time_base无效,使用采样率计算 + int sample_rate = codec_data->codec_context->sample_rate; + if (sample_rate <= 0) sample_rate = 48000; // 默认采样率 + + // 基于真实时间和采样率计算音频PTS + audio_pts = (timestamp_diff * sample_rate) / 1000000000LL; + } + } + + if (verbosity > 2) { + fprintf(stderr, "audio_pts: %ld (timestamp: %ld, first_pts: %ld)\n", + audio_pts, pts, first_pts); + } } if(outpacket->data){ @@ -166,6 +246,10 @@ void mp4_destroy_context(AVFormatContext *mp4_ctx) video_pts = 0; audio_pts = 0; first_pts = 0; + last_pts = 0; + last_video_timestamp = 0; // 重置新增的变量 + frame_count = 0; // 重置帧计数 + last_sync_check_time = 0; // 重置同步检查时间 if(mp4_ctx != NULL) { getAvformat()->m_avformat_free_context(mp4_ctx); diff --git a/libcam/libcam_v4l2core/v4l2_core.c b/libcam/libcam_v4l2core/v4l2_core.c index 2824ddfa..bb51a7a5 100644 --- a/libcam/libcam_v4l2core/v4l2_core.c +++ b/libcam/libcam_v4l2core/v4l2_core.c @@ -1115,7 +1115,7 @@ static int process_input_buffer(v4l2_dev_t *vd) * driver timestamp is unreliable * use monotonic system time */ - vd->frame_queue[qind].timestamp = ns_time_monotonic(); + vd->frame_queue[qind].timestamp = ns_time_monotonic(); vd->frame_queue[qind].index = (int)vd->buf.index; diff --git a/src/src/devnummonitor.cpp b/src/src/devnummonitor.cpp index 97454bd3..64069c63 100644 --- a/src/src/devnummonitor.cpp +++ b/src/src/devnummonitor.cpp @@ -58,7 +58,7 @@ void DevNumMonitor::timeOutSlot() } else { m_noDevice = false; emit existDevice(); - qDebug() << "existDevice!"; + // qDebug() << "existDevice!"; } } else { m_noDevice = false; diff --git a/src/src/majorimageprocessingthread.cpp b/src/src/majorimageprocessingthread.cpp index c288aa52..6a4c2bfe 100644 --- a/src/src/majorimageprocessingthread.cpp +++ b/src/src/majorimageprocessingthread.cpp @@ -334,10 +334,13 @@ void MajorImageProcessingThread::run() if (!get_capture_pause()) { //设置时间戳 set_video_timestamptmp(static_cast(m_frame->timestamp)); + if (m_firstPts == 0) { m_firstPts = m_frame->timestamp; } m_nCount = (m_frame->timestamp - m_firstPts) / 1000000000; + + lasttimestamp = m_frame->timestamp; encoder_add_video_frame(input_frame, size, static_cast(m_frame->timestamp), m_frame->isKeyframe); } else { //设置暂停时长 diff --git a/src/src/majorimageprocessingthread.h b/src/src/majorimageprocessingthread.h index 109df561..235663ee 100644 --- a/src/src/majorimageprocessingthread.h +++ b/src/src/majorimageprocessingthread.h @@ -191,6 +191,8 @@ public slots: int m_nCount; uint64_t m_firstPts; + uint64_t lasttimestamp; + QImage m_Img; //mips、wayland下使用该变量 QImage m_filterImg; //滤镜预览类使用 大小40*40 QImage m_jpgImage; // 从v4l2获取的jpg格式的视频帧图片 From 1346c80869e52f9441ecfdae66fe6e8176cc9c4e Mon Sep 17 00:00:00 2001 From: zhanghongyuan Date: Sun, 27 Jul 2025 08:39:29 +0800 Subject: [PATCH 044/107] =?UTF-8?q?fix:=20=E7=A7=BB=E9=99=A4=E9=80=8F?= =?UTF-8?q?=E6=98=8E=E7=A3=A8=E7=A0=82=E6=A0=87=E9=A2=98=E6=A0=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 移除透明磨砂标题栏,让标题栏不遮挡相机内容 Log: 移除透明磨砂标题栏 Bug: https://pms.uniontech.com/bug-view-325869.html --- src/src/mainwindow.cpp | 1 + src/src/titlebar.cpp | 20 ++++++++++++-------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/src/mainwindow.cpp b/src/src/mainwindow.cpp index 57cba718..6a63883e 100644 --- a/src/src/mainwindow.cpp +++ b/src/src/mainwindow.cpp @@ -765,6 +765,7 @@ CMainWindow::CMainWindow(QWidget *parent) m_SpaceKeyInterval = QDateTime::currentMSecsSinceEpoch(); this->setObjectName(MAIN_WINDOW); this->setAccessibleName(MAIN_WINDOW); + setTitlebarShadowEnabled(false); titlebar()->deleteLater(); setupTitlebar(); diff --git a/src/src/titlebar.cpp b/src/src/titlebar.cpp index 36404c13..3d80846f 100644 --- a/src/src/titlebar.cpp +++ b/src/src/titlebar.cpp @@ -27,7 +27,10 @@ Titlebar::Titlebar(QWidget *parent) : DBlurEffectWidget(parent), d_ptr(new Title { Q_D(Titlebar); - setAttribute(Qt::WA_TranslucentBackground, true); + // 设置DBlurEffectWidget为完全透明 + setBlurEnabled(false); // 关闭模糊效果 + setMaskAlpha(0); // 设置遮罩完全透明 + setMaskColor(QColor(0, 0, 0, 0)); // 设置遮罩颜色为完全透明 QHBoxLayout *layout = new QHBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); @@ -39,6 +42,13 @@ Titlebar::Titlebar(QWidget *parent) : DBlurEffectWidget(parent), d_ptr(new Title d->m_titlebar->setBlurBackground(false); layout->addWidget(d->m_titlebar); + d->m_shadowEffect = new QGraphicsDropShadowEffect(this); + d->m_shadowEffect->setOffset(d->offsetX, d->offsetX); + d->m_shadowEffect->setBlurRadius(d->offsetX); + d->m_shadowEffect->setColor(Qt::transparent); + + this->setGraphicsEffect(d->m_shadowEffect); + connect(DGuiApplicationHelper::instance(), &DGuiApplicationHelper::themeTypeChanged, this, &Titlebar::slotThemeTypeChanged); } @@ -72,11 +82,6 @@ void Titlebar::paintEvent(QPaintEvent *pe) QPainter painter(this); QPalette pa; - QPen pen(QColor(0, 0, 0, 0)); - QLinearGradient linearGradient(width(), 0, width(), height()); - - linearGradient.setColorAt(0, QColor(0, 0, 0, 255 * 0.5)); //垂直线性渐变 - linearGradient.setColorAt(1, QColor(0, 0, 0, 0)); if(DataManager::instance()->getdevStatus() != NOCAM) { pa.setColor(QPalette::ButtonText, d->lightColor); @@ -84,8 +89,7 @@ void Titlebar::paintEvent(QPaintEvent *pe) } painter.setRenderHint(QPainter::Antialiasing, true); - painter.setBrush(QBrush(linearGradient)); - painter.setPen(pen); + painter.setPen(Qt::transparent); painter.drawRect(rect()); } From 68762fe844253469dc2df605958d8ec02f32599a Mon Sep 17 00:00:00 2001 From: zhanghongyuan Date: Wed, 6 Aug 2025 11:30:24 +0800 Subject: [PATCH 045/107] fix: Fix crash when enabling verbose logging Resolved an issue in v4l2_controls where premature parameter release during verbose logging caused crashes. Logging parameters should be read-only (not modified), as proper release is already handled in free_v4l2_control_list. Log: Fix verbose logging initialization crash Bug: https://pms.uniontech.com/bug-view-319497.html --- libcam/libcam_v4l2core/v4l2_controls.c | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/libcam/libcam_v4l2core/v4l2_controls.c b/libcam/libcam_v4l2core/v4l2_controls.c index bfb001d9..1f720852 100644 --- a/libcam/libcam_v4l2core/v4l2_controls.c +++ b/libcam/libcam_v4l2core/v4l2_controls.c @@ -180,32 +180,24 @@ static void print_control(v4l2_ctrl_t *control, int i) printf("\tmin:%d max:%d step:%d def:%d curr:%d\n", control->control.minimum, control->control.maximum, control->control.step, control->control.default_value, control->value); - free(control->name); - control->name=NULL; break; case V4L2_CTRL_TYPE_INTEGER64: printf("control[%d]:(int64) 0x%x '%s'\n",i ,control->control.id, control->name); printf ("\tcurr:%" PRId64 "\n", control->value64); - free(control->name); - control->name=NULL; break; case V4L2_CTRL_TYPE_STRING: printf("control[%d]:(str) 0x%x '%s'\n",i ,control->control.id, control->name); printf ("\tmin:%d max:%d step:%d curr: %s\n", control->control.minimum, control->control.maximum, - control->control.step, control->string); - free(control->name); - control->name=NULL; + control->control.step, control->string); break; case V4L2_CTRL_TYPE_BOOLEAN: printf("control[%d]:(bool) 0x%x '%s'\n",i ,control->control.id, control->name); printf ("\tdef:%d curr:%d\n", - control->control.default_value, control->value); - free(control->name); - control->name=NULL; + control->control.default_value, control->value); break; case V4L2_CTRL_TYPE_MENU: @@ -213,10 +205,8 @@ static void print_control(v4l2_ctrl_t *control, int i) printf("\tmin:%d max:%d def:%d curr:%d\n", control->control.minimum, control->control.maximum, control->control.default_value, control->value); - for (j = 0; (__s32)control->menu[j].index <= control->control.maximum; j++) + for (j = 0; (__s32)control->menu[j].index <= control->control.maximum; j++) printf("\tmenu[%d]: [%d] -> '%s'\n", j, control->menu[j].index, control->menu_entry[j]); - free(control->name); - control->name=NULL; break; case V4L2_CTRL_TYPE_INTEGER_MENU: @@ -224,18 +214,14 @@ static void print_control(v4l2_ctrl_t *control, int i) printf("\tmin:%d max:%d def:%d curr:%d\n", control->control.minimum, control->control.maximum, control->control.default_value, control->value); - for (j = 0; (__s32)control->menu[j].index <= control->control.maximum; j++) + for (j = 0; (__s32)control->menu[j].index <= control->control.maximum; j++) printf("\tmenu[%d]: [%d] -> %" PRId64 " (0x%" PRIx64 ")\n", j, control->menu[j].index, (int64_t) control->menu[j].value, (int64_t) control->menu[j].value); - free(control->name); - control->name=NULL; - break; + break; case V4L2_CTRL_TYPE_BUTTON: printf("control[%d]:(button) 0x%x '%s'\n",i ,control->control.id, control->name); - free(control->name); - control->name=NULL; break; case V4L2_CTRL_TYPE_BITMASK: @@ -249,8 +235,6 @@ static void print_control(v4l2_ctrl_t *control, int i) default: printf("control[%d]:(unknown - 0x%x) 0x%x '%s'\n",i ,control->control.type, control->control.id, control->control.name); - free(control->name); - control->name=NULL; break; } } From 3a47426534f760a638fe7e3c10e451b42758192b Mon Sep 17 00:00:00 2001 From: zhanghongyuan Date: Tue, 12 Aug 2025 11:16:23 +0800 Subject: [PATCH 046/107] fix: Improve close button visibility when USB camera is connected Fixed unclear color rendering of the camera app's window close button (top-right corner) after connecting a USB camera by triggering an additional resize event to refresh the display. Log: Fix close button display issue with USB cameras Bug: https://pms.uniontech.com/bug-view-328323.html --- src/src/mainwindow.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/src/mainwindow.cpp b/src/src/mainwindow.cpp index 6a63883e..8a3a9d18 100644 --- a/src/src/mainwindow.cpp +++ b/src/src/mainwindow.cpp @@ -1255,6 +1255,11 @@ void CMainWindow::loadAfterShow() m_windowStateThread = new windowStateThread(m_bWayland, this); connect(m_windowStateThread, &windowStateThread::someWindowFullScreen, this, &CMainWindow::onStopPhotoAndRecord); + QTimer::singleShot(100, this, [=](){ + resize(this->size() + QSize(1, 1)); + resize(this->size() + QSize(-1, -1)); + }); + QJsonObject obj{ {"tid", EventLogUtils::Start}, {"mode", 1}, From 40355231ec858dba32916f785957c28ecd0d653c Mon Sep 17 00:00:00 2001 From: zhanghongyuan Date: Fri, 15 Aug 2025 15:54:05 +0800 Subject: [PATCH 047/107] fix: Improve audio-video sync compatibility in camera recording Optimized encoding parameters by increasing GOP size and reducing encoding latency, with adjusted B-frame count for better synchronization. Log: Enhance AV sync through encoding optimization Bug: https://pms.uniontech.com/task-view-380589.html --- libcam/libcam_encoder/encoder.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libcam/libcam_encoder/encoder.c b/libcam/libcam_encoder/encoder.c index 208822ff..db9fe8fe 100644 --- a/libcam/libcam_encoder/encoder.c +++ b/libcam/libcam_encoder/encoder.c @@ -592,6 +592,8 @@ static encoder_video_context_t *encoder_video_init(encoder_context_t *encoder_ct switch (video_defaults->codec_id) { case AV_CODEC_ID_H264: { video_codec_data->codec_context->me_range = 16; + video_codec_data->codec_context->gop_size = 250; + video_codec_data->codec_context->max_b_frames = 0; //av_dict_set(&video_codec_data->private_options, "rc_lookahead", "1", 0); getAvutil()->m_av_dict_set(&video_codec_data->private_options, "crf", "23", 0); getAvutil()->m_av_dict_set(&video_codec_data->private_options, "preset", "ultrafast", 0); From 8da2bc0eaf66302df57c383cc579b3f0be39359c Mon Sep 17 00:00:00 2001 From: zhanghongyuan Date: Tue, 19 Aug 2025 16:33:13 +0800 Subject: [PATCH 048/107] fix: Filter ISP pipeline devices to show only standard cameras Added intelligent device filtering in V4L2 enumeration to exclude ISP (Image Signal Processor) pipeline devices and only expose standard user-accessible camera devices. This reduces device list clutter and improves user experience by filtering out rkcif, rkisp and other ISP-related nodes that are not directly usable. Log: Implement camera device filtering for cleaner device list Bug: https://pms.uniontech.com/task-view-380631.html --- libcam/libcam_v4l2core/v4l2_devices.c | 97 +++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/libcam/libcam_v4l2core/v4l2_devices.c b/libcam/libcam_v4l2core/v4l2_devices.c index b3b20234..2738f53e 100644 --- a/libcam/libcam_v4l2core/v4l2_devices.c +++ b/libcam/libcam_v4l2core/v4l2_devices.c @@ -124,6 +124,93 @@ static void free_device_list() my_device_list.list_devices = NULL; } +/* + * 检查设备是否为标准摄像头设备 + * args: + * fd - 设备文件描述符 + * v4l2_cap - 设备能力结构体 + * device_path - 设备节点路径 (如 /dev/video0) + * + * returns: 1 if standard camera, 0 if not + */ +static int is_standard_camera_device(int fd, struct v4l2_capability *cap, const char *device_path) +{ + struct v4l2_fmtdesc fmt; + int has_standard_format = 0; + + // 1. 检查是否支持标准用户级视频格式 + memset(&fmt, 0, sizeof(fmt)); + fmt.index = 0; + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + // 标准视频格式列表 + static const uint32_t standard_formats[] = { + V4L2_PIX_FMT_MJPEG, // Motion-JPEG + V4L2_PIX_FMT_YUYV, // YUYV 4:2:2 + V4L2_PIX_FMT_H264, // H.264 + V4L2_PIX_FMT_UYVY, // UYVY 4:2:2 + V4L2_PIX_FMT_NV12, // Y/UV 4:2:0 + V4L2_PIX_FMT_NV21, // Y/VU 4:2:0 + V4L2_PIX_FMT_YUV420 // YUV 4:2:0 + }; + static const int num_standard_formats = sizeof(standard_formats) / sizeof(standard_formats[0]); + + while (xioctl(fd, VIDIOC_ENUM_FMT, &fmt) == 0) { + // 检查是否支持标准格式 + for (int i = 0; i < num_standard_formats; i++) { + if (fmt.pixelformat == standard_formats[i]) { + has_standard_format = 1; + break; + } + } + if (has_standard_format) { + break; // 找到标准格式后立即退出 + } + fmt.index++; + } + + // 2. 检查设备驱动和名称,过滤ISP设备 + static const char* isp_driver_keywords[] = { + "rkcif", "rkisp" + }; + static const char* isp_card_keywords[] = { + "rkisp", "rkcif", "statistics", "mainpath", "selfpath" + }; + static const int num_driver_keywords = sizeof(isp_driver_keywords) / sizeof(isp_driver_keywords[0]); + static const int num_card_keywords = sizeof(isp_card_keywords) / sizeof(isp_card_keywords[0]); + + int is_isp_device = 0; + + // 检查驱动名称 + for (int i = 0; i < num_driver_keywords && !is_isp_device; i++) { + if (strstr((char *)cap->driver, isp_driver_keywords[i]) != NULL) { + is_isp_device = 1; + } + } + + // 检查card名称 + for (int i = 0; i < num_card_keywords && !is_isp_device; i++) { + if (strstr((char *)cap->card, isp_card_keywords[i]) != NULL) { + is_isp_device = 1; + } + } + + // 3. 可以添加更多过滤条件 + // 检查是否为UVC驱动(标准USB摄像头) + int is_uvc_device = (strstr((char *)cap->driver, "uvcvideo") != NULL); + + // 4. 检查总线信息(USB设备通常包含"usb") + int is_usb_device = (strstr((char *)cap->bus_info, "usb") != NULL); + + if (verbosity > 1) { + printf("V4L2_CORE: Device check - %s [%s]: standard_fmt=%d, is_isp=%d, is_uvc=%d, is_usb=%d\n", + device_path, cap->card, has_standard_format, is_isp_device, is_uvc_device, is_usb_device); + } + + // 返回判断结果:有标准格式且不是ISP设备 + return (has_standard_format && !is_isp_device); +} + /* * enumerate available v4l2 devices * and creates list in vd->list_devices @@ -226,6 +313,16 @@ int enum_v4l2_devices() getV4l2()->m_v4l2_close(fd); continue; /*next dir entry*/ } + + // 检查是否为标准摄像头设备,过滤掉ISP管道设备 + if (!is_standard_camera_device(fd, &v4l2_cap, v4l2_device)) { + if (verbosity > 0) { + fprintf(stderr, "V4L2_CORE: ignore device %s - not a standard camera (driver: %s, card: %s)\n", + v4l2_device, v4l2_cap.driver, v4l2_cap.card); + } + getV4l2()->m_v4l2_close(fd); + continue; /*next dir entry*/ + } #endif getV4l2()->m_v4l2_close(fd); From 39d630b9800d0e82bc6627ac65449a871711b0a4 Mon Sep 17 00:00:00 2001 From: zhanghongyuan Date: Thu, 21 Aug 2025 09:18:44 +0800 Subject: [PATCH 049/107] fix: Add project-specific customization Implemented customized configuration for project-specific adaptations. Log: Add project customization support Bug: https://pms.uniontech.com/bug-view-380631.html --- src/assets/org.deepin.camera.encode.json | 56 ++++++++++++++---------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/src/assets/org.deepin.camera.encode.json b/src/assets/org.deepin.camera.encode.json index 592dc587..89db1c9b 100644 --- a/src/assets/org.deepin.camera.encode.json +++ b/src/assets/org.deepin.camera.encode.json @@ -1,26 +1,36 @@ { - "magic": "dsg.config.meta", - "version": "1.0", - "contents": { - "mp4EncodeMode": { - "value": -1, - "serial": 0, - "flags": ["global"], - "name": "pugx mp4 code mode", - "name[zh_CN]": "特殊编码模式", - "description": "pugx mp4 code mode", - "permissions": "readwrite", - "visibility": "private" - }, - "forceGles": { - "value": -1, - "serial": 0, - "flags": ["global"], - "name": "forc elgs show in wayland", - "name[zh_CN]": "在 wayland 下特殊显示模式", - "description": "special mode do use gles to show", - "permissions": "readwrite", - "visibility": "private" + "magic": "dsg.config.meta", + "version": "1.0", + "contents": { + "mp4EncodeMode": { + "value": -1, + "serial": 0, + "flags": ["global"], + "name": "pugx mp4 code mode", + "name[zh_CN]": "特殊编码模式", + "description": "pugx mp4 code mode", + "permissions": "readwrite", + "visibility": "private" + }, + "forceGles": { + "value": -1, + "serial": 0, + "flags": ["global"], + "name": "forc elgs show in wayland", + "name[zh_CN]": "在 wayland 下特殊显示模式", + "description": "special mode do use gles to show", + "permissions": "readwrite", + "visibility": "private" + }, + "projectID": { + "value": "", + "serial": 0, + "flags": ["global"], + "name": "project ID", + "name[zh_CN]": "不同项目下的定制内容", + "description": "Customized content under different projects", + "permissions": "readwrite", + "visibility": "private" + } } - } } \ No newline at end of file From 24f08d1004f0470d9dc758620d87e1d2baee2421 Mon Sep 17 00:00:00 2001 From: zhanghongyuan Date: Thu, 21 Aug 2025 16:10:15 +0800 Subject: [PATCH 050/107] fix: Optimize ISP device filtering for better camera compatibility Implemented intelligent ISP device filtering to improve camera device compatibility: - Keep useful ISP output devices (mainpath) that support standard video formats - Filter out problematic devices (/dev/video12) with hardware issues - Remove useless ISP pipeline nodes (statistics, params, selfpath) - Add detailed logging for device filtering decisions This ensures better camera enumeration while maintaining support for advanced hardware features like NV12 encoding on ISP devices. Log: Optimize camera device filtering with intelligent ISP handling Bug: @https://pms.uniontech.com/task-view-380629.html --- libcam/libcam_v4l2core/v4l2_devices.c | 37 ++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/libcam/libcam_v4l2core/v4l2_devices.c b/libcam/libcam_v4l2core/v4l2_devices.c index 2738f53e..bb661274 100644 --- a/libcam/libcam_v4l2core/v4l2_devices.c +++ b/libcam/libcam_v4l2core/v4l2_devices.c @@ -29,6 +29,7 @@ #include #include +#include "camview.h" #include "gviewv4l2core.h" #include "v4l2_devices.h" #include "cameraconfig.h" @@ -206,9 +207,39 @@ static int is_standard_camera_device(int fd, struct v4l2_capability *cap, const printf("V4L2_CORE: Device check - %s [%s]: standard_fmt=%d, is_isp=%d, is_uvc=%d, is_usb=%d\n", device_path, cap->card, has_standard_format, is_isp_device, is_uvc_device, is_usb_device); } - - // 返回判断结果:有标准格式且不是ISP设备 - return (has_standard_format && !is_isp_device); + + // 5. 智能ISP设备处理:保留有用的ISP输出设备 + int is_useful_isp = 0; + if (is_isp_device) { + // 专门过滤有问题的设备:/dev/video12 (selfpath有底层问题) + if (strstr((char *)device_path, "/dev/video12") != NULL) { + if (verbosity > 1) { + printf("V4L2_CORE: Filtering problematic device: %s [%s] - hardware issue\n", device_path, cap->card); + } + return 0; // 明确过滤video12 + } + + // 检查是否为有用的ISP输出设备(只保留mainpath,不要selfpath) + if (strstr((char *)cap->card, "mainpath") != NULL) { + is_useful_isp = 1; + if (verbosity > 1) { + printf("V4L2_CORE: Keeping useful ISP device: %s [%s]\n", device_path, cap->card); + } + } + + // 过滤无用的ISP设备(统计、参数、selfpath等) + if (strstr((char *)cap->card, "statistics") != NULL || + strstr((char *)cap->card, "params") != NULL || + strstr((char *)cap->card, "selfpath") != NULL) { + if (verbosity > 1) { + printf("V4L2_CORE: Filtering useless ISP device: %s [%s]\n", device_path, cap->card); + } + return 0; // 明确过滤 + } + } + + // 返回判断结果:有标准格式且(不是ISP设备 或 是有用的ISP设备) + return (has_standard_format && (!is_isp_device || is_useful_isp)); } /* From 12019b294dbed9b38dee1482dd4519c43fef7f70 Mon Sep 17 00:00:00 2001 From: zhanghongyuan Date: Fri, 22 Aug 2025 11:45:46 +0800 Subject: [PATCH 051/107] feat: Add project-specific device filtering control - Add projectID configuration support in main.cpp * Read projectID from DConfig configuration * Initialize project_id via set_project_id() function - Implement project_id management functions in camview * Add set_project_id() and get_project_id() in camview.h/c * Use safe string operations with boundary checks * Store project_id in static buffer for global access - Add conditional device filtering in v4l2_devices.c * Enable ISP device filtering only when projectID="UOS2025073011543" * Maintain backward compatibility for other configurations * Enhance logging with project_id information Log: This allows project-specific control of camera device filtering Task: https://pms.uniontech.com/task-view-380629.html --- libcam/libcam/camview.c | 16 +++++ libcam/libcam/camview.h | 25 ++++++++ libcam/libcam_v4l2core/v4l2_devices.c | 17 +++--- src/main.cpp | 84 ++++++++++++++------------- 4 files changed, 96 insertions(+), 46 deletions(-) diff --git a/libcam/libcam/camview.c b/libcam/libcam/camview.c index 345ea311..e6e25ad4 100644 --- a/libcam/libcam/camview.c +++ b/libcam/libcam/camview.c @@ -114,6 +114,7 @@ static char status_message[80]; static int encode_thread_running = 0; +static char project_id[200]; void set_video_time_capture(double video_time) { @@ -1382,3 +1383,18 @@ int get_pugx_status() { return is_pgux; } + +void set_project_id(const char *id) +{ + if (id != NULL) { + memset(project_id, 0, sizeof(project_id)); + strncpy(project_id, id, sizeof(project_id) - 1); + } else { + memset(project_id, 0, sizeof(project_id)); + } +} + +const char* get_project_id(void) +{ + return project_id; +} diff --git a/libcam/libcam/camview.h b/libcam/libcam/camview.h index e0e7e471..a58df781 100644 --- a/libcam/libcam/camview.h +++ b/libcam/libcam/camview.h @@ -34,6 +34,7 @@ extern "C" { #define VERTEXIN 0 #define TEXTUREIN 1 +#define UOS2025073011543 "UOS2025073011543" typedef struct _capture_loop_data_t { void *options; void *config; @@ -439,6 +440,30 @@ void set_forceGles(int status); int is_forceGles(); +/* + * set project id + * args: + * project_id - project id string + * + * asserts: + * none + * + * returns: none + */ +void set_project_id(const char *project_id); + +/* + * get project id + * args: + * none + * + * asserts: + * none + * + * returns: pointer to project id string + */ +const char* get_project_id(void); + #ifdef __cplusplus } #endif diff --git a/libcam/libcam_v4l2core/v4l2_devices.c b/libcam/libcam_v4l2core/v4l2_devices.c index bb661274..5fe2cf5b 100644 --- a/libcam/libcam_v4l2core/v4l2_devices.c +++ b/libcam/libcam_v4l2core/v4l2_devices.c @@ -345,14 +345,17 @@ int enum_v4l2_devices() continue; /*next dir entry*/ } - // 检查是否为标准摄像头设备,过滤掉ISP管道设备 - if (!is_standard_camera_device(fd, &v4l2_cap, v4l2_device)) { - if (verbosity > 0) { - fprintf(stderr, "V4L2_CORE: ignore device %s - not a standard camera (driver: %s, card: %s)\n", - v4l2_device, v4l2_cap.driver, v4l2_cap.card); + // when project_id equals UOS2025073011543 filter out ISP devices + const char* current_project_id = get_project_id(); + if (current_project_id != NULL && strcmp(current_project_id, UOS2025073011543) == 0) { + if (!is_standard_camera_device(fd, &v4l2_cap, v4l2_device)) { + if (verbosity > 0) { + fprintf(stderr, "V4L2_CORE: ignore device %s - not a standard camera (driver: %s, card: %s) [project_id: %s]\n", + v4l2_device, v4l2_cap.driver, v4l2_cap.card, current_project_id); + } + getV4l2()->m_v4l2_close(fd); + continue; /*next dir entry*/ } - getV4l2()->m_v4l2_close(fd); - continue; /*next dir entry*/ } #endif getV4l2()->m_v4l2_close(fd); diff --git a/src/main.cpp b/src/main.cpp index c2d55738..b3bdb187 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -121,51 +121,57 @@ int main(int argc, char *argv[]) format.setRenderableType(QSurfaceFormat::OpenGLES); format.setDefaultFormat(format); set_wayland_status(1); - - int mp4Encode = -1; + } + int mp4Encode = -1; #ifdef DTKCORE_CLASS_DConfigFile - //需要查询是否对X机型设置MP4编码缓存特殊处理 - DConfig *dconfig = DConfig::create("org.deepin.camera", "org.deepin.camera.encode"); - if (dconfig && dconfig->isValid() && dconfig->keyList().contains("mp4EncodeMode")) { - mp4Encode = dconfig->value("mp4EncodeMode").toInt(); - set_pugx_status(mp4Encode); - } + //需要查询是否对X机型设置MP4编码缓存特殊处理 + DConfig *dconfig = DConfig::create("org.deepin.camera", "org.deepin.camera.encode"); + if (dconfig && dconfig->isValid() && dconfig->keyList().contains("mp4EncodeMode")) { + mp4Encode = dconfig->value("mp4EncodeMode").toInt(); + set_pugx_status(mp4Encode); + } - int forceGles = -1; - if (dconfig && dconfig->isValid() && dconfig->keyList().contains("forceGles")) { - forceGles = dconfig->value("forceGles").toInt(); - set_forceGles(forceGles); - } + int forceGles = -1; + if (dconfig && dconfig->isValid() && dconfig->keyList().contains("forceGles")) { + forceGles = dconfig->value("forceGles").toInt(); + set_forceGles(forceGles); + } + + QString projectId = ""; + if (dconfig && dconfig->isValid() && dconfig->keyList().contains("projectID")) { + projectId = dconfig->value("projectID").toString(); + set_project_id(projectId.toUtf8().constData()); + } #endif - qInfo() << "mp4EncodeMode value is:" << get_pugx_status(); - if (mp4Encode == -1) { - //判断是否是X机型 - QStringList options; - options << QString(QStringLiteral("-c")); - options << QString(QStringLiteral("dmidecode -t 11 | grep 'String 4' | awk '{print $NF}' && " - "dmidecode -s system-product-name|awk '{print $NF}'")); - QProcess process; - process.start(QString(QStringLiteral("bash")), options); - process.waitForFinished(); - process.waitForReadyRead(); - QByteArray tempArray = process.readAllStandardOutput(); - char *charTemp = tempArray.data(); - QString str_output = QString(QLatin1String(charTemp)); - process.close(); - - if (str_output.contains("PGUX", Qt::CaseInsensitive)) { - mp4Encode = 1; - qDebug() << "this is PGUX"; - } else { - mp4Encode = 0; - } - qInfo() << "process find mp4EncodeMode value is:" << get_pugx_status(); + qInfo() << "mp4EncodeMode value is:" << get_pugx_status(); + qInfo() << "projectID value is:" << get_project_id(); + if (mp4Encode == -1) { + //判断是否是X机型 + QStringList options; + options << QString(QStringLiteral("-c")); + options << QString(QStringLiteral("dmidecode -t 11 | grep 'String 4' | awk '{print $NF}' && " + "dmidecode -s system-product-name|awk '{print $NF}'")); + QProcess process; + process.start(QString(QStringLiteral("bash")), options); + process.waitForFinished(); + process.waitForReadyRead(); + QByteArray tempArray = process.readAllStandardOutput(); + char *charTemp = tempArray.data(); + QString str_output = QString(QLatin1String(charTemp)); + process.close(); + + if (str_output.contains("PGUX", Qt::CaseInsensitive)) { + mp4Encode = 1; + qDebug() << "this is PGUX"; + } else { + mp4Encode = 0; } - - set_pugx_status(mp4Encode); - qInfo() << "last mp4EncodeMode value is:" << get_pugx_status(); + qInfo() << "process find mp4EncodeMode value is:" << get_pugx_status(); } + set_pugx_status(mp4Encode); + qInfo() << "last mp4EncodeMode value is:" << get_pugx_status(); + QTime time; time.start(); QString lutDir = LUT_DIR; From dcaa41286f37e8fcab6f370a4a41adb41631e78f Mon Sep 17 00:00:00 2001 From: zhanghongyuan Date: Sat, 11 Oct 2025 11:34:31 +0800 Subject: [PATCH 052/107] feat: Add hardware acceleration driver configuration options - Added `libVaDriverName` configuration for VAAPI hardware codec support (LIBVA_DRIVER_NAME environment variable) - Added `libVdpauDriver` configuration for VDPAU hardware codec support (VDPAU_DRIVER environment variable) - Both configurations support global read-write permissions with Chinese localization Log: Add hardware acceleration driver settings Bug: https://pms.uniontech.com/bug-view-335297.html --- src/assets/org.deepin.camera.encode.json | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/assets/org.deepin.camera.encode.json b/src/assets/org.deepin.camera.encode.json index 89db1c9b..a49e067b 100644 --- a/src/assets/org.deepin.camera.encode.json +++ b/src/assets/org.deepin.camera.encode.json @@ -31,6 +31,26 @@ "description": "Customized content under different projects", "permissions": "readwrite", "visibility": "private" + }, + "libVaDriverName": { + "value": "", + "serial": 0, + "flags": ["global"], + "name": "libVa driver name", + "name[zh_CN]": "启用VAAPI硬件编解码的驱动名称,配置环境变量LIBVA_DRIVER_NAME,如LIBVA_DRIVER_NAME=zx", + "description": "Name of the VAAPI driver for enabling hardware codec", + "permissions": "readwrite", + "visibility": "private" + }, + "libVdpauDriver": { + "value": "", + "serial": 0, + "flags": ["global"], + "name": "lib vdpau driver", + "name[zh_CN]": "启用VDPAU硬件编解码的驱动名称,配置环境变量VDPAU_DRIVER,如VDPAU_DRIVER=nvidia_vdpau", + "description": "Name of the VDPAU driver for enabling hardware codec", + "permissions": "readwrite", + "visibility": "private" } } -} \ No newline at end of file +} From 973d0cc7d7359c59955a19104c0d7dbb447bcd9c Mon Sep 17 00:00:00 2001 From: zhanghongyuan Date: Sat, 11 Oct 2025 14:06:03 +0800 Subject: [PATCH 053/107] feat: Implement hardware acceleration driver configuration support - Added set/get functions for LIBVA_DRIVER_NAME and VDPAU_DRIVER environment variables - Integrated driver configuration loading from dconfig settings during application startup - Set environment variables for VAAPI and VDPAU hardware codec acceleration - Enhanced configuration file with corrected parameter names and descriptions - Added debug logging for driver configuration values and environment variables Log: Add hardware acceleration driver configuration support Bug: https://pms.uniontech.com/bug-view-335297.html --- libcam/libcam/camview.c | 34 +++++++++++++++++ libcam/libcam/camview.h | 48 ++++++++++++++++++++++++ src/assets/org.deepin.camera.encode.json | 4 +- src/main.cpp | 24 ++++++++++++ 4 files changed, 108 insertions(+), 2 deletions(-) diff --git a/libcam/libcam/camview.c b/libcam/libcam/camview.c index e6e25ad4..92ab1240 100644 --- a/libcam/libcam/camview.c +++ b/libcam/libcam/camview.c @@ -108,6 +108,10 @@ static int statusForceGles = 0; //forceGles 1,强走GLES static int is_pgux = 0; //是否是pugx +static char libva_driver_name[200]; + +static char libvdpau_driver_name[200]; + static uint8_t soundTakePhoto = 1;//拍照声音提示 static char status_message[80]; @@ -1398,3 +1402,33 @@ const char* get_project_id(void) { return project_id; } + +void set_libva_driver_name(const char *name) +{ + if (name != NULL) { + memset(libva_driver_name, 0, sizeof(libva_driver_name)); + strncpy(libva_driver_name, name, sizeof(libva_driver_name) - 1); + } else { + memset(libva_driver_name, 0, sizeof(libva_driver_name)); + } +} + +const char* get_libva_driver_name(void) +{ + return libva_driver_name; +} + +void set_libvdpau_driver_name(const char *name) +{ + if (name != NULL) { + memset(libvdpau_driver_name, 0, sizeof(libvdpau_driver_name)); + strncpy(libvdpau_driver_name, name, sizeof(libvdpau_driver_name) - 1); + } else { + memset(libvdpau_driver_name, 0, sizeof(libvdpau_driver_name)); + } +} + +const char* get_libvdpau_driver_name(void) +{ + return libvdpau_driver_name; +} diff --git a/libcam/libcam/camview.h b/libcam/libcam/camview.h index a58df781..7d2d18ef 100644 --- a/libcam/libcam/camview.h +++ b/libcam/libcam/camview.h @@ -464,6 +464,54 @@ void set_project_id(const char *project_id); */ const char* get_project_id(void); +/* + * set libva driver name + * args: + * name - libva driver name string + * + * asserts: + * none + * + * returns: none + */ +void set_libva_driver_name(const char *name); + +/* + * get libva driver name + * args: + * none + * + * asserts: + * none + * + * returns: pointer to libva driver name string + */ +const char* get_libva_driver_name(void); + +/* + * set libvdpau driver name + * args: + * name - libvdpau driver name string + * + * asserts: + * none + * + * returns: none + */ +void set_libvdpau_driver_name(const char *name); + +/* + * get libvdpau driver name + * args: + * none + * + * asserts: + * none + * + * returns: pointer to libvdpau driver name string + */ +const char* get_libvdpau_driver_name(void); + #ifdef __cplusplus } #endif diff --git a/src/assets/org.deepin.camera.encode.json b/src/assets/org.deepin.camera.encode.json index a49e067b..fe01c2d3 100644 --- a/src/assets/org.deepin.camera.encode.json +++ b/src/assets/org.deepin.camera.encode.json @@ -36,7 +36,7 @@ "value": "", "serial": 0, "flags": ["global"], - "name": "libVa driver name", + "name": "libva driver name", "name[zh_CN]": "启用VAAPI硬件编解码的驱动名称,配置环境变量LIBVA_DRIVER_NAME,如LIBVA_DRIVER_NAME=zx", "description": "Name of the VAAPI driver for enabling hardware codec", "permissions": "readwrite", @@ -46,7 +46,7 @@ "value": "", "serial": 0, "flags": ["global"], - "name": "lib vdpau driver", + "name": "vdpau driver", "name[zh_CN]": "启用VDPAU硬件编解码的驱动名称,配置环境变量VDPAU_DRIVER,如VDPAU_DRIVER=nvidia_vdpau", "description": "Name of the VDPAU driver for enabling hardware codec", "permissions": "readwrite", diff --git a/src/main.cpp b/src/main.cpp index b3bdb187..8088e2e7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -142,9 +142,33 @@ int main(int argc, char *argv[]) projectId = dconfig->value("projectID").toString(); set_project_id(projectId.toUtf8().constData()); } + + QString libVaDriverName = ""; + if (dconfig && dconfig->isValid() && dconfig->keyList().contains("libVaDriverName")) { + libVaDriverName = dconfig->value("libVaDriverName").toString(); + set_libva_driver_name(libVaDriverName.toUtf8().constData()); + } + + QString libVdpauDriverName = ""; + if (dconfig && dconfig->isValid() && dconfig->keyList().contains("libVdpauDriver")) { + libVdpauDriverName = dconfig->value("libVdpauDriver").toString(); + set_libvdpau_driver_name(libVdpauDriverName.toUtf8().constData()); + } + + if (!libVaDriverName.isEmpty()) { + qputenv("LIBVA_DRIVER_NAME", libVaDriverName.toLocal8Bit()); + } + + if (!libVdpauDriverName.isEmpty()) { + qputenv("VDPAU_DRIVER", libVdpauDriverName.toLocal8Bit()); + } #endif qInfo() << "mp4EncodeMode value is:" << get_pugx_status(); qInfo() << "projectID value is:" << get_project_id(); + qInfo() << "libVaDriverName value is:" << get_libva_driver_name(); + qInfo() << "libVdpauDriverName value is:" << get_libvdpau_driver_name(); + qInfo() << "LIBVA_DRIVER_NAME value is:" << qgetenv("LIBVA_DRIVER_NAME"); + qInfo() << "VDPAU_DRIVER value is:" << qgetenv("VDPAU_DRIVER"); if (mp4Encode == -1) { //判断是否是X机型 QStringList options; From 69d8574a0f938f8a71b1ae877b4637a9487cf253 Mon Sep 17 00:00:00 2001 From: zhanghongyuan Date: Sat, 11 Oct 2025 15:09:51 +0800 Subject: [PATCH 054/107] feat: Add VA-API hardware acceleration for MJPEG decoding Integrated VA-API hardware decoding support for MJPEG streams alongside existing software decoding. The implementation automatically falls back to software decoding if hardware acceleration is unavailable, maintaining backward compatibility while improving performance through GPU-accelerated video processing. Log: Enable VA-API hardware acceleration for JPEG decoding Bug: https://pms.uniontech.com/bug-view-335297.html --- libcam/libcam/camview.c | 16 ++ libcam/libcam/camview.h | 12 ++ libcam/libcam_v4l2core/jpeg_decoder.c | 299 +++++++++++++++++--------- src/src/basepub/load_libs.c | 4 + src/src/basepub/load_libs.h | 6 + 5 files changed, 232 insertions(+), 105 deletions(-) diff --git a/libcam/libcam/camview.c b/libcam/libcam/camview.c index 92ab1240..e03445ff 100644 --- a/libcam/libcam/camview.c +++ b/libcam/libcam/camview.c @@ -1432,3 +1432,19 @@ const char* get_libvdpau_driver_name(void) { return libvdpau_driver_name; } + +int is_driver_available(const char *driver_name) +{ + /* Check if driver name is not NULL, not empty, and not "none" or similar invalid values */ + if (driver_name != NULL && + driver_name[0] != '\0' && + strcmp(driver_name, "none") != 0 && + strcmp(driver_name, "null") != 0 && + strcmp(driver_name, "invalid") != 0 && + strcmp(driver_name, "undefined") != 0 && + strcmp(driver_name, "unknown") != 0) { + return 1; /* Valid driver exists */ + } + + return 0; /* No valid driver */ +} diff --git a/libcam/libcam/camview.h b/libcam/libcam/camview.h index 7d2d18ef..506b8245 100644 --- a/libcam/libcam/camview.h +++ b/libcam/libcam/camview.h @@ -512,6 +512,18 @@ void set_libvdpau_driver_name(const char *name); */ const char* get_libvdpau_driver_name(void); +/* + * check if driver is available and valid + * args: + * driver_name - pointer to driver name string + * + * asserts: + * none + * + * returns: 1 if valid driver exists, 0 otherwise + */ +int is_driver_available(const char *driver_name); + #ifdef __cplusplus } #endif diff --git a/libcam/libcam_v4l2core/jpeg_decoder.c b/libcam/libcam_v4l2core/jpeg_decoder.c index 072b9616..79b6350b 100644 --- a/libcam/libcam_v4l2core/jpeg_decoder.c +++ b/libcam/libcam_v4l2core/jpeg_decoder.c @@ -37,6 +37,7 @@ #include #include +#include "camview.h" #include "gviewv4l2core.h" #include "colorspaces.h" #include "frame_decoder.h" @@ -1356,9 +1357,11 @@ void jpeg_close_decoder() typedef struct _codec_data_t { - AVCodec *codec; - AVCodecContext *context; - AVFrame *picture; + AVCodec *codec; + AVCodecContext *context; + AVFrame *picture; + AVBufferRef *hw_device_ctx; // hardware device context + enum AVPixelFormat hw_pix_fmt; // hardware pixel format } codec_data_t; /* @@ -1378,73 +1381,114 @@ int jpeg_init_decoder(int width, int height) getLoadLibsInstance()->m_avcodec_init(); #endif #if !LIBAVCODEC_VER_AT_LEAST(58,9) - /* - * register all the codecs (we can also register only the codec - * we wish to have smaller code) - */ + /* + * register all the codecs (we can also register only the codec + * we wish to have smaller code) + */ getLoadLibsInstance()->m_avcodec_register_all(); #endif getAvutil()->m_av_log_set_level(AV_LOG_PANIC); - if(jpeg_ctx != NULL) - jpeg_close_decoder(); + if(jpeg_ctx != NULL) + jpeg_close_decoder(); - jpeg_ctx = calloc(1, sizeof(jpeg_decoder_context_t)); - if(jpeg_ctx == NULL) - { - fprintf(stderr, "V4L2_CORE: FATAL memory allocation failure (jpeg_init_decoder): %s\n", strerror(errno)); - exit(-1); - } + jpeg_ctx = calloc(1, sizeof(jpeg_decoder_context_t)); + if(jpeg_ctx == NULL) + { + fprintf(stderr, "V4L2_CORE: FATAL memory allocation failure (jpeg_init_decoder): %s\n", strerror(errno)); + exit(-1); + } - codec_data_t *codec_data = calloc(1, sizeof(codec_data_t)); - if(codec_data == NULL) - { - fprintf(stderr, "V4L2_CORE: FATAL memory allocation failure (jpeg_init_decoder): %s\n", strerror(errno)); - exit(-1); - } + codec_data_t *codec_data = calloc(1, sizeof(codec_data_t)); + if(codec_data == NULL) + { + fprintf(stderr, "V4L2_CORE: FATAL memory allocation failure (jpeg_init_decoder): %s\n", strerror(errno)); + exit(-1); + } codec_data->codec = getLoadLibsInstance()->m_avcodec_find_decoder(AV_CODEC_ID_MJPEG); - if(!codec_data->codec) - { - fprintf(stderr, "V4L2_CORE: (mjpeg decoder) codec not found\n"); - free(jpeg_ctx); - free(codec_data); - jpeg_ctx = NULL; - return E_NO_CODEC; - } + if(!codec_data->codec) + { + fprintf(stderr, "V4L2_CORE: (mjpeg decoder) codec not found\n"); + free(jpeg_ctx); + free(codec_data); + jpeg_ctx = NULL; + return E_NO_CODEC; + } #if LIBAVCODEC_VER_AT_LEAST(53,6) codec_data->context = getLoadLibsInstance()->m_avcodec_alloc_context3(codec_data->codec); - getLoadLibsInstance()->m_avcodec_get_context_defaults3 && getLoadLibsInstance()->m_avcodec_get_context_defaults3 (codec_data->context, codec_data->codec); + getLoadLibsInstance()->m_avcodec_get_context_defaults3 && getLoadLibsInstance()->m_avcodec_get_context_defaults3 (codec_data->context, codec_data->codec); #else - codec_data->context = getLoadLibsInstance()->m_avcodec_alloc_context(); - getLoadLibsInstance()->m_avcodec_get_context_defaults(codec_data->context); + codec_data->dec_ctx = getLoadLibsInstance()->m_avcodec_alloc_context(); + getLoadLibsInstance()->m_avcodec_get_context_defaults(codec_data->dec_ctx); #endif - if(codec_data->context == NULL) - { - fprintf(stderr, "V4L2_CORE: FATAL memory allocation failure (h264_init_decoder): %s\n", strerror(errno)); - exit(-1); - } - - codec_data->context->pix_fmt = AV_PIX_FMT_YUV422P; - codec_data->context->width = width; - codec_data->context->height = height; - //jpeg_ctx->context->dsp_mask = (FF_MM_MMX | FF_MM_MMXEXT | FF_MM_SSE); + if(codec_data->context == NULL) + { + fprintf(stderr, "V4L2_CORE: FATAL memory allocation failure (h264_init_decoder): %s\n", strerror(errno)); + exit(-1); + } + + codec_data->context->pix_fmt = AV_PIX_FMT_YUV422P; + codec_data->context->width = width; + codec_data->context->height = height; + //jpeg_ctx->context->dsp_mask = (FF_MM_MMX | FF_MM_MMXEXT | FF_MM_SSE); + + // Initialize hardware device context (VA-API) + if (is_driver_available(get_libva_driver_name())) { + int ret = getAvutil()->m_av_hwdevice_ctx_create(&codec_data->hw_device_ctx, AV_HWDEVICE_TYPE_VAAPI, NULL, NULL, 0); + if (ret < 0) { + fprintf(stderr, "V4L2_CORE: Unable to create VA-API hardware context\n"); + // If hardware decoding initialization fails, continue using software decoding + codec_data->hw_device_ctx = NULL; + } else { + codec_data->context->hw_device_ctx = getAvutil()->m_av_buffer_ref(codec_data->hw_device_ctx); + + // Check whether the decoder supports JPEG hardware acceleration + int ret = -1; + for (int i = 0;; i++) { + const AVCodecHWConfig *config = getLoadLibsInstance()->m_avcodec_get_hw_config(codec_data->codec, i); + if (!config) break; + + if (config->device_type == AV_HWDEVICE_TYPE_VAAPI && + config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX) { + codec_data->hw_pix_fmt = config->pix_fmt; + ret = 0; + fprintf(stderr, "V4L2_CORE: (mjpeg decoder) Find supported VA-API hardware acceleration configurations\n"); + break; + } + } + if (ret < 0) { + fprintf(stderr, "V4L2_CORE: (mjpeg decoder) The decoder does not support VA-API JPEG hardware acceleration and will use software decoding\n"); + // Cleaning up hardware device context + if (codec_data->hw_device_ctx) { + getAvutil()->m_av_buffer_unref(&codec_data->hw_device_ctx); + codec_data->hw_device_ctx = NULL; + } + } else { + fprintf(stderr, "V4L2_CORE: (mjpeg decoder) Use VA-API hardware acceleration, pixel format: %s\n", + getAvutil()->m_av_get_pix_fmt_name(codec_data->hw_pix_fmt)); + } + } + } #if LIBAVCODEC_VER_AT_LEAST(53,6) if (getLoadLibsInstance()->m_avcodec_open2(codec_data->context, codec_data->codec, NULL) < 0) #else - if (getLoadLibsInstance()->m_avcodec_open(codec_data->context, codec_data->codec) < 0) + if (getLoadLibsInstance()->m_avcodec_open(codec_data->dec_ctx, codec_data->codec) < 0) #endif - { - fprintf(stderr, "V4L2_CORE: (mjpeg decoder) couldn't open codec\n"); + { + fprintf(stderr, "V4L2_CORE: (mjpeg decoder) couldn't open codec\n"); + if (codec_data->hw_device_ctx) { + getAvutil()->m_av_buffer_unref(&codec_data->hw_device_ctx); + } getLoadLibsInstance()->m_avcodec_close(codec_data->context); - free(codec_data->context); - free(codec_data); - free(jpeg_ctx); - jpeg_ctx = NULL; - return E_NO_CODEC; - } + free(codec_data->context); + free(codec_data); + free(jpeg_ctx); + jpeg_ctx = NULL; + return E_NO_CODEC; + } #if LIBAVCODEC_VER_AT_LEAST(55,28) codec_data->picture = getAvutil()->m_av_frame_alloc(); @@ -1454,23 +1498,23 @@ int jpeg_init_decoder(int width, int height) getLoadLibsInstance()->m_avcodec_get_frame_defaults(codec_data->picture); #endif - /*alloc temp buffer*/ + /*alloc temp buffer*/ jpeg_ctx->tmp_frame = calloc((size_t)(width*height*2), sizeof(uint8_t)); - if(jpeg_ctx->tmp_frame == NULL) - { - fprintf(stderr, "V4L2_CORE: FATAL memory allocation failure (jpeg_init_decoder): %s\n", strerror(errno)); - exit(-1); - } + if(jpeg_ctx->tmp_frame == NULL) + { + fprintf(stderr, "V4L2_CORE: FATAL memory allocation failure (jpeg_init_decoder): %s\n", strerror(errno)); + exit(-1); + } #if LIBAVUTIL_VER_AT_LEAST(54,6) jpeg_ctx->pic_size = getAvutil()->m_av_image_get_buffer_size(codec_data->context->pix_fmt, width, height, 1); #else - jpeg_ctx->pic_size = avpicture_get_size(codec_data->context->pix_fmt, width, height); + jpeg_ctx->pic_size = avpicture_get_size(codec_data->dec_ctx->pix_fmt, width, height); #endif - jpeg_ctx->width = width; - jpeg_ctx->height = height; - jpeg_ctx->codec_data = codec_data; + jpeg_ctx->width = width; + jpeg_ctx->height = height; + jpeg_ctx->codec_data = codec_data; - return E_OK; + return E_OK; } /* @@ -1489,39 +1533,79 @@ int jpeg_init_decoder(int width, int height) */ int jpeg_decode(uint8_t *out_buf, uint8_t *in_buf, int size) { - /*asserts*/ - assert(jpeg_ctx != NULL); - assert(in_buf != NULL); - assert(out_buf != NULL); + /*asserts*/ + assert(jpeg_ctx != NULL); + assert(in_buf != NULL); + assert(out_buf != NULL); - AVPacket avpkt; + AVPacket avpkt; getLoadLibsInstance()->m_av_init_packet(&avpkt); - avpkt.size = size; - avpkt.data = in_buf; - - codec_data_t *codec_data = (codec_data_t *) jpeg_ctx->codec_data; - - int got_frame = 0; - int ret = libav_decode(codec_data->context, codec_data->picture, &got_frame, &avpkt); - - if(ret < 0) - { - fprintf(stderr, "V4L2_CORE: (jpeg decoder) error while decoding frame\n"); - return ret; - } - - if(got_frame) - { + avpkt.size = size; + avpkt.data = in_buf; + + codec_data_t *codec_data = (codec_data_t *) jpeg_ctx->codec_data; + + int got_frame = 0; + int ret = libav_decode(codec_data->context, codec_data->picture, &got_frame, &avpkt); + + if(ret < 0) + { + fprintf(stderr, "V4L2_CORE: (jpeg decoder) error while decoding frame\n"); + return ret; + } + + if(got_frame) + { + // check use hwdec work ok + if (codec_data->hw_device_ctx && codec_data->picture->format == codec_data->hw_pix_fmt) { + AVFrame *sw_frame = getAvutil()->m_av_frame_alloc(); + if (!sw_frame) { + fprintf(stderr, "V4L2_CORE: (jpeg decoder) Failed to allocate software frame\n"); + return -1; + } + + // Transfer hardware frame data to system memory + if (getAvutil()->m_av_hwframe_transfer_data(sw_frame, codec_data->picture, 0) < 0) { + fprintf(stderr, "V4L2_CORE: (jpeg decoder) Failed to transfer hardware frame data\n"); + getAvutil()->m_av_frame_free(&sw_frame); + return -1; + } + if (verbosity > 0) { + printf(" Width: %d pixels\n", sw_frame->width); + printf(" Height: %d pixels\n", sw_frame->height); + printf(" Pixel format: %s\n", getAvutil()->m_av_get_pix_fmt_name((enum AVPixelFormat)sw_frame->format)); + printf(" Hardware pixel format: %s\n", getAvutil()->m_av_get_pix_fmt_name(codec_data->hw_pix_fmt)); + printf(" Linesize[0]: %d\n", sw_frame->linesize[0]); + printf("-------------------------\n"); + printf(" - %s\n", getAvutil()->m_av_get_pix_fmt_name((enum AVPixelFormat)AV_PIX_FMT_YUV420P)); + } #if LIBAVUTIL_VER_AT_LEAST(54,6) - getAvutil()->m_av_image_copy_to_buffer(jpeg_ctx->tmp_frame, jpeg_ctx->pic_size, - (const uint8_t * const*) codec_data->picture->data, codec_data->picture->linesize, - codec_data->context->pix_fmt, jpeg_ctx->width, jpeg_ctx->height, 1); + getAvutil()->m_av_image_copy_to_buffer(jpeg_ctx->tmp_frame, jpeg_ctx->pic_size, + (const uint8_t * const*) sw_frame->data, sw_frame->linesize, + sw_frame->format, jpeg_ctx->width, jpeg_ctx->height, 1); + if (sw_frame->format == AV_PIX_FMT_NV12) { + nv12_to_yu12(out_buf, jpeg_ctx->tmp_frame, jpeg_ctx->width, jpeg_ctx->height); + getAvutil()->m_av_frame_free(&sw_frame); + return jpeg_ctx->pic_size; + } #else - avpicture_layout((AVPicture *) codec_data->picture, codec_data->context->pix_fmt, - jpeg_ctx->width, jpeg_ctx->height, jpeg_ctx->tmp_frame, jpeg_ctx->pic_size); + avpicture_layout((AVPicture *) sw_frame, sw_frame->format, + jpeg_ctx->width, jpeg_ctx->height, jpeg_ctx->tmp_frame, jpeg_ctx->pic_size); #endif + getAvutil()->m_av_frame_free(&sw_frame); + } else { + // Software decoding: Use decoded frames directly +#if LIBAVUTIL_VER_AT_LEAST(54,6) + getAvutil()->m_av_image_copy_to_buffer(jpeg_ctx->tmp_frame, jpeg_ctx->pic_size, + (const uint8_t * const*) codec_data->picture->data, codec_data->picture->linesize, + codec_data->context->pix_fmt, jpeg_ctx->width, jpeg_ctx->height, 1); +#else + avpicture_layout((AVPicture *) codec_data->picture, codec_data->dec_ctx->pix_fmt, + jpeg_ctx->width, jpeg_ctx->height, jpeg_ctx->tmp_frame, jpeg_ctx->pic_size); +#endif + } if (codec_data->context->pix_fmt == AV_PIX_FMT_YUVJ422P) { /* libavcodec output is in yuvj422p */ @@ -1539,9 +1623,9 @@ int jpeg_decode(uint8_t *out_buf, uint8_t *in_buf, int size) return jpeg_ctx->pic_size; }else return 0; - } - else - return 0; + } + else + return 0; } @@ -1557,32 +1641,37 @@ int jpeg_decode(uint8_t *out_buf, uint8_t *in_buf, int size) */ void jpeg_close_decoder() { - if(jpeg_ctx == NULL) - return; + if(jpeg_ctx == NULL) + return; - codec_data_t *codec_data = (codec_data_t *) jpeg_ctx->codec_data; + codec_data_t *codec_data = (codec_data_t *) jpeg_ctx->codec_data; getLoadLibsInstance()->m_avcodec_close(codec_data->context); - free(codec_data->context); + free(codec_data->context); #if LIBAVCODEC_VER_AT_LEAST(55,28) getAvutil()->m_av_frame_free(&codec_data->picture); #else - #if LIBAVCODEC_VER_AT_LEAST(54,28) - getLoadLibsInstance()->m_avcodec_free_frame(&codec_data->picture); - #else - av_freep(&codec_data->picture); - #endif +#if LIBAVCODEC_VER_AT_LEAST(54,28) + getLoadLibsInstance()->m_avcodec_free_frame(&codec_data->picture); +#else + av_freep(&codec_data->picture); +#endif #endif - if(jpeg_ctx->tmp_frame) - free(jpeg_ctx->tmp_frame); + // Release hardware device context + if (codec_data->hw_device_ctx) { + getAvutil()->m_av_buffer_unref(&codec_data->hw_device_ctx); + } - free(codec_data); - free(jpeg_ctx); + if(jpeg_ctx->tmp_frame) + free(jpeg_ctx->tmp_frame); - jpeg_ctx = NULL; + free(codec_data); + free(jpeg_ctx); + + jpeg_ctx = NULL; } #endif diff --git a/src/src/basepub/load_libs.c b/src/src/basepub/load_libs.c index 34559c9b..a159f228 100644 --- a/src/src/basepub/load_libs.c +++ b/src/src/basepub/load_libs.c @@ -121,6 +121,8 @@ static LoadLibs *newClass(void) PrintError(); pLibs->m_avcodec_receive_packet = (uos_avcodec_receive_packet)dlsym(handle, "avcodec_receive_packet"); PrintError(); + pLibs->m_avcodec_get_hw_config = (uos_avcodec_get_hw_config)dlsym(handle, "avcodec_get_hw_config"); + PrintError(); pLibs->m_av_packet_free = (uos_av_packet_free)dlsym(handle, "av_packet_free"); PrintError(); pLibs->m_avcodec_fill_audio_frame = (uos_avcodec_fill_audio_frame)dlsym(handle, "avcodec_fill_audio_frame"); @@ -342,6 +344,8 @@ static LoadAvutil *newAvutil(void) PrintError(); Avutil->m_av_get_media_type_string = (uos_av_get_media_type_string)dlsym(handle5, "av_get_media_type_string"); PrintError(); + Avutil->m_av_get_pix_fmt_name = (uos_av_get_pix_fmt_name)dlsym(handle5, "av_get_pix_fmt_name"); + PrintError(); Avutil->m_av_image_get_buffer_size = (uos_av_image_get_buffer_size)dlsym(handle5, "av_image_get_buffer_size"); PrintError(); //----vaapi---- diff --git a/src/src/basepub/load_libs.h b/src/src/basepub/load_libs.h index e890a841..3ce2e4bc 100644 --- a/src/src/basepub/load_libs.h +++ b/src/src/basepub/load_libs.h @@ -45,6 +45,8 @@ typedef int (*uos_avcodec_send_packet)(AVCodecContext *avctx, const AVPacket *av typedef int (*uos_avcodec_receive_frame)(AVCodecContext *avctx, AVFrame *frame); //int avcodec_receive_packet(AVCodecContext *avctx, AVPacket *avpkt); typedef int (*uos_avcodec_receive_packet)(AVCodecContext *avctx, AVPacket *avpkt); +//const AVCodecHWConfig *avcodec_get_hw_config(const AVCodec *codec, int index); +typedef const AVCodecHWConfig *(*uos_avcodec_get_hw_config)(const AVCodec *codec, int index); //void av_packet_free(AVPacket **pkt); typedef void (*uos_av_packet_free)(AVPacket **pkt); //int avcodec_fill_audio_frame(AVFrame *frame, int nb_channels,enum AVSampleFormat sample_fmt, const uint8_t *buf,int buf_size, int align); @@ -128,6 +130,7 @@ typedef struct _LoadLibs { uos_avcodec_send_packet m_avcodec_send_packet; uos_avcodec_receive_frame m_avcodec_receive_frame; uos_avcodec_receive_packet m_avcodec_receive_packet; + uos_avcodec_get_hw_config m_avcodec_get_hw_config; uos_av_packet_free m_av_packet_free; uos_avcodec_fill_audio_frame m_avcodec_fill_audio_frame; uos_av_packet_unref m_av_packet_unref; @@ -235,6 +238,8 @@ typedef int (*uos_av_samples_get_buffer_size)(int *linesize, int nb_channels, in enum AVSampleFormat sample_fmt, int align); //const char *av_get_media_type_string(enum AVMediaType media_type); typedef const char *(*uos_av_get_media_type_string)(enum AVMediaType media_type); +//const char *av_get_pix_fmt_name(enum AVPixelFormat pix_fmt); +typedef const char *(*uos_av_get_pix_fmt_name)(enum AVPixelFormat pix_fmt); //int av_image_get_buffer_size(enum AVPixelFormat pix_fmt, int width, int height, int align); typedef int (*uos_av_image_get_buffer_size)(enum AVPixelFormat pix_fmt, int width, int height, int align); @@ -254,6 +259,7 @@ typedef struct _LoadAvutil { uos_av_free m_av_free; uos_av_samples_get_buffer_size m_av_samples_get_buffer_size; uos_av_get_media_type_string m_av_get_media_type_string;// + uos_av_get_pix_fmt_name m_av_get_pix_fmt_name; uos_av_image_get_buffer_size m_av_image_get_buffer_size; //----VAAPI------ uos_av_hwdevice_ctx_create m_av_hwdevice_ctx_create; From d2d696ecd7e8c8b5fb357f305a6c7b68ebf31fc5 Mon Sep 17 00:00:00 2001 From: lichaofan Date: Tue, 21 Oct 2025 19:48:43 +0800 Subject: [PATCH 055/107] fix: Occasional abnormal color of title bar buttons. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Title bar buttons needs to change based on whether there is a preview screen or not; otherwise, it will display abnormally. Meanwhile, add some necessary logs. fix: 标题栏按钮颜色偶现异常。 标题栏按钮颜色需要根据是否有预览画面而变化,不然会显示异常。 同时,加入一些必要的日志。 Bug: https://pms.uniontech.com/bug-view-337503.html --- src/main.cpp | 12 ++++++++---- src/src/devnummonitor.cpp | 4 ++++ src/src/mainwindow.cpp | 3 +++ src/src/majorimageprocessingthread.cpp | 3 +++ src/src/videowidget.cpp | 11 +++++++++++ 5 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 8088e2e7..147a8e41 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -95,6 +95,12 @@ static bool CheckFFmpegEnv() int main(int argc, char *argv[]) { + // 将日志配置提前,以确保所有日志没有遗漏 + //qputenv("QT_LOGGING_RULES", "*.debug=true;*.info=true"); + DLogManager::registerConsoleAppender(); + DLogManager::registerFileAppender(); + qInfo() << "LogFile:" << DLogManager::getlogFilePath(); + // Task 326583 不参与合成器崩溃重连 unsetenv("QT_WAYLAND_RECONNECT"); @@ -108,6 +114,7 @@ int main(int argc, char *argv[]) } } DataManager::instance()->setEncodeEnv(bFFmpegEnv ? FFmpeg_Env : GStreamer_Env); + qWarning() << "EncodeEnv:" << (bFFmpegEnv ? "FFmpeg_Env" : "GStreamer_Env"); //root login for this application if (!QString(qgetenv("XDG_CURRENT_DESKTOP")).toLower().startsWith("deepin")) { @@ -222,12 +229,9 @@ int main(int argc, char *argv[]) qApp->setApplicationDisplayName(QObject::tr("Camera")); //设置产品名称 qApp->setProductName(QObject::tr("Camera")); - //日志 - DLogManager::registerConsoleAppender(); - DLogManager::registerFileAppender(); - qInfo() << "LogFile:" << DLogManager::getlogFilePath(); //版本 qApp->setApplicationVersion(DApplication::buildVersion(VERSION)); + qWarning() << "Version:" << DApplication::buildVersion(VERSION); QIcon myIcon = QIcon::fromTheme("deepin-camera"); qApp->setWindowIcon(myIcon); qApp->setProductIcon(myIcon);//08月21获悉已添加到系统,故更改为从系统获取 diff --git a/src/src/devnummonitor.cpp b/src/src/devnummonitor.cpp index 64069c63..d6ea7e5f 100644 --- a/src/src/devnummonitor.cpp +++ b/src/src/devnummonitor.cpp @@ -51,11 +51,15 @@ void DevNumMonitor::timeOutSlot() if (get_device_list()->num_devices < 1) { //没有设备发送信号 if (!m_noDevice) { + qWarning() << "No device found"; emit noDeviceFound(); m_noDevice = true; } qDebug() << "There is no camera connected!"; } else { + if (m_noDevice) { + qWarning() << "Device found"; + } m_noDevice = false; emit existDevice(); // qDebug() << "existDevice!"; diff --git a/src/src/mainwindow.cpp b/src/src/mainwindow.cpp index 8a3a9d18..638f8d96 100644 --- a/src/src/mainwindow.cpp +++ b/src/src/mainwindow.cpp @@ -1297,6 +1297,7 @@ void CMainWindow::updateBlockSystem(bool bTrue) void CMainWindow::onNoCam() { + qDebug() << __func__; m_pTitlebar->titlebar()->setBackgroundTransparent(false); m_pTitlebar->slotThemeTypeChanged(); showChildWidget(); @@ -1384,6 +1385,7 @@ void CMainWindow::onDirectoryChanged(const QString &filePath) void CMainWindow::onSwitchCameraSuccess(const QString &cameraName) { + qWarning() << __func__ << cameraName; QStringList tmpList = cameraName.split(":"); if (!tmpList.isEmpty()) { m_labelCameraName->setText(tmpList[0]); @@ -1873,6 +1875,7 @@ void CMainWindow::initConnection() connect(m_videoPre, SIGNAL(noCamAvailable()), this, SLOT(onNoCam())); connect(m_videoPre, &videowidget::camAvailable, this, [=](){ m_pTitlebar->titlebar()->setBackgroundTransparent(true); + m_pTitlebar->slotThemeTypeChanged(); }); //设置新的分辨率 connect(m_videoPre, SIGNAL(sigDeviceChange()), &Settings::get(), SLOT(setNewResolutionList())); diff --git a/src/src/majorimageprocessingthread.cpp b/src/src/majorimageprocessingthread.cpp index 6a4c2bfe..929ee474 100644 --- a/src/src/majorimageprocessingthread.cpp +++ b/src/src/majorimageprocessingthread.cpp @@ -34,11 +34,13 @@ MajorImageProcessingThread::MajorImageProcessingThread():m_bHorizontalMirror(fal void MajorImageProcessingThread::stop() { + qDebug() << __func__; m_stopped = 1; } void MajorImageProcessingThread::init() { + qDebug() << __func__; m_stopped = 0; m_majorindex = -1; m_frame = nullptr; @@ -138,6 +140,7 @@ void MajorImageProcessingThread::processingImage(QImage& img) void MajorImageProcessingThread::run() { + qDebug() << __func__; if (m_eEncodeEnv != QCamera_Env) { m_videoDevice = get_v4l2_device_handler(); v4l2core_start_stream(m_videoDevice); diff --git a/src/src/videowidget.cpp b/src/src/videowidget.cpp index c255b131..8e837130 100644 --- a/src/src/videowidget.cpp +++ b/src/src/videowidget.cpp @@ -279,6 +279,7 @@ void videowidget::delayInit() void videowidget::showNocam() { + qDebug() << __func__; if (!m_pNormalView->isVisible()) m_pNormalView->show(); @@ -388,6 +389,7 @@ void videowidget::showCamUsed() #ifndef __mips__ void videowidget::ReceiveOpenGLstatus(bool result) { + //qDebug() << "ReceiveOpenGLstatus" << result; if (result && m_openglwidget) { //Success if (m_pCamErrItem->isVisible()) @@ -625,6 +627,7 @@ void videowidget::resizeEvent(QResizeEvent *size) void videowidget::showCountdown() { + qDebug() << __func__; if (DataManager::instance()->getdevStatus() == NOCAM) { if (m_flashTimer->isActive()) @@ -842,6 +845,7 @@ void videowidget::showRecTime() void videowidget::flash() { + qDebug() << __func__; if (get_sound_of_takeing_photo()) m_takePicSound->play(); @@ -1019,9 +1023,11 @@ void videowidget::onEndBtnClicked() void videowidget::onRestartDevices() { if (DataManager::instance()->getdevStatus() != CAM_CANUSE) { + qDebug() << "Device status:" << DataManager::instance()->getdevStatus(); onChangeDev(); if (DataManager::instance()->getdevStatus() == CAM_CANUSE) { + qDebug() << "Device status:" << DataManager::instance()->getdevStatus(); emit sigDeviceChange(); QPalette plt = palette(); plt.setColor(QPalette::Window, Qt::white); @@ -1036,6 +1042,7 @@ void videowidget::onRestartDevices() void videowidget::onChangeDev() { + qDebug() << __func__; v4l2_dev_t *devicehandler = get_v4l2_device_handler(); if (m_imgPrcThread != nullptr) @@ -1088,6 +1095,7 @@ void videowidget::onChangeDev() int videowidget::switchCamera(const char *device, const char *devName) { + qWarning() << __func__ << device << devName; if (NULL == device) { return -1; } @@ -1097,6 +1105,7 @@ int videowidget::switchCamera(const char *device, const char *devName) } else { ret = 0; } + qInfo() << "Camera init:" << ret; if (ret == E_OK) { m_imgPrcThread->init(); m_imgPrcThread->start(); @@ -1143,6 +1152,7 @@ QString videowidget::getSaveFilePrefix() void videowidget::onTakePic(bool bTrue) { + qDebug() << __func__ << bTrue; g_Enum_Camera_State = PICTRUE; if (bTrue) { @@ -1410,6 +1420,7 @@ void videowidget::itemPosChange() void videowidget::stopEverything() { + qDebug() << __func__; if (m_countTimer->isActive()) m_countTimer->stop(); From 7bf3f81428415df325576ee498e07a8ee738b561 Mon Sep 17 00:00:00 2001 From: lichaofan Date: Fri, 24 Oct 2025 11:32:28 +0800 Subject: [PATCH 056/107] chore: Correction of some misspelled words. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 一些单词拼写错误的纠正。 phote => photo nublock => unblock offect => offset priview => preview pictrue => picture falsh => flash --- src/src/mainwindow.cpp | 20 ++++++++++---------- src/src/videowidget.cpp | 24 ++++++++++++------------ src/src/videowidget.h | 8 ++++---- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/src/mainwindow.cpp b/src/src/mainwindow.cpp index 638f8d96..24a293b5 100644 --- a/src/src/mainwindow.cpp +++ b/src/src/mainwindow.cpp @@ -62,7 +62,7 @@ const int CMainWindow::minWindowHeight = 510; const int rightOffset = 10; const int SwitchcameraDiam = 40; //切换摄像头直径 -const int photeRecordDiam = 64; +const int photoRecordDiam = 64; const int snapLabelDiam = 52; const int switchBtnWidth = 50; const int switchBtnHeight = 26; @@ -893,7 +893,7 @@ void CMainWindow::initBlockShutdown() if (m_reply.isValid()) { QDBusReply tmp = m_reply; m_reply = QDBusReply(); - qDebug() << "init Nublock shutdown."; + qDebug() << "init Unblock shutdown."; } } @@ -923,7 +923,7 @@ void CMainWindow::initBlockSleep() if (m_replySleep.isValid()) { QDBusReply tmp = m_replySleep; m_replySleep = QDBusReply(); - qDebug() << "init Nublock sleep."; + qDebug() << "init Unblock sleep."; } } @@ -1279,7 +1279,7 @@ void CMainWindow::updateBlockSystem(bool bTrue) } else { QDBusReply tmp = m_reply; m_reply = QDBusReply(); - qDebug() << "Nublock shutdown."; + qDebug() << "Unblock shutdown."; } } if (m_bWayland) { @@ -1290,7 +1290,7 @@ void CMainWindow::updateBlockSystem(bool bTrue) } else { QDBusReply tmp = m_replySleep; m_replySleep = QDBusReply(); - qDebug() << "Nublock sleep."; + qDebug() << "Unblock sleep."; } } } @@ -1953,7 +1953,7 @@ void CMainWindow::initRightButtons() m_cameraSwitchBtn->setToolTip(tr("Switch Cameras")); m_photoRecordBtn = new photoRecordBtn(this); - m_photoRecordBtn->setFixedSize(photeRecordDiam, photeRecordDiam); + m_photoRecordBtn->setFixedSize(photoRecordDiam, photoRecordDiam); m_photoRecordBtn->setObjectName(BUTTON_PICTURE_VIDEO); m_photoRecordBtn->setAccessibleName(BUTTON_PICTURE_VIDEO); m_photoRecordBtn->setToolTip(tr("Photo")); @@ -1998,10 +1998,10 @@ void CMainWindow::locateRightButtons() if (nullptr == m_photoRecordBtn) { return; } - int buttonCenterX = width() - rightOffset - photeRecordDiam / 2; + int buttonCenterX = width() - rightOffset - photoRecordDiam / 2; int buttonCenterY = height() / 2; - int photoRecordLeftX = buttonCenterX - photeRecordDiam / 2; - int photoRecordLeftY = buttonCenterY - photeRecordDiam / 2; + int photoRecordLeftX = buttonCenterX - photoRecordDiam / 2; + int photoRecordLeftY = buttonCenterY - photoRecordDiam / 2; m_photoRecordBtn->move(photoRecordLeftX, photoRecordLeftY); int switchCameraOffset = height() / 15; @@ -2010,7 +2010,7 @@ void CMainWindow::locateRightButtons() m_cameraSwitchBtn->move(switchCameraX, switchCameraY); int switchBtnX = buttonCenterX - switchBtnWidth / 2; - int switchBtnY = photoRecordLeftY + photeRecordDiam; + int switchBtnY = photoRecordLeftY + photoRecordDiam; m_modeSwitchBox->move(switchBtnX, switchBtnY); int snapLabelOffset = height() / 10; diff --git a/src/src/videowidget.cpp b/src/src/videowidget.cpp index 8e837130..875032d5 100644 --- a/src/src/videowidget.cpp +++ b/src/src/videowidget.cpp @@ -35,9 +35,9 @@ #define COUNTDOWN_WIDTH 32 #define COUNTDOWN_HEIGHT 61 -#define COUNTDOWN_OFFECT 20 +#define COUNTDOWN_OFFSET 20 -static PRIVIEW_ENUM_STATE g_Enum_Camera_State = PICTRUE; +static PREVIEW_ENUM_STATE g_Enum_Camera_State = PICTURE; // 重写QGraphicsView类,在子类中,直接将鼠标事件路由到QWidget,这样QGraphicsScene不会接收和处理鼠标事件 // bug 100791 @@ -431,7 +431,7 @@ void videowidget::ReceiveOpenGLstatus(bool result) } } - if (!m_openglwidget->isVisible() && !m_isFalsh) + if (!m_openglwidget->isVisible() && !m_isFlash) m_openglwidget->show(); malloc_trim(0); @@ -455,7 +455,7 @@ void videowidget::ReceiveMajorImage(QImage *image, int result) case 0: //Success // m_imgPrcThread->m_rwMtxImg.lock(); - if (!m_isFalsh) + if (!m_isFlash) m_pNormalView->show(); m_pCamErrItem->hide(); m_pSvgItem->hide(); @@ -526,11 +526,11 @@ void videowidget::onReachMaxDelayedFrames() m_openglwidget->hide(); } -void videowidget::showCountDownLabel(PRIVIEW_ENUM_STATE state) +void videowidget::showCountDownLabel(PREVIEW_ENUM_STATE state) { QString str; switch (state) { - case PICTRUE: + case PICTURE: m_recordingTimeWidget->hide(); break; @@ -604,7 +604,7 @@ void videowidget::resizeEvent(QResizeEvent *size) height() - m_recordingTimeWidget->height() - 15); m_dLabel->move((width() - m_dLabel->width()) / 2, - (height() - m_dLabel->height()) - COUNTDOWN_OFFECT); + (height() - m_dLabel->height()) - COUNTDOWN_OFFSET); if (m_pCamErrItem->isVisible()) { @@ -661,7 +661,7 @@ void videowidget::showCountdown() emit updateRecordState(photoRecordBtn::Recording); } - if (g_Enum_Camera_State == PICTRUE) { + if (g_Enum_Camera_State == PICTURE) { if (m_nInterval == 0 && m_curTakePicTime >= 0) { if (m_flashEnable && 1 == m_nMaxContinuous) { int index = QApplication::desktop()->screenNumber(this); @@ -674,7 +674,7 @@ void videowidget::showCountdown() qDebug() << "flashTimer->start();"; if (m_pNormalView) { - m_isFalsh = true; + m_isFlash = true; m_pNormalView->hide(); } if (m_openglwidget) @@ -762,7 +762,7 @@ void videowidget::showCountdown() } else { m_dLabel->setText(QString::number(m_nInterval)); m_dLabel->show(); - showCountDownLabel(PICTRUE); //拍照录像都要显示倒计时 + showCountDownLabel(PICTURE); //拍照录像都要显示倒计时 m_nInterval--; qInfo() << "m_nInterval:" << m_nInterval; } @@ -856,7 +856,7 @@ void videowidget::flash() } else { m_pNormalView->show(); } - m_isFalsh = false; + m_isFlash = false; #endif m_flashLabel->hide(); //为避免没有关闭,放到定时器里边关闭 @@ -1153,7 +1153,7 @@ QString videowidget::getSaveFilePrefix() void videowidget::onTakePic(bool bTrue) { qDebug() << __func__ << bTrue; - g_Enum_Camera_State = PICTRUE; + g_Enum_Camera_State = PICTURE; if (bTrue) { //1、重置状态 diff --git a/src/src/videowidget.h b/src/src/videowidget.h index 8c9cd022..7ab89f60 100644 --- a/src/src/videowidget.h +++ b/src/src/videowidget.h @@ -48,9 +48,9 @@ class QGraphicsSvgItem; #define FLASH_TIME 500//拍照闪光时间,500毫秒 /** -* @brief PRIVIEW_ENUM_STATE 枚举拍照,无设备,录像 +* @brief PREVIEW_ENUM_STATE 枚举拍照,无设备,录像 */ -enum PRIVIEW_ENUM_STATE {PICTRUE, NODEVICE, VIDEO}; +enum PREVIEW_ENUM_STATE {PICTURE, NODEVICE, VIDEO}; // 重写QGraphicsView类,在子类中,直接将鼠标事件路由到QWidget,这样QGraphicsScene不会接收和处理鼠标事件 class QGraphicsViewEx : public QGraphicsView @@ -378,7 +378,7 @@ private slots: * @brief showCountDownLabel 显示录制和拍照倒计时 * @param state 当前状态(拍照,没有设备,视频) */ - void showCountDownLabel(PRIVIEW_ENUM_STATE state); + void showCountDownLabel(PREVIEW_ENUM_STATE state); /** * @brief forbidScrollBar 禁止滚轮显示区域 @@ -465,7 +465,7 @@ private slots: GstVideoWriter *m_videoWriter; //基于GStreamer实现的视频帧数据写入器 efilterType m_filterType; //当前选择的滤镜名称 int m_exposure; - bool m_isFalsh = false; + bool m_isFlash = false; }; From 1f11afa9e35b83c912a08dc88a66db97a000ece7 Mon Sep 17 00:00:00 2001 From: lichaofan Date: Wed, 29 Oct 2025 14:18:32 +0800 Subject: [PATCH 057/107] fix: Address potential data truncation issue. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The maximum value of the `uint8_t` type is 255. Using a `uint8_t` type cast can lead to potential data truncation problems. fix: 修改潜在的数据截断问题。 uint8_t类型最大值是255,使用uint8_t强制转换会导致潜在的数据截断问题。 --- libcam/libcam_v4l2core/frame_decoder.c | 4 ++-- libcam/libcam_v4l2core/jpeg_decoder.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libcam/libcam_v4l2core/frame_decoder.c b/libcam/libcam_v4l2core/frame_decoder.c index 5e4e0150..63366fa8 100644 --- a/libcam/libcam_v4l2core/frame_decoder.c +++ b/libcam/libcam_v4l2core/frame_decoder.c @@ -99,7 +99,7 @@ int alloc_v4l2_frames(v4l2_dev_t *vd) exit(-1); } - vd->frame_queue[i].yuv_frame = calloc((uint8_t)framesizeIn, sizeof(uint8_t)); + vd->frame_queue[i].yuv_frame = calloc((size_t) framesizeIn, sizeof(uint8_t)); if(vd->frame_queue[i].yuv_frame == NULL) { fprintf(stderr, "V4L2_CORE: FATAL memory allocation failure (alloc_v4l2_frames): %s\n", strerror(errno)); @@ -108,7 +108,7 @@ int alloc_v4l2_frames(v4l2_dev_t *vd) } - vd->h264_last_IDR = calloc((uint8_t)(width * height), sizeof(uint8_t)); + vd->h264_last_IDR = calloc((size_t) width * (size_t) height, sizeof(uint8_t)); if(vd->h264_last_IDR == NULL) { fprintf(stderr, "V4L2_CORE: FATAL memory allocation failure (alloc_v4l2_frames): %s\n", strerror(errno)); diff --git a/libcam/libcam_v4l2core/jpeg_decoder.c b/libcam/libcam_v4l2core/jpeg_decoder.c index 79b6350b..e64f7e60 100644 --- a/libcam/libcam_v4l2core/jpeg_decoder.c +++ b/libcam/libcam_v4l2core/jpeg_decoder.c @@ -1552,7 +1552,7 @@ int jpeg_decode(uint8_t *out_buf, uint8_t *in_buf, int size) if(ret < 0) { - fprintf(stderr, "V4L2_CORE: (jpeg decoder) error while decoding frame\n"); + fprintf(stderr, "V4L2_CORE: (jpeg decoder) error while decoding frame, code(%d)\n", ret); return ret; } From db157c593386eb5d6f9a405ab5c2d2999dd5b9f5 Mon Sep 17 00:00:00 2001 From: lichaofan Date: Tue, 28 Oct 2025 19:39:17 +0800 Subject: [PATCH 058/107] fix: Temporarily block 8K resolution to avoid app crashes. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The app crashes when decoding preview images with 8K resolution. Temporarily block the 8K resolution, and the restriction will be lifted after the decoding issue is thoroughly investigated. fix: 暂时屏蔽8k分辨率,避免应用崩溃。 应用在解码8k分辨率的预览图时会崩溃,暂时屏蔽8k分辨率,待解码问题研究清楚后再放开限制。 Bug: https://pms.uniontech.com/bug-view-339033.html --- libcam/libcam_v4l2core/v4l2_core.c | 25 ++++++++------- libcam/libcam_v4l2core/v4l2_formats.c | 45 +++++++++++++++++---------- libcam/libcam_v4l2core/v4l2_formats.h | 17 ++++++++++ src/src/LPF_V4L2.c | 6 ++++ 4 files changed, 64 insertions(+), 29 deletions(-) diff --git a/libcam/libcam_v4l2core/v4l2_core.c b/libcam/libcam_v4l2core/v4l2_core.c index bb51a7a5..357af10c 100644 --- a/libcam/libcam_v4l2core/v4l2_core.c +++ b/libcam/libcam_v4l2core/v4l2_core.c @@ -1696,18 +1696,19 @@ void v4l2core_prepare_valid_resolution(v4l2_dev_t *vd) } } - for(int i=0; i < vd->list_stream_formats[format_index].numb_res; i++) - { - if( my_width <= vd->list_stream_formats[format_index].list_stream_cap[i].width && - my_height <= vd->list_stream_formats[format_index].list_stream_cap[i].height && - ((vd->list_stream_formats[format_index].list_stream_cap[i].width % 8) == 0 - && (vd->list_stream_formats[format_index].list_stream_cap[i].width % 16) == 0 - && (vd->list_stream_formats[format_index].list_stream_cap[i].height % 8) == 0)) - { - my_width = vd->list_stream_formats[format_index].list_stream_cap[i].width; - my_height = vd->list_stream_formats[format_index].list_stream_cap[i].height; - } - } + // 查找可以支持的最大分辨率(目前类似8000x6000的解码问题未解决,故要限制最大分辨率) + printf("V4L2_CORE: valid resolution counts: %d\n", vd->list_stream_formats[format_index].numb_res); + for(int i=0; i < vd->list_stream_formats[format_index].numb_res; i++) + { + int w = vd->list_stream_formats[format_index].list_stream_cap[i].width; + int h = vd->list_stream_formats[format_index].list_stream_cap[i].height; + printf("V4L2_CORE: - valid resolution(%dx%d)\n", w, h); + if (my_width <= w && my_height <= h && is_valid_resolution(w, h)) { + my_width = w; + my_height = h; + } + } + printf("V4L2_CORE: select resolution(%dx%d)\n", my_width, my_height); } /* diff --git a/libcam/libcam_v4l2core/v4l2_formats.c b/libcam/libcam_v4l2core/v4l2_formats.c index 161c3ee5..92f320f4 100644 --- a/libcam/libcam_v4l2core/v4l2_formats.c +++ b/libcam/libcam_v4l2core/v4l2_formats.c @@ -678,27 +678,32 @@ int get_format_resolution_index(v4l2_dev_t *vd, int format, int width, int heigh return (-1); } + // 查找输入的分辨率是否在支持的分辨率列表中(目前类似8000x6000的解码问题未解决,故要限制最大分辨率) int i=0; for(i=0; i < vd->list_stream_formats[format].numb_res; i++) { - if( width == vd->list_stream_formats[format].list_stream_cap[i].width && - height == vd->list_stream_formats[format].list_stream_cap[i].height) - return (i); + int w = vd->list_stream_formats[format].list_stream_cap[i].width; + int h = vd->list_stream_formats[format].list_stream_cap[i].height; + if (width == w && height == h && is_valid_resolution(w, h)) { + return i; + } + } + + // 查找可以支持的最大分辨率(目前类似8000x6000的解码问题未解决,故要限制最大分辨率) + int tempwidth = 0; + int tempheight = 0; + int index = -1; + for(i=0; i < vd->list_stream_formats[format].numb_res; i++) + { + int w = vd->list_stream_formats[format].list_stream_cap[i].width; + int h = vd->list_stream_formats[format].list_stream_cap[i].height; + if (tempwidth <= w && tempheight <= h && is_valid_resolution(w, h)) { + tempwidth = w; + tempheight = h; + index = i; + } } - int tempwidth = 0; - int tempheight = 0; - int index = -1; - for(i=0; i < vd->list_stream_formats[format].numb_res; i++) - { - if( tempwidth <= vd->list_stream_formats[format].list_stream_cap[i].width && - tempheight <= vd->list_stream_formats[format].list_stream_cap[i].height) - { - tempwidth = vd->list_stream_formats[format].list_stream_cap[i].width; - tempheight = vd->list_stream_formats[format].list_stream_cap[i].height; - index = i; - } - } - return (index); + return index; } /* @@ -738,3 +743,9 @@ void free_frame_formats(v4l2_dev_t *vd) free(vd->list_stream_formats); vd->list_stream_formats = NULL; } + +int is_valid_resolution(int width, int height) +{ + // 目前类似8000x6000的解码问题未解决,故要限制最大分辨率 + return (width < MAX_WIDTH_LIMIT && height < MAX_HEIGHT_LIMIT) && (width % 16 == 0 && height % 8 == 0); +} diff --git a/libcam/libcam_v4l2core/v4l2_formats.h b/libcam/libcam_v4l2core/v4l2_formats.h index 61c1e7f3..99201a7f 100644 --- a/libcam/libcam_v4l2core/v4l2_formats.h +++ b/libcam/libcam_v4l2core/v4l2_formats.h @@ -24,6 +24,9 @@ #include "gviewv4l2core.h" #include "v4l2_core.h" +#define MAX_WIDTH_LIMIT 7680 +#define MAX_HEIGHT_LIMIT 4320 + /* * check pixelformat against decoder support formats * args: @@ -93,4 +96,18 @@ int get_format_resolution_index(v4l2_dev_t *vd, int format, int width, int heigh */ void free_frame_formats(v4l2_dev_t *vd); +/* + * check if requested resolution is valid + * args: + * width - requested width + * height - requested height + * + * asserts: + * none + * + * returns: TRUE(1) if valid + * FALSE(0) if not + */ +int is_valid_resolution(int width, int height); + #endif diff --git a/src/src/LPF_V4L2.c b/src/src/LPF_V4L2.c index a91fd419..f70bebaf 100644 --- a/src/src/LPF_V4L2.c +++ b/src/src/LPF_V4L2.c @@ -210,6 +210,12 @@ int camInit(const char *devicename) if ((strcmp(my_config->device_name, devlist->list_devices[my_vd->this_device].name) == 0) && (strcmp(my_config->device_location, my_vd->videodevice) == 0)) { v4l2core_prepare_new_resolution(my_vd, my_config->width, my_config->height); + // 分辨率可能已经被校正 + if (my_config->width != get_my_width() || my_config->height != get_my_height()) { + printf("%s: adjust resolution(%dx%d => %dx%d)\n", __func__, my_config->width, my_config->height, get_my_width(), get_my_height()); + my_config->width = get_my_width(); + my_config->height = get_my_height(); + } ret = v4l2core_update_old_format(my_vd, my_config->width, my_config->height, v4l2core_get_requested_frame_format(my_vd)); } else { v4l2core_prepare_valid_resolution(my_vd); From cc3a13b73defebe5f5b5bc77544e86fef5d76363 Mon Sep 17 00:00:00 2001 From: lichaofan Date: Tue, 4 Nov 2025 19:41:28 +0800 Subject: [PATCH 059/107] fix: When the screen is locked while using the camera, face recognition fails to work after unlocking. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The camera occupies the camera device, preventing the unlocking program from accessing it. Therefore, the camera should release the camera device when the screen is locked and re-occupy it after unlocking. fix: 使用相机的时候锁屏,解锁无法使用人脸识别。 相机占用了摄像头设备,导致解锁程序打不开摄像头设备。所以,相机应该在锁屏的时候释放摄像头设备,待解锁之后再占用摄像头设备。 Bug: https://pms.uniontech.com/bug-view-339625.html --- libcam/libcam/cameraconfig.c | 2 +- libcam/libcam_v4l2core/gui.c | 2 +- libcam/libcam_v4l2core/jpeg_decoder.c | 6 ++++++ libcam/libcam_v4l2core/v4l2_devices.c | 8 ++++---- src/src/devnummonitor.cpp | 5 ++++- src/src/mainwindow.cpp | 4 ++++ src/src/videowidget.cpp | 14 ++++++++++++++ src/src/videowidget.h | 8 +++++++- 8 files changed, 41 insertions(+), 8 deletions(-) diff --git a/libcam/libcam/cameraconfig.c b/libcam/libcam/cameraconfig.c index 2fdf4a8a..786af2cd 100644 --- a/libcam/libcam/cameraconfig.c +++ b/libcam/libcam/cameraconfig.c @@ -231,7 +231,7 @@ int config_load(const char *filename) /*skip invalid lines */ if(!token || !value || strlen(token) < 1 || strlen(value) < 1) { - fprintf(stderr, "deepin-camera: (config) skiping invalid config entry at line %i\n", line); + fprintf(stderr, "deepin-camera: (config) skipping invalid config entry at line %i: %s\n", line, bufp); if(token) free(token); if(value) diff --git a/libcam/libcam_v4l2core/gui.c b/libcam/libcam_v4l2core/gui.c index 2c5dd5d9..c742c352 100644 --- a/libcam/libcam_v4l2core/gui.c +++ b/libcam/libcam_v4l2core/gui.c @@ -690,7 +690,7 @@ void set_photo_name(const char *name) fprintf(stderr, "deepin-camera: no valid file extension for image file %s\n", name); - fprintf(stderr, "deepin-camera: using format %i\n", get_photo_format()); + fprintf(stderr, "deepin-camera: using format %i (1:IMG_FMT_JPG, 2:IMG_FMT_PNG, 3:IMG_FMT_BMP)\n", get_photo_format()); switch(get_photo_format()) { case IMG_FMT_JPG: diff --git a/libcam/libcam_v4l2core/jpeg_decoder.c b/libcam/libcam_v4l2core/jpeg_decoder.c index e64f7e60..8995c3e4 100644 --- a/libcam/libcam_v4l2core/jpeg_decoder.c +++ b/libcam/libcam_v4l2core/jpeg_decoder.c @@ -1598,6 +1598,12 @@ int jpeg_decode(uint8_t *out_buf, uint8_t *in_buf, int size) } else { // Software decoding: Use decoded frames directly #if LIBAVUTIL_VER_AT_LEAST(54,6) + if (verbosity > 0) { + printf("codec_data size(%dx%d) linesize(%d) format(%s) jpeg_ctx size(%dx%d) pic_size(%d)\n", codec_data->picture->width, codec_data->picture->height, + codec_data->picture->linesize[0], + getAvutil()->m_av_get_pix_fmt_name((enum AVPixelFormat)codec_data->picture->format), + jpeg_ctx->width, jpeg_ctx->height, jpeg_ctx->pic_size); + } getAvutil()->m_av_image_copy_to_buffer(jpeg_ctx->tmp_frame, jpeg_ctx->pic_size, (const uint8_t * const*) codec_data->picture->data, codec_data->picture->linesize, codec_data->context->pix_fmt, jpeg_ctx->width, jpeg_ctx->height, 1); diff --git a/libcam/libcam_v4l2core/v4l2_devices.c b/libcam/libcam_v4l2core/v4l2_devices.c index 5fe2cf5b..86b35b59 100644 --- a/libcam/libcam_v4l2core/v4l2_devices.c +++ b/libcam/libcam_v4l2core/v4l2_devices.c @@ -425,7 +425,7 @@ int enum_v4l2_devices() getUdev()->m_udev_enumerate_unref(enumerate); my_device_list.num_devices = num_dev; - printf("my_device_list.num_devices is %d\n", num_dev); + printf("V4L2_CORE: num_devices is %d\n", num_dev); return(E_OK); } @@ -467,16 +467,16 @@ void v4l2core_init_device_list() * none * * returns: - * videodevice index in device list [0 - num_devices[ or -1 on error + * videodevice index in device list [0 - num_devices] or -1 on error */ int v4l2core_get_device_index(const char *videodevice) { - if(my_device_list.num_devices > 0 && my_device_list.list_devices != NULL && videodevice != NULL) + if(my_device_list.num_devices > 0 && my_device_list.list_devices != NULL && videodevice != NULL) { int dev_index = 0; for(dev_index = 0; dev_index < my_device_list.num_devices; ++dev_index) { - fprintf(stderr,"v4l2core_get_device_index dev_index(%d) videodevice:%x device:%x\n", dev_index, (unsigned int)videodevice, (unsigned int)(my_device_list.list_devices[dev_index].device)); + fprintf(stderr,"V4L2CORE: v4l2core_get_device_index: dev_index(%d) videodevice(%s) device(%s)\n", dev_index, videodevice, my_device_list.list_devices[dev_index].device); if(strcmp(videodevice, my_device_list.list_devices[dev_index].device)==0) { my_device_list.list_devices[dev_index].current = 1; diff --git a/src/src/devnummonitor.cpp b/src/src/devnummonitor.cpp index d6ea7e5f..0283dcd9 100644 --- a/src/src/devnummonitor.cpp +++ b/src/src/devnummonitor.cpp @@ -58,7 +58,10 @@ void DevNumMonitor::timeOutSlot() qDebug() << "There is no camera connected!"; } else { if (m_noDevice) { - qWarning() << "Device found"; + v4l2_dev_sys_data_t *v4l2_devices = get_device_list()->list_devices; + if (v4l2_devices) { + qWarning() << "Device found:" << v4l2_devices[0].device << v4l2_devices[0].name; + } } m_noDevice = false; emit existDevice(); diff --git a/src/src/mainwindow.cpp b/src/src/mainwindow.cpp index 24a293b5..b92877c0 100644 --- a/src/src/mainwindow.cpp +++ b/src/src/mainwindow.cpp @@ -1306,6 +1306,7 @@ void CMainWindow::onNoCam() void CMainWindow::stopCancelContinuousRecording(bool bTrue) { + qDebug() << __func__ << bTrue; if (bTrue) { onStopPhotoAndRecord(); } @@ -1425,6 +1426,9 @@ void CMainWindow::onTimeoutLock(const QString &serviceName, QVariantMap key2valu onStopPhotoAndRecord(); } // } + + // 锁屏时,停用摄像头,因为用户可能需要人脸解锁。解锁后,恢复使用摄像头。 + m_videoPre->onLockedScreen(key2value.value("Locked").value()); } void CMainWindow::onTrashFile(const QString &fileName) diff --git a/src/src/videowidget.cpp b/src/src/videowidget.cpp index 875032d5..ecef45c5 100644 --- a/src/src/videowidget.cpp +++ b/src/src/videowidget.cpp @@ -503,6 +503,15 @@ void videowidget::ReceiveMajorImage(QImage *image, int result) } } +void videowidget::onLockedScreen(bool bLocked) +{ + m_isLockedScreen = bLocked; + if (m_isLockedScreen) { + // 复用现有函数,达到关闭摄像头的效果 + this->onReachMaxDelayedFrames(); + } +} + void videowidget::onReachMaxDelayedFrames() { check_device_list_events(get_v4l2_device_handler()); @@ -1022,6 +1031,11 @@ void videowidget::onEndBtnClicked() void videowidget::onRestartDevices() { + if (m_isLockedScreen) { + qDebug() << __func__ << "bypass reason(locked screen)"; + return; + } + if (DataManager::instance()->getdevStatus() != CAM_CANUSE) { qDebug() << "Device status:" << DataManager::instance()->getdevStatus(); onChangeDev(); diff --git a/src/src/videowidget.h b/src/src/videowidget.h index 7ab89f60..71dcd5ff 100644 --- a/src/src/videowidget.h +++ b/src/src/videowidget.h @@ -320,6 +320,12 @@ public slots: */ void onFilterDisplayChanged(int bDisplay); + /** + * @brief 锁屏事件 + * @param bLocked 是否处于锁屏状态 + */ + void onLockedScreen(bool bLocked); + private slots: /** * @brief ReceiveMajorImage 处理视频帧 mips、wayland下使用 @@ -466,7 +472,7 @@ private slots: efilterType m_filterType; //当前选择的滤镜名称 int m_exposure; bool m_isFlash = false; - + bool m_isLockedScreen = false; // 是否处于锁屏状态 }; #endif // VIDEOWIDGET_H From 6ebb1846001d180d9ef9f9a079086990bc5427c7 Mon Sep 17 00:00:00 2001 From: zhanghongyuan Date: Mon, 13 Oct 2025 14:23:33 +0800 Subject: [PATCH 060/107] fix: [log] verbosity configuration initialization order - Added verbosity field to config structure for persistent storage - Fixed initialization sequence to load verbosity from config before updating options - Ensured debug level is set from saved configuration rather than default options - Maintained configuration file compatibility with new verbosity parameter Log: Fix debug level configuration loading sequence --- libcam/libcam/cameraconfig.c | 46 +++++++++++++++++++++--------------- libcam/libcam/cameraconfig.h | 1 + src/src/LPF_V4L2.c | 7 +++--- 3 files changed, 32 insertions(+), 22 deletions(-) diff --git a/libcam/libcam/cameraconfig.c b/libcam/libcam/cameraconfig.c index 786af2cd..6cbb8565 100644 --- a/libcam/libcam/cameraconfig.c +++ b/libcam/libcam/cameraconfig.c @@ -48,27 +48,28 @@ static config_t my_config = .device_name = NULL, .device_location = NULL, .format = V4L2_PIX_FMT_MJPEG, - .render = "sdl", - .gui = "qt5", - .audio = "port", - .capture = "mmap", + .render = "sdl", + .gui = "qt5", + .audio = "port", + .capture = "mmap", .video_codec = "mjpg",/*yuy2,mjpg,mpeg,flv1,wmv1,mpg2,mp43,dx50,h264,hevc,vp80,vp90,theo*/ .audio_codec = "aac", - .profile_name = NULL, - .profile_path = NULL, + .profile_name = NULL, + .profile_path = NULL, .video_name = NULL, - .video_path = NULL, - .photo_name = NULL, - .photo_path = NULL, - .video_sufix = 1, - .photo_sufix = 1, - .fps_num = 1, + .video_path = NULL, + .photo_name = NULL, + .photo_path = NULL, + .video_sufix = 1, + .photo_sufix = 1, + .fps_num = 1, .fps_denom = 30, .audio_device = -1,/*will use API default in this case*/ - .video_fx = 0, /*no video fx*/ - .audio_fx = 0, /*no audio fx*/ - .osd_mask = 0, /*REND_OSD_NONE*/ - .crosshair_color=0x0000FF00, /*osd crosshair rgb color (0x00RRGGBB)*/ + .video_fx = 0, /*no video fx*/ + .audio_fx = 0, /*no audio fx*/ + .osd_mask = 0, /*REND_OSD_NONE*/ + .crosshair_color=0x0000FF00, /*osd crosshair rgb color (0x00RRGGBB)*/ + .verbosity=0 }; /* @@ -149,9 +150,10 @@ int config_save(const char *filename) fprintf(fp, "#OSD mask \n"); fprintf(fp, "osd_mask=0x%x\n", my_config.osd_mask); fprintf(fp, "crosshair_color=0x%x\n", my_config.crosshair_color); - + fprintf(fp, "#verbosity \n"); + fprintf(fp, "verbosity=%i\n", my_config.verbosity); /* return to system locale */ - setlocale(LC_NUMERIC, ""); + setlocale(LC_NUMERIC, ""); /* flush stream buffers to filesystem */ fflush(fp); @@ -310,6 +312,10 @@ int config_load(const char *filename) free(my_config.photo_path); my_config.photo_path = strdup(value); } + else if(strcmp(token, "verbosity") == 0) + { + my_config.verbosity = (int) strtoul(value, NULL, 10); + } // else if(strcmp(token, "video_sufix") == 0) // { // my_config.video_sufix = (int) strtoul(value, NULL, 10); @@ -454,7 +460,9 @@ void config_update(options_t *my_options) free(my_config.photo_path); my_config.photo_path = strdup(my_options->photo_path); } - + /*check for verbosity options*/ + if(my_options->verbosity >= 0) + my_config.verbosity = my_options->verbosity; } /* diff --git a/libcam/libcam/cameraconfig.h b/libcam/libcam/cameraconfig.h index ed4f9b5e..ac6e2d4c 100644 --- a/libcam/libcam/cameraconfig.h +++ b/libcam/libcam/cameraconfig.h @@ -64,6 +64,7 @@ typedef struct _config_t { uint32_t audio_fx; uint32_t osd_mask; /*OSD bit mask*/ uint32_t crosshair_color; /*osd crosshair rgb color (0x00RRGGBB)*/ + int verbosity; } config_t; /*video sufix flag*/ diff --git a/src/src/LPF_V4L2.c b/src/src/LPF_V4L2.c index f70bebaf..3a8efe2e 100644 --- a/src/src/LPF_V4L2.c +++ b/src/src/LPF_V4L2.c @@ -49,11 +49,12 @@ int camInit(const char *devicename) free(device_name); /*加载配置文件*/ config_load(config_file); - /*用option更新配置文件*/ - config_update(my_options); /*获取配置项数据*/ config_t *my_config = config_get(); - debug_level = my_options->verbosity; + debug_level = my_config->verbosity; + my_options->verbosity = my_config->verbosity; + /*用option更新配置文件*/ + config_update(my_options); int audio = AUDIO_PORTAUDIO; From 25477850875d01dd29ebb40e5230719919d7e0a6 Mon Sep 17 00:00:00 2001 From: zhanghongyuan Date: Mon, 17 Nov 2025 14:17:33 +0800 Subject: [PATCH 061/107] fix(udev): add subsystem and devtype function loading - fix log crush in check_device_list_events() --- src/src/basepub/load_libs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/src/basepub/load_libs.c b/src/src/basepub/load_libs.c index a159f228..fe0a1b27 100644 --- a/src/src/basepub/load_libs.c +++ b/src/src/basepub/load_libs.c @@ -440,6 +440,8 @@ static LoadUdev *newUdev(void) PrintError(); pUdev->m_udev_monitor_receive_device = (uos_udev_monitor_receive_device)dlsym(handle, "udev_monitor_receive_device"); PrintError(); + pUdev->m_udev_device_get_subsystem = (uos_udev_device_get_subsystem)dlsym(handle, "udev_device_get_subsystem"); + PrintError(); pUdev->m_udev_device_get_devtype = (uos_udev_device_get_devtype)dlsym(handle, "udev_device_get_devtype"); PrintError(); pUdev->m_udev_device_get_action = (uos_udev_device_get_action)dlsym(handle, "udev_device_get_action"); From eb8d03f9a3b42eaa44676fc27c276dce95134881 Mon Sep 17 00:00:00 2001 From: zhanghongyuan Date: Mon, 17 Nov 2025 14:05:30 +0800 Subject: [PATCH 062/107] feat(perf): add periodic decode timing measurements and reduce verbose logging - Add decode performance monitoring that measures and logs decode time every 5 operations - Reduce verbose logging frequency in JPEG decoder to print every 5th frame instead of every frame - Include QElapsedTimer header for timing functionality - Maintain existing behavior when verbosity is disabled --- libcam/libcam_v4l2core/jpeg_decoder.c | 13 +++++++++---- libcam/libcam_v4l2core/v4l2_core.h | 5 +++++ src/src/majorimageprocessingthread.cpp | 16 +++++++++++++++- src/src/majorimageprocessingthread.h | 1 + 4 files changed, 30 insertions(+), 5 deletions(-) diff --git a/libcam/libcam_v4l2core/jpeg_decoder.c b/libcam/libcam_v4l2core/jpeg_decoder.c index 8995c3e4..cf65efa6 100644 --- a/libcam/libcam_v4l2core/jpeg_decoder.c +++ b/libcam/libcam_v4l2core/jpeg_decoder.c @@ -1598,11 +1598,16 @@ int jpeg_decode(uint8_t *out_buf, uint8_t *in_buf, int size) } else { // Software decoding: Use decoded frames directly #if LIBAVUTIL_VER_AT_LEAST(54,6) + static int decodeCount = 0; if (verbosity > 0) { - printf("codec_data size(%dx%d) linesize(%d) format(%s) jpeg_ctx size(%dx%d) pic_size(%d)\n", codec_data->picture->width, codec_data->picture->height, - codec_data->picture->linesize[0], - getAvutil()->m_av_get_pix_fmt_name((enum AVPixelFormat)codec_data->picture->format), - jpeg_ctx->width, jpeg_ctx->height, jpeg_ctx->pic_size); + if (decodeCount % LOGGING_INTERVAL == LOGGING_INTERVAL - 1) { + printf("codec_data size(%dx%d) linesize(%d) format(%s) jpeg_ctx size(%dx%d) pic_size(%d)\n", codec_data->picture->width, codec_data->picture->height, + codec_data->picture->linesize[0], + getAvutil()->m_av_get_pix_fmt_name((enum AVPixelFormat)codec_data->picture->format), + jpeg_ctx->width, jpeg_ctx->height, jpeg_ctx->pic_size); + decodeCount = 0; + } + decodeCount++; } getAvutil()->m_av_image_copy_to_buffer(jpeg_ctx->tmp_frame, jpeg_ctx->pic_size, (const uint8_t * const*) codec_data->picture->data, codec_data->picture->linesize, diff --git a/libcam/libcam_v4l2core/v4l2_core.h b/libcam/libcam_v4l2core/v4l2_core.h index 0d9ada9a..de1bb3bd 100644 --- a/libcam/libcam_v4l2core/v4l2_core.h +++ b/libcam/libcam_v4l2core/v4l2_core.h @@ -91,3 +91,8 @@ struct _v4l2_dev_t }; void /*__attribute__ ((constructor))*/ v4l2core_init(); #endif + +/* + * logging interval + */ +#define LOGGING_INTERVAL 5 diff --git a/src/src/majorimageprocessingthread.cpp b/src/src/majorimageprocessingthread.cpp index 929ee474..01907e7d 100644 --- a/src/src/majorimageprocessingthread.cpp +++ b/src/src/majorimageprocessingthread.cpp @@ -194,7 +194,21 @@ void MajorImageProcessingThread::run() } m_result = -1; - m_frame = v4l2core_get_decoded_frame(m_videoDevice); + if (config_get()->verbosity > 0) { + static QElapsedTimer decodeTimer; + static int decodeCount = 0; + if (decodeCount % LOGGING_INTERVAL == LOGGING_INTERVAL - 1) { + decodeTimer.start(); + m_frame = v4l2core_get_decoded_frame(m_videoDevice); + qDebug() << "v4l2 decoded time:" << decodeTimer.elapsed() << "ms"; + decodeCount = 0; + } else { + m_frame = v4l2core_get_decoded_frame(m_videoDevice); + decodeCount++; + } + } else { + m_frame = v4l2core_get_decoded_frame(m_videoDevice); + } if (m_frame == nullptr) { framedely++; diff --git a/src/src/majorimageprocessingthread.h b/src/src/majorimageprocessingthread.h index 235663ee..5376ae4b 100644 --- a/src/src/majorimageprocessingthread.h +++ b/src/src/majorimageprocessingthread.h @@ -11,6 +11,7 @@ #include #include #include +#include #include "datamanager.h" From c546603c2f09f8f740660807d997b3232eca24a0 Mon Sep 17 00:00:00 2001 From: lichaofan Date: Thu, 20 Nov 2025 16:27:53 +0800 Subject: [PATCH 063/107] fix: m_isFlash is placed in the wrong place. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit m_isFlash变量放错了位置,导致MIPS架构的相机在拍照后预览出现黑屏。 Bug: https://pms.uniontech.com/bug-view-341465.html --- src/src/videowidget.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/src/videowidget.cpp b/src/src/videowidget.cpp index ecef45c5..5f1431ca 100644 --- a/src/src/videowidget.cpp +++ b/src/src/videowidget.cpp @@ -865,9 +865,8 @@ void videowidget::flash() } else { m_pNormalView->show(); } - m_isFlash = false; - #endif + m_isFlash = false; m_flashLabel->hide(); //为避免没有关闭,放到定时器里边关闭 if (m_curTakePicTime == 0) From 51b80762ee12155a345b5549a2654911439ce2fd Mon Sep 17 00:00:00 2001 From: lichaofan Date: Wed, 17 Dec 2025 16:13:33 +0800 Subject: [PATCH 064/107] feat: Listen for SIGTERM and exit the application gracefully. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DDE may kill the deepin-camera circumstances, the logging system would consider it. 监听 SIGTERM 信号,正常退出应用。 由于DDE在某些情况下会kill掉deepin-camera进程,同时埋点会认为deepin-camera出错,所以这里监听信号,正常退出。 --- src/main.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index 147a8e41..4d690d1f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -31,6 +31,7 @@ extern "C" { #include #include #include +#include #ifndef DEEPIN_CAMERA_PRO #include "config.h" @@ -93,8 +94,19 @@ static bool CheckFFmpegEnv() return false; } +// 由于DDE在某些情况下会kill掉deepin-camera进程,同时埋点会认为deepin-camera出错,所以这里监听信号,正常退出 +// 添加信号处理函数 +static void handleSignal(int sig) +{ + qWarning() << "Received signal:" << sig; + exit(0); +} + int main(int argc, char *argv[]) { + // 注册信号处理函数 + signal(SIGTERM, handleSignal); // kill默认发送的信号 + // 将日志配置提前,以确保所有日志没有遗漏 //qputenv("QT_LOGGING_RULES", "*.debug=true;*.info=true"); DLogManager::registerConsoleAppender(); From eabd1bc472ad5d94abd845b15c30c8835aca7386 Mon Sep 17 00:00:00 2001 From: lichaofan Date: Wed, 17 Dec 2025 17:42:36 +0800 Subject: [PATCH 065/107] fix: Limit the available resolution to 3840x2160. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Due to issues with the upstream guvcview project (such as stripes and crashes) when decoding resolutions above 3840x2160, we need to limit the available resolution to 3840x2160. 限制可用分辨率到3840x2160。 由于上游guvcview项目在解码3840x2160分辨率以上时会出现异常(出现条纹、崩溃等),所以我们需要限制可用分辨率到3840x2160。 Bug: https://pms.uniontech.com/bug-view-343291.html --- libcam/libcam_v4l2core/v4l2_core.c | 3 ++- libcam/libcam_v4l2core/v4l2_formats.c | 12 ++++++++---- libcam/libcam_v4l2core/v4l2_formats.h | 4 ++-- src/src/Settings.cpp | 16 ++++++++-------- src/src/mainwindow.cpp | 16 +++++++--------- 5 files changed, 27 insertions(+), 24 deletions(-) diff --git a/libcam/libcam_v4l2core/v4l2_core.c b/libcam/libcam_v4l2core/v4l2_core.c index 357af10c..bcb1830f 100644 --- a/libcam/libcam_v4l2core/v4l2_core.c +++ b/libcam/libcam_v4l2core/v4l2_core.c @@ -1696,7 +1696,8 @@ void v4l2core_prepare_valid_resolution(v4l2_dev_t *vd) } } - // 查找可以支持的最大分辨率(目前类似8000x6000的解码问题未解决,故要限制最大分辨率) + // 查找可以支持的最大分辨率 + // 由于上游guvcview项目在解码3840x2160分辨率以上时会出现异常(出现条纹、崩溃等),所以我们需要限制可用分辨率到3840x2160 printf("V4L2_CORE: valid resolution counts: %d\n", vd->list_stream_formats[format_index].numb_res); for(int i=0; i < vd->list_stream_formats[format_index].numb_res; i++) { diff --git a/libcam/libcam_v4l2core/v4l2_formats.c b/libcam/libcam_v4l2core/v4l2_formats.c index 92f320f4..da651e1b 100644 --- a/libcam/libcam_v4l2core/v4l2_formats.c +++ b/libcam/libcam_v4l2core/v4l2_formats.c @@ -678,7 +678,8 @@ int get_format_resolution_index(v4l2_dev_t *vd, int format, int width, int heigh return (-1); } - // 查找输入的分辨率是否在支持的分辨率列表中(目前类似8000x6000的解码问题未解决,故要限制最大分辨率) + // 查找输入的分辨率是否在支持的分辨率列表中 + // 由于上游guvcview项目在解码3840x2160分辨率以上时会出现异常(出现条纹、崩溃等),所以我们需要限制可用分辨率到3840x2160 int i=0; for(i=0; i < vd->list_stream_formats[format].numb_res; i++) { @@ -689,7 +690,8 @@ int get_format_resolution_index(v4l2_dev_t *vd, int format, int width, int heigh } } - // 查找可以支持的最大分辨率(目前类似8000x6000的解码问题未解决,故要限制最大分辨率) + // 查找可以支持的最大分辨率 + // 由于上游guvcview项目在解码3840x2160分辨率以上时会出现异常(出现条纹、崩溃等),所以我们需要限制可用分辨率到3840x2160 int tempwidth = 0; int tempheight = 0; int index = -1; @@ -746,6 +748,8 @@ void free_frame_formats(v4l2_dev_t *vd) int is_valid_resolution(int width, int height) { - // 目前类似8000x6000的解码问题未解决,故要限制最大分辨率 - return (width < MAX_WIDTH_LIMIT && height < MAX_HEIGHT_LIMIT) && (width % 16 == 0 && height % 8 == 0); + // 由于上游guvcview项目在解码3840x2160分辨率以上时会出现异常(出现条纹、崩溃等),所以我们需要限制可用分辨率到3840x2160 + return (width > 0 && height > 0) + && (width <= MAX_WIDTH_LIMIT && height <= MAX_HEIGHT_LIMIT) + && (width % 16 == 0 && height % 8 == 0); } diff --git a/libcam/libcam_v4l2core/v4l2_formats.h b/libcam/libcam_v4l2core/v4l2_formats.h index 99201a7f..dafed99c 100644 --- a/libcam/libcam_v4l2core/v4l2_formats.h +++ b/libcam/libcam_v4l2core/v4l2_formats.h @@ -24,8 +24,8 @@ #include "gviewv4l2core.h" #include "v4l2_core.h" -#define MAX_WIDTH_LIMIT 7680 -#define MAX_HEIGHT_LIMIT 4320 +#define MAX_WIDTH_LIMIT 3840 +#define MAX_HEIGHT_LIMIT 2160 /* * check pixelformat against decoder support formats diff --git a/src/src/Settings.cpp b/src/src/Settings.cpp index cd6d58ed..645dc00c 100644 --- a/src/src/Settings.cpp +++ b/src/src/Settings.cpp @@ -3,8 +3,12 @@ // // SPDX-License-Identifier: GPL-3.0-or-later +extern "C" { +#include "v4l2_formats.h" +} #include "Settings.h" #include "camview.h" +#include "v4l2_formats.h" #include "gviewv4l2core.h" #include "capplication.h" #include "camera.h" @@ -112,15 +116,11 @@ void Settings::setNewResolutionList() if (format_index >= 0 && resolu_index >= 0) { for (int i = 0 ; i < list_stream_formats[format_index].numb_res; i++) { - if ((list_stream_formats[format_index].list_stream_cap[i].width > 0 - && list_stream_formats[format_index].list_stream_cap[i].height > 0) && - (list_stream_formats[format_index].list_stream_cap[i].width < 7680 - && list_stream_formats[format_index].list_stream_cap[i].height < 4320) && - ((list_stream_formats[format_index].list_stream_cap[i].width % 8) == 0 - && (list_stream_formats[format_index].list_stream_cap[i].width % 16) == 0 - && (list_stream_formats[format_index].list_stream_cap[i].height % 8) == 0)) { + int w = list_stream_formats[format_index].list_stream_cap[i].width; + int h = list_stream_formats[format_index].list_stream_cap[i].height; + if (is_valid_resolution(w, h)) { //加入分辨率的字符串 - QString res_str = QString("%1x%2").arg(list_stream_formats[format_index].list_stream_cap[i].width).arg(list_stream_formats[format_index].list_stream_cap[i].height); + QString res_str = QString("%1x%2").arg(w).arg(h); //去重 if (resolutionDatabase.contains(res_str) == false) resolutionDatabase.append(res_str); diff --git a/src/src/mainwindow.cpp b/src/src/mainwindow.cpp index b92877c0..c9fe9b7c 100644 --- a/src/src/mainwindow.cpp +++ b/src/src/mainwindow.cpp @@ -3,6 +3,9 @@ // // SPDX-License-Identifier: GPL-3.0-or-later +extern "C" { +#include "v4l2_formats.h" +} #include "mainwindow.h" #include "capplication.h" #include "v4l2_core.h" @@ -1107,16 +1110,11 @@ void CMainWindow::settingDialog() //format_index = -1 &&resolu_index = -1 表示设备被占用或者不存在 for (int i = 0 ; i < list_stream_formats[format_index].numb_res; i++) { - - if ((list_stream_formats[format_index].list_stream_cap[i].width > 0 - && list_stream_formats[format_index].list_stream_cap[i].height > 0) && - (list_stream_formats[format_index].list_stream_cap[i].width < 7680 - && list_stream_formats[format_index].list_stream_cap[i].height < 4320) && - ((list_stream_formats[format_index].list_stream_cap[i].width % 8) == 0 - && (list_stream_formats[format_index].list_stream_cap[i].width % 16) == 0 - && (list_stream_formats[format_index].list_stream_cap[i].height % 8) == 0)) { + int w = list_stream_formats[format_index].list_stream_cap[i].width; + int h = list_stream_formats[format_index].list_stream_cap[i].height; + if (is_valid_resolution(w, h)) { //加入分辨率的字符串 - QString res_str = QString("%1x%2").arg(list_stream_formats[format_index].list_stream_cap[i].width).arg(list_stream_formats[format_index].list_stream_cap[i].height); + QString res_str = QString("%1x%2").arg(w).arg(h); //去重 if (resolutionDatabase.contains(res_str) == false) From 4c8d01143a88d15b15823b5ebf57566188e5bb50 Mon Sep 17 00:00:00 2001 From: lichaofan Date: Thu, 25 Dec 2025 21:34:21 +0800 Subject: [PATCH 066/107] fix: audio_free_buffers() add a NULL check. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On the Zhaoxin processor, there is a probabilistic occurrence of null pointer/double-free issues with `audio_buffers[i].data`, so a NULL check needs to be added. 在兆芯处理器上,audio_buffers[i].data 概率性出现空指针/重复释放的情况,所以需要增加 NULL 判断。 Bug: https://pms.uniontech.com/bug-view-345713.html --- libcam/libcam_audio/audio.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libcam/libcam_audio/audio.c b/libcam/libcam_audio/audio.c index 3195bfb6..930fb879 100644 --- a/libcam/libcam_audio/audio.c +++ b/libcam/libcam_audio/audio.c @@ -131,7 +131,13 @@ static void audio_free_buffers() for(i = 0; i < AUDBUFF_NUM; ++i) { + // 在兆芯处理器上,audio_buffers[i].data 概率性出现空指针/重复释放的情况,所以这里需要增加判断 + if (audio_buffers[i].data == NULL) { + continue; + } + free(audio_buffers[i].data); + audio_buffers[i].data = NULL; } free(audio_buffers); From a8dd2398156f419417ab3a3f3b59dde8256e1fcb Mon Sep 17 00:00:00 2001 From: lichaofan Date: Thu, 25 Dec 2025 11:04:31 +0800 Subject: [PATCH 067/107] fix: Listen for SIGTERM and exit the application gracefully. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DDE may kill the deepin-camera circumstances, the logging system would consider it. We use QApplication::quit() to exit more gracefully. 监听 SIGTERM 信号,正常退出应用。 由于DDE在某些情况下会kill掉deepin-camera进程,同时埋点会认为deepin-camera出错,所以这里监听信号,正常退出。 在HW机器、SW机器上,发现使用exit(0)退出会导致Qt某些函数空指针异常,从而导致崩溃,疑似在资源回收环节出了问题。所以我们使用QApplication::quit()更优雅地退出。 Bug: https://pms.uniontech.com/bug-view-344677.html --- src/main.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 4d690d1f..b2e1c5bf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -99,14 +99,13 @@ static bool CheckFFmpegEnv() static void handleSignal(int sig) { qWarning() << "Received signal:" << sig; - exit(0); + // 在HW机器、SW机器上,发现使用exit(0)退出会导致Qt某些函数空指针异常,从而导致崩溃,疑似在资源回收环节出了问题。所以我们使用QApplication::quit()更优雅地退出。 + QApplication::quit(); + //exit(0); } int main(int argc, char *argv[]) { - // 注册信号处理函数 - signal(SIGTERM, handleSignal); // kill默认发送的信号 - // 将日志配置提前,以确保所有日志没有遗漏 //qputenv("QT_LOGGING_RULES", "*.debug=true;*.info=true"); DLogManager::registerConsoleAppender(); @@ -222,6 +221,9 @@ int main(int argc, char *argv[]) qDebug() << QString("initFilters cost %1 ms").arg(time.elapsed()); CApplication a(argc, argv); + // 注册信号处理函数 + // 放在此处,是为了确保Application已经创建了实例 + signal(SIGTERM, handleSignal); // kill默认发送的信号 //gst_init(&argc, &argv); qApp->setObjectName("deepin-camera"); From 9bd8e963d8c5308ebd67066ed47bfaae36ea90e7 Mon Sep 17 00:00:00 2001 From: lichaofan Date: Sat, 31 Jan 2026 13:38:12 +0800 Subject: [PATCH 068/107] feat: The prompt images for the FLM(support camera switch) have been optimized. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The prompt images for the FLM(support camera switch) have been optimized, and secondary prompts have also been added. FLM设备(带有摄像头开关)的提示图片进行了优化,同时增加了二级提示。 Task: https://pms.uniontech.com/task-view-386441.html --- src/assets/assets.qrc | 2 + .../icons/dark/camera_switch_not_on_dark.svg | 57 +++++++++++ .../icons/light/camera_switch_not_on.svg | 57 +++++++++++ src/assets/org.deepin.camera.encode.json | 10 ++ src/main.cpp | 5 + src/src/basepub/datamanager.h | 12 +++ src/src/videowidget.cpp | 95 ++++++++++++++++--- src/src/videowidget.h | 1 + src/translations/deepin-camera_zh_CN.ts | 4 + 9 files changed, 231 insertions(+), 12 deletions(-) create mode 100644 src/assets/images/icons/dark/camera_switch_not_on_dark.svg create mode 100644 src/assets/images/icons/light/camera_switch_not_on.svg diff --git a/src/assets/assets.qrc b/src/assets/assets.qrc index 77242fc9..ca85a2a6 100644 --- a/src/assets/assets.qrc +++ b/src/assets/assets.qrc @@ -7,6 +7,7 @@ images/icons/warning.svg deepin-camera.svg images/icons/light/Not connected.svg + images/icons/light/camera_switch_not_on.svg images/icons/light/photograph.svg images/icons/light/record video.svg images/icons/light/select-hover.svg @@ -18,6 +19,7 @@ images/icons/light/Stop Recording.svg images/icons/light/Timer Status.svg images/icons/dark/Not connected_dark.svg + images/icons/dark/camera_switch_not_on_dark.svg images/icons/dark/Take up_dark.svg images/icons/dark/button/photograph_dark.svg images/icons/dark/button/record video_dark.svg diff --git a/src/assets/images/icons/dark/camera_switch_not_on_dark.svg b/src/assets/images/icons/dark/camera_switch_not_on_dark.svg new file mode 100644 index 00000000..724e054a --- /dev/null +++ b/src/assets/images/icons/dark/camera_switch_not_on_dark.svg @@ -0,0 +1,57 @@ + + + 插图 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/icons/light/camera_switch_not_on.svg b/src/assets/images/icons/light/camera_switch_not_on.svg new file mode 100644 index 00000000..724e054a --- /dev/null +++ b/src/assets/images/icons/light/camera_switch_not_on.svg @@ -0,0 +1,57 @@ + + + 插图 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/org.deepin.camera.encode.json b/src/assets/org.deepin.camera.encode.json index fe01c2d3..af63d8ca 100644 --- a/src/assets/org.deepin.camera.encode.json +++ b/src/assets/org.deepin.camera.encode.json @@ -51,6 +51,16 @@ "description": "Name of the VDPAU driver for enabling hardware codec", "permissions": "readwrite", "visibility": "private" + }, + "supportCameraSwitch": { + "value": false, + "serial": 0, + "flags": ["global"], + "name": "is support camera switch or not", + "name[zh_CN]": "是否带有摄像头开关", + "description": "is support camera switch or not", + "permissions": "readwrite", + "visibility": "private" } } } diff --git a/src/main.cpp b/src/main.cpp index b2e1c5bf..b934b93c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -11,6 +11,7 @@ extern "C" { #include "cameraconfig.h" #include "acobjectlist.h" #include "dbus_adpator.h" +#include #ifdef DTKCORE_CLASS_DConfigFile #include @@ -173,6 +174,10 @@ int main(int argc, char *argv[]) set_libvdpau_driver_name(libVdpauDriverName.toUtf8().constData()); } + if (dconfig && dconfig->isValid() && dconfig->keyList().contains("supportCameraSwitch")) { + DataManager::instance()->setIsSupportCameraSwitch(dconfig->value("supportCameraSwitch").toBool()); + } + if (!libVaDriverName.isEmpty()) { qputenv("LIBVA_DRIVER_NAME", libVaDriverName.toLocal8Bit()); } diff --git a/src/src/basepub/datamanager.h b/src/src/basepub/datamanager.h index e2c6c16d..be097979 100644 --- a/src/src/basepub/datamanager.h +++ b/src/src/basepub/datamanager.h @@ -143,6 +143,17 @@ class DataManager: public QObject void setEncExists(bool status); bool encExists(); + /** + * @brief 设置是否带有摄像头开关 + * @param isTrue + */ + void setIsSupportCameraSwitch(bool isTrue) { m_isSupportCameraSwitch = isTrue; }; + /** + * @brief 获取是否带有摄像头开关 + * @return + */ + bool isSupportCameraSwitch() { return m_isSupportCameraSwitch; }; + private: DataManager(); static DataManager *m_dataManager; @@ -152,5 +163,6 @@ class DataManager: public QObject EncodeEnv m_encodeEnv; volatile enum DeviceStatus m_devStatus; bool m_H264EncoderExists; + bool m_isSupportCameraSwitch = false; // 是否带有摄像头开关 }; #endif // DATAMANAGER_H diff --git a/src/src/videowidget.cpp b/src/src/videowidget.cpp index 5f1431ca..45a7d775 100644 --- a/src/src/videowidget.cpp +++ b/src/src/videowidget.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #define COUNTDOWN_WIDTH 32 #define COUNTDOWN_HEIGHT 61 @@ -120,6 +121,10 @@ videowidget::videowidget(DWidget *parent) // 画布错误提示图元 m_pCamErrItem = new QGraphicsTextItem; m_pCamErrItem->setZValue(2); + m_pCamErrItemSub = new QGraphicsTextItem; + m_pCamErrItemSub->setTextWidth(370); + m_pCamErrItemSub->document()->setDefaultTextOption(QTextOption(Qt::AlignCenter)); // 设置文本居中 + m_pCamErrItemSub->setZValue(2); m_pGridLayout = new QGridLayout(this); DLabel *recordingRedStatus = new DLabel;//录制状态红点 @@ -143,6 +148,7 @@ videowidget::videowidget(DWidget *parent) m_pNormalScene->addItem(m_pNormalItem); m_pNormalScene->addItem(m_pSvgItem); m_pNormalScene->addItem(m_pCamErrItem); + m_pNormalScene->addItem(m_pCamErrItemSub); m_pNormalScene->addItem(m_pGridLineItem); recordingwidgetlay->setSpacing(0); @@ -283,8 +289,10 @@ void videowidget::showNocam() if (!m_pNormalView->isVisible()) m_pNormalView->show(); - if (!m_pCamErrItem->isVisible()) + if (!m_pCamErrItem->isVisible()) { m_pCamErrItem->show(); + m_pCamErrItemSub->show(); + } if (!m_pSvgItem->isVisible()) m_pSvgItem->show(); @@ -303,16 +311,29 @@ void videowidget::showNocam() emit sigDeviceChange(); + QString strsub; if (DGuiApplicationHelper::LightType == DGuiApplicationHelper::instance()->themeType()) { - m_pSvgItem->setSharedRenderer(new QSvgRenderer(QString(":/images/icons/light/Not connected.svg"), this)); + if (DataManager::instance()->isSupportCameraSwitch()) { + m_pSvgItem->setSharedRenderer(new QSvgRenderer(QString(":/images/icons/light/camera_switch_not_on.svg"), this)); + strsub = tr("Your camera might not be turned on. If you need to use it, please check whether the hardware switch of the camera or the camera hotkey on the keyboard is enabled"); + } else { + m_pSvgItem->setSharedRenderer(new QSvgRenderer(QString(":/images/icons/light/Not connected.svg"), this)); + } QColor clr(255, 255, 255); clr.setAlphaF(0.8); m_pCamErrItem->setDefaultTextColor(clr); + m_pCamErrItemSub->setDefaultTextColor(clr); } else { - m_pSvgItem->setSharedRenderer(new QSvgRenderer(QString(":/images/icons/dark/Not connected_dark.svg"), this)); + if (DataManager::instance()->isSupportCameraSwitch()) { + m_pSvgItem->setSharedRenderer(new QSvgRenderer(QString(":/images/icons/dark/camera_switch_not_on_dark.svg"), this)); + strsub = tr("Your camera might not be turned on. If you need to use it, please check whether the hardware switch of the camera or the camera hotkey on the keyboard is enabled"); + } else { + m_pSvgItem->setSharedRenderer(new QSvgRenderer(QString(":/images/icons/dark/Not connected_dark.svg"), this)); + } QColor clr(Qt::white); clr.setAlphaF(0.2); m_pCamErrItem->setDefaultTextColor(clr); + m_pCamErrItemSub->setDefaultTextColor(clr); } QFont ft("SourceHanSansSC"); @@ -321,12 +342,17 @@ void videowidget::showNocam() m_pCamErrItem->setFont(ft); QString str(tr("No webcam found"));//未连接摄像头 m_pCamErrItem->setPlainText(str); + QFont ftsub("SourceHanSansSC"); + ftsub.setPixelSize(12); + m_pCamErrItemSub->setFont(ftsub); + m_pCamErrItemSub->setPlainText(strsub); m_pNormalScene->setSceneRect(m_pSvgItem->boundingRect()); m_flashLabel->hide(); itemPosChange(); m_pCamErrItem->show(); + m_pCamErrItemSub->show(); m_pSvgItem->show(); emit noCam(); @@ -362,24 +388,32 @@ void videowidget::showCamUsed() clrText.setAlphaF(0.8); m_pCamErrItem->setDefaultTextColor(clrText);//浅色主题文字和图片是白色,特殊处理 m_pCamErrItem->setPlainText(str); + m_pCamErrItemSub->setDefaultTextColor(clrText); + m_pCamErrItemSub->setPlainText(QString()); } else { m_pSvgItem->setSharedRenderer(new QSvgRenderer(QString(":/images/icons/dark/Take up_dark.svg"), this)); QColor clrText(Qt::white); clrText.setAlphaF(0.2); m_pCamErrItem->setDefaultTextColor(clrText); m_pCamErrItem->setPlainText(str); + m_pCamErrItemSub->setDefaultTextColor(clrText); + m_pCamErrItemSub->setPlainText(QString()); } QFont ft("SourceHanSansSC"); ft.setWeight(QFont::DemiBold); ft.setPixelSize(17); m_pCamErrItem->setFont(ft); + QFont ftsub("SourceHanSansSC"); + ftsub.setPixelSize(12); + m_pCamErrItemSub->setFont(ftsub); m_pNormalScene->setSceneRect(m_pSvgItem->boundingRect()); m_flashLabel->hide(); itemPosChange(); m_pCamErrItem->show(); + m_pCamErrItemSub->show(); m_pSvgItem->show(); emit noCamAvailable(); @@ -392,8 +426,10 @@ void videowidget::ReceiveOpenGLstatus(bool result) //qDebug() << "ReceiveOpenGLstatus" << result; if (result && m_openglwidget) { //Success - if (m_pCamErrItem->isVisible()) + if (m_pCamErrItem->isVisible()) { m_pCamErrItem->hide(); + m_pCamErrItemSub->hide(); + } if (m_pSvgItem->isVisible()) m_pSvgItem->hide(); @@ -458,6 +494,7 @@ void videowidget::ReceiveMajorImage(QImage *image, int result) if (!m_isFlash) m_pNormalView->show(); m_pCamErrItem->hide(); + m_pCamErrItemSub->hide(); m_pSvgItem->hide(); m_pNormalItem->show(); @@ -545,6 +582,7 @@ void videowidget::showCountDownLabel(PREVIEW_ENUM_STATE state) case VIDEO: m_pCamErrItem->hide(); + m_pCamErrItemSub->show(); m_pSvgItem->hide(); if (!get_capture_pause()) {//判断是否是暂停状态 @@ -597,6 +635,7 @@ void videowidget::showCountDownLabel(PREVIEW_ENUM_STATE state) default: m_pCamErrItem->hide(); + m_pCamErrItemSub->hide(); m_pSvgItem->hide(); m_recordingTimeWidget->hide(); break; @@ -619,10 +658,12 @@ void videowidget::resizeEvent(QResizeEvent *size) if (m_pCamErrItem->isVisible()) { itemPosChange(); m_pCamErrItem->show(); + m_pCamErrItemSub->show(); m_pSvgItem->show(); } else { itemPosChange(); m_pCamErrItem->hide(); + m_pCamErrItemSub->hide(); } if (m_gridlinewidget) @@ -764,6 +805,7 @@ void videowidget::showCountdown() m_countTimer->start(m_nMaxInterval == 34 ? 0 : 1000); m_pCamErrItem->hide(); + m_pCamErrItemSub->hide(); m_pSvgItem->hide(); m_pNormalView->hide(); } @@ -945,8 +987,10 @@ void videowidget::onEndBtnClicked() if (m_recordingTimer->isActive()) m_recordingTimer->stop(); - if (m_pCamErrItem->isVisible() && (m_imgPrcThread->getStatus() == 0) && DataManager::instance()->encodeEnv() != QCamera_Env) + if (m_pCamErrItem->isVisible() && (m_imgPrcThread->getStatus() == 0) && DataManager::instance()->encodeEnv() != QCamera_Env) { m_pCamErrItem->hide(); + m_pCamErrItemSub->hide(); + } if (m_pSvgItem->isVisible() && (m_imgPrcThread->getStatus() == 0) && DataManager::instance()->encodeEnv() != QCamera_Env) m_pSvgItem->hide(); @@ -1173,8 +1217,10 @@ void videowidget::onTakePic(bool bTrue) if (m_countTimer->isActive()) m_countTimer->stop(); - if (m_pCamErrItem->isVisible() && (m_imgPrcThread->getStatus() == 0)) + if (m_pCamErrItem->isVisible() && (m_imgPrcThread->getStatus() == 0)) { m_pCamErrItem->hide(); + m_pCamErrItemSub->hide(); + } if (m_pSvgItem->isVisible() && (m_imgPrcThread->getStatus() == 0)) m_pSvgItem->hide(); @@ -1226,8 +1272,10 @@ void videowidget::onTakeVideo() //点一次开,再点一次关 if (m_countTimer->isActive()) m_countTimer->stop(); - if (m_pCamErrItem->isVisible()) + if (m_pCamErrItem->isVisible()) { m_pCamErrItem->hide(); + m_pCamErrItemSub->hide(); + } if (m_pSvgItem->isVisible()) m_pSvgItem->hide(); @@ -1258,8 +1306,10 @@ void videowidget::onTakeVideo() //点一次开,再点一次关 if (m_countTimer->isActive()) m_countTimer->stop(); - if (m_pCamErrItem->isVisible()) + if (m_pCamErrItem->isVisible()) { m_pCamErrItem->hide(); + m_pCamErrItemSub->hide(); + } if (m_pSvgItem->isVisible()) m_pSvgItem->hide(); @@ -1426,9 +1476,11 @@ void videowidget::startCaptureVideo() void videowidget::itemPosChange() { m_pCamErrItem->setPos((m_pSvgItem->boundingRect().width() - static_cast(m_pCamErrItem->boundingRect().width())) / 2, m_pSvgItem->boundingRect().height()); + m_pCamErrItemSub->setPos((m_pSvgItem->boundingRect().width() - static_cast(m_pCamErrItemSub->boundingRect().width())) / 2, m_pSvgItem->boundingRect().height() + m_pCamErrItem->boundingRect().height()); m_pSvgItem->update(); m_pCamErrItem->update(); + m_pCamErrItemSub->update(); } void videowidget::stopEverything() @@ -1440,8 +1492,10 @@ void videowidget::stopEverything() m_flashLabel->hide(); - if (m_pCamErrItem->isVisible()) + if (m_pCamErrItem->isVisible()) { m_pCamErrItem->hide(); + m_pCamErrItemSub->hide(); + } if (m_pSvgItem->isVisible()) m_pSvgItem->hide(); @@ -1459,10 +1513,15 @@ void videowidget::stopEverything() void videowidget::onThemeTypeChanged(DGuiApplicationHelper::ColorType themeType) { if (m_pSvgItem->isVisible()) { - QString str; + QString str, strsub; if (themeType == DGuiApplicationHelper::LightType) { if (DataManager::instance()->getdevStatus() == NOCAM) { - m_pSvgItem->setSharedRenderer(new QSvgRenderer(QString(":/images/icons/light/Not connected.svg"), this)); + if (DataManager::instance()->isSupportCameraSwitch()) { + m_pSvgItem->setSharedRenderer(new QSvgRenderer(QString(":/images/icons/light/camera_switch_not_on.svg"), this)); + strsub = tr("Your camera might not be turned on. If you need to use it, please check whether the hardware switch of the camera or the camera hotkey on the keyboard is enabled"); + } else { + m_pSvgItem->setSharedRenderer(new QSvgRenderer(QString(":/images/icons/light/Not connected.svg"), this)); + } str = tr("No webcam found");//未连接摄像头 } else {//仅CAM_CANNOT_USE m_pSvgItem->setSharedRenderer(new QSvgRenderer(QString(":/images/icons/light/Take up.svg"), this)); @@ -1473,10 +1532,17 @@ void videowidget::onThemeTypeChanged(DGuiApplicationHelper::ColorType themeType) clrText.setAlphaF(0.8); m_pCamErrItem->setDefaultTextColor(clrText); m_pCamErrItem->setPlainText(str); + m_pCamErrItemSub->setDefaultTextColor(clrText); + m_pCamErrItemSub->setPlainText(strsub); } else if (themeType == DGuiApplicationHelper::DarkType) { if (DataManager::instance()->getdevStatus() == NOCAM) { qDebug() << "changed theme 3"; - m_pSvgItem->setSharedRenderer(new QSvgRenderer(QString(":/images/icons/dark/Not connected_dark.svg"), this)); + if (DataManager::instance()->isSupportCameraSwitch()) { + m_pSvgItem->setSharedRenderer(new QSvgRenderer(QString(":/images/icons/dark/camera_switch_not_on_dark.svg"), this)); + strsub = tr("Your camera might not be turned on. If you need to use it, please check whether the hardware switch of the camera or the camera hotkey on the keyboard is enabled"); + } else { + m_pSvgItem->setSharedRenderer(new QSvgRenderer(QString(":/images/icons/dark/Not connected_dark.svg"), this)); + } str = tr("No webcam found");//未连接摄像头 } else {//仅CAM_CANNOT_USE qDebug() << "changed theme 4"; @@ -1488,12 +1554,17 @@ void videowidget::onThemeTypeChanged(DGuiApplicationHelper::ColorType themeType) clor.setAlphaF(0.2); m_pCamErrItem->setDefaultTextColor(clor);//浅色主题文字和图片是白色,特殊处理 m_pCamErrItem->setPlainText(str); + m_pCamErrItemSub->setDefaultTextColor(clor); + m_pCamErrItemSub->setPlainText(strsub); } QFont ft("SourceHanSansSC"); ft.setWeight(QFont::DemiBold); ft.setPixelSize(17); m_pCamErrItem->setFont(ft); + QFont ftsub("SourceHanSansSC"); + ftsub.setPixelSize(12); + m_pCamErrItemSub->setFont(ftsub); if (DataManager::instance()->getdevStatus() == NOCAM) { m_pNormalScene->setSceneRect(m_pSvgItem->boundingRect()); itemPosChange(); diff --git a/src/src/videowidget.h b/src/src/videowidget.h index 71dcd5ff..56bb0e37 100644 --- a/src/src/videowidget.h +++ b/src/src/videowidget.h @@ -465,6 +465,7 @@ private slots: QGraphicsPixmapItem *m_pNormalItem; QGraphicsTextItem *m_pCamErrItem; //摄像头异常提示 + QGraphicsTextItem *m_pCamErrItemSub; //摄像头异常提示,二级提示 bool m_flashEnable; //是否闪光灯 bool m_bPhoto = true; //相机当前状态,默认为拍照状态 diff --git a/src/translations/deepin-camera_zh_CN.ts b/src/translations/deepin-camera_zh_CN.ts index fde6e9a7..84ca307a 100644 --- a/src/translations/deepin-camera_zh_CN.ts +++ b/src/translations/deepin-camera_zh_CN.ts @@ -334,6 +334,10 @@ No webcam found 未连接摄像头 + + Your camera might not be turned on. If you need to use it, please check whether the hardware switch of the camera or the camera hotkey on the keyboard is enabled + 你的摄像头可能未开启,如需使用,请检查摄像头的硬件开关或键盘上的摄像头热键是否开启 + The webcam is in use 摄像头已被占用 From 0d20c750b323e755196b6c443f1651202d8f3717 Mon Sep 17 00:00:00 2001 From: lichaofan Date: Tue, 3 Mar 2026 16:47:02 +0800 Subject: [PATCH 069/107] fix: In the prompt interface, the grid is hidden to improve user experience. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the prompt interface, the grid is hidden to improve user experience. 提示界面下,不显示井字格,提升用户体验。 Bug: https://pms.uniontech.com/bug-view-351495.html --- src/src/videowidget.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/src/videowidget.cpp b/src/src/videowidget.cpp index 45a7d775..0bf8a8ef 100644 --- a/src/src/videowidget.cpp +++ b/src/src/videowidget.cpp @@ -303,8 +303,10 @@ void videowidget::showNocam() m_openglwidget->hide(); if (m_GridType != Grid_None) { - if (!m_pGridLineItem->isVisible()) - m_pGridLineItem->show(); + // 提示界面不显示井字格 + if (m_pGridLineItem->isVisible()) { + m_pGridLineItem->hide(); + } if (m_gridlinewidget->isVisible()) m_gridlinewidget->hide(); } @@ -374,8 +376,10 @@ void videowidget::showCamUsed() m_openglwidget->hide(); if (m_GridType != Grid_None) { - if (!m_pGridLineItem->isVisible()) - m_pGridLineItem->show(); + // 提示界面不显示井字格 + if (m_pGridLineItem->isVisible()) { + m_pGridLineItem->hide(); + } if (m_gridlinewidget->isVisible()) m_gridlinewidget->hide(); } @@ -1648,7 +1652,10 @@ void videowidget::setGridType(GridType type) m_pGridLineItem->hide(); } else { m_gridlinewidget->hide(); - m_pGridLineItem->show(); + // 提示界面不显示井字格 + if (!m_pSvgItem->isVisible()) { + m_pGridLineItem->show(); + } } } } From 452f4000fb4d562dff781fdcf088725d52724344 Mon Sep 17 00:00:00 2001 From: lichaofan Date: Wed, 4 Mar 2026 10:20:13 +0800 Subject: [PATCH 070/107] fix: Add DConfig for preview with no delay. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add DConfig for preview with no delay. DConfig中增加关于预览无延迟的配置。 Bug: https://pms.uniontech.com/bug-view-351345.html --- src/assets/org.deepin.camera.encode.json | 10 ++++++++++ src/main.cpp | 4 ++++ src/src/basepub/datamanager.h | 12 ++++++++++++ src/src/majorimageprocessingthread.cpp | 2 +- 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/assets/org.deepin.camera.encode.json b/src/assets/org.deepin.camera.encode.json index af63d8ca..7370ce3d 100644 --- a/src/assets/org.deepin.camera.encode.json +++ b/src/assets/org.deepin.camera.encode.json @@ -61,6 +61,16 @@ "description": "is support camera switch or not", "permissions": "readwrite", "visibility": "private" + }, + "previewNoDelay": { + "value": false, + "serial": 0, + "flags": ["global"], + "name": "is preview no delay or not", + "name[zh_CN]": "是否预览无延迟", + "description": "is preview no delay or not", + "permissions": "readwrite", + "visibility": "private" } } } diff --git a/src/main.cpp b/src/main.cpp index b934b93c..252a11c8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -178,6 +178,10 @@ int main(int argc, char *argv[]) DataManager::instance()->setIsSupportCameraSwitch(dconfig->value("supportCameraSwitch").toBool()); } + if (dconfig && dconfig->isValid() && dconfig->keyList().contains("previewNoDelay")) { + DataManager::instance()->setPreviewNoDelay(dconfig->value("previewNoDelay").toBool()); + } + if (!libVaDriverName.isEmpty()) { qputenv("LIBVA_DRIVER_NAME", libVaDriverName.toLocal8Bit()); } diff --git a/src/src/basepub/datamanager.h b/src/src/basepub/datamanager.h index be097979..db704291 100644 --- a/src/src/basepub/datamanager.h +++ b/src/src/basepub/datamanager.h @@ -154,6 +154,17 @@ class DataManager: public QObject */ bool isSupportCameraSwitch() { return m_isSupportCameraSwitch; }; + /** + * @brief 设置是否预览无延迟 + * @param isTrue + */ + void setPreviewNoDelay(bool isTrue) { m_isPreviewNoDelay = isTrue; }; + /** + * @brief 获取是否预览无延迟 + * @return + */ + bool isPreviewNoDelay() { return m_isPreviewNoDelay; }; + private: DataManager(); static DataManager *m_dataManager; @@ -164,5 +175,6 @@ class DataManager: public QObject volatile enum DeviceStatus m_devStatus; bool m_H264EncoderExists; bool m_isSupportCameraSwitch = false; // 是否带有摄像头开关 + bool m_isPreviewNoDelay = false; // 是否预览无延迟 }; #endif // DATAMANAGER_H diff --git a/src/src/majorimageprocessingthread.cpp b/src/src/majorimageprocessingthread.cpp index 01907e7d..53c497b0 100644 --- a/src/src/majorimageprocessingthread.cpp +++ b/src/src/majorimageprocessingthread.cpp @@ -487,7 +487,7 @@ void MajorImageProcessingThread::run() break; #endif //保证画面流畅的前提下降低刷新率 - if(m_nVdWidth <= 1920) { + if (!DataManager::instance()->isPreviewNoDelay() && m_nVdWidth <= 1920) { msleep(33); } } From 7420a340a1a5041881e3b05fe955b6ae34e28983 Mon Sep 17 00:00:00 2001 From: lichaofan Date: Tue, 10 Mar 2026 11:03:55 +0800 Subject: [PATCH 071/107] fix: a display logic error in the secondary prompt. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is a display logic error in the secondary prompt, and it should be consistent with the display logic of the primary prompt. 二级提示的显示逻辑错误,应该和一级提示的显示逻辑保持一致。 --- src/src/videowidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/src/videowidget.cpp b/src/src/videowidget.cpp index 0bf8a8ef..c084e867 100644 --- a/src/src/videowidget.cpp +++ b/src/src/videowidget.cpp @@ -586,7 +586,7 @@ void videowidget::showCountDownLabel(PREVIEW_ENUM_STATE state) case VIDEO: m_pCamErrItem->hide(); - m_pCamErrItemSub->show(); + m_pCamErrItemSub->hide(); m_pSvgItem->hide(); if (!get_capture_pause()) {//判断是否是暂停状态 From 6934da133bbecaaf3dbbb5bdc864c3a0496abb29 Mon Sep 17 00:00:00 2001 From: lichaofan Date: Thu, 12 Mar 2026 21:03:38 +0800 Subject: [PATCH 072/107] feat: Add the logic for switching cameras by USB groups. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the logic for switching cameras by USB groups. 增加按USB分组切换摄像头的逻辑。 代码来自xiwo分支。 --- src/assets/org.deepin.camera.encode.json | 10 ++ src/main.cpp | 6 ++ src/src/basepub/datamanager.h | 11 ++ src/src/videowidget.cpp | 127 +++++++++++++++++++---- src/src/videowidget.h | 8 ++ 5 files changed, 140 insertions(+), 22 deletions(-) diff --git a/src/assets/org.deepin.camera.encode.json b/src/assets/org.deepin.camera.encode.json index 7370ce3d..90ad17b9 100644 --- a/src/assets/org.deepin.camera.encode.json +++ b/src/assets/org.deepin.camera.encode.json @@ -71,6 +71,16 @@ "description": "is preview no delay or not", "permissions": "readwrite", "visibility": "private" + }, + "enableUsbGroup": { + "value": false, + "serial": 0, + "flags": ["global"], + "name": "enable USB group", + "name[zh_CN]": "是否启用USB摄像头分组", + "description": "Enable USB group", + "permissions": "readwrite", + "visibility": "private" } } } diff --git a/src/main.cpp b/src/main.cpp index 252a11c8..c40765ad 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -182,6 +182,12 @@ int main(int argc, char *argv[]) DataManager::instance()->setPreviewNoDelay(dconfig->value("previewNoDelay").toBool()); } + if (dconfig && dconfig->isValid() && dconfig->keyList().contains("enableUsbGroup")) { + bool enable = dconfig->value("enableUsbGroup").toBool(); + qInfo() << "enable USB group:" << enable; + DataManager::instance()->setEnableUsbGroup(enable); + } + if (!libVaDriverName.isEmpty()) { qputenv("LIBVA_DRIVER_NAME", libVaDriverName.toLocal8Bit()); } diff --git a/src/src/basepub/datamanager.h b/src/src/basepub/datamanager.h index db704291..fafa8068 100644 --- a/src/src/basepub/datamanager.h +++ b/src/src/basepub/datamanager.h @@ -165,6 +165,16 @@ class DataManager: public QObject */ bool isPreviewNoDelay() { return m_isPreviewNoDelay; }; + /** + * @brief 设置是否启用USB摄像头分组 + * @param enable + */ + void setEnableUsbGroup(bool enable) { m_enableUsbGroup = enable; }; + /** + * @brief 获取是否启用USB摄像头分组 + * @return + */ + bool isEnableUsbGroup() const { return m_enableUsbGroup; }; private: DataManager(); static DataManager *m_dataManager; @@ -176,5 +186,6 @@ class DataManager: public QObject bool m_H264EncoderExists; bool m_isSupportCameraSwitch = false; // 是否带有摄像头开关 bool m_isPreviewNoDelay = false; // 是否预览无延迟 + bool m_enableUsbGroup = false; // 是否启用USB摄像头分组 }; #endif // DATAMANAGER_H diff --git a/src/src/videowidget.cpp b/src/src/videowidget.cpp index c084e867..ec2dac2f 100644 --- a/src/src/videowidget.cpp +++ b/src/src/videowidget.cpp @@ -1118,37 +1118,89 @@ void videowidget::onChangeDev() } v4l2_device_list_t *devlist = get_device_list(); - if (devlist->num_devices == 2) { - for (int i = 0 ; i < devlist->num_devices; i++) { - QString str1 = QString(devlist->list_devices[i].device); - if (str != str1) { - if (E_OK == switchCamera(devlist->list_devices[i].device, devlist->list_devices[i].name)) { - break; + if (devlist == nullptr) { + qWarning() << "get device list FAILED"; + return; + } + + // USB摄像头分组相关逻辑来自xiwo分支,是否开启由DConfig控制 + int groupNum = 1; + QVector>> vGroupData; + // 如果未启用USB摄像头分组,则分组数默认为1,保持原有逻辑; + // 如果启用USB摄像头分组,则实际获取USB分组情况,根据分组结果进行处理; + if (DataManager::instance()->isEnableUsbGroup()) { + // 必须确保 devlist 的生命周期长于 vGroupData 的使用周期。 + // 如果 devlist 在 vGroupData 使用完毕前被释放,将导致悬空指针,引发崩溃。 + // 好在 vGroupData 只在本函数中使用,不会在其他地方被引用,所以不会导致悬空指针问题。 + groupNum = getUSBCameraGroup(devlist, vGroupData); + qInfo() << __func__ << "groupNum:" << groupNum; + } + if (groupNum == 1) { + if (devlist->num_devices == 2) { + for (int i = 0 ; i < devlist->num_devices; i++) { + const char *curDev = devlist->list_devices[i].device; + if (str != curDev) { + if (E_OK == switchCamera(curDev, devlist->list_devices[i].name)) { + break; + } } } - } - } else { - if (devlist->num_devices == 0) { - DataManager::instance()->setdevStatus(NOCAM); - showNocam(); - } + } else { + if (devlist->num_devices == 0) { + DataManager::instance()->setdevStatus(NOCAM); + showNocam(); + } - for (int i = 0 ; i < devlist->num_devices; i++) { - QString str1 = QString(devlist->list_devices[i].device); + for (int i = 0 ; i < devlist->num_devices; i++) { + const char *curDev = devlist->list_devices[i].device; + if (str == curDev) { + if (i == devlist->num_devices - 1) { + switchCamera(devlist->list_devices[0].device, devlist->list_devices[0].name); + break; + } else { + switchCamera(devlist->list_devices[i + 1].device, devlist->list_devices[i + 1].name); + break; + } + } - if (str == str1) { - if (i == devlist->num_devices - 1) { + if (str.isEmpty()) { switchCamera(devlist->list_devices[0].device, devlist->list_devices[0].name); break; - } else { - switchCamera(devlist->list_devices[i + 1].device, devlist->list_devices[i + 1].name); - break; } } + } + } else { + if (groupNum == 2) { + for (int i = 0 ; i < vGroupData.count(); i++) { + const char *curDev = vGroupData[i].second[0]->device; + if (str != curDev) { + if (E_OK == switchCamera(curDev, vGroupData[i].second[0]->name)) { + break; + } + } + } + } else { + if (devlist->num_devices == 0) { + DataManager::instance()->setdevStatus(NOCAM); + showNocam(); + } - if (str.isEmpty()) { - switchCamera(devlist->list_devices[0].device, devlist->list_devices[0].name); - break; + for (int i = 0 ; i < vGroupData.count(); i++) { + const char *curDev = vGroupData[i].second[0]->device; + if (str == curDev) { + if (i == vGroupData.count() - 1) { + switchCamera(vGroupData[0].second[0]->device, vGroupData[0].second[0]->name); + break; + } else { + switchCamera(vGroupData[i + 1].second[0]->device, vGroupData[i + 1].second[0]->name); + break; + } + } + + if (str.isEmpty()) { + switchCamera(vGroupData[0].second[0]->device, vGroupData[0].second[0]->name); + break; + } } } } @@ -1200,6 +1252,37 @@ int videowidget::switchCamera(const char *device, const char *devName) return ret; } +int videowidget::getUSBCameraGroup(v4l2_device_list_t *devlist, QVector>> &vGroupData) +{ + // 来自xiwo分支,根据location进行分组 + // 收到建议使用 QMap> 来存储分组数据,但我们担心影响现有代码逻辑, + // 所以暂时保留 QVector>> 来存储分组数据。 + if (devlist == nullptr) { + qWarning() << __func__ << "devlist is NULL!"; + return 0; + } + + for (int i = 0 ; i < devlist->num_devices; i++) { + QString location = QString(devlist->list_devices[i].location); + + int j = 0; + for (; j < vGroupData.count(); j++) { + if (location == vGroupData.at(j).first) { + break; + } + } + if (j == vGroupData.count()) { + QVector vList; + vList.append(&devlist->list_devices[i]); + vGroupData.append(qMakePair(location, vList)); + } else { + QVector &vlist = vGroupData[j].second; + vlist.append(&devlist->list_devices[i]); + } + } + return vGroupData.count(); +} + QString videowidget::getSaveFilePrefix() { QString filePrefix = "Camera_"; diff --git a/src/src/videowidget.h b/src/src/videowidget.h index 56bb0e37..54b03c12 100644 --- a/src/src/videowidget.h +++ b/src/src/videowidget.h @@ -420,6 +420,14 @@ private slots: */ int switchCamera(const char *device, const char *devName); + /** + * @brief 获取USB摄像头分组 + * @param devlist 设备列表 + * @param vGroupData 分组 + * @return 分组个数 + */ + int getUSBCameraGroup(v4l2_device_list_t *devlist, QVector>> &vGroupData); + /** * @brief getSaveFilePrefix * @return UOS_ 专业版 DEEPIN_ 社区版 CAMERA_ 其他 From b5c2d8e2c23c292c68ea58f83d9e8eaaced2ae0e Mon Sep 17 00:00:00 2001 From: lichaofan Date: Fri, 13 Mar 2026 17:52:25 +0800 Subject: [PATCH 073/107] feat: enable the configuration for 8K preview. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the DConfig mechanism to enable the configuration for 8K preview. 使用DConfig机制,开放8K预览功能,同时8K不支持录像。 代码来自xiwo分支。 Bug: https://pms.uniontech.com/bug-view-349401.html --- libcam/libcam_v4l2core/v4l2_formats.c | 40 ++++++++++++++++++++++++ libcam/libcam_v4l2core/v4l2_formats.h | 25 +++++++++++++++ src/assets/org.deepin.camera.encode.json | 10 ++++++ src/main.cpp | 11 +++++++ src/src/basepub/datamanager.h | 13 ++++++++ src/src/mainwindow.cpp | 28 ++++++++++++++++- src/src/mainwindow.h | 5 +++ src/src/rollingbox.cpp | 7 +++++ src/src/rollingbox.h | 5 +++ 9 files changed, 143 insertions(+), 1 deletion(-) diff --git a/libcam/libcam_v4l2core/v4l2_formats.c b/libcam/libcam_v4l2core/v4l2_formats.c index da651e1b..a3d1a8df 100644 --- a/libcam/libcam_v4l2core/v4l2_formats.c +++ b/libcam/libcam_v4l2core/v4l2_formats.c @@ -119,6 +119,9 @@ static uint32_t decoder_supported_formats[] = 0 }; +// 是否开启8K预览 +static int enable_8k_preview = 0; + /* FIXME: doesn't support bigendian formats=> fourcc | (1 << 31) * get pixelformat from fourcc * args: @@ -748,8 +751,45 @@ void free_frame_formats(v4l2_dev_t *vd) int is_valid_resolution(int width, int height) { + // 希沃的8K分辨率是8192x2772,过多限制会导致此分辨率不可用 + if (enable_8k_preview) { + return (width > 0 && height > 0) + && (width % 16 == 0 && height % 4 == 0); + } + // 由于上游guvcview项目在解码3840x2160分辨率以上时会出现异常(出现条纹、崩溃等),所以我们需要限制可用分辨率到3840x2160 return (width > 0 && height > 0) && (width <= MAX_WIDTH_LIMIT && height <= MAX_HEIGHT_LIMIT) && (width % 16 == 0 && height % 8 == 0); } + +/* + * set enable 8k preview + * args: + * enable - enable 8k preview + * + * asserts: + * none + * + * returns: void + */ +void set_enable_8k_preview(int enable) +{ + enable_8k_preview = enable; +} + +/* + * check if 8k preview is enabled + * args: + * none + * + * asserts: + * none + * + * returns: TRUE(1) if enabled + * FALSE(0) if not + */ +int is_enable_8k_preview() +{ + return enable_8k_preview; +} diff --git a/libcam/libcam_v4l2core/v4l2_formats.h b/libcam/libcam_v4l2core/v4l2_formats.h index dafed99c..ab50576c 100644 --- a/libcam/libcam_v4l2core/v4l2_formats.h +++ b/libcam/libcam_v4l2core/v4l2_formats.h @@ -110,4 +110,29 @@ void free_frame_formats(v4l2_dev_t *vd); */ int is_valid_resolution(int width, int height); +/* + * set enable 8k preview + * args: + * enable - enable 8k preview + * + * asserts: + * none + * + * returns: void + */ +void set_enable_8k_preview(int enable); + +/* + * check if 8k preview is enabled + * args: + * none + * + * asserts: + * none + * + * returns: TRUE(1) if enabled + * FALSE(0) if not + */ +int is_enable_8k_preview(); + #endif diff --git a/src/assets/org.deepin.camera.encode.json b/src/assets/org.deepin.camera.encode.json index 90ad17b9..9b30cf0e 100644 --- a/src/assets/org.deepin.camera.encode.json +++ b/src/assets/org.deepin.camera.encode.json @@ -81,6 +81,16 @@ "description": "Enable USB group", "permissions": "readwrite", "visibility": "private" + }, + "enable8kPreview": { + "value": false, + "serial": 0, + "flags": ["global"], + "name": "enable 8k preview", + "name[zh_CN]": "是否启用8K预览", + "description": "Enable 8k preview", + "permissions": "readwrite", + "visibility": "private" } } } diff --git a/src/main.cpp b/src/main.cpp index c40765ad..ce2f1917 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,6 +5,7 @@ extern "C" { #include "camview.h" +#include "v4l2_formats.h" } #include "mainwindow.h" #include "capplication.h" @@ -188,6 +189,16 @@ int main(int argc, char *argv[]) DataManager::instance()->setEnableUsbGroup(enable); } + // 是否开启8K预览通过DConfig控制,目前要求开启8K预览的厂家是希沃 + // 希沃的8K分辨率是8192x2772,希沃在8K预览的时候表现正常,在录像的时候表现异常,所以在开启8K预览的时候我们会禁用录像功能 + // 8K预览功能默认关闭,因为多个厂家的摄像头在8K预览的时候表现异常 + if (dconfig && dconfig->isValid() && dconfig->keyList().contains("enable8kPreview")) { + bool enable = dconfig->value("enable8kPreview").toBool(); + qInfo() << "enable 8K preview:" << enable; + DataManager::instance()->setEnable8kPreview(enable); + set_enable_8k_preview(enable ? 1 : 0); + } + if (!libVaDriverName.isEmpty()) { qputenv("LIBVA_DRIVER_NAME", libVaDriverName.toLocal8Bit()); } diff --git a/src/src/basepub/datamanager.h b/src/src/basepub/datamanager.h index fafa8068..fd9d1f54 100644 --- a/src/src/basepub/datamanager.h +++ b/src/src/basepub/datamanager.h @@ -175,6 +175,18 @@ class DataManager: public QObject * @return */ bool isEnableUsbGroup() const { return m_enableUsbGroup; }; + + /** + * @brief 设置是否启用8K预览 + * @param enable + */ + void setEnable8kPreview(bool enable) { m_enable8kPreview = enable; }; + + /** + * @brief 获取是否启用8K预览 + * @return + */ + bool isEnable8kPreview() const { return m_enable8kPreview; }; private: DataManager(); static DataManager *m_dataManager; @@ -187,5 +199,6 @@ class DataManager: public QObject bool m_isSupportCameraSwitch = false; // 是否带有摄像头开关 bool m_isPreviewNoDelay = false; // 是否预览无延迟 bool m_enableUsbGroup = false; // 是否启用USB摄像头分组 + bool m_enable8kPreview = false; // 是否启用8K预览 }; #endif // DATAMANAGER_H diff --git a/src/src/mainwindow.cpp b/src/src/mainwindow.cpp index c9fe9b7c..d8aa03bd 100644 --- a/src/src/mainwindow.cpp +++ b/src/src/mainwindow.cpp @@ -1394,6 +1394,7 @@ void CMainWindow::onSwitchCameraSuccess(const QString &cameraName) m_labelCameraName->show(); m_filterName->hide(); m_showCameraNameTimer->start(); + showChildWidget(); } void CMainWindow::onTimeoutLock(const QString &serviceName, QVariantMap key2value, QStringList) @@ -2216,6 +2217,13 @@ void CMainWindow::onSettingsDlgClose() if (bPathChanged) { reflushSnapshotLabel(); } + + // 8k分辨率时不显示录像功能 + bool isResolutionTooHigh = checkResolutionTooHigh(); + if (isResolutionTooHigh) { + m_modeSwitchBox->reset(); + } + showChildWidget(); } void CMainWindow::onEnableSettings(bool bTrue) @@ -2327,9 +2335,12 @@ void CMainWindow::showChildWidget() showWidget(m_photoRecordBtn, true); return; } + + // 8k分辨率时不显示录像功能 + bool isResolutionTooHigh = checkResolutionTooHigh(); showWidget(m_snapshotLabel, true); showWidget(m_cameraSwitchBtn, m_bSwitchCameraShowEnable); - showWidget(m_modeSwitchBox, true); + showWidget(m_modeSwitchBox, !isResolutionTooHigh); showWidget(m_photoRecordBtn, true); showWidget(m_takePhotoSettingArea, true); showWidget(m_filterName, m_bShowFilterName); @@ -2348,6 +2359,21 @@ void CMainWindow::showWidget(DWidget *widget, bool bShow) } } +bool CMainWindow::checkResolutionTooHigh() const +{ + int currentWidth = 0; + int currentHeight = 0; + v4l2_dev_t *fd = get_v4l2_device_handler(); + if (fd) { + currentWidth = v4l2core_get_frame_width(fd); + currentHeight = v4l2core_get_frame_height(fd); + } + bool isTrue = currentWidth > MAX_WIDTH_LIMIT || currentHeight > MAX_HEIGHT_LIMIT; + qInfo() << __func__ << isTrue << currentWidth << "x" << currentHeight; + + return isTrue; +} + CMainWindow::~CMainWindow() { if (m_devnumMonitor) { diff --git a/src/src/mainwindow.h b/src/src/mainwindow.h index d76d46a3..ec7d32c9 100644 --- a/src/src/mainwindow.h +++ b/src/src/mainwindow.h @@ -201,6 +201,11 @@ class CMainWindow : public DMainWindow */ void getMediaFileInfoList(const QString &path, QFileInfoList &fileList); + /** + * @brief 检测分辨率是否太高,8K分辨率不显示录像功能 + */ + bool checkResolutionTooHigh() const; + private slots: /** * @brief setSelBtnHide 设置切换相机按钮隐藏 diff --git a/src/src/rollingbox.cpp b/src/src/rollingbox.cpp index 62107ec3..f29e3dfa 100644 --- a/src/src/rollingbox.cpp +++ b/src/src/rollingbox.cpp @@ -301,3 +301,10 @@ void RollingBox::setDeviation(int n) update(); } +void RollingBox::reset() +{ + m_currentIndex = m_rangeMin; + m_deviation = 0; + emit currentValueChanged(m_currentIndex); + update(); +} diff --git a/src/src/rollingbox.h b/src/src/rollingbox.h index 3e381e95..c323a865 100644 --- a/src/src/rollingbox.h +++ b/src/src/rollingbox.h @@ -36,6 +36,11 @@ class RollingBox : public QWidget */ int getCurrentValue(); + /** + * @brief 重置至初始位置 + */ + void reset(); + protected: /** * @brief 鼠标按下事件 From 183e017c67513974b76786469eb03df8f2e2b6e8 Mon Sep 17 00:00:00 2001 From: lichaofan Date: Tue, 17 Mar 2026 11:09:17 +0800 Subject: [PATCH 074/107] feat: enable the configuration for device blacklist. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the DConfig mechanism to enable the configuration for device blacklist. 使用DConfig机制,开发设备黑名单功能,处在黑名单中的设备不会被应用显示。如果现有设备全部在黑名单中,则会有一个默认设备用于预览。 代码来自xiwo分支。 Bug: https://pms.uniontech.com/bug-view-349401.html --- src/assets/org.deepin.camera.encode.json | 10 ++ src/main.cpp | 6 + src/src/basepub/datamanager.cpp | 48 +++++++ src/src/basepub/datamanager.h | 12 ++ src/src/devnummonitor.cpp | 5 +- src/src/devnummonitor.h | 5 + src/src/mainwindow.cpp | 6 + src/src/videowidget.cpp | 160 ++++++++++++++++------- src/src/videowidget.h | 77 +++++++++++ 9 files changed, 283 insertions(+), 46 deletions(-) diff --git a/src/assets/org.deepin.camera.encode.json b/src/assets/org.deepin.camera.encode.json index 9b30cf0e..18e14441 100644 --- a/src/assets/org.deepin.camera.encode.json +++ b/src/assets/org.deepin.camera.encode.json @@ -91,6 +91,16 @@ "description": "Enable 8k preview", "permissions": "readwrite", "visibility": "private" + }, + "deviceBlacklist": { + "value": [], + "serial": 0, + "flags": ["global"], + "name": "device blacklist", + "name[zh_CN]": "设备黑名单", + "description": "Set device blacklist, format: vid,pid,name", + "permissions": "readwrite", + "visibility": "private" } } } diff --git a/src/main.cpp b/src/main.cpp index ce2f1917..4481f2dc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -199,6 +199,12 @@ int main(int argc, char *argv[]) set_enable_8k_preview(enable ? 1 : 0); } + if (dconfig && dconfig->isValid() && dconfig->keyList().contains("deviceBlacklist")) { + QStringList deviceBlacklist = dconfig->value("deviceBlacklist").toStringList(); + qInfo() << "device blacklist:" << deviceBlacklist; + DataManager::instance()->setDeviceBlacklist(deviceBlacklist); + } + if (!libVaDriverName.isEmpty()) { qputenv("LIBVA_DRIVER_NAME", libVaDriverName.toLocal8Bit()); } diff --git a/src/src/basepub/datamanager.cpp b/src/src/basepub/datamanager.cpp index 4fbbd3c6..3c0f5448 100644 --- a/src/src/basepub/datamanager.cpp +++ b/src/src/basepub/datamanager.cpp @@ -55,6 +55,54 @@ bool DataManager::encExists(){ return m_H264EncoderExists; } +void DataManager::setDeviceBlacklist(const QStringList &blacklist) +{ + // 无论是否为空,都先清空现有黑名单 + m_deviceBlacklistSet.clear(); + if (blacklist.isEmpty()) { + qInfo() << "Empty blacklist provided"; + return; + } + + // 每一条黑名单项的格式都是 vid,pid,name + // 其中vid和pid都是4位十六进制数,name是设备名称 + // 后续匹配操作的时候,我们会忽略大小写 + for (const QString &item : blacklist) { + QStringList parts = item.split(","); + if (parts.size() != 3) { + qWarning() << "Drop blacklist item(format error):" << item; + continue; + } + + // 验证VID和PID是否为4位十六进制数 + static const QRegularExpression hexPattern("^[0-9a-fA-F]{4}$"); + if (!hexPattern.match(parts[0]).hasMatch() || !hexPattern.match(parts[1]).hasMatch()) { + qWarning() << "Drop blacklist item(invalid VID/PID):" << item; + continue; + } + + // 验证设备名称不为空,且长度不超过100个字符 + if (parts[2].trimmed().isEmpty() || parts[2].size() > 100) { + qWarning() << "Drop blacklist item(empty device name OR too long):" << item; + continue; + } + + qInfo() << "Add blacklist item:" << item; + m_deviceBlacklistSet.insert(item.toLower()); + } +}; + +bool DataManager::isDeviceValid(const QString &vid, const QString &pid, const QString &name) +{ + // 参数验证 + if (vid.isEmpty() || pid.isEmpty() || name.isEmpty()) { + return true; // 空参数视为有效,避免误判 + } + + QString key = vid.toLower() + "," + pid.toLower() + "," + name.toLower(); + return !m_deviceBlacklistSet.contains(key); +} + DataManager *DataManager::instance() { if (m_dataManager == nullptr) { diff --git a/src/src/basepub/datamanager.h b/src/src/basepub/datamanager.h index fd9d1f54..97fe125b 100644 --- a/src/src/basepub/datamanager.h +++ b/src/src/basepub/datamanager.h @@ -187,6 +187,17 @@ class DataManager: public QObject * @return */ bool isEnable8kPreview() const { return m_enable8kPreview; }; + + /** + * @brief 设置Camera设备黑名单 + * @param blacklist + */ + void setDeviceBlacklist(const QStringList &blacklist); + /** + * @brief 检查当前设备是否有效 + * @return + */ + bool isDeviceValid(const QString &vid, const QString &pid, const QString &name); private: DataManager(); static DataManager *m_dataManager; @@ -200,5 +211,6 @@ class DataManager: public QObject bool m_isPreviewNoDelay = false; // 是否预览无延迟 bool m_enableUsbGroup = false; // 是否启用USB摄像头分组 bool m_enable8kPreview = false; // 是否启用8K预览 + QSet m_deviceBlacklistSet; // 设备黑名单 }; #endif // DATAMANAGER_H diff --git a/src/src/devnummonitor.cpp b/src/src/devnummonitor.cpp index 0283dcd9..4d50c5b5 100644 --- a/src/src/devnummonitor.cpp +++ b/src/src/devnummonitor.cpp @@ -44,7 +44,10 @@ void DevNumMonitor::startCheck() void DevNumMonitor::timeOutSlot() { - check_device_list_events(get_v4l2_device_handler()); + // 检查设备列表变化事件 + if (check_device_list_events(get_v4l2_device_handler())) { + emit deviceListChanged(); + } if (get_device_list()->num_devices <= 1) { emit seltBtnStateDisable(); diff --git a/src/src/devnummonitor.h b/src/src/devnummonitor.h index 1176ffbc..551c1894 100644 --- a/src/src/devnummonitor.h +++ b/src/src/devnummonitor.h @@ -60,6 +60,11 @@ class DevNumMonitor: public QObject */ void existDevice(); + /** + * @brief deviceListChanged 相机设备列表改变信号 + */ + void deviceListChanged(); + protected: /** * @brief run 运行 diff --git a/src/src/mainwindow.cpp b/src/src/mainwindow.cpp index d8aa03bd..0b7c0935 100644 --- a/src/src/mainwindow.cpp +++ b/src/src/mainwindow.cpp @@ -1240,6 +1240,7 @@ void CMainWindow::loadAfterShow() if(DataManager::instance()->encodeEnv() != QCamera_Env) { connect(m_devnumMonitor, SIGNAL(existDevice()), m_videoPre, SLOT(onRestartDevices()));//重启设备 connect(m_devnumMonitor, SIGNAL(noDeviceFound()), m_videoPre, SLOT(onRestartDevices()));//重启设备 + connect(m_devnumMonitor, SIGNAL(deviceListChanged()), m_videoPre, SLOT(updateValidDevices())); // 更新可用设备列表 } else if (DataManager::instance()->encodeEnv() == QCamera_Env) { initCameraConnection(); } @@ -2037,6 +2038,11 @@ void CMainWindow::onLocalTimeChanged() void CMainWindow::setSelBtnShow() { + // 有效设备个数小于等于1,不显示切换按钮 + if (m_videoPre->getValidDeviceNum() <= 1) { + return; + } + m_bSwitchCameraShowEnable = true; if (m_cameraSwitchBtn->isHidden()) { showChildWidget(); diff --git a/src/src/videowidget.cpp b/src/src/videowidget.cpp index ec2dac2f..58f28dd5 100644 --- a/src/src/videowidget.cpp +++ b/src/src/videowidget.cpp @@ -276,8 +276,18 @@ void videowidget::delayInit() m_flashLabel->hide(); QString device = dc::Settings::get().getBackOption("device").toString(); - //启动视频 - switchCamera(device.toStdString().c_str(), ""); + // 启动视频预览 + // 如果配置的设备无效,切换到第一个有效的设备 + // 如果有效的设备也不存在,走默认流程 + updateValidDevices(); + if (!isDeviceValidByDevice(device)) { + QString validDevice = getFirstValidDevice(); + qWarning() << "INVALID device from config:" << device << ", found first valid device:" << validDevice; + switchCamera(validDevice.toStdString().c_str(), ""); + } else { + qInfo() << "VALID device from config:" << device; + switchCamera(device.toStdString().c_str(), ""); // 走默认逻辑 + } QObject::connect(DGuiApplicationHelper::instance(), &DGuiApplicationHelper::themeTypeChanged, this, &videowidget::onThemeTypeChanged); @@ -1135,38 +1145,25 @@ void videowidget::onChangeDev() groupNum = getUSBCameraGroup(devlist, vGroupData); qInfo() << __func__ << "groupNum:" << groupNum; } - if (groupNum == 1) { - if (devlist->num_devices == 2) { - for (int i = 0 ; i < devlist->num_devices; i++) { - const char *curDev = devlist->list_devices[i].device; - if (str != curDev) { - if (E_OK == switchCamera(curDev, devlist->list_devices[i].name)) { - break; - } - } - } + // 如果摄像头设备个数为0,分组情况就不用考虑了,直接显示无摄像头提示 + if (devlist->num_devices == 0) { + DataManager::instance()->setdevStatus(NOCAM); + showNocam(); + } else if (groupNum == 0) { + switchCamera("", ""); // 无有效设备,但是有设备,走默认逻辑 + } else if (groupNum == 1) { + if (m_validDevices.empty()) { + switchCamera("", ""); // 无有效设备,但是有设备,走默认逻辑 } else { - if (devlist->num_devices == 0) { - DataManager::instance()->setdevStatus(NOCAM); - showNocam(); - } - - for (int i = 0 ; i < devlist->num_devices; i++) { - const char *curDev = devlist->list_devices[i].device; - if (str == curDev) { - if (i == devlist->num_devices - 1) { - switchCamera(devlist->list_devices[0].device, devlist->list_devices[0].name); - break; - } else { - switchCamera(devlist->list_devices[i + 1].device, devlist->list_devices[i + 1].name); - break; - } - } - - if (str.isEmpty()) { - switchCamera(devlist->list_devices[0].device, devlist->list_devices[0].name); - break; - } + int idx = getValidDeviceIndexByDevice(str); + if (idx == -1 || idx >= m_validDevices.size() - 1) { + // 获取第一个有效设备,直接切换到该设备 + const ValidDevice &dev = m_validDevices[0]; + switchCamera(dev.getDevice().toStdString().c_str(), dev.getName().toStdString().c_str()); + } else { + // 切换到当前设备的下一个有效设备 + const ValidDevice &dev = m_validDevices[idx + 1]; + switchCamera(dev.getDevice().toStdString().c_str(), dev.getName().toStdString().c_str()); } } } else { @@ -1180,14 +1177,11 @@ void videowidget::onChangeDev() } } } else { - if (devlist->num_devices == 0) { - DataManager::instance()->setdevStatus(NOCAM); - showNocam(); - } - + bool found = false; // 标记是否找到当前设备 for (int i = 0 ; i < vGroupData.count(); i++) { const char *curDev = vGroupData[i].second[0]->device; if (str == curDev) { + found = true; if (i == vGroupData.count() - 1) { switchCamera(vGroupData[0].second[0]->device, vGroupData[0].second[0]->name); break; @@ -1196,11 +1190,10 @@ void videowidget::onChangeDev() break; } } - - if (str.isEmpty()) { - switchCamera(vGroupData[0].second[0]->device, vGroupData[0].second[0]->name); - break; - } + } + if (!found) { + // 未找到当前设备,切换到第一个设备 + switchCamera(vGroupData[0].second[0]->device, vGroupData[0].second[0]->name); } } } @@ -1257,12 +1250,16 @@ int videowidget::getUSBCameraGroup(v4l2_device_list_t *devlist, QVector> 来存储分组数据,但我们担心影响现有代码逻辑, // 所以暂时保留 QVector>> 来存储分组数据。 - if (devlist == nullptr) { + if (devlist == nullptr || devlist->list_devices == nullptr || devlist->num_devices == 0) { qWarning() << __func__ << "devlist is NULL!"; return 0; } - for (int i = 0 ; i < devlist->num_devices; i++) { + for (int i = 0; i < devlist->num_devices; i++) { + if (!isDeviceValidByDevice(devlist->list_devices[i].device)) { + continue; // 无效设备不参与分组 + } + QString location = QString(devlist->list_devices[i].location); int j = 0; @@ -1756,6 +1753,79 @@ void videowidget::onFilterDisplayChanged(int bDisplay) m_imgPrcThread->setFilterGroupState(bDisplay); } +QString videowidget::getFirstValidDevice() +{ + // 加锁,确保线程安全 + QReadLocker locker(&m_mutexValidDevices); + if (m_validDevices.isEmpty()) { + qWarning() << __func__ << "no valid device!"; + return ""; + } + + // 返回第一个有效相机设备的设备节点路径 + const ValidDevice &dev = m_validDevices.first(); + qInfo() << __func__ << dev.getVid() << dev.getPid() << dev.getName() << dev.getDevice(); + return dev.getDevice(); +} + +void videowidget::updateValidDevices() +{ + qInfo() << __func__; + // 加锁,确保线程安全 + QWriteLocker locker(&m_mutexValidDevices); + m_validDevices.clear(); // 清空有效相机设备列表 + + v4l2_device_list_t *devList = get_device_list(); + if (!devList) { + qWarning() << __func__ << "get device list FAILED!"; + return; + } + + v4l2_dev_sys_data_t *v4l2_devices = devList->list_devices; + if (!v4l2_devices) { + qWarning() << __func__ << "get device list FAILED!"; + return; + } + + for (int i = 0; i < devList->num_devices; i++) { + // 获取设备的VID和PID,不足4位用0填充 + QString vid = formatDeviceId(v4l2_devices[i].vendor); + QString pid = formatDeviceId(v4l2_devices[i].product); + if (DataManager::instance()->isDeviceValid(vid, pid, v4l2_devices[i].name)) { + qInfo() << __func__ << "found valid device:" << vid << pid << v4l2_devices[i].name << v4l2_devices[i].device; + // 添加有效相机设备 + m_validDevices.push_back(ValidDevice(vid, pid, v4l2_devices[i].name, v4l2_devices[i].device)); + continue; + } + + qInfo() << __func__ << "found invalid device(blacklist):" << vid << pid << v4l2_devices[i].name << v4l2_devices[i].device; + } +} + +bool videowidget::isDeviceValidByDevice(const QString &device) +{ + return getValidDeviceIndexByDevice(device) != -1; +} + +int videowidget::getValidDeviceIndexByDevice(const QString &device) +{ + // 加锁,确保线程安全 + QReadLocker locker(&m_mutexValidDevices); + for (int i = 0; i < m_validDevices.size(); i++) { + if (m_validDevices[i].getDevice() == device) { + return i; + } + } + return -1; +} + +int videowidget::getValidDeviceNum() +{ + // 加锁,确保线程安全 + QReadLocker locker(&m_mutexValidDevices); + return m_validDevices.size(); +} + videowidget::~videowidget() { m_imgPrcThread->stop(); diff --git a/src/src/videowidget.h b/src/src/videowidget.h index 54b03c12..317038cb 100644 --- a/src/src/videowidget.h +++ b/src/src/videowidget.h @@ -21,6 +21,7 @@ #include #include #include +#include #include "LPF_V4L2.h" #include "majorimageprocessingthread.h" @@ -64,6 +65,40 @@ class QGraphicsViewEx : public QGraphicsView virtual void mouseMoveEvent(QMouseEvent* e) override; }; +/** +* @brief ValidDevice 有效相机设备,与黑名单机制配套使用 +*/ +class ValidDevice +{ +public: + ValidDevice() = default; + ValidDevice(const QString &_vid, const QString &_pid, const QString &_name, const QString &_device) + : vid(_vid), pid(_pid), name(_name), device(_device) {} + + bool operator==(const ValidDevice &other) const { + return vid == other.vid && pid == other.pid && + name == other.name && device == other.device; + } + + // Setter 方法 + void setVid(const QString &_vid) { vid = _vid; } + void setPid(const QString &_pid) { pid = _pid; } + void setName(const QString &_name) { name = _name; } + void setDevice(const QString &_device) { device = _device; } + + // Getter 方法 + QString getVid() const { return vid; } + QString getPid() const { return pid; } + QString getName() const { return name; } + QString getDevice() const { return device; } + +private: + QString vid; // 相机VID + QString pid; // 相机PID + QString name; // 相机名称 + QString device; // 相机设备节点路径 +}; + /** * @brief videowidget 完成拍照,录像相关工作 * 连拍,延时拍照录像,闪光灯,文件保存等 @@ -266,6 +301,11 @@ class videowidget : public DWidget */ void showCamUsed(); + /** + * @brief getValidDeviceNum 获取有效设备数量 + * @return 有效设备数量 + */ + int getValidDeviceNum(); public slots: /** * @brief onTakePic 拍照事件响应 @@ -326,6 +366,11 @@ public slots: */ void onLockedScreen(bool bLocked); + /** + * @brief 更新有效相机设备列表 + */ + void updateValidDevices(); + private slots: /** * @brief ReceiveMajorImage 处理视频帧 mips、wayland下使用 @@ -433,6 +478,36 @@ private slots: * @return UOS_ 专业版 DEEPIN_ 社区版 CAMERA_ 其他 */ QString getSaveFilePrefix(); + + /** + * @brief formatDeviceId 格式化设备ID + * @param id 设备ID + * @return 格式化后的设备ID + */ + static QString formatDeviceId(uint id) { + // 格式化设备ID为4位十六进制数,不足4位用0填充 + return QString("%1").arg(id, 4, 16, QLatin1Char('0')); + } + + /** + * @brief 获取第一个有效的设备 + * @return 没找到时返回空字符串 + */ + QString getFirstValidDevice(); + + /** + * @brief 判断设备是否有效 + * @param device 设备识别路径 /dev/video* + * @return true 有效 false 无效 + */ + bool isDeviceValidByDevice(const QString &device); + + /** + * @brief 获取设备在有效设备列表中的索引 + * @param device 设备识别路径 /dev/video* + * @return 索引 无效时返回-1 + */ + int getValidDeviceIndexByDevice(const QString &device); public: MajorImageProcessingThread *m_imgPrcThread; AudioProcessingThread *m_audPrcThread; @@ -482,6 +557,8 @@ private slots: int m_exposure; bool m_isFlash = false; bool m_isLockedScreen = false; // 是否处于锁屏状态 + QVector m_validDevices; // 有效相机设备列表 + QReadWriteLock m_mutexValidDevices; // 有效相机设备列表读写锁 }; #endif // VIDEOWIDGET_H From 2cdcb53958330636948b7df4132e1599bc1b379f Mon Sep 17 00:00:00 2001 From: lichaofan Date: Thu, 19 Mar 2026 15:09:53 +0800 Subject: [PATCH 075/107] feat: enable the configuration for the preferred resolution. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the DConfig mechanism to enable the configuration for the preferred resolution. 使用DConfig机制,开放首选分辨率的配置功能。 Task: https://pms.uniontech.com/task-view-387315.html --- libcam/libcam_v4l2core/v4l2_core.c | 48 +++++++++++++++++---- libcam/libcam_v4l2core/v4l2_formats.c | 55 ++++++++++++++++++++++++ libcam/libcam_v4l2core/v4l2_formats.h | 37 ++++++++++++++++ src/assets/org.deepin.camera.encode.json | 10 +++++ src/main.cpp | 12 ++++++ src/src/basepub/datamanager.cpp | 47 ++++++++++++++++++++ src/src/basepub/datamanager.h | 14 ++++++ 7 files changed, 214 insertions(+), 9 deletions(-) diff --git a/libcam/libcam_v4l2core/v4l2_core.c b/libcam/libcam_v4l2core/v4l2_core.c index bcb1830f..4da187c3 100644 --- a/libcam/libcam_v4l2core/v4l2_core.c +++ b/libcam/libcam_v4l2core/v4l2_core.c @@ -1696,20 +1696,50 @@ void v4l2core_prepare_valid_resolution(v4l2_dev_t *vd) } } - // 查找可以支持的最大分辨率 - // 由于上游guvcview项目在解码3840x2160分辨率以上时会出现异常(出现条纹、崩溃等),所以我们需要限制可用分辨率到3840x2160 - printf("V4L2_CORE: valid resolution counts: %d\n", vd->list_stream_formats[format_index].numb_res); - for(int i=0; i < vd->list_stream_formats[format_index].numb_res; i++) + int found_preferred = 0; // 是否找到首选分辨率 + int pref_w = get_preferred_resolution_width(); + int pref_h = get_preferred_resolution_height(); + // 最大分辨率 + int max_width = 0; + int max_height = 0; + // 通过一次遍历,找出首选分辨率,同时找出最大分辨率。虽然最大分辨率可能用不到,但是便于调试分析 + for (int i = 0; i < vd->list_stream_formats[format_index].numb_res; i++) { int w = vd->list_stream_formats[format_index].list_stream_cap[i].width; int h = vd->list_stream_formats[format_index].list_stream_cap[i].height; - printf("V4L2_CORE: - valid resolution(%dx%d)\n", w, h); - if (my_width <= w && my_height <= h && is_valid_resolution(w, h)) { - my_width = w; - my_height = h; + if (is_valid_resolution(w, h)) + { + // 找出首选分辨率 + printf("V4L2_CORE: check valid resolution, width: %d, height: %d, preferred width: %d, preferred height: %d\n", + w, h, pref_w, pref_h); + if (!found_preferred && pref_w != 0 && pref_h != 0 && w == pref_w && h == pref_h) { + printf("V4L2_CORE: preferred resolution found, width: %d, height: %d\n", w, h); + found_preferred = 1; + } + + // 找出最大分辨率 + if (w > max_width || (w == max_width && h > max_height)) { + max_width = w; + max_height = h; + } + } + } + printf("V4L2_CORE: max resolution found, width: %d, height: %d\n", max_width, max_height); + if (found_preferred) { + // 有首选分辨率,使用首选分辨率 + printf("V4L2_CORE: use preferred resolution, width: %d, height: %d\n", pref_w, pref_h); + my_width = pref_w; + my_height = pref_h; + } else { + // 没有首选分辨率,使用最大分辨率 + printf("V4L2_CORE: use max resolution, width: %d, height: %d\n", max_width, max_height); + my_width = max_width; + my_height = max_height; + // 极端情况,没有可用分辨率,发出错误提示 + if (max_width == 0 || max_height == 0) { + printf("V4L2_CORE: ERROR: no valid resolution found!\n"); } } - printf("V4L2_CORE: select resolution(%dx%d)\n", my_width, my_height); } /* diff --git a/libcam/libcam_v4l2core/v4l2_formats.c b/libcam/libcam_v4l2core/v4l2_formats.c index a3d1a8df..9e705e90 100644 --- a/libcam/libcam_v4l2core/v4l2_formats.c +++ b/libcam/libcam_v4l2core/v4l2_formats.c @@ -121,6 +121,9 @@ static uint32_t decoder_supported_formats[] = // 是否开启8K预览 static int enable_8k_preview = 0; +// 首选分辨率 +static int preferred_resolution_width = 0; +static int preferred_resolution_height = 0; /* FIXME: doesn't support bigendian formats=> fourcc | (1 << 31) * get pixelformat from fourcc @@ -793,3 +796,55 @@ int is_enable_8k_preview() { return enable_8k_preview; } + +/** + * set preferred resolution + * args: + * width - preferred width + * height - preferred height + * + * asserts: + * none + * + * returns: void + */ +void set_preferred_resolution(int width, int height) +{ + if (width <= 0 || height <= 0) { + printf("V4L2_CORE: Invalid preferred resolution: %dx%d\n", width, height); + return; + } + + preferred_resolution_width = width; + preferred_resolution_height = height; +} + +/** + * get preferred resolution width + * args: + * none + * + * asserts: + * none + * + * returns: preferred width + */ +int get_preferred_resolution_width() +{ + return preferred_resolution_width; +} + +/** + * get preferred resolution height + * args: + * none + * + * asserts: + * none + * + * returns: preferred height + */ +int get_preferred_resolution_height() +{ + return preferred_resolution_height; +} diff --git a/libcam/libcam_v4l2core/v4l2_formats.h b/libcam/libcam_v4l2core/v4l2_formats.h index ab50576c..0ce1a362 100644 --- a/libcam/libcam_v4l2core/v4l2_formats.h +++ b/libcam/libcam_v4l2core/v4l2_formats.h @@ -135,4 +135,41 @@ void set_enable_8k_preview(int enable); */ int is_enable_8k_preview(); +/** + * set preferred resolution + * args: + * width - preferred width + * height - preferred height + * + * asserts: + * none + * + * returns: void + */ +void set_preferred_resolution(int width, int height); + +/** + * get preferred resolution width + * args: + * none + * + * asserts: + * none + * + * returns: preferred width + */ +int get_preferred_resolution_width(); + +/** + * get preferred resolution height + * args: + * none + * + * asserts: + * none + * + * returns: preferred height + */ +int get_preferred_resolution_height(); + #endif diff --git a/src/assets/org.deepin.camera.encode.json b/src/assets/org.deepin.camera.encode.json index 18e14441..a8bfab9a 100644 --- a/src/assets/org.deepin.camera.encode.json +++ b/src/assets/org.deepin.camera.encode.json @@ -101,6 +101,16 @@ "description": "Set device blacklist, format: vid,pid,name", "permissions": "readwrite", "visibility": "private" + }, + "preferredResolution": { + "value": "", + "serial": 0, + "flags": ["global"], + "name": "preferred resolution", + "name[zh_CN]": "首选分辨率", + "description": "Set preferred resolution", + "permissions": "readwrite", + "visibility": "private" } } } diff --git a/src/main.cpp b/src/main.cpp index 4481f2dc..99bef41a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -205,6 +205,18 @@ int main(int argc, char *argv[]) DataManager::instance()->setDeviceBlacklist(deviceBlacklist); } + if (dconfig && dconfig->isValid() && dconfig->keyList().contains("preferredResolution")) { + QString preferredResolution = dconfig->value("preferredResolution").toString(); + qInfo() << "preferred resolution:" << preferredResolution; + if (!preferredResolution.isEmpty()) { + DataManager::instance()->setPreferredResolution(preferredResolution); + QSize size = DataManager::instance()->getPreferredResolution(); + if (!size.isNull()) { + set_preferred_resolution(size.width(), size.height()); + } + } + } + if (!libVaDriverName.isEmpty()) { qputenv("LIBVA_DRIVER_NAME", libVaDriverName.toLocal8Bit()); } diff --git a/src/src/basepub/datamanager.cpp b/src/src/basepub/datamanager.cpp index 3c0f5448..8c290718 100644 --- a/src/src/basepub/datamanager.cpp +++ b/src/src/basepub/datamanager.cpp @@ -3,6 +3,10 @@ // // SPDX-License-Identifier: GPL-3.0-or-later +extern "C" { +#include "v4l2_formats.h" +} + #include "datamanager.h" #include "../capplication.h" @@ -103,6 +107,48 @@ bool DataManager::isDeviceValid(const QString &vid, const QString &pid, const QS return !m_deviceBlacklistSet.contains(key); } +void DataManager::setPreferredResolution(const QString &resolution) +{ + if (resolution.isEmpty()) { + qInfo() << "Preferred resolution is empty"; + return; + } + + QStringList parts = resolution.split("x"); + if (parts.size() != 2) { + qWarning() << "Invalid resolution format:" << resolution << "Expected format: WIDTHxHEIGHT"; + return; + } + + bool widthOk, heightOk; + int width = parts[0].toInt(&widthOk); + int height = parts[1].toInt(&heightOk); + + if (!widthOk || !heightOk || width <= 0 || height <= 0) { + qWarning() << "Invalid resolution values:" << resolution; + return; + } + + // 添加合理的上限检查,例如16K + static const int MAX_RESOLUTION = 16384; + if (width > MAX_RESOLUTION || height > MAX_RESOLUTION) { + qWarning() << "Resolution exceeds maximum limit:" << resolution; + return; + } + + if (!is_valid_resolution(width, height)) { + qWarning() << "Resolution does not meet validation requirements:" << resolution; + return; + } + + m_preferredResolution = QSize(width, height); +} + +QSize DataManager::getPreferredResolution() +{ + return m_preferredResolution; +} + DataManager *DataManager::instance() { if (m_dataManager == nullptr) { @@ -121,5 +167,6 @@ DataManager::DataManager() m_encodeEnv = GStreamer_Env; m_devStatus = DeviceStatus::NOCAM; m_H264EncoderExists = false; + m_preferredResolution = QSize(0, 0); } diff --git a/src/src/basepub/datamanager.h b/src/src/basepub/datamanager.h index 97fe125b..729c3b75 100644 --- a/src/src/basepub/datamanager.h +++ b/src/src/basepub/datamanager.h @@ -8,6 +8,7 @@ #include #include +#include enum GridType { @@ -198,6 +199,18 @@ class DataManager: public QObject * @return */ bool isDeviceValid(const QString &vid, const QString &pid, const QString &name); + + /** + * @brief 设置首选分辨率 + * @param resolution 分辨率字符串,格式如 "1920x1080" + */ + void setPreferredResolution(const QString &resolution); + + /** + * @brief 获取首选分辨率 + * @return 分辨率 + */ + QSize getPreferredResolution(); private: DataManager(); static DataManager *m_dataManager; @@ -212,5 +225,6 @@ class DataManager: public QObject bool m_enableUsbGroup = false; // 是否启用USB摄像头分组 bool m_enable8kPreview = false; // 是否启用8K预览 QSet m_deviceBlacklistSet; // 设备黑名单 + QSize m_preferredResolution; // 首选分辨率 }; #endif // DATAMANAGER_H From 36e1019c5f337da2d489bf2029e7eb003afac29a Mon Sep 17 00:00:00 2001 From: zhangjiarui Date: Mon, 27 Apr 2026 16:38:01 +0800 Subject: [PATCH 076/107] refactor(video): change default video format to webm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unify video format selection logic across all devices. Change default format from mp4 to webm for better compatibility. 统一所有设备的视频格式选择逻辑,将默认格式从 mp4 改为 webm 以提升兼容性。 Log: 修改默认录制视频格式为 webm PMS: https://pms.uniontech.com/bug-view-358869.html Influence: 新用户默认使用 webm 格式录制视频,用户仍可在设置中切换为 mp4。已有用户配置不受影响。 --- src/src/Settings.cpp | 8 ++------ src/src/videowidget.cpp | 15 +++++++++------ 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/src/Settings.cpp b/src/src/Settings.cpp index 645dc00c..725aa15b 100644 --- a/src/src/Settings.cpp +++ b/src/src/Settings.cpp @@ -54,12 +54,8 @@ void Settings::init() if (DataManager::instance()->encodeEnv() == FFmpeg_Env) { if (DataManager::instance()->encExists()) { GlobalUtils::loadCameraConf(); - if (!GlobalUtils::isLowPerformanceBoard()) { - videoFormatList << tr("mp4") << tr("webm"); - } else { - videoFormatList << tr("webm") << tr("mp4"); - } - + // webm 作为默认格式(索引0),mp4 作为备选(索引1) + videoFormatList << tr("webm") << tr("mp4"); } else { videoFormatList << tr("webm"); m_settings->setOption("outsetting.outformat.vidformat", 0); diff --git a/src/src/videowidget.cpp b/src/src/videowidget.cpp index 58f28dd5..92e619dc 100644 --- a/src/src/videowidget.cpp +++ b/src/src/videowidget.cpp @@ -222,14 +222,17 @@ videowidget::videowidget(DWidget *parent) // 默认不显示网格线 setGridType(Grid_None); - if (DataManager::instance()->encodeEnv() != FFmpeg_Env || !DataManager::instance()->encExists() || GlobalUtils::isLowPerformanceBoard()) { + // 默认使用 webm 格式 + if (DataManager::instance()->encodeEnv() != FFmpeg_Env || !DataManager::instance()->encExists()) { m_videoFormat = "webm"; - } - if (dc::Settings::get().getOption("outsetting.outformat.vidformat").toInt()) { - if (!GlobalUtils::isLowPerformanceBoard()) - m_videoFormat = "webm"; - else + } else { + // 根据配置选择格式:0=webm(默认), 1=mp4 + int formatIndex = dc::Settings::get().getOption("outsetting.outformat.vidformat").toInt(); + if (formatIndex == 1) { m_videoFormat = "mp4"; + } else { + m_videoFormat = "webm"; + } } } From f4dbb60d5963186e9675b1da13215184722299dd Mon Sep 17 00:00:00 2001 From: zhangjiarui Date: Thu, 30 Apr 2026 11:42:32 +0800 Subject: [PATCH 077/107] chore: bump version 6.0.13 bump version Log: bump version --- debian/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index 167fb5d9..1ce730f8 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +deepin-camera (6.0.13) unstable; urgency=medium + + * tag 6.0.13 + + -- zhangjiarui Thu, 30 Apr 2026 11:36:13 +0800 + deepin-camera (6.0.12) unstable; urgency=medium * tag 6.0.12 From f60594edef17bc0f2b0a362c6ba408f6609b69be Mon Sep 17 00:00:00 2001 From: Resurgamz <108165585+Resurgamz@users.noreply.github.com> Date: Thu, 30 Apr 2026 13:10:58 +0800 Subject: [PATCH 078/107] Adjust video format list order for performance Reorder video format list based on performance board check. --- src/src/Settings.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/src/Settings.cpp b/src/src/Settings.cpp index 725aa15b..2907f166 100644 --- a/src/src/Settings.cpp +++ b/src/src/Settings.cpp @@ -54,8 +54,11 @@ void Settings::init() if (DataManager::instance()->encodeEnv() == FFmpeg_Env) { if (DataManager::instance()->encExists()) { GlobalUtils::loadCameraConf(); - // webm 作为默认格式(索引0),mp4 作为备选(索引1) - videoFormatList << tr("webm") << tr("mp4"); + if (!GlobalUtils::isLowPerformanceBoard()) { + videoFormatList << tr("mp4") << tr("webm"); + } else { + videoFormatList << tr("webm") << tr("mp4"); + } } else { videoFormatList << tr("webm"); m_settings->setOption("outsetting.outformat.vidformat", 0); From 461e84cc3eb91a25dd69b1608df38e8d302ae4c1 Mon Sep 17 00:00:00 2001 From: Resurgamz <108165585+Resurgamz@users.noreply.github.com> Date: Thu, 30 Apr 2026 13:11:31 +0800 Subject: [PATCH 079/107] Update Settings.cpp --- src/src/Settings.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/src/Settings.cpp b/src/src/Settings.cpp index 2907f166..44ea0028 100644 --- a/src/src/Settings.cpp +++ b/src/src/Settings.cpp @@ -59,6 +59,7 @@ void Settings::init() } else { videoFormatList << tr("webm") << tr("mp4"); } + } else { videoFormatList << tr("webm"); m_settings->setOption("outsetting.outformat.vidformat", 0); From 8d965a3fe39350e0d9dd3b046b74bbfc7029c94a Mon Sep 17 00:00:00 2001 From: Resurgamz <108165585+Resurgamz@users.noreply.github.com> Date: Thu, 30 Apr 2026 13:11:53 +0800 Subject: [PATCH 080/107] Update Settings.cpp --- src/src/Settings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/src/Settings.cpp b/src/src/Settings.cpp index 44ea0028..645dc00c 100644 --- a/src/src/Settings.cpp +++ b/src/src/Settings.cpp @@ -59,7 +59,7 @@ void Settings::init() } else { videoFormatList << tr("webm") << tr("mp4"); } - + } else { videoFormatList << tr("webm"); m_settings->setOption("outsetting.outformat.vidformat", 0); From 3e05381bcfbc419dba4466b110de3d5c60c6c352 Mon Sep 17 00:00:00 2001 From: Resurgamz <108165585+Resurgamz@users.noreply.github.com> Date: Thu, 30 Apr 2026 13:14:36 +0800 Subject: [PATCH 081/107] Update videowidget.cpp --- src/src/videowidget.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/src/videowidget.cpp b/src/src/videowidget.cpp index 92e619dc..8b579696 100644 --- a/src/src/videowidget.cpp +++ b/src/src/videowidget.cpp @@ -222,17 +222,15 @@ videowidget::videowidget(DWidget *parent) // 默认不显示网格线 setGridType(Grid_None); - // 默认使用 webm 格式 - if (DataManager::instance()->encodeEnv() != FFmpeg_Env || !DataManager::instance()->encExists()) { + if (DataManager::instance()->encodeEnv() != FFmpeg_Env || !DataManager::instance()->encExists() || GlobalUtils::isLowPerformanceBoard()) { m_videoFormat = "webm"; - } else { - // 根据配置选择格式:0=webm(默认), 1=mp4 - int formatIndex = dc::Settings::get().getOption("outsetting.outformat.vidformat").toInt(); - if (formatIndex == 1) { - m_videoFormat = "mp4"; - } else { + } + if (dc::Settings::get().getOption("outsetting.outformat.vidformat").toInt()) { + if (!GlobalUtils::isLowPerformanceBoard()) m_videoFormat = "webm"; - } + else + m_videoFormat = "mp4"; + } } } From def69ea2f13e5ecde7d95f1128ae0ecad434e295 Mon Sep 17 00:00:00 2001 From: Resurgamz <108165585+Resurgamz@users.noreply.github.com> Date: Thu, 30 Apr 2026 13:14:57 +0800 Subject: [PATCH 082/107] Update videowidget.cpp --- src/src/videowidget.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/src/videowidget.cpp b/src/src/videowidget.cpp index 8b579696..58f28dd5 100644 --- a/src/src/videowidget.cpp +++ b/src/src/videowidget.cpp @@ -230,7 +230,6 @@ videowidget::videowidget(DWidget *parent) m_videoFormat = "webm"; else m_videoFormat = "mp4"; - } } } From 5bcb2206b6fbccee7d5c067e6b9cd74a2f4e16b7 Mon Sep 17 00:00:00 2001 From: Resurgamz <108165585+Resurgamz@users.noreply.github.com> Date: Thu, 30 Apr 2026 13:33:21 +0800 Subject: [PATCH 083/107] Revert "Update videowidget.cpp" This reverts commit def69ea2f13e5ecde7d95f1128ae0ecad434e295. --- src/src/videowidget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/src/videowidget.cpp b/src/src/videowidget.cpp index 58f28dd5..8b579696 100644 --- a/src/src/videowidget.cpp +++ b/src/src/videowidget.cpp @@ -230,6 +230,7 @@ videowidget::videowidget(DWidget *parent) m_videoFormat = "webm"; else m_videoFormat = "mp4"; + } } } From e725b92260bc14588c6f3c3ff8838dd3c3007bff Mon Sep 17 00:00:00 2001 From: Resurgamz <108165585+Resurgamz@users.noreply.github.com> Date: Thu, 30 Apr 2026 13:33:21 +0800 Subject: [PATCH 084/107] Revert "Update videowidget.cpp" This reverts commit 3e05381bcfbc419dba4466b110de3d5c60c6c352. --- src/src/videowidget.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/src/videowidget.cpp b/src/src/videowidget.cpp index 8b579696..92e619dc 100644 --- a/src/src/videowidget.cpp +++ b/src/src/videowidget.cpp @@ -222,15 +222,17 @@ videowidget::videowidget(DWidget *parent) // 默认不显示网格线 setGridType(Grid_None); - if (DataManager::instance()->encodeEnv() != FFmpeg_Env || !DataManager::instance()->encExists() || GlobalUtils::isLowPerformanceBoard()) { + // 默认使用 webm 格式 + if (DataManager::instance()->encodeEnv() != FFmpeg_Env || !DataManager::instance()->encExists()) { m_videoFormat = "webm"; - } - if (dc::Settings::get().getOption("outsetting.outformat.vidformat").toInt()) { - if (!GlobalUtils::isLowPerformanceBoard()) - m_videoFormat = "webm"; - else + } else { + // 根据配置选择格式:0=webm(默认), 1=mp4 + int formatIndex = dc::Settings::get().getOption("outsetting.outformat.vidformat").toInt(); + if (formatIndex == 1) { m_videoFormat = "mp4"; - } + } else { + m_videoFormat = "webm"; + } } } From 9441adcae564ebab6cc2f2c43ebdbe2205e1c2d3 Mon Sep 17 00:00:00 2001 From: Resurgamz <108165585+Resurgamz@users.noreply.github.com> Date: Thu, 30 Apr 2026 13:33:21 +0800 Subject: [PATCH 085/107] Revert "Update Settings.cpp" This reverts commit 8d965a3fe39350e0d9dd3b046b74bbfc7029c94a. --- src/src/Settings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/src/Settings.cpp b/src/src/Settings.cpp index 645dc00c..44ea0028 100644 --- a/src/src/Settings.cpp +++ b/src/src/Settings.cpp @@ -59,7 +59,7 @@ void Settings::init() } else { videoFormatList << tr("webm") << tr("mp4"); } - + } else { videoFormatList << tr("webm"); m_settings->setOption("outsetting.outformat.vidformat", 0); From 72aa9d39060b26ad433622415d894ec2e56ac790 Mon Sep 17 00:00:00 2001 From: Resurgamz <108165585+Resurgamz@users.noreply.github.com> Date: Thu, 30 Apr 2026 13:33:21 +0800 Subject: [PATCH 086/107] Revert "Update Settings.cpp" This reverts commit 461e84cc3eb91a25dd69b1608df38e8d302ae4c1. --- src/src/Settings.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/src/Settings.cpp b/src/src/Settings.cpp index 44ea0028..2907f166 100644 --- a/src/src/Settings.cpp +++ b/src/src/Settings.cpp @@ -59,7 +59,6 @@ void Settings::init() } else { videoFormatList << tr("webm") << tr("mp4"); } - } else { videoFormatList << tr("webm"); m_settings->setOption("outsetting.outformat.vidformat", 0); From b4eed5421befca6f777f99c22e7d97c333f93fc2 Mon Sep 17 00:00:00 2001 From: Resurgamz <108165585+Resurgamz@users.noreply.github.com> Date: Thu, 30 Apr 2026 13:33:21 +0800 Subject: [PATCH 087/107] Revert "Adjust video format list order for performance" This reverts commit f60594edef17bc0f2b0a362c6ba408f6609b69be. --- src/src/Settings.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/src/Settings.cpp b/src/src/Settings.cpp index 2907f166..725aa15b 100644 --- a/src/src/Settings.cpp +++ b/src/src/Settings.cpp @@ -54,11 +54,8 @@ void Settings::init() if (DataManager::instance()->encodeEnv() == FFmpeg_Env) { if (DataManager::instance()->encExists()) { GlobalUtils::loadCameraConf(); - if (!GlobalUtils::isLowPerformanceBoard()) { - videoFormatList << tr("mp4") << tr("webm"); - } else { - videoFormatList << tr("webm") << tr("mp4"); - } + // webm 作为默认格式(索引0),mp4 作为备选(索引1) + videoFormatList << tr("webm") << tr("mp4"); } else { videoFormatList << tr("webm"); m_settings->setOption("outsetting.outformat.vidformat", 0); From 96b81541b753524d25874af3fa094895aa485e89 Mon Sep 17 00:00:00 2001 From: Resurgamz <108165585+Resurgamz@users.noreply.github.com> Date: Thu, 30 Apr 2026 13:33:21 +0800 Subject: [PATCH 088/107] Revert "chore: bump version 6.0.13 bump version" This reverts commit f4dbb60d5963186e9675b1da13215184722299dd. --- debian/changelog | 6 ------ 1 file changed, 6 deletions(-) diff --git a/debian/changelog b/debian/changelog index 1ce730f8..167fb5d9 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,9 +1,3 @@ -deepin-camera (6.0.13) unstable; urgency=medium - - * tag 6.0.13 - - -- zhangjiarui Thu, 30 Apr 2026 11:36:13 +0800 - deepin-camera (6.0.12) unstable; urgency=medium * tag 6.0.12 From ddce7c1c12626cc47b004db96b637cdfbaf56e6e Mon Sep 17 00:00:00 2001 From: Resurgamz <108165585+Resurgamz@users.noreply.github.com> Date: Thu, 30 Apr 2026 13:33:21 +0800 Subject: [PATCH 089/107] Revert "refactor(video): change default video format to webm" This reverts commit 36e1019c5f337da2d489bf2029e7eb003afac29a. --- src/src/Settings.cpp | 8 ++++++-- src/src/videowidget.cpp | 15 ++++++--------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/src/Settings.cpp b/src/src/Settings.cpp index 725aa15b..645dc00c 100644 --- a/src/src/Settings.cpp +++ b/src/src/Settings.cpp @@ -54,8 +54,12 @@ void Settings::init() if (DataManager::instance()->encodeEnv() == FFmpeg_Env) { if (DataManager::instance()->encExists()) { GlobalUtils::loadCameraConf(); - // webm 作为默认格式(索引0),mp4 作为备选(索引1) - videoFormatList << tr("webm") << tr("mp4"); + if (!GlobalUtils::isLowPerformanceBoard()) { + videoFormatList << tr("mp4") << tr("webm"); + } else { + videoFormatList << tr("webm") << tr("mp4"); + } + } else { videoFormatList << tr("webm"); m_settings->setOption("outsetting.outformat.vidformat", 0); diff --git a/src/src/videowidget.cpp b/src/src/videowidget.cpp index 92e619dc..58f28dd5 100644 --- a/src/src/videowidget.cpp +++ b/src/src/videowidget.cpp @@ -222,17 +222,14 @@ videowidget::videowidget(DWidget *parent) // 默认不显示网格线 setGridType(Grid_None); - // 默认使用 webm 格式 - if (DataManager::instance()->encodeEnv() != FFmpeg_Env || !DataManager::instance()->encExists()) { + if (DataManager::instance()->encodeEnv() != FFmpeg_Env || !DataManager::instance()->encExists() || GlobalUtils::isLowPerformanceBoard()) { m_videoFormat = "webm"; - } else { - // 根据配置选择格式:0=webm(默认), 1=mp4 - int formatIndex = dc::Settings::get().getOption("outsetting.outformat.vidformat").toInt(); - if (formatIndex == 1) { - m_videoFormat = "mp4"; - } else { + } + if (dc::Settings::get().getOption("outsetting.outformat.vidformat").toInt()) { + if (!GlobalUtils::isLowPerformanceBoard()) m_videoFormat = "webm"; - } + else + m_videoFormat = "mp4"; } } From 7d34be8119307ca09cf54f43d4460b49a46c1076 Mon Sep 17 00:00:00 2001 From: zhangjiarui Date: Thu, 30 Apr 2026 13:39:57 +0800 Subject: [PATCH 090/107] chore: bump version 6.0.13 bump version Log: bump version --- debian/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index 167fb5d9..c73dbabb 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +deepin-camera (6.0.13) unstable; urgency=medium + + * tag 6.0.13 + +-- zhangjiarui Thu, 30 Apr 2026 11:36:13 +0800 + deepin-camera (6.0.12) unstable; urgency=medium * tag 6.0.12 From dc12dc886b3fc5eb23f6c060f17374e8707850bc Mon Sep 17 00:00:00 2001 From: zhangjiarui Date: Thu, 21 May 2026 21:11:18 +0800 Subject: [PATCH 091/107] fix(ui): set icon opacity for photo mode buttons in takePhotoSettingAreaWidget MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add setIconOpacity(1) calls for flashlight, delay, filters, and exposure buttons when entering photo mode to restore correct visual state 修复(ui): 拍照模式下恢复按钮图标透明度状态 进入拍照模式时对闪光灯、延迟拍摄、滤镜、曝光按钮调用 setIconOpacity(1), 恢复按钮图标正常透明度显示 Log: 修复拍照模式按钮图标透明度异常 Bug: https://pms.uniontech.com/bug-view-196565.html --- src/src/takephotosettingareawidget.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/src/takephotosettingareawidget.cpp b/src/src/takephotosettingareawidget.cpp index 3297e8b5..f90dd631 100644 --- a/src/src/takephotosettingareawidget.cpp +++ b/src/src/takephotosettingareawidget.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020 ~ 2021 Uniontech Software Technology Co.,Ltd. +// Copyright (C) 2020 ~ 2026 Uniontech Software Technology Co.,Ltd. // SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -1545,6 +1545,10 @@ void takePhotoSettingAreaWidget::setState(bool bPhoto) m_flashlightUnfoldBtn->setOpacity(102); m_filtersUnfoldBtn->setOpacity(102); m_exposureBtn->setOpacity(102); + m_flashlightUnfoldBtn->setIconOpacity(1); + m_delayUnfoldBtn->setIconOpacity(1); + m_filtersUnfoldBtn->setIconOpacity(1); + m_exposureBtn->setIconOpacity(1); } else { m_flashlightUnfoldBtn->setVisible(false); m_filtersUnfoldBtn->setVisible(false); From 011f0095a98d427d2b63d144cd309140f05704f5 Mon Sep 17 00:00:00 2001 From: zhangjiarui Date: Mon, 25 May 2026 17:40:58 +0800 Subject: [PATCH 092/107] fix(ui): remove transparent separator lines between filter buttons in photo setting area MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Change scrollLayout spacing from 2px to 0px to eliminate visible gaps between filter preview buttons - The 2px spacing combined with WA_TranslucentBackground caused the underlying viewport background to show through, creating transparent separator lines between each filter option 修复(ui): 去掉拍照设置区域滤镜按钮之间的透明分割线 - 将 scrollLayout 间距从 2px 改为 0px,消除滤镜预览按钮之间的可见间隙 - 2px 间距与 WA_TranslucentBackground 配合导致下层 viewport 背景透出,在每个滤镜选项之间形成透明分割线 Log: 去掉滤镜选择面板中各滤镜之间的透明分割线,将 QVBoxLayout 间距从 2px 改为 0px Bug: https://pms.uniontech.com/bug-view-160651.html --- src/src/filterpreviewbutton.cpp | 2 +- src/src/takephotosettingareawidget.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/src/filterpreviewbutton.cpp b/src/src/filterpreviewbutton.cpp index e833caf4..1583f84d 100644 --- a/src/src/filterpreviewbutton.cpp +++ b/src/src/filterpreviewbutton.cpp @@ -16,7 +16,7 @@ extern "C" { DWIDGET_USE_NAMESPACE; -#define MARGIN 5 +#define MARGIN 6 #define IMAGE_SIZE 40 #define BUTTON_SIZE (IMAGE_SIZE + MARGIN * 2) diff --git a/src/src/takephotosettingareawidget.cpp b/src/src/takephotosettingareawidget.cpp index f90dd631..8465890a 100644 --- a/src/src/takephotosettingareawidget.cpp +++ b/src/src/takephotosettingareawidget.cpp @@ -152,7 +152,7 @@ void takePhotoSettingAreaWidget::initButtons() m_scrollAreaWidget->setAttribute(Qt::WA_TranslucentBackground, true); QVBoxLayout *scrollLayout = new QVBoxLayout(m_scrollAreaWidget); scrollLayout->setContentsMargins(0, 0, 0, 0); - scrollLayout->setSpacing(2); + scrollLayout->setSpacing(0); m_scrollAreaWidget->setLayout(scrollLayout); m_scrollArea = new QScrollArea(this); m_scrollArea->setFrameShape(QFrame::NoFrame); From c985023bd3cdd78565db7279052ce6b1b032c204 Mon Sep 17 00:00:00 2001 From: zhangjiarui Date: Thu, 28 May 2026 14:54:25 +0800 Subject: [PATCH 093/107] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=91=84?= =?UTF-8?q?=E5=83=8F=E5=A4=B4=E9=87=8D=E8=BF=9E=E5=92=8C=E9=87=8D=E5=90=AF?= =?UTF-8?q?=E5=90=8E=E5=88=86=E8=BE=A8=E7=8E=87=E6=81=A2=E5=A4=8D=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ON 阶段 setData 触发 DTK widget 重建时读到 OFF 阶段清零的 value=0, 中间态的 resolutionchanged 异步将相机切到错误分辨率,settingDialog 重新打开时 以相机当前错误分辨率覆盖了已保存的用户选择。 - ON 分支用 m_updatingResolution 标志抑制 setData/setOption 的中间态信号, QTimer::singleShot 在所有排队信号处理后发射一次正确值 - settingDialog 优先读 option 已保存值,设备分辨率作为 fallback - switchCameraSuccess 连接 setNewResolutionList,启动和重连均触发 ON 分支恢复 - switchCameraSuccess 无条件发射,构造函数路径也能进入 ON 分支 Log: 修复摄像头重连和应用重启后分辨率恢复为默认值 Bug: https://pms.uniontech.com/bug-view-363077.html --- src/src/Settings.cpp | 20 ++++++++++++++------ src/src/Settings.h | 3 ++- src/src/mainwindow.cpp | 23 +++++++++++++++-------- src/src/videowidget.cpp | 6 ++---- 4 files changed, 33 insertions(+), 19 deletions(-) diff --git a/src/src/Settings.cpp b/src/src/Settings.cpp index 645dc00c..afd28586 100644 --- a/src/src/Settings.cpp +++ b/src/src/Settings.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020 ~ 2021 Uniontech Software Technology Co.,Ltd. +// Copyright (C) 2020 ~ 2026 Uniontech Software Technology Co.,Ltd. // SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -155,17 +155,23 @@ void Settings::setNewResolutionList() for (int i = 0; i < resolutionDatabase.size(); i++) { QStringList resolutiontemp = resolutionDatabase[i].split("x"); - if ((v4l2core_get_frame_width(get_v4l2_device_handler()) == resolutiontemp[0].toInt()) && - (v4l2core_get_frame_height(get_v4l2_device_handler()) == resolutiontemp[1].toInt())) { + if (resolutiontemp.size() >= 2 && + v4l2core_get_frame_width(get_v4l2_device_handler()) == resolutiontemp[0].toInt() && + v4l2core_get_frame_height(get_v4l2_device_handler()) == resolutiontemp[1].toInt()) { defres = i; //set selected resolution index break; } } - + // 抑制中间态的 resolutionchanged, 仅在最后发射一次正确值 + m_updatingResolution = true; resolutionmodeFamily->setData("items", resolutionDatabase); - - //设置当前分辨率的索引 m_settings->setOption(QString("outsetting.resolutionsetting.resolution"), defres); + QTimer::singleShot(0, this, [this, resolutionDatabase, defres]() { + m_updatingResolution = false; + if (defres >= 0 && defres < resolutionDatabase.size()) { + emit resolutionchanged(resolutionDatabase[defres]); + } + }); } else { resolutionDatabase.clear(); resolutionDatabase.append(QString(tr("None"))); @@ -222,6 +228,8 @@ QVariant Settings::getBackOption(const QString &opt) void Settings::onValueChanged(const QString & key, const QVariant & value) { if (key.startsWith("outsetting.resolutionsetting.resolution")) { + if (m_updatingResolution) + return; auto mode_opt = m_settings->option("outsetting.resolutionsetting.resolution"); if (value >= 0 && mode_opt->data("items").toStringList().size() > value.toInt()) { QString mode = mode_opt->data("items").toStringList()[value.toInt()]; diff --git a/src/src/Settings.h b/src/src/Settings.h index 584e09c7..77c0472f 100644 --- a/src/src/Settings.h +++ b/src/src/Settings.h @@ -1,4 +1,4 @@ -// Copyright (C) 2020 ~ 2021 Uniontech Software Technology Co.,Ltd. +// Copyright (C) 2020 ~ 2026 Uniontech Software Technology Co.,Ltd. // SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -160,6 +160,7 @@ public slots: QString m_configPath; QPointer m_settings; QSettingBackend* m_backend; + bool m_updatingResolution = false; }; } diff --git a/src/src/mainwindow.cpp b/src/src/mainwindow.cpp index 0b7c0935..ad87fd98 100644 --- a/src/src/mainwindow.cpp +++ b/src/src/mainwindow.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020 ~ 2021 Uniontech Software Technology Co.,Ltd. +// Copyright (C) 2020 ~ 2026 Uniontech Software Technology Co.,Ltd. // SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -1148,15 +1148,21 @@ void CMainWindow::settingDialog() } - for (int i = 0; i < resolutionDatabase.size(); i++) { - QStringList resolutiontemp = resolutionDatabase[i].split("x"); + int savedRes = resolutionmodeFamily->value().toInt(); + if (savedRes >= 0 && savedRes < resolutionDatabase.size()) { + defres = savedRes; + } else { + for (int i = 0; i < resolutionDatabase.size(); i++) { + QStringList resolutiontemp = resolutionDatabase[i].split("x"); + + if (resolutiontemp.size() >= 2 && + v4l2core_get_frame_width(get_v4l2_device_handler()) == resolutiontemp[0].toInt() && + v4l2core_get_frame_height(get_v4l2_device_handler()) == resolutiontemp[1].toInt()) { + defres = i; //设置分辨率下拉菜单当前索引 + break; + } - if ((v4l2core_get_frame_width(get_v4l2_device_handler()) == resolutiontemp[0].toInt()) && - (v4l2core_get_frame_height(get_v4l2_device_handler()) == resolutiontemp[1].toInt())) { - defres = i; //设置分辨率下拉菜单当前索引 - break; } - } resolutionmodeFamily->setData("items", resolutionDatabase); @@ -1994,6 +2000,7 @@ void CMainWindow::initRightButtons() connect(&m_fileWatcherUp, SIGNAL(fileChanged(const QString &)), this, SLOT(onDirectoryChanged(const QString &))); //摄像头切换成功信号 connect(m_videoPre, SIGNAL(switchCameraSuccess(const QString &)), this, SLOT(onSwitchCameraSuccess(const QString &))); + connect(m_videoPre, SIGNAL(switchCameraSuccess(const QString &)), &Settings::get(), SLOT(setNewResolutionList())); locateRightButtons(); } diff --git a/src/src/videowidget.cpp b/src/src/videowidget.cpp index 58f28dd5..308b5d7e 100644 --- a/src/src/videowidget.cpp +++ b/src/src/videowidget.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020 ~ 2021 Uniontech Software Technology Co.,Ltd. +// Copyright (C) 2020 ~ 2026 Uniontech Software Technology Co.,Ltd. // SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -1217,9 +1217,7 @@ int videowidget::switchCamera(const char *device, const char *devName) m_imgPrcThread->start(); DataManager::instance()->setdevStatus(CAM_CANUSE); //切换摄像机成功,发送设备名称信号到主界面。 - if (devName && strlen(devName)) { - emit switchCameraSuccess(devName); - } + emit switchCameraSuccess(devName ? devName : ""); dc::Settings::get().setBackOption("device", device); } else if (ret == E_FORMAT_ERR) { v4l2_dev_t *vd = get_v4l2_device_handler(); From 8061c9d2b59dbd93abf6b72495b584bb743ac271 Mon Sep 17 00:00:00 2001 From: zhangjiarui Date: Thu, 28 May 2026 20:43:42 +0800 Subject: [PATCH 094/107] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20setNewResol?= =?UTF-8?q?utionList=20=E6=8E=92=E5=BA=8F=E4=B8=8D=E4=B8=80=E8=87=B4?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=E5=88=86=E8=BE=A8=E7=8E=87=E7=B4=A2=E5=BC=95?= =?UTF-8?q?=E9=94=99=E4=BD=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit setNewResolutionList 排序条件使用了 <=,相同宽度时无条件交换, 导致排序结果与 settingDialog 不一致。摄像头重连后保存的索引值 在重新打开设置界面时映射到了错误的分辨率(如 640x480 显示为 640x360)。 Log: 修复 setNewResolutionList 排序不一致导致分辨率索引错位 Bug: https://pms.uniontech.com/bug-view-363077.html --- src/src/Settings.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/src/Settings.cpp b/src/src/Settings.cpp index afd28586..4009d21a 100644 --- a/src/src/Settings.cpp +++ b/src/src/Settings.cpp @@ -136,8 +136,8 @@ void Settings::setNewResolutionList() QStringList resolutiontemp1 = resolutionDatabase[j].split("x"); QStringList resolutiontemp2 = resolutionDatabase[j + 1].split("x"); - if ((resolutiontemp1[0].toInt() <= resolutiontemp2[0].toInt()) - || (resolutiontemp1[1].toInt() < resolutiontemp2[1].toInt())) { + if ((resolutiontemp1[0].toInt() < resolutiontemp2[0].toInt()) || + (resolutiontemp1[0].toInt() == resolutiontemp2[0].toInt() && (resolutiontemp1[1].toInt() < resolutiontemp2[1].toInt()))) { QString resolutionstr = resolutionDatabase[j + 1]; resolutionDatabase[j + 1] = resolutionDatabase[j]; resolutionDatabase[j] = resolutionstr; From 4cb38b140dde9f574a6517c3f9e7f2141bdea02f Mon Sep 17 00:00:00 2001 From: zhangjiarui Date: Fri, 29 May 2026 15:39:11 +0800 Subject: [PATCH 095/107] =?UTF-8?q?fix(encoder):=20=E5=8A=A8=E6=80=81?= =?UTF-8?q?=E8=B0=83=E6=95=B4=E8=BE=93=E5=87=BA=E7=BC=93=E5=86=B2=E5=8C=BA?= =?UTF-8?q?=E5=A4=A7=E5=B0=8F=EF=BC=8C=E8=A7=A3=E5=86=B3=E7=BC=96=E7=A0=81?= =?UTF-8?q?=E5=8C=85=E8=B6=85=E9=99=90=E6=97=B6=E9=9D=99=E9=BB=98=E4=B8=A2?= =?UTF-8?q?=E5=B8=A7=E9=97=AE=E9=A2=98=20=20=20=E5=BD=93=E7=BC=96=E7=A0=81?= =?UTF-8?q?=E5=8C=85=E5=A4=A7=E5=B0=8F=E8=B6=85=E8=BF=87=E8=BE=93=E5=87=BA?= =?UTF-8?q?=E7=BC=93=E5=86=B2=E5=8C=BA=E6=97=B6=EF=BC=8C=E6=9B=BF=E6=8D=A2?= =?UTF-8?q?=E5=8E=9F=E6=9C=89=E7=9A=84=E9=9D=99=E9=BB=98=E4=B8=A2=E5=BC=83?= =?UTF-8?q?=E8=A1=8C=E4=B8=BA=E4=B8=BA=E5=8A=A8=E6=80=81=E6=89=A9=E5=AE=B9?= =?UTF-8?q?=EF=BC=881.5=E5=80=8D=20=20=20=20=20=20=20=20=20=20=20=20=20=20?= =?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=E5=A2=9E?= =?UTF-8?q?=E9=95=BF=EF=BC=89=EF=BC=8C=E6=9C=80=E5=A4=A7=E5=88=86=E9=85=8D?= =?UTF-8?q?=E4=B8=8A=E9=99=90=E4=B8=BA=20max(width*height/2,=202MB)?= =?UTF-8?q?=EF=BC=8C=E9=98=B2=E6=AD=A2=E5=86=85=E5=AD=98=E6=97=A0=E9=99=90?= =?UTF-8?q?=E5=A2=9E=E9=95=BF=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Log: 修复编码器输出缓冲区溢出时静默丢帧的问题 Bug: https://pms.uniontech.com/bug-view-345769.html --- libcam/libcam_encoder/encoder.c | 73 +++++++++++++++++++++++++++++---- 1 file changed, 65 insertions(+), 8 deletions(-) diff --git a/libcam/libcam_encoder/encoder.c b/libcam/libcam_encoder/encoder.c index db9fe8fe..834e4779 100644 --- a/libcam/libcam_encoder/encoder.c +++ b/libcam/libcam_encoder/encoder.c @@ -1581,6 +1581,61 @@ static int libav_get_encode(AVCodecContext *avctx, AVPacket *pkt, int *got_packe // return ret; // } +/* + * Ensure output buffer is large enough for the encoded packet. + * Dynamically resizes the buffer if needed (1.5x reserved space, capped at + * max(width*height/2, 2MB)). Drops the frame if it exceeds the reasonable + * upper limit or if realloc fails. + * + * Returns: 1 if data was successfully copied to outbuf, + * 0 if frame was dropped (caller must continue to next iteration). + */ +static int resize_outbuf_if_needed(encoder_video_context_t *enc_video_ctx, + encoder_context_t *encoder_ctx, + AVPacket *pkt) +{ + /* Guard against invalid negative pkt->size to prevent memcpy overflow, + * since negative int is implicitly converted to a huge size_t value. */ + if (pkt->size < 0) { + fprintf(stderr, "ENCODER: invalid packet size %d, dropping frame\n", pkt->size); + return 0; + } + + if (pkt->size <= enc_video_ctx->outbuf_size) { + memcpy(enc_video_ctx->outbuf, pkt->data, pkt->size); + return 1; + } + + /* Buffer limit: width * height / 2, with 2MB minimum protection */ + int max_reasonable_size = encoder_ctx->video_width * encoder_ctx->video_height / 2; + if (max_reasonable_size < 2 * 1024 * 1024) + max_reasonable_size = 2 * 1024 * 1024; + + if (pkt->size > max_reasonable_size) { + fprintf(stderr, "ENCODER: packet size %d exceeds reasonable limit (%d), dropping frame\n", + pkt->size, max_reasonable_size); + return 0; + } + + /* Reserve extra space (1.5x) to avoid frequent reallocations */ + int alloc_size = pkt->size + (pkt->size >> 1); + if (alloc_size > max_reasonable_size) + alloc_size = max_reasonable_size; + + fprintf(stderr, "ENCODER: resizing output buffer (%i -> %i, reserved %i)\n", + enc_video_ctx->outbuf_size, pkt->size, alloc_size); + uint8_t *new_buf = realloc(enc_video_ctx->outbuf, alloc_size); + if (new_buf) { + enc_video_ctx->outbuf = new_buf; + enc_video_ctx->outbuf_size = alloc_size; + memcpy(enc_video_ctx->outbuf, pkt->data, pkt->size); + return 1; + } + + fprintf(stderr, "ENCODER: failed to allocate %d bytes, dropping frame\n", alloc_size); + return 0; +} + /* * encode video frame * args: @@ -1702,10 +1757,11 @@ int encoder_encode_video(encoder_context_t *encoder_ctx, void *input_frame) enc_video_ctx->flags = pkt->flags; enc_video_ctx->duration = pkt->duration; - if (pkt->size <= enc_video_ctx->outbuf_size) - memcpy(enc_video_ctx->outbuf, pkt->data, pkt->size); - else - fprintf(stderr, "video packet size is bigger than output buffer(%i>%i)\n", pkt->size, enc_video_ctx->outbuf_size); + if (!resize_outbuf_if_needed(enc_video_ctx, encoder_ctx, pkt)) { + last_video_pts = enc_video_ctx->pts; + getLoadLibsInstance()->m_av_packet_unref(pkt); + continue; + } /* free any side data since we cannot return it */ if (pkt->side_data_elems > 0) { @@ -2682,10 +2738,11 @@ int encoder_encode_video_vaapi(encoder_context_t *encoder_ctx, void *input_frame enc_video_ctx->flags = pkt->flags; enc_video_ctx->duration = pkt->duration; - if (pkt->size <= enc_video_ctx->outbuf_size) - memcpy(enc_video_ctx->outbuf, pkt->data, pkt->size); - else - fprintf(stderr, "video packet size is bigger than output buffer(%i>%i)\n", pkt->size, enc_video_ctx->outbuf_size); + if (!resize_outbuf_if_needed(enc_video_ctx, encoder_ctx, pkt)) { + last_video_pts = enc_video_ctx->pts; + getLoadLibsInstance()->m_av_packet_unref(pkt); + continue; + } /* free any side data since we cannot return it */ if (pkt->side_data_elems > 0) { From b3e6a2723eb81f9d581c3085fdaf855e7dcf3836 Mon Sep 17 00:00:00 2001 From: zhangjiarui Date: Fri, 5 Jun 2026 10:47:21 +0800 Subject: [PATCH 096/107] fix(config): support low performance device config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Log: 支持通过配置标记低性能设备 Bug: https://pms.uniontech.com/bug-view-358869.html Influence: 可通过配置直接识别低性能设备,优化低性能设备判断逻辑。 --- src/assets/org.deepin.camera.encode.json | 10 ++++++++++ src/src/globalutils.cpp | 23 ++++++++++++++++++++++- src/src/globalutils.h | 1 + 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/assets/org.deepin.camera.encode.json b/src/assets/org.deepin.camera.encode.json index a8bfab9a..ff29a8cd 100644 --- a/src/assets/org.deepin.camera.encode.json +++ b/src/assets/org.deepin.camera.encode.json @@ -111,6 +111,16 @@ "description": "Set preferred resolution", "permissions": "readwrite", "visibility": "private" + }, + "isLowPerformanceDevice": { + "value": false, + "serial": 0, + "flags": ["global"], + "name": "is low performance device", + "name[zh_CN]": "是否是低性能设备", + "description": "Is low performance device", + "permissions": "readwrite", + "visibility": "private" } } } diff --git a/src/src/globalutils.cpp b/src/src/globalutils.cpp index 24aa7390..f4a5156e 100644 --- a/src/src/globalutils.cpp +++ b/src/src/globalutils.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020 ~ 2021 Uniontech Software Technology Co.,Ltd. +// Copyright (C) 2020 ~ 2026 Uniontech Software Technology Co.,Ltd. // SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -11,11 +11,17 @@ #include #include +#ifdef DTKCORE_CLASS_DConfigFile +#include +#include +#endif + // 相机配置文件 const QString CAMERA_CONF_PATH = "/usr/share/deepin-camera/camera.conf"; #define LOW_PERFORMANCE_BOARD "LowPerformanceBoard" QStringList GlobalUtils::m_LowPerformanceBoards = QStringList(); +bool GlobalUtils::m_IsLowPerformanceDevice = false; struct DMIInfo { QString biosManufacturer; @@ -56,6 +62,12 @@ const QDBusArgument &operator>>(const QDBusArgument &argument, DMIInfo &mystruct bool GlobalUtils::isLowPerformanceBoard() { +#ifdef DTKCORE_CLASS_DConfigFile + if (m_IsLowPerformanceDevice) { + return true; + } +#endif + qDBusRegisterMetaType(); QDBusInterface *monitorInterface = new QDBusInterface("com.deepin.system.SystemInfo", "/com/deepin/system/SystemInfo", "org.freedesktop.DBus.Properties", QDBusConnection::systemBus()); if (!monitorInterface->isValid()) @@ -86,4 +98,13 @@ void GlobalUtils::loadCameraConf() } else { m_LowPerformanceBoards = QStringList(); } + +#ifdef DTKCORE_CLASS_DConfigFile + m_IsLowPerformanceDevice = false; + std::unique_ptr dconfig( + DTK_CORE_NAMESPACE::DConfig::create("org.deepin.camera", "org.deepin.camera.encode")); + if (dconfig && dconfig->isValid() && dconfig->keyList().contains("isLowPerformanceDevice")) { + m_IsLowPerformanceDevice = dconfig->value("isLowPerformanceDevice").toBool(); + } +#endif } diff --git a/src/src/globalutils.h b/src/src/globalutils.h index 51e021d4..ee3b6680 100644 --- a/src/src/globalutils.h +++ b/src/src/globalutils.h @@ -19,6 +19,7 @@ class GlobalUtils private: static QStringList m_LowPerformanceBoards; + static bool m_IsLowPerformanceDevice; }; #endif // GLOBALUTILS_H From 6bc3ae09bce535875217de64c91be149c452fb47 Mon Sep 17 00:00:00 2001 From: zhangjiarui Date: Fri, 5 Jun 2026 16:22:14 +0800 Subject: [PATCH 097/107] =?UTF-8?q?fix:=20=E5=B0=86=E6=91=84=E5=83=8F?= =?UTF-8?q?=E5=A4=B4=E5=8D=A1=E7=89=87=E8=BF=87=E6=BB=A4=E5=85=B3=E9=94=AE?= =?UTF-8?q?=E5=AD=97=E6=94=B9=E4=B8=BA=20DConfig=20=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将原先在 enum_v4l2_devices 中硬编码的摄像头卡片关键字迁移到 org.deepin.camera.encode.json 的 CardKeywords 配置项中,并在启动时 从 DConfig 读取后动态传递给 libcam 使用,支持后续通过配置增删过滤关键字。 Log: 将摄像头卡片过滤关键字设置为DConfig配置 Bug: https://pms.uniontech.com/bug-view-363739.html --- libcam/libcam/camview.c | 79 ++++++++++++++++++++++++ libcam/libcam/camview.h | 26 ++++++++ libcam/libcam_v4l2core/v4l2_devices.c | 15 +++++ src/assets/org.deepin.camera.encode.json | 10 +++ src/main.cpp | 20 ++++++ src/src/globalutils.cpp | 26 ++++++++ src/src/globalutils.h | 4 ++ 7 files changed, 180 insertions(+) diff --git a/libcam/libcam/camview.c b/libcam/libcam/camview.c index e03445ff..7d187ad2 100644 --- a/libcam/libcam/camview.c +++ b/libcam/libcam/camview.c @@ -30,6 +30,7 @@ #include #include #include +#include #include /* support for internationalization - i18n */ #include @@ -120,6 +121,38 @@ static int encode_thread_running = 0; static char project_id[200]; +static char **card_keywords = NULL; +static int card_keyword_count = 0; + +static int is_invalid_card_keyword(const char *keyword) +{ + if (keyword == NULL || keyword[0] == '\0') { + return 1; + } + + for (const char *p = keyword; *p != '\0'; p++) { + if (!isspace((unsigned char)*p)) { + return 0; + } + } + + return 1; +} + +static void clear_card_keywords(void) +{ + if (card_keywords == NULL) { + return; + } + + for (int i = 0; i < card_keyword_count; i++) { + free(card_keywords[i]); + } + free(card_keywords); + card_keywords = NULL; + card_keyword_count = 0; +} + void set_video_time_capture(double video_time) { video_time_capture = video_time; @@ -1403,6 +1436,52 @@ const char* get_project_id(void) return project_id; } +void set_card_keywords(const char **keywords, int count) +{ + clear_card_keywords(); + + if (keywords == NULL || count <= 0) { + return; + } + + int valid_count = 0; + for (int i = 0; i < count; i++) { + if (!is_invalid_card_keyword(keywords[i])) { + valid_count++; + } + } + + if (valid_count == 0) { + return; + } + + card_keywords = calloc((size_t)valid_count, sizeof(char *)); + if (card_keywords == NULL) { + fprintf(stderr, "deepin-camera: failed to allocate card keywords\n"); + return; + } + + for (int i = 0; i < count; i++) { + if (is_invalid_card_keyword(keywords[i])) { + continue; + } + + card_keywords[card_keyword_count] = strdup(keywords[i]); + if (card_keywords[card_keyword_count] != NULL) { + card_keyword_count++; + } + } +} + +const char** get_card_keywords(int *count) +{ + if (count != NULL) { + *count = card_keyword_count; + } + + return (const char **)card_keywords; +} + void set_libva_driver_name(const char *name) { if (name != NULL) { diff --git a/libcam/libcam/camview.h b/libcam/libcam/camview.h index 506b8245..625f0b83 100644 --- a/libcam/libcam/camview.h +++ b/libcam/libcam/camview.h @@ -464,6 +464,32 @@ void set_project_id(const char *project_id); */ const char* get_project_id(void); +/* + * set camera card keywords + * args: + * keywords - camera card keyword string array. Each string is copied by this function; + * caller retains ownership of the input array and strings. + * count - keyword count + * + * asserts: + * none + * + * returns: none + */ +void set_card_keywords(const char **keywords, int count); + +/* + * get camera card keywords + * args: + * count - output keyword count + * + * asserts: + * none + * + * returns: pointer to camera card keyword string array + */ +const char** get_card_keywords(int *count); + /* * set libva driver name * args: diff --git a/libcam/libcam_v4l2core/v4l2_devices.c b/libcam/libcam_v4l2core/v4l2_devices.c index 86b35b59..2c8a1c3f 100644 --- a/libcam/libcam_v4l2core/v4l2_devices.c +++ b/libcam/libcam_v4l2core/v4l2_devices.c @@ -345,6 +345,21 @@ int enum_v4l2_devices() continue; /*next dir entry*/ } + int num_card_keywords = 0; + const char **card_keywords = get_card_keywords(&num_card_keywords); + + int is_card_keyword_device = 0; + for (int i = 0; i < num_card_keywords; i++) { + if(card_keywords[i] != NULL && strstr((const char *)v4l2_cap.card, card_keywords[i]) != NULL) { + is_card_keyword_device = 1; + break; + } + } + if(is_card_keyword_device) { + getV4l2()->m_v4l2_close(fd); + continue; /*next dir entry*/ + } + // when project_id equals UOS2025073011543 filter out ISP devices const char* current_project_id = get_project_id(); if (current_project_id != NULL && strcmp(current_project_id, UOS2025073011543) == 0) { diff --git a/src/assets/org.deepin.camera.encode.json b/src/assets/org.deepin.camera.encode.json index ff29a8cd..c9759b48 100644 --- a/src/assets/org.deepin.camera.encode.json +++ b/src/assets/org.deepin.camera.encode.json @@ -102,6 +102,16 @@ "permissions": "readwrite", "visibility": "private" }, + "CardKeywords": { + "value": ["IR Cam", "IR Camera", "Infrared", "IR_", "-IR", "ir_cam"], + "serial": 0, + "flags": ["global"], + "name": "camera card keywords", + "name[zh_CN]": "摄像头卡片名称关键字", + "description": "Set camera card name keywords", + "permissions": "readwrite", + "visibility": "private" + }, "preferredResolution": { "value": "", "serial": 0, diff --git a/src/main.cpp b/src/main.cpp index 99bef41a..fefa4861 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -12,6 +12,7 @@ extern "C" { #include "cameraconfig.h" #include "acobjectlist.h" #include "dbus_adpator.h" +#include "globalutils.h" #include #ifdef DTKCORE_CLASS_DConfigFile @@ -29,6 +30,8 @@ extern "C" { #include #include +#include +#include #include #include @@ -205,6 +208,23 @@ int main(int argc, char *argv[]) DataManager::instance()->setDeviceBlacklist(deviceBlacklist); } + if (dconfig && dconfig->isValid() && dconfig->keyList().contains("CardKeywords")) { + QStringList cardKeywords = GlobalUtils::parseStringListConfig(dconfig->value("CardKeywords")); + QVector keywordBytes; + keywordBytes.reserve(cardKeywords.size()); + for (const QString &keyword : cardKeywords) { + keywordBytes.append(keyword.toUtf8()); + } + + QVector keywordData; + keywordData.reserve(keywordBytes.size()); + for (const QByteArray &keyword : keywordBytes) { + keywordData.append(keyword.constData()); + } + qInfo() << "card keywords:" << cardKeywords; + set_card_keywords(keywordData.data(), keywordData.size()); + } + if (dconfig && dconfig->isValid() && dconfig->keyList().contains("preferredResolution")) { QString preferredResolution = dconfig->value("preferredResolution").toString(); qInfo() << "preferred resolution:" << preferredResolution; diff --git a/src/src/globalutils.cpp b/src/src/globalutils.cpp index f4a5156e..d7702e30 100644 --- a/src/src/globalutils.cpp +++ b/src/src/globalutils.cpp @@ -108,3 +108,29 @@ void GlobalUtils::loadCameraConf() } #endif } + +QStringList GlobalUtils::parseStringListConfig(const QVariant &value) +{ + QStringList rawList; + + if (value.type() == QVariant::StringList) { + rawList = value.toStringList(); + } else if (value.type() == QVariant::List) { + const QVariantList variantList = value.toList(); + for (const QVariant &item : variantList) { + if (item.type() == QVariant::String) { + rawList.append(item.toString()); + } + } + } else { + return QStringList(); + } + + QStringList result; + for (const QString &keyword : rawList) { + if (!keyword.trimmed().isEmpty()) { + result.append(keyword); + } + } + return result; +} diff --git a/src/src/globalutils.h b/src/src/globalutils.h index ee3b6680..2572a129 100644 --- a/src/src/globalutils.h +++ b/src/src/globalutils.h @@ -7,6 +7,8 @@ #define GLOBALUTILS_H #include +#include +#include class GlobalUtils { @@ -17,6 +19,8 @@ class GlobalUtils // 加载相机配置 static void loadCameraConf(); + static QStringList parseStringListConfig(const QVariant &value); + private: static QStringList m_LowPerformanceBoards; static bool m_IsLowPerformanceDevice; From 12ff976da90e5c8b9ff874adc199d2154bd2ee1a Mon Sep 17 00:00:00 2001 From: ZhangTingan Date: Tue, 12 May 2026 14:26:40 +0800 Subject: [PATCH 098/107] fix(a/v-sync): use monotonic clock for audio PTS to fix desync Audio PTS was derived from the hardware device timestamp while video PTS used CLOCK_MONOTONIC, causing progressive A/V drift. Unify both to ns_time_monotonic(). Also preserve original_pts for the muxer to avoid precision loss from audio codec time_base rescaling. log: fix bug Bug:https://pms.uniontech.com/bug-view-363537.html --- libcam/libcam/camview.c | 12 +++++++++--- libcam/libcam_encoder/encoder.c | 4 +++- libcam/libcam_encoder/gviewencoder.h | 1 + libcam/libcam_encoder/muxer.c | 2 +- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/libcam/libcam/camview.c b/libcam/libcam/camview.c index 7d187ad2..f52bda77 100644 --- a/libcam/libcam/camview.c +++ b/libcam/libcam/camview.c @@ -37,6 +37,7 @@ #include #include "gviewv4l2core.h" +#include "core_time.h" #include "gviewrender.h" #include "gviewencoder.h" #include "gview.h" @@ -728,6 +729,11 @@ static void *audio_processing_loop(void *data) render_set_osd_mask(osd_mask); + /* init reference to system monotonic clock on first run */ + if (audio_timestamp_reference == 0) { + audio_timestamp_reference = ns_time_monotonic(); + audio_timestamp_tmp = audio_timestamp_reference; + } while(video_capture_get_save_video()) { if(get_capture_pause()) @@ -735,7 +741,7 @@ static void *audio_processing_loop(void *data) int ret = audio_get_next_buffer(audio_ctx, audio_buff, sample_type, my_audio_mask); if(ret == 0) { - audio_pause_timestamp = audio_buff->timestamp - audio_timestamp_tmp; + audio_pause_timestamp = ns_time_monotonic() - audio_timestamp_tmp; } continue; } @@ -743,7 +749,7 @@ static void *audio_processing_loop(void *data) int ret = audio_get_next_buffer(audio_ctx, audio_buff, sample_type, my_audio_mask); - audio_timestamp_tmp = audio_buff->timestamp; + audio_timestamp_tmp = ns_time_monotonic(); if(audio_pause_timestamp != 0) { audio_timestamp_reference += audio_pause_timestamp; audio_pause_timestamp = 0; @@ -758,7 +764,7 @@ static void *audio_processing_loop(void *data) .tv_nsec = 1000000};/*nanosec*/ nanosleep(&req, NULL); } else if(ret == 0) { - encoder_ctx->enc_audio_ctx->pts = audio_buff->timestamp - audio_timestamp_reference; + encoder_ctx->enc_audio_ctx->pts = ns_time_monotonic() - audio_timestamp_reference; /*OSD vu meter level*/ render_set_vu_level(audio_buff->level_meter); diff --git a/libcam/libcam_encoder/encoder.c b/libcam/libcam_encoder/encoder.c index 834e4779..32a8313b 100644 --- a/libcam/libcam_encoder/encoder.c +++ b/libcam/libcam_encoder/encoder.c @@ -48,6 +48,7 @@ #include #include "cameraconfig.h" +#include "core_time.h" #include "gviewencoder.h" #include "encoder.h" #include "stream_io.h" @@ -1361,7 +1362,7 @@ int encoder_flush_video_buffer(encoder_context_t *encoder_ctx) if (verbosity > 1) printf("ENCODER: flushed %i delayed video frames\n", flushed_frame_counter); - if (!buffer_count) { + if (!buffer_count) { fprintf(stderr, "ENCODER: (flush video buffer) max processed buffers reached\n"); return -1; } @@ -1941,6 +1942,7 @@ int encoder_encode_audio(encoder_context_t *encoder_ctx, void *audio_data) audio_codec_data->codec_context->time_base.den); } } + enc_audio_ctx->original_pts = enc_audio_ctx->pts; ret = libav_send_encode( audio_codec_data->codec_context, audio_codec_data->frame); diff --git a/libcam/libcam_encoder/gviewencoder.h b/libcam/libcam_encoder/gviewencoder.h index 714b33b3..1f94a1f6 100644 --- a/libcam/libcam_encoder/gviewencoder.h +++ b/libcam/libcam_encoder/gviewencoder.h @@ -183,6 +183,7 @@ typedef struct _encoder_audio_context_t { int outbuf_coded_size; int64_t pts; + int64_t original_pts; /* 纳秒时间戳,不被编码器覆盖,用于 muxer PTS 计算 */ int64_t dts; int flags; int duration; diff --git a/libcam/libcam_encoder/muxer.c b/libcam/libcam_encoder/muxer.c index 7d10fcc8..08c5ff8e 100644 --- a/libcam/libcam_encoder/muxer.c +++ b/libcam/libcam_encoder/muxer.c @@ -218,7 +218,7 @@ int encoder_write_audio_data(encoder_context_t *encoder_ctx) 1, enc_audio_ctx->outbuf, (uint32_t)enc_audio_ctx->outbuf_coded_size, - (uint64_t)enc_audio_ctx->pts, + (uint64_t)enc_audio_ctx->original_pts, enc_audio_ctx->flags); break; From 5f5fff21982aed478e041ec704126cc9340f66c4 Mon Sep 17 00:00:00 2001 From: zhangjiarui Date: Mon, 15 Jun 2026 14:16:51 +0800 Subject: [PATCH 099/107] =?UTF-8?q?fix(camera):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E6=91=84=E5=83=8F=E5=A4=B4=E8=A2=AB=E5=8D=A0=E7=94=A8=E6=97=B6?= =?UTF-8?q?=E4=BB=8D=E6=98=BE=E7=A4=BA=E5=80=92=E8=AE=A1=E6=97=B6=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Log: 修复摄像头被占用时仍显示倒计时的问题 Bug: https://pms.uniontech.com/bug-view-364831.html Influence: 摄像头被其它应用占用时,点击拍照或录像不再显示0或负数倒计时;日志中的camera_connected仅在摄 像头可用时记录为true。 --- src/src/mainwindow.cpp | 16 ++++++++++------ src/src/titlebar.cpp | 6 +++--- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/src/mainwindow.cpp b/src/src/mainwindow.cpp index ad87fd98..862e633d 100644 --- a/src/src/mainwindow.cpp +++ b/src/src/mainwindow.cpp @@ -1269,7 +1269,7 @@ void CMainWindow::loadAfterShow() {"tid", EventLogUtils::Start}, {"mode", 1}, {"version", VERSION}, - {"camera_connected", DataManager::instance()->getdevStatus() ? true : false} + {"camera_connected", DataManager::instance()->getdevStatus() == CAM_CANUSE} }; EventLogUtils::get().writeLogs(obj); } @@ -1481,21 +1481,21 @@ void CMainWindow::onPhotoRecordBtnClked() QJsonObject obj { {"tid", m_photoRecordBtn->photoState() ? EventLogUtils::StartPhoto : EventLogUtils::StartRecording}, {"version", VERSION}, - {"camera_connected", DataManager::instance()->getdevStatus() ? true : false} + {"camera_connected", DataManager::instance()->getdevStatus() == CAM_CANUSE} }; if(!m_bRecording) EventLogUtils::get().writeLogs(obj); - //没有摄像机,不进行任何操作 - if (NOCAM == DataManager::instance()->getdevStatus()) { - return; - } //拍照模式下 if (true == m_photoRecordBtn->photoState()) { //正在拍照 if (photoNormal != m_photoState) { m_videoPre->onTakePic(false); } else { + //摄像头不可用时,不开启新的拍照动作 + if (CAM_CANUSE != DataManager::instance()->getdevStatus()) { + return; + } int nContinuous = Settings::get().getOption("photosetting.photosnumber.takephotos").toInt(); if (nContinuous > 1) { // 仅在连拍模式下才开启窗口状态监听线程 @@ -1509,6 +1509,10 @@ void CMainWindow::onPhotoRecordBtnClked() if (true == m_bRecording) { m_videoPre->onEndBtnClicked(); } else { + //摄像头不可用时,不开启新的录像动作 + if (CAM_CANUSE != DataManager::instance()->getdevStatus()) { + return; + } QFileInfo fi(m_videoPath); if (!fi.isWritable()) return; diff --git a/src/src/titlebar.cpp b/src/src/titlebar.cpp index 3d80846f..ae1b0368 100644 --- a/src/src/titlebar.cpp +++ b/src/src/titlebar.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -62,7 +62,7 @@ void Titlebar::slotThemeTypeChanged() { Q_D(const Titlebar); QPalette pa; - if(DataManager::instance()->getdevStatus() != NOCAM) { + if(DataManager::instance()->getdevStatus() == CAM_CANUSE) { pa.setColor(QPalette::ButtonText, d->lightColor); d->m_titlebar->setPalette(pa); } else{ @@ -83,7 +83,7 @@ void Titlebar::paintEvent(QPaintEvent *pe) QPainter painter(this); QPalette pa; - if(DataManager::instance()->getdevStatus() != NOCAM) { + if(DataManager::instance()->getdevStatus() == CAM_CANUSE) { pa.setColor(QPalette::ButtonText, d->lightColor); d->m_titlebar->setPalette(pa); } From ced1680fde66c51f3c129a1c41094f7069a77d82 Mon Sep 17 00:00:00 2001 From: zhanghongyuan Date: Tue, 23 Jun 2026 15:32:53 +0800 Subject: [PATCH 100/107] feat(config): add useRgbData config to control RGB preview mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add DConfig option "useRgbData" to control whether YUV frames are converted to RGB for preview rendering. Supports three modes: -1: auto (default, let system decide) 0: force disable 1: force enable 添加DConfig配置项"useRgbData",控制预览时是否将YUV帧数据转换为RGB格式。 支持三态:-1自动判断(默认)、0强制关闭、1强制开启。 Log: 添加RGB预览模式配置项 PMS: BUG-366739 Influence: 通过DConfig配置可强制控制预览RGB数据的使用,便于排查特定机型显示异常问题。 --- src/assets/org.deepin.camera.encode.json | 10 ++++++++++ src/main.cpp | 10 ++++++++++ src/src/basepub/datamanager.h | 13 +++++++++++++ src/src/majorimageprocessingthread.cpp | 8 ++++++++ 4 files changed, 41 insertions(+) diff --git a/src/assets/org.deepin.camera.encode.json b/src/assets/org.deepin.camera.encode.json index c9759b48..da1ab435 100644 --- a/src/assets/org.deepin.camera.encode.json +++ b/src/assets/org.deepin.camera.encode.json @@ -131,6 +131,16 @@ "description": "Is low performance device", "permissions": "readwrite", "visibility": "private" + }, + "useRgbData": { + "value": -1, + "serial": 0, + "flags": ["global"], + "name": "use RGB data for preview", + "name[zh_CN]": "是否使用RGB数据进行预览显示,-1表示不设置,由系统自动判断;0表示强制关闭;1表示强制开启", + "description": "Force use RGB data for preview rendering. -1: not set (auto), 0: force disable, 1: force enable. When enabled, YUV frames will be converted to RGB format before display.", + "permissions": "readwrite", + "visibility": "private" } } } diff --git a/src/main.cpp b/src/main.cpp index fefa4861..b1f5f18d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -237,6 +237,16 @@ int main(int argc, char *argv[]) } } + if (dconfig && dconfig->isValid() && dconfig->keyList().contains("useRgbData")) { + int useRgbData = dconfig->value("useRgbData").toInt(); + if (useRgbData != -1 && useRgbData != 0 && useRgbData != 1) { + qWarning() << "Invalid useRgbData value in config:" << useRgbData << "- mapping to default value -1 (auto)"; + useRgbData = -1; + } + qInfo() << "use RGB data for preview:" << useRgbData; + DataManager::instance()->setUseRgbData(useRgbData); + } + if (!libVaDriverName.isEmpty()) { qputenv("LIBVA_DRIVER_NAME", libVaDriverName.toLocal8Bit()); } diff --git a/src/src/basepub/datamanager.h b/src/src/basepub/datamanager.h index 729c3b75..26d01293 100644 --- a/src/src/basepub/datamanager.h +++ b/src/src/basepub/datamanager.h @@ -211,6 +211,18 @@ class DataManager: public QObject * @return 分辨率 */ QSize getPreferredResolution(); + + /** + * @brief 设置RGB数据预览模式 + * @param mode -1:不设置(自动), 0:强制关闭, 1:强制开启 + */ + void setUseRgbData(int mode) { m_useRgbData = mode; }; + + /** + * @brief 获取RGB数据预览模式 + * @return -1:不设置(自动), 0:强制关闭, 1:强制开启 + */ + int getUseRgbData() const { return m_useRgbData; }; private: DataManager(); static DataManager *m_dataManager; @@ -226,5 +238,6 @@ class DataManager: public QObject bool m_enable8kPreview = false; // 是否启用8K预览 QSet m_deviceBlacklistSet; // 设备黑名单 QSize m_preferredResolution; // 首选分辨率 + int m_useRgbData = -1; // RGB数据预览模式:-1不设置(自动), 0强制关闭, 1强制开启 }; #endif // DATAMANAGER_H diff --git a/src/src/majorimageprocessingthread.cpp b/src/src/majorimageprocessingthread.cpp index 53c497b0..644bb135 100644 --- a/src/src/majorimageprocessingthread.cpp +++ b/src/src/majorimageprocessingthread.cpp @@ -282,6 +282,14 @@ void MajorImageProcessingThread::run() if (GStreamer_Env == m_eEncodeEnv) bUseRgb = true; + // DConfig配置控制RGB数据使用模式,-1表示不设置(由系统自动判断),0表示强制关闭,1表示强制开启 + int useRgbData = DataManager::instance()->getUseRgbData(); + if (useRgbData == 1) { + bUseRgb = true; + } else if (useRgbData == 0) { + bUseRgb = false; + } + if (bUseRgb || (m_bPhoto && m_filtersGroupDislay)) { if (m_nVdWidth != static_cast(m_frame->width) || m_nVdHeight != static_cast(m_frame->height)) { m_nVdWidth = static_cast(m_frame->width); From 6cab0d44e91f8c00c8276183827c2034ff753616 Mon Sep 17 00:00:00 2001 From: zhanghongyuan Date: Mon, 29 Jun 2026 13:02:03 +0800 Subject: [PATCH 101/107] fix(camera): prefer DConfig resolution over local config (BUG-366203) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When preferredResolution is set via DConfig, use it directly instead of the locally cached resolution from config file on first launch. DConfig的preferredResolution配置优先于本地配置文件中的分辨率, 修复首次打开应用时仍使用本地旧配置的问题。 Log: 修复preferredResolution首次启动不生效的问题 PMS: BUG-366203 Influence: 设置preferredResolution后首次启动即可生效,无需重启两次。 --- src/src/LPF_V4L2.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/src/LPF_V4L2.c b/src/src/LPF_V4L2.c index 3a8efe2e..7a79ecdf 100644 --- a/src/src/LPF_V4L2.c +++ b/src/src/LPF_V4L2.c @@ -1,5 +1,5 @@ -// Copyright (C) 2020 ~ 2021 Uniontech Software Technology Co.,Ltd. -// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +// Copyright (C) 2020 - 2026 Uniontech Software Technology Co.,Ltd. +// SPDX-FileCopyrightText: 2023 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -18,6 +18,7 @@ extern "C" { #include "audio.h" #include "core_io.h" #include "colorspaces.h" +#include "v4l2_formats.h" int camInit(const char *devicename) { @@ -210,12 +211,15 @@ int camInit(const char *devicename) v4l2core_prepare_new_format(my_vd, (int)my_config->format); if ((strcmp(my_config->device_name, devlist->list_devices[my_vd->this_device].name) == 0) && (strcmp(my_config->device_location, my_vd->videodevice) == 0)) { - v4l2core_prepare_new_resolution(my_vd, my_config->width, my_config->height); - // 分辨率可能已经被校正 - if (my_config->width != get_my_width() || my_config->height != get_my_height()) { - printf("%s: adjust resolution(%dx%d => %dx%d)\n", __func__, my_config->width, my_config->height, get_my_width(), get_my_height()); + // DConfig preferredResolution 优先于本地配置文件中的分辨率 + if (get_preferred_resolution_width() > 0 && get_preferred_resolution_height() > 0) { + v4l2core_prepare_new_resolution(my_vd, + get_preferred_resolution_width(), + get_preferred_resolution_height()); my_config->width = get_my_width(); my_config->height = get_my_height(); + } else { + v4l2core_prepare_new_resolution(my_vd, my_config->width, my_config->height); } ret = v4l2core_update_old_format(my_vd, my_config->width, my_config->height, v4l2core_get_requested_frame_format(my_vd)); } else { From dd548492cff5dec54a75027891fa4efbcabe5b3f Mon Sep 17 00:00:00 2001 From: zhanghongyuan Date: Mon, 29 Jun 2026 13:29:53 +0800 Subject: [PATCH 102/107] chore: add .gitignore for C++ and Qt artifacts Added a .gitignore file to exclude common C++ object files, Qt build artifacts, and QtCreator-specific configurations. This prevents generated files and local IDE settings from being accidentally committed to the repository. --- .gitignore | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..e0118edd --- /dev/null +++ b/.gitignore @@ -0,0 +1,56 @@ +# C++ objects and libs +*.slo +*.lo +*.o +*.a +*.la +*.lai +*.so +*.so.* +*.dll +*.dylib + +# Qt-es +object_script.*.Release +object_script.*.Debug +*_plugin_import.cpp +/.qmake.cache +/.qmake.stash +*.pro.user +*.pro.user.* +*.qbs.user +*.qbs.user.* +*.moc +moc_*.cpp +moc_*.h +qrc_*.cpp +ui_*.h +*.qmlc +*.jsc +Makefile* +*build-* +build/ +*.qm +*.prl +*.qmlls.ini + +# Qt unit tests +target_wrapper.* + +# QtCreator +*.autosave + +# QtCreator Qml +*.qmlproject.user +*.qmlproject.user.* + +# QtCreator CMake +CMakeLists.txt.user* + +# QtCreator 4.8< compilation database +compile_commands.json + +# QtCreator local machine specific files for imported projects +*creator.user* + +*_qmlcache.qrc \ No newline at end of file From 5a8a1a95a3cde2db35a48658f53a566fc97430e1 Mon Sep 17 00:00:00 2001 From: zhangjiarui Date: Thu, 30 Jul 2026 19:14:33 +0800 Subject: [PATCH 103/107] fix(camera): warm up shutter audio on demand MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace QSound with QSoundEffect and silently warm the audio stream before playing each shutter sound.\n\n使用 QSoundEffect 替换 QSound,并在播放快门音前静音预热音频流。\n\nLog: 修复快门音首声音量偏小的问题\nPMS: https://pms.uniontech.com/bug-view-369937.html\nInfluence: 空闲后的快门声音量正常,且不维持持续音频流。 --- src/src/videowidget.cpp | 66 +++++++++++++++++++++++++++++++++++++---- src/src/videowidget.h | 12 ++++++-- 2 files changed, 69 insertions(+), 9 deletions(-) diff --git a/src/src/videowidget.cpp b/src/src/videowidget.cpp index 308b5d7e..0e709d7e 100644 --- a/src/src/videowidget.cpp +++ b/src/src/videowidget.cpp @@ -84,7 +84,14 @@ videowidget::videowidget(DWidget *parent) m_pNormalItem->setZValue(0); m_bActive = false; //是否录制中 - m_takePicSound = new QSound(":/resource/Camera.wav"); + m_takePicSound = new QSoundEffect(this); + m_takePicSound->setSource(QUrl("qrc:/resource/Camera.wav")); + m_takePicSound->setLoopCount(1); + m_takePicSound->setVolume(1.0); + connect(m_takePicSound, &QSoundEffect::playingChanged, + this, &videowidget::onShutterSoundPlayingChanged); + connect(m_takePicSound, &QSoundEffect::statusChanged, + this, &videowidget::onShutterSoundStatusChanged); m_countTimer = new QTimer(this); m_flashTimer = new QTimer(this); m_recordingTimer = new QTimer(this); @@ -908,11 +915,60 @@ void videowidget::showRecTime() m_recordingTime->setText(strTime); } +void videowidget::startShutterSoundWarmup() +{ + if (m_shutterSoundWarming || m_takePicSound->status() != QSoundEffect::Ready) { + return; + } + + m_shutterSoundWarming = true; + m_takePicSound->setVolume(0.0); + m_takePicSound->play(); +} + +void videowidget::onShutterSoundPlayingChanged() +{ + if (!m_shutterSoundWarming) { + return; + } + + if (m_takePicSound->isPlaying()) { + m_takePicSound->stop(); + return; + } + + m_shutterSoundWarming = false; + m_takePicSound->setVolume(1.0); + if (m_shutterSoundPending && get_sound_of_takeing_photo()) { + m_shutterSoundPending = false; + QTimer::singleShot(0, this, [this] { + if (get_sound_of_takeing_photo()) { + m_takePicSound->play(); + } + }); + return; + } + m_shutterSoundPending = false; +} + +void videowidget::onShutterSoundStatusChanged() +{ + if (m_takePicSound->status() == QSoundEffect::Error) { + m_shutterSoundWarming = false; + m_shutterSoundPending = false; + m_takePicSound->setVolume(1.0); + } else if (m_shutterSoundPending) { + startShutterSoundWarmup(); + } +} + void videowidget::flash() { qDebug() << __func__; - if (get_sound_of_takeing_photo()) - m_takePicSound->play(); + if (get_sound_of_takeing_photo()) { + m_shutterSoundPending = true; + startShutterSoundWarmup(); + } #ifndef __mips__ if (!get_wayland_status()) { @@ -1845,6 +1901,7 @@ videowidget::~videowidget() delete m_flashLabel; m_flashLabel = nullptr; + m_takePicSound->stop(); delete m_takePicSound; m_takePicSound = nullptr; @@ -1854,9 +1911,6 @@ videowidget::~videowidget() delete m_pNormalScene; m_pNormalScene = nullptr; - delete m_takePicSound; - m_takePicSound = nullptr; - delete m_pGridLayout; m_pGridLayout = nullptr; diff --git a/src/src/videowidget.h b/src/src/videowidget.h index 317038cb..feb32a48 100644 --- a/src/src/videowidget.h +++ b/src/src/videowidget.h @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -388,16 +388,20 @@ private slots: * @brief onReachMaxDelayedFrames 达到视频帧最大延迟 */ void onReachMaxDelayedFrames(); - /** * @brief flash 闪光 */ void flash(); + void startShutterSoundWarmup(); + void onShutterSoundPlayingChanged(); + void onShutterSoundStatusChanged(); + /** * @brief slotresolutionchanged 分辨率改变槽函数 * @param 分辨率字符串(如:1920*1080) */ + void slotresolutionchanged(const QString &); /** @@ -529,7 +533,9 @@ private slots: DLabel *m_recordingTime; //录制时长 QString m_videoFormat; //录制视频格式 - QSound *m_takePicSound; //拍照声音 + QSoundEffect *m_takePicSound; //拍照声音 + bool m_shutterSoundWarming = false; + bool m_shutterSoundPending = false; QString m_savePicFolder; //图片文件夹路径 QString m_saveVdFolder; //视频文件夹路径 QTimer *m_countTimer; //倒计时定时器 From c9d987f5658483311a4475ceeef97337e6ca6980 Mon Sep 17 00:00:00 2001 From: zhanghongyuan Date: Tue, 18 Aug 2026 09:06:07 +0800 Subject: [PATCH 104/107] fix: sync resolution config after prepare_new_resolution (#372317) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sync my_config width/height with actual values after v4l2core_prepare_new_resolution to avoid config mismatch. 在 v4l2core_prepare_new_resolution 调用后同步 my_config 的 宽高配置,避免配置值与实际分辨率不一致。 Log: 同步分辨率配置 PMS: BUG-372317 Influence: 修复相机分辨率配置与实际设置不同步的问题,确保配置文件记录的分辨率与实际使用的分辨率一致。 --- src/src/LPF_V4L2.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/src/LPF_V4L2.c b/src/src/LPF_V4L2.c index 7a79ecdf..a6a180b4 100644 --- a/src/src/LPF_V4L2.c +++ b/src/src/LPF_V4L2.c @@ -220,6 +220,8 @@ int camInit(const char *devicename) my_config->height = get_my_height(); } else { v4l2core_prepare_new_resolution(my_vd, my_config->width, my_config->height); + my_config->width = get_my_width(); + my_config->height = get_my_height(); } ret = v4l2core_update_old_format(my_vd, my_config->width, my_config->height, v4l2core_get_requested_frame_format(my_vd)); } else { From 9adf064aa12e38c1f714634dc072c4d5b871e675 Mon Sep 17 00:00:00 2001 From: deepin-admin-bot Date: Wed, 19 Aug 2026 08:01:12 +0000 Subject: [PATCH 105/107] chore: Sync by https://github.com/linuxdeepin/.github/commit/a300f8523d4876677112edab6a0772f7ad112976 sync by github workflow Log: none Influence: none --- .github/workflows/call-update-changelog.yml | 53 +++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 .github/workflows/call-update-changelog.yml diff --git a/.github/workflows/call-update-changelog.yml b/.github/workflows/call-update-changelog.yml new file mode 100644 index 00000000..b76b9b3f --- /dev/null +++ b/.github/workflows/call-update-changelog.yml @@ -0,0 +1,53 @@ +name: Call update changelog + +on: + workflow_dispatch: + inputs: + version: + description: "Target version; leave empty to auto bump" + required: false + type: string + name: + description: "Maintainer name used in debian/changelog" + required: true + type: string + email: + description: "Maintainer email used in debian/changelog" + required: true + type: string + base_branch: + description: "Base branch to read and target" + required: false + default: master + type: string + distribution: + description: "Changelog distribution" + required: false + default: unstable + type: string + create_pr: + description: "Create a pull request after generating changelog" + required: false + default: true + type: boolean + +jobs: + update_changelog: + uses: linuxdeepin/.github/.github/workflows/update-changelog.yml@master + with: + version: ${{ inputs.version }} + name: ${{ inputs.name }} + email: ${{ inputs.email }} + base_branch: ${{ inputs.base_branch }} + distribution: ${{ inputs.distribution }} + create_pr: ${{ inputs.create_pr }} + secrets: inherit + + show_result: + runs-on: ubuntu-latest + needs: update_changelog + steps: + - name: Show update changelog result + run: | + echo "Version: ${{ needs.update_changelog.outputs.version }}" + echo "Pull Request URL: ${{ needs.update_changelog.outputs.pr_url }}" From e0bd925e04ab77aa3519d67c757eabf050f2452c Mon Sep 17 00:00:00 2001 From: zhanghongyuan Date: Mon, 17 Aug 2026 09:56:12 +0800 Subject: [PATCH 106/107] fix: use real MJPG decoded size instead of negotiated resolution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not preset decoder width/height before avcodec_open2(); let FFmpeg parse the real size from the JPEG SOF header. Copy decoded frames using the actual sw_frame/picture dimensions and realloc buffers when needed. Add jpeg_get_decoded_size() and trim yuv_frame to the real decoded size. 不在 avcodec_open2() 前预设解码器宽高,改由 FFmpeg 从 JPEG SOF 头解析 真实尺寸。按实际解码帧尺寸拷贝并在需要时 realloc 缓冲。新增 jpeg_get_decoded_size(),并在首帧后将 yuv_frame 收紧到真实解码尺寸。 Log: 修复MJPG解码尺寸与协商分辨率不一致导致的解码失败和画面错位 PMS: BUG-372317 Influence: 修复相机协商与实际分辨率不一致导致的解码失败、画面错位及内存浪费。 --- libcam/libcam_v4l2core/frame_decoder.c | 40 +++++++++++++++ libcam/libcam_v4l2core/gviewv4l2core.h | 1 + libcam/libcam_v4l2core/jpeg_decoder.c | 69 +++++++++++++++++++++++--- libcam/libcam_v4l2core/jpeg_decoder.h | 10 ++++ 4 files changed, 112 insertions(+), 8 deletions(-) diff --git a/libcam/libcam_v4l2core/frame_decoder.c b/libcam/libcam_v4l2core/frame_decoder.c index 63366fa8..a5845b13 100644 --- a/libcam/libcam_v4l2core/frame_decoder.c +++ b/libcam/libcam_v4l2core/frame_decoder.c @@ -134,6 +134,7 @@ int alloc_v4l2_frames(v4l2_dev_t *vd) /*frame queue*/ for(i=0; iframe_queue_size; ++i) { + vd->frame_queue[i].yuv_frame_max_size = (size_t) framesizeIn; vd->frame_queue[i].yuv_frame = calloc((size_t) framesizeIn, sizeof(uint8_t)); if(vd->frame_queue[i].yuv_frame == NULL) { @@ -346,6 +347,7 @@ void clean_v4l2_frames(v4l2_dev_t *vd) free(vd->frame_queue[i].yuv_frame); vd->frame_queue[i].yuv_frame = NULL; } + vd->frame_queue[i].yuv_frame_max_size = 0; } if(vd->h264_last_IDR) @@ -828,6 +830,44 @@ int decode_v4l2_frame(v4l2_dev_t *vd, v4l2_frame_buff_t *frame) //} if(verbosity > 3) fprintf(stderr, "V4L2_CORE: (jpeg decoder) decode frame of size %i\n", ret); + if (ret >= 0) + { + int real_w = 0; + int real_h = 0; + if (jpeg_get_decoded_size(&real_w, &real_h) == 0 && + real_w > 0 && real_h > 0 && + (real_w != frame->width || real_h != frame->height)) + { + if(verbosity > 0) + fprintf(stderr, "V4L2_CORE: (jpeg decoder) frame size %dx%d != negotiated %dx%d, using real size\n", + real_w, real_h, frame->width, frame->height); + frame->width = real_w; + frame->height = real_h; + } + + if (real_w > 0 && real_h > 0) + { + size_t need = (size_t)real_w * (size_t)real_h * 3 / 2; + if (need > 0 && need != frame->yuv_frame_max_size) + { + uint8_t *p = (uint8_t *)realloc(frame->yuv_frame, need); + if (p) + { + frame->yuv_frame = p; + frame->yuv_frame_max_size = need; + if(verbosity > 0) + fprintf(stderr, "V4L2_CORE: (jpeg decoder) yuv_frame trimmed %dx%d (%zu bytes)\n", + real_w, real_h, need); + } + else + { + if(verbosity > 0) + fprintf(stderr, "V4L2_CORE: (jpeg decoder) realloc failed for yuv_frame, keep old size\n"); + return E_ALLOC_ERR; + } + } + } + } ret = E_OK; break; diff --git a/libcam/libcam_v4l2core/gviewv4l2core.h b/libcam/libcam_v4l2core/gviewv4l2core.h index 7d8c7098..85a0640a 100644 --- a/libcam/libcam_v4l2core/gviewv4l2core.h +++ b/libcam/libcam_v4l2core/gviewv4l2core.h @@ -256,6 +256,7 @@ typedef struct _v4l2_frame_buff_t { uint64_t timestamp; // captured frame timestamp uint8_t *raw_frame; // pointer to raw frame + size_t yuv_frame_max_size; //maximum size for decoded yuv frame (bytes); MJPG is trimmed to real decoded size after 1st frame uint8_t *yuv_frame; // pointer to decoded yuv frame uint8_t *h264_frame; // pointer to regular or demultiplexed h264 frame uint8_t *tmp_buffer; //temporary buffer used in decoding diff --git a/libcam/libcam_v4l2core/jpeg_decoder.c b/libcam/libcam_v4l2core/jpeg_decoder.c index cf65efa6..e3c8b1cc 100644 --- a/libcam/libcam_v4l2core/jpeg_decoder.c +++ b/libcam/libcam_v4l2core/jpeg_decoder.c @@ -1430,8 +1430,6 @@ int jpeg_init_decoder(int width, int height) } codec_data->context->pix_fmt = AV_PIX_FMT_YUV422P; - codec_data->context->width = width; - codec_data->context->height = height; //jpeg_ctx->context->dsp_mask = (FF_MM_MMX | FF_MM_MMXEXT | FF_MM_SSE); // Initialize hardware device context (VA-API) @@ -1582,9 +1580,26 @@ int jpeg_decode(uint8_t *out_buf, uint8_t *in_buf, int size) printf(" - %s\n", getAvutil()->m_av_get_pix_fmt_name((enum AVPixelFormat)AV_PIX_FMT_YUV420P)); } #if LIBAVUTIL_VER_AT_LEAST(54,6) - getAvutil()->m_av_image_copy_to_buffer(jpeg_ctx->tmp_frame, jpeg_ctx->pic_size, - (const uint8_t * const*) sw_frame->data, sw_frame->linesize, - sw_frame->format, jpeg_ctx->width, jpeg_ctx->height, 1); + { + int dec_w = sw_frame->width; + int dec_h = sw_frame->height; + int need = getAvutil()->m_av_image_get_buffer_size(sw_frame->format, dec_w, dec_h, 1); + if (need > 0 && (size_t)need > (size_t)jpeg_ctx->pic_size) { + uint8_t *p = realloc(jpeg_ctx->tmp_frame, (size_t)need); + if (!p) { + fprintf(stderr, "V4L2_CORE: (jpeg decoder) realloc failed for tmp_frame\n"); + getAvutil()->m_av_frame_free(&sw_frame); + return -1; + } + jpeg_ctx->tmp_frame = p; + jpeg_ctx->pic_size = need; + } + jpeg_ctx->width = dec_w; + jpeg_ctx->height = dec_h; + getAvutil()->m_av_image_copy_to_buffer(jpeg_ctx->tmp_frame, jpeg_ctx->pic_size, + (const uint8_t * const*) sw_frame->data, sw_frame->linesize, + sw_frame->format, dec_w, dec_h, 1); + } if (sw_frame->format == AV_PIX_FMT_NV12) { nv12_to_yu12(out_buf, jpeg_ctx->tmp_frame, jpeg_ctx->width, jpeg_ctx->height); getAvutil()->m_av_frame_free(&sw_frame); @@ -1609,9 +1624,26 @@ int jpeg_decode(uint8_t *out_buf, uint8_t *in_buf, int size) } decodeCount++; } - getAvutil()->m_av_image_copy_to_buffer(jpeg_ctx->tmp_frame, jpeg_ctx->pic_size, - (const uint8_t * const*) codec_data->picture->data, codec_data->picture->linesize, - codec_data->context->pix_fmt, jpeg_ctx->width, jpeg_ctx->height, 1); + { + int dec_w = codec_data->picture->width; + int dec_h = codec_data->picture->height; + enum AVPixelFormat dec_fmt = codec_data->picture->format; + int need = getAvutil()->m_av_image_get_buffer_size(dec_fmt, dec_w, dec_h, 1); + if (need > 0 && (size_t)need > (size_t)jpeg_ctx->pic_size) { + uint8_t *p = realloc(jpeg_ctx->tmp_frame, (size_t)need); + if (!p) { + fprintf(stderr, "V4L2_CORE: (jpeg decoder) realloc failed for tmp_frame\n"); + return -1; + } + jpeg_ctx->tmp_frame = p; + jpeg_ctx->pic_size = need; + } + jpeg_ctx->width = dec_w; + jpeg_ctx->height = dec_h; + getAvutil()->m_av_image_copy_to_buffer(jpeg_ctx->tmp_frame, jpeg_ctx->pic_size, + (const uint8_t * const*) codec_data->picture->data, codec_data->picture->linesize, + dec_fmt, dec_w, dec_h, 1); + } #else avpicture_layout((AVPicture *) codec_data->picture, codec_data->dec_ctx->pix_fmt, jpeg_ctx->width, jpeg_ctx->height, jpeg_ctx->tmp_frame, jpeg_ctx->pic_size); @@ -1640,6 +1672,27 @@ int jpeg_decode(uint8_t *out_buf, uint8_t *in_buf, int size) } +/* + * get real (decoded) frame size + * args: + * out_w - pointer to receive real decoded width (may be NULL) + * out_h - pointer to receive real decoded height (may be NULL) + * + * asserts: + * none + * + * returns: 0 on success (valid size available); negative if not initialized + * or not decoded yet + */ +int jpeg_get_decoded_size(int *out_w, int *out_h) +{ + if (jpeg_ctx == NULL || jpeg_ctx->width <= 0 || jpeg_ctx->height <= 0) + return -1; + if (out_w) *out_w = jpeg_ctx->width; + if (out_h) *out_h = jpeg_ctx->height; + return 0; +} + /* * close (m)jpeg decoder context * args: diff --git a/libcam/libcam_v4l2core/jpeg_decoder.h b/libcam/libcam_v4l2core/jpeg_decoder.h index f3fa8102..f9aa7ced 100644 --- a/libcam/libcam_v4l2core/jpeg_decoder.h +++ b/libcam/libcam_v4l2core/jpeg_decoder.h @@ -75,6 +75,16 @@ int jpeg_init_decoder(int width, int height); */ int jpeg_decode(uint8_t *out_buf, uint8_t *in_buf, int size); +/* + * get real (decoded) frame size after jpeg_decode() + * args: + * out_w - pointer to receive real decoded width (may be NULL) + * out_h - pointer to receive real decoded height (may be NULL) + * + * returns: 0 - OK; negative - not initialized or not decoded yet + */ +int jpeg_get_decoded_size(int *out_w, int *out_h); + /* * close (m)jpeg decoder context * args: From 7e02f7fc8d950e976c520bb2860eaadf17658bd7 Mon Sep 17 00:00:00 2001 From: zhangjiarui Date: Fri, 30 Oct 2026 01:00:49 +0800 Subject: [PATCH 107/107] fix: prevent crash when QCamera initialization fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Root cause: startCamera() constructs QCameraInfo from a QCamera object immediately after creation without checking error state; when UVC control query times out (GET_MAX returns -110), the QCamera internal state is invalid and QCameraInfo dereferences a null pointer, causing segfault at offset 8 2. Fix: add QCamera::error() check after construction, clean up and return early on error; connect QCamera::error signal to emit cameraCannotUsed; only construct QCameraInfo when QCamera is valid; apply same error() guard in restartCamera() before QCameraInfo construction 3. Impact: camera initialization failures are handled gracefully instead of crashing; no behavior change for valid camera devices fix: 修复QCamera初始化失败时的段错误问题 1. 根因:startCamera()在new QCamera()后未检查错误状态即构造 QCameraInfo,当UVC控制查询超时(GET_MAX返回-110)时QCamera内部 状态无效,QCameraInfo解引用空指针导致段错误 2. 方案:构造后增加error()检查,错误时清理并提前返回;连接 QCamera::error信号以发出cameraCannotUsed;仅在QCamera有效时 构造QCameraInfo;restartCamera()中同类QCameraInfo构造同步 增加error()检查 3. 影响:相机初始化失败时优雅处理而非崩溃,对有效设备无行为变化 PMS: BUG-236931 --- src/src/camera.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/src/camera.cpp b/src/src/camera.cpp index 5883e717..0cfec5a4 100755 --- a/src/src/camera.cpp +++ b/src/src/camera.cpp @@ -135,7 +135,7 @@ void Camera::restartCamera() { if (!m_camera || m_camera->status() == QCamera::UnloadedStatus) { QList availableCams = QCameraInfo::availableCameras(); - if ((availableCams.isEmpty() || (m_camera && availableCams.indexOf(QCameraInfo(*m_camera)) != -1)) + if ((availableCams.isEmpty() || (m_camera && m_camera->error() == QCamera::NoError && availableCams.indexOf(QCameraInfo(*m_camera)) != -1)) && !m_cameraDevList.isEmpty()) { emit cameraCannotUsed(); return; @@ -242,10 +242,18 @@ void Camera::startCamera(const QString &devName) stopCamera(); m_camera = new QCamera(devName.toStdString().c_str()); - QCameraInfo cameraInfo(*m_camera); - m_curDevName = devName; connect(m_camera, SIGNAL(statusChanged(QCamera::Status)), this, SLOT(onCameraStatusChanged(QCamera::Status))); + connect(m_camera, SIGNAL(error(QCamera::Error)), this, SIGNAL(cameraCannotUsed())); + + if (m_camera->error() != QCamera::NoError) { + stopCamera(); + emit cameraCannotUsed(); + return; + } + + QCameraInfo cameraInfo(*m_camera); + m_curDevName = devName; m_imageCapture = new QCameraImageCapture(m_camera); m_mediaRecoder = new QMediaRecorder(m_camera);