From d5b079dac2663cb983ae1fb38549a551055b8759 Mon Sep 17 00:00:00 2001 From: for13to1 Date: Sat, 25 Jul 2026 09:41:35 +0800 Subject: [PATCH 1/2] fix(playlist): guard YUV handler casts for compressed video --- .../src/playlistitem/playlistItemCompressedVideo.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/YUViewLib/src/playlistitem/playlistItemCompressedVideo.cpp b/YUViewLib/src/playlistitem/playlistItemCompressedVideo.cpp index 30dd3dfc5..f9cdbdbed 100644 --- a/YUViewLib/src/playlistitem/playlistItemCompressedVideo.cpp +++ b/YUViewLib/src/playlistitem/playlistItemCompressedVideo.cpp @@ -1307,8 +1307,10 @@ void playlistItemCompressedVideo::displaySignalComboBoxChanged(int idx) // A different display signal was chosen. Invalidate the cache and signal that we will need a // redraw. auto yuvVideo = dynamic_cast(this->video.get()); - yuvVideo->showPixelValuesAsDiff = this->loadingDecoder->isSignalDifference(idx); - yuvVideo->invalidateAllBuffers(); + if (yuvVideo) + yuvVideo->showPixelValuesAsDiff = this->loadingDecoder->isSignalDifference(idx); + if (this->video) + this->video->invalidateAllBuffers(); emit SignalItemChanged(true, RECACHE_CLEAR); } @@ -1326,9 +1328,10 @@ void playlistItemCompressedVideo::decoderComboxBoxChanged(int idx) // A different display signal was chosen. Invalidate the cache and signal that we will need a // redraw. auto yuvVideo = dynamic_cast(this->video.get()); - if (this->loadingDecoder) + if (yuvVideo && this->loadingDecoder) yuvVideo->showPixelValuesAsDiff = this->loadingDecoder->isSignalDifference(idx); - yuvVideo->invalidateAllBuffers(); + if (this->video) + this->video->invalidateAllBuffers(); // Reset the decoded frame indices so that decoding of the current frame is triggered this->currentFrameIdx[0] = -1; From 5cc98191a52cca0173bacf8df398e3878dad0364 Mon Sep 17 00:00:00 2001 From: Christian Feldmann Date: Fri, 7 Aug 2026 11:23:19 +0200 Subject: [PATCH 2/2] Wen through the other dynamic casts and improved the code a bit. --- .../playlistItemCompressedVideo.cpp | 2 +- .../src/playlistitem/playlistItemOverlay.cpp | 35 ++++----- .../src/playlistitem/playlistItemOverlay.h | 2 +- YUViewLib/src/ui/Mainwindow.cpp | 19 ++--- .../src/ui/widgets/PlaylistTreeWidget.cpp | 77 ++++++++----------- YUViewLib/src/video/caching/VideoCache.cpp | 17 ++-- YUViewLib/src/video/rgb/videoHandlerRGB.cpp | 8 +- YUViewLib/src/video/videoHandler.cpp | 4 +- .../src/video/videoHandlerDifference.cpp | 4 +- YUViewLib/src/video/yuv/videoHandlerYUV.cpp | 10 +-- 10 files changed, 80 insertions(+), 98 deletions(-) diff --git a/YUViewLib/src/playlistitem/playlistItemCompressedVideo.cpp b/YUViewLib/src/playlistitem/playlistItemCompressedVideo.cpp index f9cdbdbed..913a2d197 100644 --- a/YUViewLib/src/playlistitem/playlistItemCompressedVideo.cpp +++ b/YUViewLib/src/playlistitem/playlistItemCompressedVideo.cpp @@ -698,7 +698,7 @@ void playlistItemCompressedVideo::loadRawData(int frameIdx, bool caching) auto ffmpegDec = (caching ? dynamic_cast(this->cachingDecoder.get()) : dynamic_cast(this->loadingDecoder.get())); - if (!ffmpegDec->pushAVPacket(pkt)) + if (!ffmpegDec || !ffmpegDec->pushAVPacket(pkt)) { if (ffmpegDec->state() != decoder::DecoderState::RetrieveFrames) // The decoder did not switch to decoding frame mode. Error. diff --git a/YUViewLib/src/playlistitem/playlistItemOverlay.cpp b/YUViewLib/src/playlistitem/playlistItemOverlay.cpp index 271948c22..c03dfc37b 100644 --- a/YUViewLib/src/playlistitem/playlistItemOverlay.cpp +++ b/YUViewLib/src/playlistitem/playlistItemOverlay.cpp @@ -575,7 +575,7 @@ void playlistItemOverlay::slotControlChanged() this->arangementMode = this->ui.comboBoxArangementMode->currentIndex(); for (int i = 1; i < this->childCount(); i++) { - auto p = this->getCutomPositionOfItem(i); + auto p = this->getCustomPositionOfItem(i); this->customPositions[i - 1] = p; } @@ -759,36 +759,30 @@ void playlistItemOverlay::updateCustomPositionGrid() } } -QPoint playlistItemOverlay::getCutomPositionOfItem(int itemIdx) const +QPoint playlistItemOverlay::getCustomPositionOfItem(int itemIdx) const { assert(itemIdx >= 1); - if (this->customPositionGrid == nullptr) - return {}; - if (this->customPositionGrid->columnCount() < 3) + if (!this->customPositionGrid || this->customPositionGrid->columnCount() < 3) return {}; int gridRowIdx = itemIdx - 1; if (gridRowIdx >= this->customPositionGrid->rowCount()) - return QPoint(); + return {}; // There should be 2 spin boxes in this row - auto layoutItemX = this->customPositionGrid->itemAtPosition(gridRowIdx, 1); - auto layoutWidgetX = dynamic_cast(layoutItemX); - if (layoutWidgetX == nullptr) + auto layoutWidgetX = dynamic_cast(this->customPositionGrid->itemAtPosition(gridRowIdx, 1)); + if (!layoutWidgetX) return {}; - auto widgetX = dynamic_cast(layoutWidgetX->widget()); - auto spinBoxX = dynamic_cast(widgetX); - if (spinBoxX == nullptr) + auto spinBoxX = dynamic_cast(layoutWidgetX->widget()); + if (!spinBoxX) return {}; - auto layoutItemY = this->customPositionGrid->itemAtPosition(gridRowIdx, 2); - auto layoutWidgetY = dynamic_cast(layoutItemY); - if (layoutWidgetY == nullptr) + auto layoutWidgetY = dynamic_cast(this->customPositionGrid->itemAtPosition(gridRowIdx, 2)); + if (!layoutWidgetY) return {}; - auto widgetY = dynamic_cast(layoutWidgetY->widget()); - auto spinBoxY = dynamic_cast(widgetY); - if (spinBoxY == nullptr) + auto spinBoxY = dynamic_cast(layoutWidgetY->widget()); + if (!spinBoxY) return {}; return QPoint(spinBoxX->value(), spinBoxY->value()); @@ -800,9 +794,8 @@ void playlistItemOverlay::guessBestLayout() bool statisticsPresent = false; for (int i = 0; i < this->childCount(); i++) { - auto childItem = this->getChildPlaylistItem(i); - auto childStas = dynamic_cast(childItem); - if (childStas) + auto childStats = dynamic_cast(this->getChildPlaylistItem(i)); + if (childStats) statisticsPresent = true; } diff --git a/YUViewLib/src/playlistitem/playlistItemOverlay.h b/YUViewLib/src/playlistitem/playlistItemOverlay.h index abdbc8ab6..9bd1115ed 100644 --- a/YUViewLib/src/playlistitem/playlistItemOverlay.h +++ b/YUViewLib/src/playlistitem/playlistItemOverlay.h @@ -109,7 +109,7 @@ class playlistItemOverlay : public playlistItemContainer QGridLayout *customPositionGrid{}; void updateCustomPositionGrid(); void clear(int startRow); - QPoint getCutomPositionOfItem(int itemIndex) const; + QPoint getCustomPositionOfItem(int itemIndex) const; int overlayMode{0}; int arangementMode{0}; diff --git a/YUViewLib/src/ui/Mainwindow.cpp b/YUViewLib/src/ui/Mainwindow.cpp index e0c6852b0..e20940931 100644 --- a/YUViewLib/src/ui/Mainwindow.cpp +++ b/YUViewLib/src/ui/Mainwindow.cpp @@ -227,12 +227,10 @@ MainWindow::MainWindow(bool useAlternativeSources, QWidget *parent) : QMainWindo QWidget *MainWindow::getMainWindow() { - QWidgetList l = QApplication::topLevelWidgets(); - for (QWidget *w : l) + for (const auto widget : QApplication::topLevelWidgets()) { - MainWindow *mw = dynamic_cast(w); - if (mw) - return mw; + if (const auto mainWindow = dynamic_cast(widget)) + return mainWindow; } return nullptr; } @@ -798,17 +796,16 @@ void MainWindow::updateSettings() // Set the right theme QSettings settings; QString themeName = settings.value("Theme", "Default").toString(); - QString themeFile = functions::getThemeFileName(themeName); + QString themeFileName = functions::getThemeFileName(themeName); QString styleSheet; - if (!themeFile.isEmpty()) + if (!themeFileName.isEmpty()) { // Get the qss text of the theme - QFile f(themeFile); - if (f.exists()) + QFile themeFile(themeFileName); + if (themeFile.exists() && themeFile.open(QFile::ReadOnly | QFile::Text)) { - f.open(QFile::ReadOnly | QFile::Text); - QTextStream ts(&f); + QTextStream ts(&themeFile); styleSheet = ts.readAll(); // Now replace the placeholder color values with the real values diff --git a/YUViewLib/src/ui/widgets/PlaylistTreeWidget.cpp b/YUViewLib/src/ui/widgets/PlaylistTreeWidget.cpp index 447a9e6da..1d14232be 100644 --- a/YUViewLib/src/ui/widgets/PlaylistTreeWidget.cpp +++ b/YUViewLib/src/ui/widgets/PlaylistTreeWidget.cpp @@ -170,18 +170,18 @@ PlaylistTreeWidget::~PlaylistTreeWidget() playlistItem *PlaylistTreeWidget::getDropTarget(const QPoint &pos) const { - auto pItem = dynamic_cast(this->itemAt(pos)); - if (pItem != nullptr) - { - // check if dropped on or below/above pItem - auto rc = this->visualItemRect(pItem); - auto rcNew = QRect(rc.left(), rc.top() + 2, rc.width(), rc.height() - 4); - if (!rcNew.contains(pos, true)) - // dropped next to pItem - pItem = nullptr; - } + auto item = dynamic_cast(this->itemAt(pos)); + if (!item) + return {}; - return pItem; + // check if dropped on or below/above pItem + auto rc = this->visualItemRect(item); + auto rcNew = QRect(rc.left(), rc.top() + 2, rc.width(), rc.height() - 4); + if (!rcNew.contains(pos, true)) + // dropped next to item + return nullptr; + + return item; } void PlaylistTreeWidget::dragMoveEvent(QDragMoveEvent *event) @@ -244,19 +244,14 @@ void PlaylistTreeWidget::dropEvent(QDropEvent *event) } else { - // get the list of the items that are about to be dragged - QList dragItems = selectedItems(); - - // Actually move all the items QTreeWidget::dropEvent(event); // Query the selected items that were dropped and add a new bufferStatusWidget // for each of them. The old bufferStatusWidget will be deleted by the tree widget. QList toRows; - for (QTreeWidgetItem *item : dragItems) + for (auto item : selectedItems()) { - playlistItem *plItem = dynamic_cast(item); - if (plItem) + if (const auto plItem = dynamic_cast(item)) setItemWidget(item, 1, new bufferStatusWidget(plItem, this)); } @@ -283,9 +278,9 @@ void PlaylistTreeWidget::updateAllContainterItems() { for (int i = 0; i < topLevelItemCount(); i++) { - QTreeWidgetItem *item = topLevelItem(i); - playlistItemContainer *containerItem = dynamic_cast(item); - if (containerItem != nullptr) + auto item = topLevelItem(i); + auto containerItem = dynamic_cast(item); + if (containerItem) containerItem->updateChildItems(); } } @@ -311,8 +306,8 @@ void PlaylistTreeWidget::addDifferenceItem() QVector selection; for (int i = 0; i < this->selectedItems().count(); i++) { - auto item = dynamic_cast(this->selectedItems()[i]); - if (item->canBeUsedInProcessing()) + auto plItem = dynamic_cast(this->selectedItems()[i]); + if (plItem && plItem->canBeUsedInProcessing()) selection.append(this->selectedItems()[i]); } @@ -399,8 +394,7 @@ void PlaylistTreeWidget::addOverlayItem() QList selection; for (int i = 0; i < selectedItems().count(); i++) { - playlistItem *item = dynamic_cast(selectedItems()[i]); - if (item) + if (const auto plItem = dynamic_cast(selectedItems()[i])) selection.append(selectedItems()[i]); } @@ -510,8 +504,8 @@ void PlaylistTreeWidget::slotItemChanged(bool redraw, recacheIndicator recache) if (recache != RECACHE_NONE) { - playlistItem *senderItem = dynamic_cast(sender); - emit signalItemRecache(senderItem, recache); + auto senderItem = dynamic_cast(sender); + emit signalItemRecache(senderItem, recache); } } @@ -665,7 +659,7 @@ void PlaylistTreeWidget::deletePlaylistItems(bool deleteAllItems) QList unfoldedItemList; for (playlistItem *plItem : itemList) { - playlistItemContainer *containerItem = dynamic_cast(plItem); + auto containerItem = dynamic_cast(plItem); if (containerItem) { // Add all children (if not yet in the list) @@ -692,8 +686,7 @@ void PlaylistTreeWidget::deletePlaylistItems(bool deleteAllItems) // If the item is in a container item we have to inform the container that the item will be // deleted. - playlistItem *parentItem = plItem->parentPlaylistItem(); - if (parentItem) + if (auto parentItem = plItem->parentPlaylistItem()) parentItem->itemAboutToBeDeleted(plItem); else { @@ -818,10 +811,8 @@ QString PlaylistTreeWidget::getPlaylistString(QDir dirName) // Append all the playlist items to the output for (int i = 0; i < topLevelItemCount(); ++i) { - QTreeWidgetItem *item = topLevelItem(i); - playlistItem *plItem = dynamic_cast(item); - - plItem->savePlaylist(plist, dirName); + if (auto plItm = dynamic_cast(topLevelItem(i))) + plItm->savePlaylist(plist, dirName); } // Append the view states @@ -852,7 +843,8 @@ void PlaylistTreeWidget::savePlaylistToFile() // Write the XML structure to file QFile file(filename); - file.open(QIODevice::WriteOnly | QIODevice::Text); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) + return; QTextStream outStream(&file); outStream << getPlaylistString(dirName); file.close(); @@ -977,9 +969,7 @@ void PlaylistTreeWidget::checkAndUpdateItems() for (int i = 0; i < topLevelItemCount(); ++i) { auto plItem = dynamic_cast(this->topLevelItem(i)); - - // Check (and reset) the flag if the source was changed. - if (plItem->isSourceChanged()) + if (plItem && plItem->isSourceChanged()) changedItems.push_back(plItem); } @@ -1012,8 +1002,8 @@ void PlaylistTreeWidget::updateSettings() { for (int i = 0; i < this->topLevelItemCount(); ++i) { - auto plItem = dynamic_cast(this->topLevelItem(i)); - plItem->updateSettings(); + if (auto plItem = dynamic_cast(this->topLevelItem(i))) + plItem->updateSettings(); } } @@ -1129,15 +1119,12 @@ QList PlaylistTreeWidget::getAllPlaylistItems(const bool topLeve QList returnList; for (int i = 0; i < topLevelItemCount(); i++) { - QTreeWidgetItem *item = topLevelItem(i); - playlistItem *plItem = dynamic_cast(item); - if (plItem != nullptr) + if (auto plItem = dynamic_cast(topLevelItem(i))) { returnList.append(plItem); if (!topLevelOnly) { - playlistItemContainer *container = dynamic_cast(plItem); - if (container) + if (auto container = dynamic_cast(plItem)) returnList.append(container->getAllChildPlaylistItems()); } } diff --git a/YUViewLib/src/video/caching/VideoCache.cpp b/YUViewLib/src/video/caching/VideoCache.cpp index a1240e17c..6d84cbe50 100644 --- a/YUViewLib/src/video/caching/VideoCache.cpp +++ b/YUViewLib/src/video/caching/VideoCache.cpp @@ -285,9 +285,12 @@ void VideoCache::loadFrame(playlistItem *item, int frameIndex, int loadingSlot) void VideoCache::interactiveLoaderFinished() { // Get the thread that caused this call - QObject *sender = QObject::sender(); - LoadingWorker *worker = dynamic_cast(sender); - int threadID = (interactiveThread[0]->worker() == worker) ? 0 : 1; + auto sender = QObject::sender(); + auto worker = dynamic_cast(sender); + if (!worker) + return; + + auto threadID = (interactiveThread[0]->worker() == worker) ? 0 : 1; assert(worker == interactiveThread[0]->worker() || worker == interactiveThread[1]->worker()); // Check the list of items that are scheduled for deletion. Because a loading thread finished, @@ -879,9 +882,11 @@ void VideoCache::watchItemForCachingFinished(playlistItem *item) void VideoCache::threadCachingFinished() { // Get the thread that caused this call - QObject *sender = QObject::sender(); - LoadingWorker *worker = dynamic_cast(sender); - Q_ASSERT_X(worker->isWorking(), Q_FUNC_INFO, "The worker that just finished was not working?"); + auto sender = QObject::sender(); + auto worker = dynamic_cast(sender); + Q_ASSERT_X( + worker && worker->isWorking(), Q_FUNC_INFO, "The worker that just finished was not working?"); + worker->setWorking(false); DEBUG_CACHING_DETAIL( "VideoCache::threadCachingFinished - state %d - worker %p", workersState, worker); diff --git a/YUViewLib/src/video/rgb/videoHandlerRGB.cpp b/YUViewLib/src/video/rgb/videoHandlerRGB.cpp index b72b156e7..88fd9021e 100644 --- a/YUViewLib/src/video/rgb/videoHandlerRGB.cpp +++ b/YUViewLib/src/video/rgb/videoHandlerRGB.cpp @@ -158,7 +158,7 @@ QStringPairList videoHandlerRGB::getPixelValues(const QPoint &pixelP if (item2 != nullptr) { auto rgbItem2 = dynamic_cast(item2); - if (rgbItem2 == nullptr) + if (!rgbItem2) // The second item is not a videoHandlerRGB. Get the values from the FrameHandler. return FrameHandler::getPixelValues(pixelPos, frameIdx, item2, frameIdx1); @@ -772,7 +772,7 @@ void videoHandlerRGB::drawPixelValues(QPainter *painter, // Get the other RGB item (if any) auto rgbItem2 = dynamic_cast(item2); - if (item2 != nullptr && rgbItem2 == nullptr) + if (item2 && !rgbItem2) { // The second item is not a videoHandlerRGB item FrameHandler::drawPixelValues( @@ -869,8 +869,8 @@ QImage videoHandlerRGB::calculateDifference(FrameHandler *item2, const int amplificationFactor, const bool markDifference) { - videoHandlerRGB *rgbItem2 = dynamic_cast(item2); - if (rgbItem2 == nullptr) + auto rgbItem2 = dynamic_cast(item2); + if (!rgbItem2) // The given item is not a RGB source. We cannot compare raw RGB values to non raw RGB values. // Call the base class comparison function to compare the items using the RGB 888 values. return videoHandler::calculateDifference( diff --git a/YUViewLib/src/video/videoHandler.cpp b/YUViewLib/src/video/videoHandler.cpp index 611e5c474..339b12874 100644 --- a/YUViewLib/src/video/videoHandler.cpp +++ b/YUViewLib/src/video/videoHandler.cpp @@ -229,8 +229,8 @@ QImage videoHandler::calculateDifference(FrameHandler *item2, const bool markDifference) { // Try to cast item2 to a videoHandler - videoHandler *videoItem2 = dynamic_cast(item2); - if (videoItem2 == nullptr) + auto videoItem2 = dynamic_cast(item2); + if (!videoItem2) { // The item2 is not a videoItem but this one is. if (currentImageIndex != frameIdxItem0) diff --git a/YUViewLib/src/video/videoHandlerDifference.cpp b/YUViewLib/src/video/videoHandlerDifference.cpp index 6cb11c55e..de3c3b44e 100644 --- a/YUViewLib/src/video/videoHandlerDifference.cpp +++ b/YUViewLib/src/video/videoHandlerDifference.cpp @@ -119,7 +119,7 @@ void videoHandlerDifference::loadFrameDifference(int frameIndex, bool) // make sure that the right frame is loaded for the video item. const auto video0 = dynamic_cast(inputVideo[0].data()); const auto video1 = dynamic_cast(inputVideo[1].data()); - if (video0 == nullptr && video1 != nullptr && video1->getCurrentImageIndex() != frameIndex) + if (!video0 && video1 && video1->getCurrentImageIndex() != frameIndex) video1->loadFrame(frameIndex); // Calculate the difference @@ -278,7 +278,7 @@ void videoHandlerDifference::reportFirstDifferencePosition(QList &info int firstX, firstY, partIndex = 0; auto videoYUV0 = dynamic_cast(inputVideo[0].data()); - if (videoYUV0 != NULL && videoYUV0->isDiffReady()) + if (videoYUV0 && videoYUV0->isDiffReady()) { // find first difference using YUV instead of QImage. The latter does not work for 10bit // videos and very small differences, since it only supports 8bit diff --git a/YUViewLib/src/video/yuv/videoHandlerYUV.cpp b/YUViewLib/src/video/yuv/videoHandlerYUV.cpp index 013affa53..b08b08e74 100644 --- a/YUViewLib/src/video/yuv/videoHandlerYUV.cpp +++ b/YUViewLib/src/video/yuv/videoHandlerYUV.cpp @@ -2704,7 +2704,7 @@ QStringPairList videoHandlerYUV::getPixelValues(const QPoint &pixelP if (item2 != nullptr) { auto yuvItem2 = dynamic_cast(item2); - if (yuvItem2 == nullptr) + if (!yuvItem2) // The given item is not a YUV source. We cannot compare YUV values to non YUV values. // Call the base class comparison function to compare the items using the RGB values. return FrameHandler::getPixelValues(pixelPos, frameIdx, item2, frameIdx1); @@ -2821,8 +2821,8 @@ void videoHandlerYUV::drawPixelValues(QPainter *painter, const int frameIdxItem1) { // Get the other YUV item (if any) - auto yuvItem2 = (item2 == nullptr) ? nullptr : dynamic_cast(item2); - if (item2 != nullptr && yuvItem2 == nullptr) + auto yuvItem2 = dynamic_cast(item2); + if (item2 && !yuvItem2) { // The other item is not a yuv item FrameHandler::drawPixelValues( @@ -3537,8 +3537,8 @@ QImage videoHandlerYUV::calculateDifference(FrameHandler *item2, { this->diffReady = false; - videoHandlerYUV *yuvItem2 = dynamic_cast(item2); - if (yuvItem2 == nullptr) + auto yuvItem2 = dynamic_cast(item2); + if (!yuvItem2) // The given item is not a YUV source. We cannot compare YUV values to non YUV values. // Call the base class comparison function to compare the items using the RGB values. return videoHandler::calculateDifference(