--- a +++ b/mainwindow.cpp @@ -0,0 +1,860 @@ +/* + Copyright (C) 2011 Arnaud Champenois arthelion92@gmail.com + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ +#include "mainwindow.h" +#include "ui_mainwindow.h" +#include <QFileDialog> +#include <QTime> +#include <QErrorMessage> +#include <QMessageBox> +#include <QSettings> +#include <sstream> +#include <math.h> +#include <QDropEvent> +#include <QUrl> + +#include "videosegment.h" +#include "kernel.hpp" +#include "filecopier.h" +#include "launchprocess.h" +#include "videosegmentlistitem.h" +#include "utils.h" +#include "about.h" + +const double theMinStdDev = 5; + +#ifdef DEBUG +#include <stdio.h> +#include <stdlib.h> + +static FILE*theFilePt = NULL; +void print_log(const QString&aString) +{ + if(theFilePt == NULL) + { unlink("debug.txt"); theFilePt = fopen("debug.txt","a"); } + + fprintf(theFilePt,"%s\n",aString.toStdString().c_str()); +} +#endif + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow) +{ + ui->setupUi(this); + mDecoderPt = NULL; + mInfoLabel = new QLabel(); + mPosLabel = new QLabel(); + mAspectLabel = new QLabel(); + mCorrLabel = new QLabel(); + mSelLabel = new QLabel(); + ui->statusBar->addWidget(mInfoLabel); + ui->statusBar->addWidget(mPosLabel); + ui->statusBar->addWidget(mAspectLabel); + ui->statusBar->addWidget(mCorrLabel); + ui->statusBar->addWidget(mSelLabel); + ui->VideoFrame->SetMainWindow(this); + mInSlider = false; + SetClosedState(); + + mInfoLabel->setText(QString("VidePub ")+QString(VIDEPUB_VERSION)); + mMarginBefore = mMarginAfter = 10000; + mLastCorrelation = -1; + ReadSettings(); +} + +MainWindow::~MainWindow() +{ + Close(); + SaveSettings(); + delete ui; +#ifdef DEBUG + if(theFilePt) fclose(theFilePt); +#endif +} + +void MainWindow::SetClosedState() +{ + ui->actionDetect_Segments->setEnabled(false); + ui->TimeSlider->setEnabled(false); + ui->PrevButton->setEnabled(false); + ui->NextButton->setEnabled(false); + ui->FastPrevButton->setEnabled(false); + ui->FastNextButton->setEnabled(false); + ui->AddBt->setEnabled(false); + ui->NextLogoOn->setEnabled(false); + ui->NextLogoOff->setEnabled(false); + + SetSaveState(false); +} + +void MainWindow::SetOpenedState() +{ + ui->actionDetect_Segments->setEnabled(false); + ui->TimeSlider->setEnabled(true); + ui->PrevButton->setEnabled(true); + ui->NextButton->setEnabled(true); + ui->FastPrevButton->setEnabled(true); + ui->FastNextButton->setEnabled(true); + ui->PrevButton->setEnabled(true); + ui->AddBt->setEnabled(true); + ui->NextLogoOn->setEnabled(false); + ui->NextLogoOff->setEnabled(false); + + SetSaveState(false); +} + +void MainWindow::SetLogoState() +{ + ui->actionDetect_Segments->setEnabled(true); + ui->TimeSlider->setEnabled(true); + ui->PrevButton->setEnabled(true); + ui->NextButton->setEnabled(true); + ui->FastPrevButton->setEnabled(true); + ui->FastNextButton->setEnabled(true); + ui->NextLogoOn->setEnabled(true); + ui->NextLogoOff->setEnabled(true); + + SetSaveState(false); +} + +void MainWindow::SetDetectedState() +{ + SetSaveState(false); + ui->actionDetect_Segments->setEnabled(true); + ui->TimeSlider->setEnabled(true); + ui->PrevButton->setEnabled(true); + ui->NextButton->setEnabled(true); + ui->FastPrevButton->setEnabled(true); + ui->FastNextButton->setEnabled(true); + ui->NextLogoOn->setEnabled(true); + ui->NextLogoOff->setEnabled(true); +} + +void MainWindow::SetSaveState(bool aSelected) +{ + ui->GotoBeginBt->setEnabled(aSelected); + ui->GoToEndBt->setEnabled(aSelected); + ui->SetBeginBt->setEnabled(aSelected); + ui->SetEndBt->setEnabled(aSelected); + ui->DeleteBt->setEnabled(aSelected); + ui->MergeBt->setEnabled(aSelected); + ui->actionSave_selection->setEnabled(aSelected); +} + + +void MainWindow::Error(QString aMessage) +{ + QMessageBox::critical(this,tr("Error"),aMessage,QMessageBox::Ok, + QMessageBox::NoButton); +} + + +void MainWindow::Close() +{ + if(mDecoderPt) + { + delete mDecoderPt; mDecoderPt = NULL; + mPosLabel->setText(""); + mPosLabel->setText(""); + ui->RegionList->clear(); + mLogo = QImage(); + SetClosedState(); + mLastCorrelation = -1; + } +} + +void MainWindow::PrintPosition() +{ + int64_t aPos = mDecoderPt->GetMSPosition(); + QString aString = tr("Pos :"); + aString += std::MsToString(aPos); + mPosLabel->setText(aString); + mInSlider = true; + ui->TimeSlider->setValue(aPos/1000); + int64_t aNum,aDen; + mDecoderPt->GetAspectRatio(aNum,aDen); + aString = QString("%1/%2").arg(aNum).arg(aDen); + mAspectLabel->setText(aString); + + if(HasLogo()) + { + const QImage & anImage = GetCurrentImage(); + if(!anImage.isNull()) + { + mLastCorrelation = ComputeCorrelation(anImage); + aString = tr("Score : %1").arg(mLastCorrelation,4,'g',2); + mCorrLabel->setText(aString); + } + } + + mInSlider = false; +} + +void MainWindow::UseFileInfo() +{ + QString aString = tr("Length :"); + aString += std::MsToString(mFileInfo.mLength); + mInfoLabel->setText(aString); + aString = tr("Pos :"); + aString += "00:00:00"; + mPosLabel->setText(aString); + aString = QString("%1/%2").arg(mFileInfo.mAspectRatio[0]).arg(mFileInfo.mAspectRatio[1]); + mAspectLabel->setText(aString); + ui->TimeSlider->setMaximum(mFileInfo.mLength/1000); + ui->VideoFrame->resize(mFileInfo.mWidth,mFileInfo.mHeight); +} + +bool MainWindow::Open(const QString&aFileName) +{ + if(aFileName.isEmpty()) return false; + + Close(); + mDecoderPt = new FFMPEGDecoder(); + if(!mDecoderPt->Open(aFileName)) + { Close(); return false; } + + mInputFileName = aFileName; + + if(mDecoderPt->GetFileInfo(mFileInfo)) + UseFileInfo(); + + ShowNextFrame(); + SetOpenedState(); + + return true; +} + +static inline double sqr(double a) { return a*a; } + +void MainWindow::ComputeStats(const QImage& anImage, + const QRect& anArea, + double*aMeanArray, + double*aStdDevArray) +{ + double aSum[3] = { 0,0,0 }; + double aSqrSum[3] = { 0,0,0 }; + double aCount = anArea.height()*anArea.width(); + + for(int y=anArea.top(),t=0;t<anArea.height();y++,t++) + { + const uchar*aBits = anImage.scanLine(y); + for(int x=anArea.left(),u=0;u<anArea.width();x++,u++) + { + for(int i=0;i<3;i++) + { + aSum[i] += aBits[3*x+i]; + aSqrSum[i] += sqr(aBits[3*x+i]); + } + } + } + + for(int i=0;i<3;i++) + { + aMeanArray[i] = aSum[i]/aCount; + aStdDevArray[i] = sqrt(aSqrSum[i]/aCount-sqr(aMeanArray[i])); + } + +} + +double MainWindow::ComputeCorrelation(const QImage &anImageIn) +{ + double aMax = -1; + QRect aRect = mLogoRect; + const int MaxOffset = 2; // Bagottement sauce TF1 + + // On cherche un peu au dessus et en dessous + for(int anYOffset = -MaxOffset;anYOffset<=MaxOffset;anYOffset++) + { + // Et un peu sur les bords aussi + for(int anXOffset = -MaxOffset;anXOffset<=MaxOffset;anXOffset++) + { + aRect.moveTo(mLogoRect.left()+anXOffset,mLogoRect.top()+anYOffset); + + if(aRect.intersect(anImageIn.rect()) != aRect) + continue; + + double anImaMean[3],anImaStd[3]; + double aCorrSum[3] = { 0,0,0 }; + + ComputeStats(anImageIn,aRect,anImaMean,anImaStd); + double aCount = aRect.height()*aRect.width(); + + for(int y=aRect.top(),t=0;t<aRect.height();y++,t++) + { + const uchar*anIma = anImageIn.scanLine(y); + const uchar*aLogo = mLogo.scanLine(t); + for(int x=aRect.left(),u=0;u<aRect.width();x++,u++) + { + for(int i=0;i<3;i++) + { + aCorrSum[i] += ((anIma[3*x+i]-anImaMean[i])*(aLogo[3*u+i]-mMean[i])); + } + } + } + + double aMin = -1; + for(int i=0;i<3;i++) + { + // Filtrage des plans unis + if(anImaStd[i]<theMinStdDev || mStdDev[i]<theMinStdDev) continue; + aCorrSum[i] /= (aCount*mStdDev[i]*anImaStd[i]); + if(aCorrSum[i]<aMin || aMin == -1) + aMin = aCorrSum[i]; + } + if(aMin>aMax) + aMax = aMin; + } + } + return aMax; +} + +void MainWindow::SetLogo(const QRect &anArea, const QImage &anImage) +{ + mLogo = anImage; + mLogoRect = anArea; + ComputeStats(mLogo,mLogo.rect(),mMean,mStdDev); + int aCount = 0; + for(int i=0;i<3;i++) + { + if(mStdDev[i]<theMinStdDev) aCount++; + } + + if(aCount == 3) + { + Error(tr("Logo too uniform")); + mLogo = QImage(); + mLogoRect = QRect(); + return; + } + + PrintPosition(); + SetLogoState(); + ExtractSegments(); +} + +void MainWindow::ShowNextFrame() +{ + if(IsClosed()) return; + QImage anImage; + if(mDecoderPt->ReadNextImage(anImage,true)) + { + ui->VideoFrame->SetImage(anImage); + PrintPosition(); + } +} + +void MainWindow::FlushAll() +{ + QCoreApplication::processEvents(); + QCoreApplication::sendPostedEvents(); + QCoreApplication::flush(); +} + +const QImage& MainWindow::GetCurrentImage() const +{ + return ui->VideoFrame->GetImage(); +} + +bool MainWindow::ExtractSegments() +{ + const double aCorrelScore = 0.5; + + if(IsClosed() || !HasLogo()) return false; + + ui->RegionList->clear(); + LaunchProcess aProcessDialog(mMarginBefore,mMarginAfter,this); + if(aProcessDialog.exec() == QDialog::Rejected) + return false; + + mMarginBefore = aProcessDialog.GetMarginBefore(); + mMarginAfter = aProcessDialog.GetMarginAfter(); + + mInSlider = true; + + mDecoderPt->Rewind(); + + VPosition anInc = mDecoderPt->GetVPosition(10000); + VPosition aMarginBefore = mDecoderPt->GetVPosition(mMarginBefore); + VPosition aMarginAfter = mDecoderPt->GetVPosition(mMarginAfter); + + int64_t aPos2 = 0; + + VideoSegment aSegment; + int64_t aTickLength = mFileInfo.mLength; + VPosition aPos; + aPos.mMsPos = 0; + bool aInCorrelation = false; + bool aJumpCorrelation = false; + VPosition aFullMargin = aMarginBefore+aMarginAfter+anInc; + + QProgressDialog aProgress(this); + aProgress.setCancelButtonText(tr("Cancel")); + aProgress.setLabelText(tr("Searching...")); + aProgress.setRange(ui->TimeSlider->minimum(),ui->TimeSlider->maximum()); + + for(;aPos.mMsPos < aTickLength;) + { + if(aProgress.wasCanceled()) + break; + + if(aPos2 >= 10) + { + aProgress.setValue(aPos.mMsPos/1000); + FlushAll(); + aPos2 = 0; + } + QImage aNewImage; + if(!mDecoderPt->ReadNextImage(aNewImage,true)) break; + aPos = mDecoderPt->GetPosition(); + aPos2++; + + double aCorrelation = ComputeCorrelation(aNewImage); + if(aCorrelation>=aCorrelScore) + { + if(aInCorrelation && aSegment.IsValid()) + aSegment.mEnd = aPos; // continue la séquence + else + { + // on raffine le début à la trame près + if(!aSegment.IsValid() || aPos>aSegment.mEnd+anInc) + mDecoderPt->SeekFrame(aPos-anInc,FFMPEGDecoder::FRAME_SEEK_SET); + else + mDecoderPt->SeekFrame(aSegment.mEnd,FFMPEGDecoder::FRAME_SEEK_SET); + + // Si par hasard on retombait dans une (ancienne) bonne corrélation, on avance + while(mDecoderPt->ReadNextImage(aNewImage,true) && + ComputeCorrelation(aNewImage)>=aCorrelScore); + + // Puis on cherche le "vrai" début (en espérant qu'il n'y en ait pas 36 entre les deux...) + while(ComputeCorrelation(aNewImage)<aCorrelScore && + mDecoderPt->ReadNextImage(aNewImage,true)); + + aPos = mDecoderPt->GetPosition(); + + if(aSegment.IsValid()) + { + if(aPos>aSegment.mEnd+aFullMargin) + { + if(aSegment.GetLength()>anInc.mMsPos) + { + aSegment.mBegin -= aMarginBefore; + aSegment.mEnd += aMarginAfter; + new VideoSegmentListItem(aSegment,ui->RegionList); + } + aSegment.Clear(); // On recommence un nouveau segment + } + else + { + aSegment.mEnd = aPos; + } + } + + if(!aSegment.IsValid()) + { + aSegment.mBegin = aPos; + aSegment.mEnd = aPos+mDecoderPt->GetVPosition(1); + } + } + aInCorrelation = true; + aJumpCorrelation = false; + } + else + { + if(aInCorrelation && aSegment.IsValid() && !aJumpCorrelation) + { + if(aPos>aSegment.mEnd+anInc) + mDecoderPt->SeekFrame(aSegment.mEnd-anInc,FFMPEGDecoder::FRAME_SEEK_SET); + else + mDecoderPt->SeekFrame(aSegment.mEnd,FFMPEGDecoder::FRAME_SEEK_SET); + + while(mDecoderPt->ReadNextImage(aNewImage,true) && + ComputeCorrelation(aNewImage)>=aCorrelScore); + aPos = mDecoderPt->GetPosition(); + aSegment.mEnd = aPos; + double aScore = -1; + // Verif qu'on a rien dans l'intervalle qui suit + while(mDecoderPt->ReadNextImage(aNewImage,true) && + (aPos-aSegment.mEnd)<anInc && aScore<aCorrelScore) + { + aScore=ComputeCorrelation(aNewImage); + aPos = mDecoderPt->GetPosition(); + } + + if(aScore>=aCorrelScore) + { + aSegment.mEnd = aPos; + aInCorrelation = true; + aJumpCorrelation = true; + } + else + aInCorrelation = false; + } + else + aInCorrelation = false; + } + + if(!mDecoderPt->SeekFrame(anInc,FFMPEGDecoder::FRAME_SEEK_CUR)) break; + } + + if(aSegment.IsValid()) + new VideoSegmentListItem(aSegment,ui->RegionList); + + + mInSlider = false; + + if(ui->RegionList->count()>0) + SetDetectedState(); + + return true; +} + +void MainWindow::Rewind() +{ + if(!mDecoderPt) return; + mDecoderPt->Rewind(); + ShowNextFrame(); +} + + +/*=============================================================== +Toutes les callbacks IHM Qt +=================================================================*/ +void MainWindow::on_actionQuitter_triggered() +{ + QCoreApplication * anApptPt = QCoreApplication::instance (); + anApptPt->exit(); +} + +void MainWindow::on_actionOuvrir_triggered() +{ + QString aFileName = QFileDialog::getOpenFileName(this, + tr("Open video file"), + mInputFileName, + tr("MPEG stream files (*.ts)")); + Open(aFileName); + +} + +void MainWindow::on_actionDetect_Segments_triggered() +{ + ExtractSegments(); +} + +void MainWindow::on_GotoBeginBt_clicked() +{ + VideoSegment aSegment; + if(!ui->RegionList->GetSelection(aSegment)) return; + + mDecoderPt->SeekPosition(aSegment.mBegin.mFilePos); + ShowNextFrame(); +} + +void MainWindow::on_GoToEndBt_clicked() +{ + VideoSegment aSegment; + if(!ui->RegionList->GetSelection(aSegment)) return; + + mDecoderPt->SeekPosition(aSegment.mEnd.mFilePos); + ShowNextFrame(); +} + +void MainWindow::on_actionSave_selection_triggered() +{ + if(!mDecoderPt) return; + + QList<VideoSegment> aList = ui->RegionList->GetSelectedItems(); + if(aList.empty()) return; + + QFile aFile(mLastOutputFile); + FileNameString aFileNameString = mLastOutputFile.toStdString(); + + int i = 0; + while(aFile.exists()) + aFile.setFileName(aFileNameString.GetPath(i++)); + + QString aFileName = QFileDialog::getSaveFileName(this, + tr("OuputFileName"), + aFile.fileName(), + tr("Video stream (*.ts)")); + if(aFileName.isEmpty()) return; + + aFile.setFileName(aFileName); + + mLastOutputFile = aFile.fileName(); + + + FileCopier aCopier; + + if(!aCopier.Open(mInputFileName,mLastOutputFile)) + { + Error(tr("Impossible to open output file")); + return; + } + + QProgressDialog aProgress(this); + aProgress.setCancelButtonText(tr("Cancel")); + + QList<VideoSegment>::iterator anIter; + for(anIter = aList.begin(); + anIter != aList.end(); + anIter++) + { + VideoSegment&aSegment = (*anIter); + + aProgress.setLabelText(QString("%1%2").arg(tr("Saving segment ")).arg(aSegment.GetString())); + aProgress.setRange(aSegment.mBegin.mFilePos,aSegment.mEnd.mFilePos); + + if(!aCopier.Write(aSegment,&aProgress)) + { + Error(tr("Saving interrupted")); + break; + } + } +} + +void MainWindow::on_RegionList_itemSelectionChanged() +{ + QList<VideoSegment> aList = ui->RegionList->GetSelectedItems(); + int64_t aLength = 0; + QList<VideoSegment>::iterator anIter; + for(anIter = aList.begin(); + anIter != aList.end(); + anIter++) + { + VideoSegment&aSegment = (*anIter); + aLength += aSegment.GetLength(); + } + if(aLength>0) + { + QString aString = QString("%1%2").arg(tr("Selection :")).arg(std::MsToString(aLength)); + mSelLabel->setText(aString); + SetSaveState(true); + } + else + { + SetSaveState(false); + mSelLabel->setText(tr("No selection")); + } +} + +void MainWindow::dropEvent(QDropEvent *event) +{ + const QMimeData *mimeData = event->mimeData(); + QUrl anURL = mimeData->urls().front(); + + Close(); + QString aString = anURL.toLocalFile(); + Open(aString); +} + +void MainWindow::dragEnterEvent(QDragEnterEvent *event) +{ + const QMimeData *mimeData = event->mimeData(); + + if(mimeData->hasUrls()) + { + QUrl anURL = mimeData->urls().front(); + QString aString = anURL.toLocalFile(); + FileNameString aFNS = aString.toAscii().data(); + if(aFNS.TestExtension("ts")) + event->acceptProposedAction(); + } +} + +void MainWindow::on_TimeSlider_valueChanged(int aValue) +{ + if(!mDecoderPt || mInSlider) return; + + int64_t aMSValue = aValue*1000; + if(mDecoderPt->SeekFrame(aMSValue,FFMPEGDecoder::FRAME_SEEK_SET)) + ShowNextFrame(); + else Error(tr("Impossible to seek in video")); + +} + +void MainWindow::on_PrevButton_clicked() +{ + int64_t aDeltaMSValue = -500; + int64_t aPos = mDecoderPt->GetMSPosition(); + +FFWD_AGAIN: + if(!mDecoderPt->SeekFrame(aDeltaMSValue,FFMPEGDecoder::FRAME_SEEK_CUR)) return; + + QImage anImage; + if(!mDecoderPt->ReadNextImage(anImage,true)) return; + + if(mDecoderPt->GetMSPosition() >= aPos && aPos>-aDeltaMSValue) + { + aDeltaMSValue -= 250; + goto FFWD_AGAIN; + } + else + { + ui->VideoFrame->SetImage(anImage); + PrintPosition(); + } +} + +void MainWindow::on_FastPrevButton_clicked() +{ + int64_t aDeltaMSValue = -10000; + + int64_t aPos = mDecoderPt->GetMSPosition(); + +FFWD_AGAIN: + if(!mDecoderPt->SeekFrame(aDeltaMSValue,FFMPEGDecoder::FRAME_SEEK_CUR)) return; + ShowNextFrame(); + if(mDecoderPt->GetMSPosition() >= aPos && aPos>-aDeltaMSValue) + { + aDeltaMSValue -= 10000; + goto FFWD_AGAIN; + } +} + +void MainWindow::on_FastNextButton_clicked() +{ + const int64_t aDeltaMSValue = 10000; + mDecoderPt->SeekFrame(aDeltaMSValue,FFMPEGDecoder::FRAME_SEEK_CUR); + ShowNextFrame(); +} + +void MainWindow::on_NextButton_clicked() +{ + ShowNextFrame(); +} + +void MainWindow::on_MergeBt_clicked() +{ + ui->RegionList->MergeSelection(); +} + +void MainWindow::on_DeleteBt_clicked() +{ + ui->RegionList->DeleteSelection(); +} + +void MainWindow::on_SetBeginBt_clicked() +{ + VPosition aPos = mDecoderPt->GetPosition(); + ui->RegionList->SetSelectionBegin(aPos); +} + +void MainWindow::on_SetEndBt_clicked() +{ + VPosition aPos = mDecoderPt->GetPosition(); + ui->RegionList->SetSelectionEnd(aPos); +} + +void MainWindow::on_AddBt_clicked() +{ + VPosition aPos = mDecoderPt->GetPosition(); + VPosition anEnd = aPos+mDecoderPt->GetVPosition(1000); + ui->RegionList->AddNewRegion(aPos,anEnd); +} + +void MainWindow::SaveSettings() +{ + QSettings aSet(QSettings::IniFormat,QSettings::UserScope,"Arthelion","VidePub"); + + aSet.setValue("Version",1); + aSet.setValue("LastInputFile",mInputFileName); + aSet.setValue("LastOutputFile",mLastOutputFile); + aSet.setValue("MarginBefore",mMarginBefore); + aSet.setValue("MarginAfter",mMarginAfter); +} + +void MainWindow::ReadSettings() +{ + QSettings aSet(QSettings::IniFormat,QSettings::UserScope,"Arthelion","VidePub"); + QFile aFile(aSet.fileName()); + if(!aFile.exists()) return; + + mInputFileName = aSet.value("LastInputFile").toString(); + mLastOutputFile = aSet.value("LastOutputFile").toString(); + mMarginBefore = aSet.value("MarginBefore").toInt(); + mMarginAfter = aSet.value("MarginAfter").toInt(); +} + +void MainWindow::on_NextLogoOn_clicked() +{ + if(!mDecoderPt || !HasLogo()) return; + const double aCorrelScore = 0.4; + + QProgressDialog aProgress(this); + aProgress.setCancelButtonText(tr("Cancel")); + aProgress.setLabelText(tr("Searching...")); + aProgress.setRange(ui->TimeSlider->value(),ui->TimeSlider->maximum()); + FlushAll(); + + QImage anImage; + int i=150; + + while(mDecoderPt->ReadNextImage(anImage,true) && + ComputeCorrelation(anImage)<aCorrelScore) + { + i++; + aProgress.setValue(mDecoderPt->GetMSPosition()*1000); + if(i==300) + { + FlushAll(); + if(aProgress.wasCanceled()) break; + i=0; + } + } + + + ui->VideoFrame->SetImage(anImage); + PrintPosition(); +} + +void MainWindow::on_NextLogoOff_clicked() +{ + if(!mDecoderPt || !HasLogo()) return; + const double aCorrelScore = 0.4; + + QProgressDialog aProgress(this); + aProgress.setCancelButtonText(tr("Cancel")); + aProgress.setLabelText(tr("Searching...")); + aProgress.setRange(ui->TimeSlider->value(),ui->TimeSlider->maximum()); + FlushAll(); + + QImage anImage; + int i=150; + + while(mDecoderPt->ReadNextImage(anImage,true) && + ComputeCorrelation(anImage)>=aCorrelScore) + { + i++; + aProgress.setValue(mDecoderPt->GetMSPosition()*1000); + if(i==300) + { + FlushAll(); + if(aProgress.wasCanceled()) break; + i=0; + } + } + + + ui->VideoFrame->SetImage(anImage); + PrintPosition(); +} + +void MainWindow::on_actionAbout_VidePub_triggered() +{ + About anAbout(this); + anAbout.exec(); +}